android不规则图形控件显示背景图片以及点击效果,多边形控件实例
我们在开发应用的过程中,经常会遇见美术突发奇想,给你来个狂拽酷炫效果的情况。下面我们就来说一下多边形控件,以及他的点击。
先上图
一、首先定义各种图形
1.菱形
public class DiamondView extends ImageView { private Context mContext; private int mWidth; private int mHeight; // 以上方角点所在的点位置为模式名 public static final int TYPE_LEFT_TOP = 0; private int mMode; private int mColor; private String mText; // 四个点的顺序,从leftTop开始计算,顺时针数过去,依次四个点 private int mPointOne[]; private int mPointTwo[]; private int mPointThree[]; private int mPointFour[]; private Path mPath; private Paint mPaint; private boolean isClicked = false; //是否被按下 public DiamondView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; mPath = new Path(); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mColor = Color.parseColor("#FFFFFF"); mPaint.setColor(mColor); } public void setMode(int model) { mMode = model; postInvalidate(); } public void setColor(int color) { mColor = color; postInvalidate(); } public void setText(String text) { mText = text; } @Override protected void onDraw(Canvas canvas) { canvas.clipPath(mPath, Region.Op.INTERSECT); super.onDraw(canvas); if(!isClicked) { mPaint.setColor(Color.argb(180, 0, 0, 0)); canvas.drawPath(mPath, mPaint); } if(mText != null) { mPaint.setFakeBoldText(true); mPaint.setTextSize(sp2px(mContext,13)); mPaint.setColor(mColor); float tw = mPaint.measureText(mText); float th = mPaint.measureText(mText)/mText.length(); switch (mMode) { case TYPE_LEFT_TOP: canvas.drawText(mText, (mWidth - tw)/2f, (mHeight+th)/2f, mPaint); break; } } } @Override protected void onSizeChanged(int width, int height, int oldw, int oldh) { super.onSizeChanged(width, height, oldw, oldh); mWidth = width; mHeight = height; switch (mMode) { case TYPE_LEFT_TOP: mPointOne = new int[] { 0, 0 }; mPointTwo = new int[] { width*140/250, 0 }; mPointThree = new int[] { width, height }; mPointFour = new int[] { width*110/250, height }; break; } if (null != mPointOne) { mPath.moveTo(mPointOne[0], mPointOne[1]); mPath.lineTo(mPointTwo[0], mPointTwo[1]); mPath.lineTo(mPointThree[0], mPointThree[1]); mPath.lineTo(mPointFour[0], mPointFour[1]); mPath.close(); } } @Override public boolean onTouchEvent(MotionEvent event) { RectF bounds = new RectF(); mPath.computeBounds(bounds, true); Region region = new Region(); region.setPath(mPath, new Region((int)bounds.left, (int)bounds.top,(int)bounds.right, (int)bounds.bottom)); boolean ct = region.contains((int)event.getX(), (int)event.getY()); if(event.getAction() == MotionEvent.ACTION_DOWN){ if(ct){ isClicked = true; invalidate(); return true; } return false; }else if(event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL){ if(isClicked){ isClicked = false; invalidate(); if (null != mOnClickListener && ct && event.getAction() != MotionEvent.ACTION_CANCEL) { mOnClickListener.onClick(this); return true; } } return false; }else if(event.getAction() == MotionEvent.ACTION_MOVE){ return isClicked; } return super.onTouchEvent(event); } private OnClickListener mOnClickListener; public void setOnViewClickListener(OnClickListener clickListener){ mOnClickListener = clickListener; } //计算两点的距离 private int distance(PointF point1, PointF point2) { int disX = (int) Math.abs(point1.x - point2.x); int disY = (int) Math.abs(point1.y - point2.y); return (int) Math.sqrt(Math.pow(disX, 2) + Math.pow(disY, 2)); } //将sp值转换为px值,保证文字大小不变 public static int sp2px(Context context, float spValue) { final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; return (int) (spValue * fontScale + 0.5f); }
}
绘制图形主要依靠Path来定义四个点,围成一个菱形。在ondraw的时候再调用
canvas.clipPath(mPath, Region.Op.INTERSECT);来切割画布,使得图片显示范围也在菱形内。
点击的时候靠的是Region 和path配合使用,判断点击的点是否在path勾勒的范围内,从而控制触摸事件。
除了菱形以外,还有其他的形状的类,代码太多不一一列举,文章结尾会附带完整项目包。
各种形状定义好之后就是排布
先写在xml布局文件中
<com.example.lupingshenqi.QiQiaoLayout android:id="@+id/activity_main_qiqiaolayout" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" android:padding="10dp"> <com.example.lupingshenqi.TriangleView android:id="@+id/classify_1" android:layout_width="100dp" android:layout_height="100dp" /> <com.example.lupingshenqi.TriangleView android:id="@+id/classify_2" android:layout_width="100dp" android:layout_height="100dp" /> <com.example.lupingshenqi.TriangleView android:id="@+id/classify_3" android:layout_width="100dp" android:layout_height="100dp" /> <com.example.lupingshenqi.DiamondView android:id="@+id/classify_4" android:layout_width="100dp" android:layout_height="100dp" /> <com.example.lupingshenqi.TriangleView android:id="@+id/classify_5" android:layout_width="100dp" android:layout_height="100dp" /> <com.example.lupingshenqi.SquareView android:id="@+id/classify_6" android:layout_width="100dp" android:layout_height="100dp" /> <com.example.lupingshenqi.TriangleView android:id="@+id/classify_7" android:layout_width="100dp" android:layout_height="100dp" /> <com.example.lupingshenqi.TriangleView android:id="@+id/classify_8" android:layout_width="100dp" android:layout_height="100dp" /> </com.example.lupingshenqi.QiQiaoLayout>
然后是在onSizeChanged的时候进行重新排布
public class QiQiaoLayout extends RelativeLayout{ private ArrayList<CategoryBean> mClassifyList = new ArrayList<>(); public QiQiaoLayout(Context context, AttributeSet attrs) { super(context, attrs); } public void setDate(ArrayList<CategoryBean> list){ mClassifyList.clear(); if(list!=null){ mClassifyList.addAll(list); } if(mClassifyList!=null){ for (int i=0;i<mClassifyList.size() && i<getChildCount();i++) { CategoryBean bean = mClassifyList.get(i); if(getChildAt(i) instanceof TriangleView){ TriangleView view = (TriangleView)getChildAt(i); GlideImageLoadUtils.displayImage(getContext(), bean.categoryIconUrl, view, GlideImageLoadUtils.getIconNormalOptions()); view.setText(bean.categoryName); view.setOnViewClickListener(new OnClickListener() { @Override public void onClick(View view) { Toast.makeText(getContext(),"点击了按钮!",Toast.LENGTH_SHORT).show(); } }); }else if(getChildAt(i) instanceof DiamondView) { DiamondView view = (DiamondView)getChildAt(i); GlideImageLoadUtils.displayImage(getContext(), bean.categoryIconUrl, view, GlideImageLoadUtils.getIconNormalOptions()); view.setText(bean.categoryName); view.setOnViewClickListener(new OnClickListener() { @Override public void onClick(View view) { Toast.makeText(getContext(),"点击了按钮!",Toast.LENGTH_SHORT).show(); } }); }else if(getChildAt(i) instanceof SquareView) { SquareView view = (SquareView)getChildAt(i); GlideImageLoadUtils.displayImage(getContext(), bean.categoryIconUrl, view, GlideImageLoadUtils.getIconNormalOptions()); view.setText(bean.categoryName); view.setOnViewClickListener(new OnClickListener() { @Override public void onClick(View view) { Toast.makeText(getContext(),"点击了按钮!",Toast.LENGTH_SHORT).show(); } }); } } } postInvalidate(); } @Override protected void onFinishInflate() { super.onFinishInflate(); TriangleView mClassifyView1 = (TriangleView) findViewById(R.id.classify_1); mClassifyView1.setMode(TriangleView.TYPE_LEFT_TOP); TriangleView mClassifyView2 = (TriangleView) findViewById(R.id.classify_2); mClassifyView2.setMode(TriangleView.TYPE_RIGHT_BOTTOM); TriangleView mClassifyView3 = (TriangleView) findViewById(R.id.classify_3); mClassifyView3.setMode(TriangleView.TYPE_RIGHT_MIDDLE); DiamondView mClassifyView4 = (DiamondView) findViewById(R.id.classify_4); mClassifyView4.setMode(DiamondView.TYPE_LEFT_TOP); TriangleView mClassifyView5 = (TriangleView) findViewById(R.id.classify_5); mClassifyView5.setMode(TriangleView.TYPE_RIGHT_BOTTOM_SMAILL); SquareView mClassifyView6 = (SquareView) findViewById(R.id.classify_6); TriangleView mClassifyView7 = (TriangleView) findViewById(R.id.classify_7); mClassifyView7.setMode(TriangleView.TYPE_LEFT_BOTTOM); TriangleView mClassifyView8 = (TriangleView) findViewById(R.id.classify_8); mClassifyView8.setMode(TriangleView.TYPE_RIGHT_TOP); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); w = w - getPaddingRight() - getPaddingLeft(); float scale = w/660f; QiQiaoLayout.LayoutParams params = new QiQiaoLayout.LayoutParams((int)(230*scale),(int)(230*scale)); params.setMargins(0,0,(int)(10*scale),(int)(10*scale)); getChildAt(0).setLayoutParams(params); params = new QiQiaoLayout.LayoutParams((int)(230*scale),(int)(230*scale)); params.setMargins((int)(10*scale),(int)(10*scale),0,0); getChildAt(1).setLayoutParams(params); params = new QiQiaoLayout.LayoutParams((int)(120*scale),(int)(240*scale)); params.setMargins((int)(253*scale),0,0,0); getChildAt(2).setLayoutParams(params); params = new QiQiaoLayout.LayoutParams((int)(250*scale),(int)(110*scale)); params.setMargins((int)(270*scale),0,0,(int)(10*scale)); getChildAt(3).setLayoutParams(params); params = new QiQiaoLayout.LayoutParams((int)(120*scale),(int)(120*scale)); params.setMargins((int)(270*scale),(int)(120*scale),0,0); getChildAt(4).setLayoutParams(params); params = new QiQiaoLayout.LayoutParams((int)(120*scale),(int)(120*scale)); params.setMargins((int)(400*scale),(int)(120*scale),0,0); getChildAt(5).setLayoutParams(params); params = new QiQiaoLayout.LayoutParams((int)(120*scale),(int)(120*scale)); params.setMargins((int)(530*scale),(int)(120*scale),0,0); getChildAt(6).setLayoutParams(params); params = new QiQiaoLayout.LayoutParams((int)(230*scale),(int)(230*scale)); params.setMargins((int)(430*scale),0,0,0); getChildAt(7).setLayoutParams(params); }
话不多说,看整个项目的代码更容易明白,项目地址是
https://pan.baidu.com/s/1bFvakI