自定义View之案列篇(一):鞭炮
licqi
8年前
<p>老规矩,先来看看类似过年放的鞭炮的效果图:</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/cc69adbc38e524c8efeb36cc5c4901d5.png"></p> <p style="text-align: center;">block</p> <p>学习博客也是学习一种变通的思想,能够举一反三,才能掌握真正的精髓。</p> <p>这里留下一个小小的挑战:</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/9507b725df21922555398771998c5330.png"></p> <p style="text-align: center;">block</p> <p>怎么获取菱形区域的点击事件?欢迎留言,欢迎讨论,谢谢。</p> <p>我临时的处理方法是以菱形的内切圆来处理点击事情的。</p> <h3>鞭炮布局(BlockFrameLayout)</h3> <p>分析效果图,可以看出魔方布局是由一块块小的菱形按照某种规律组合而成的,我们这里以繁化简,先来看看一块小的菱形:</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/162526dc18159088d85a7ab00ace83b2.png"></p> <p style="text-align: center;">block</p> <p>接着看看三块菱形组成的图案:</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/772f0440516000ad3488c573afaceed9.png"></p> <p style="text-align: center;">block</p> <p>看看最后的效果图:</p> <p style="text-align: center;"><img src="https://simg.open-open.com/show/54f1e0899b453f8cf1b4dad53b49d41d.png"></p> <p style="text-align: center;">block</p> <p>是不是已经发现规律了啊?对的,以三块菱形为一组,从上往下就组成了最终的图案。</p> <p>核心思想:分析前三块菱形和后三块菱形的坐标变化。</p> <p>相信你已经找到了:</p> <pre> if ((i + 1) % 3 == 1) { //第一块 startX = getWidth() / 2 - mChildSize / 2; startY = mChildSize * bulge; } else if ((i + 1) % 3 == 2) { //第二块 startX = getWidth() / 2 - mChildSize; startY = mChildSize * bulge + mChildSize / 2; } else if ((i + 1) % 3 == 0) { //第三块 startX = getWidth() / 2; startY = mChildSize * bulge + mChildSize / 2; bulge++; }</pre> <p>那么 onLayout 方法:</p> <pre> final int childCount = getChildCount(); int startX = 0; int startY = 0; int bulge = 0; for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); if (childView.getVisibility() == GONE) { continue; } if ((i + 1) % 3 == 1) { startX = getWidth() / 2 - mChildSize / 2; startY = mChildSize * bulge; } else if ((i + 1) % 3 == 2) { startX = getWidth() / 2 - mChildSize; startY = mChildSize * bulge + mChildSize / 2; } else if ((i + 1) % 3 == 0) { startX = getWidth() / 2; startY = mChildSize * bulge + mChildSize / 2; bulge++; } childView.layout(startX, startY, startX + mChildSize, startY + mChildSize); }</pre> <p>如果对于自定义 ViewGroup 流程有什么疑问的童鞋,请查看我自定义系类前面的几篇博客。</p> <h3>菱形(BlockView )</h3> <p>BlockView 类比较简单,我这里就直接贴出代码,有什么疑问的请留言,会第一时间给你回复。</p> <pre> package com.github.blockdemo.widget; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; /** * Created by Administrator on 10/17 0017. */ public class BlockView extends View { private Context mContext; private Paint mPaint; private Paint mTextPaint; private Path mPath; private String mText; private Paint.FontMetrics mMetrics; private OnClickListener mOnClickListener; private boolean mClickEnable = true; public BlockView(Context context) { this(context, null); } public BlockView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public BlockView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mContext = context; mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(Color.parseColor("#3F51B5")); mTextPaint = new Paint(); mTextPaint.setAntiAlias(true); mTextPaint.setStyle(Paint.Style.FILL); mTextPaint.setColor(Color.parseColor("#FFFFFF")); mPath = new Path(); mText = "8"; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPath.reset(); mPath.moveTo(getWidth() / 2, 0); mPath.lineTo(0, getHeight() / 2); mPath.lineTo(getWidth() / 2, getHeight()); mPath.lineTo(getWidth(), getHeight() / 2); mPath.close(); canvas.drawPath(mPath, mPaint); mTextPaint.setTextSize(getWidth() / 4); mMetrics = mTextPaint.getFontMetrics(); mTextPaint.setTextAlign(Paint.Align.CENTER); canvas.drawText(mText, getWidth() / 2, getHeight() / 2 + (mMetrics.bottom - mMetrics.top) / 2 - mMetrics.bottom, mTextPaint); } public void setPaintColor(int... colors) { if (colors != null) mPaint.setColor(colors[0]); } public void setText(String text) { mText = text; } public int dip2px(float dpValue) { final float scale = mContext.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: float x = event.getX(); float y = event.getY(); int centerX = getWidth() / 2; int centerY = getHeight() / 2; //注意下这里以菱形的内切圆来处理点击事件,如果你有什么好的方案请留言 if ((centerX - x) * (centerX - x) + (centerY - y) * (centerY - y) <= getWidth() * getWidth() / 8) { if (mOnClickListener != null && mClickEnable) { mOnClickListener.BlockOnClickListener(mText); mClickEnable = false; } } break; case MotionEvent.ACTION_UP: mClickEnable = true; break; default: break; } return true; } public interface OnClickListener { void BlockOnClickListener(String text); } public void setBlockOnClickListener(OnClickListener onClickListener) { this.mOnClickListener = onClickListener; } }</pre> <p> </p> <p> </p> <p> </p>