设计部要求背景实现一个背景边框带圆弧的效果:
所以想着用自定义控件画一个背景。
为了方便,继承的是LinearLayout,在onMeasure中先获取控件宽高:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int measuredWidth = 0; int measuredHeight = 0; final int childCount = getChildCount(); measureChildren(widthMeasureSpec, heightMeasureSpec); int widthSpaceSize = MeasureSpec.getSize(widthMeasureSpec); int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); int heightSpaceSize = MeasureSpec.getSize(heightMeasureSpec); int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); if (childCount == 0) { setMeasuredDimension(0, 0); } else if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) { final View childView = getChildAt(0); measuredWidth = childView.getMeasuredWidth() * childCount; measuredHeight = childView.getMeasuredHeight(); setMeasuredDimension(measuredWidth, measuredHeight); } else if (heightSpecMode == MeasureSpec.AT_MOST) { final View childView = getChildAt(0); measuredHeight = childView.getMeasuredHeight(); setMeasuredDimension(widthSpaceSize, childView.getMeasuredHeight()); } else if (widthSpecMode == MeasureSpec.AT_MOST) { final View childView = getChildAt(0); measuredWidth = childView.getMeasuredWidth() * childCount; setMeasuredDimension(measuredWidth, heightSpaceSize); } mWidthMode = measuredWidth; mHeightMode = measuredHeight; Log.i("yan", "高度:" + mWidthMode + "宽度:" + mHeightMode); }
因为是viewgroup,所以给控件绘图的方法写在dispatchDraw方法中
@Override protected void dispatchDraw(Canvas canvas) { initDrawBg(canvas);//放在super前是后景,相反是前景,前景会覆盖子布局 super.dispatchDraw(canvas); }
用path画出路径,然后用paint填充。
private void initDrawBg(Canvas canvas) { canvas.drawColor(Color.parseColor("#00FFFFFF"));//绘制透明色 int size = 26; mPaint = new Paint(); mpath = new Path(); mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(Color.WHITE); mPaint.setAntiAlias(true); mpath.lineTo(mWidthMode - size, 0); RectF rectF1 = new RectF(mWidthMode - size, -size, mWidthMode + size, size); mpath.arcTo(rectF1, -180, -90); mpath.lineTo(mWidthMode, mHeightMode - size); RectF rectF2 = new RectF(mWidthMode - size, mHeightMode - size, mWidthMode + size, mHeightMode + size); mpath.arcTo(rectF2, -90, -90); mpath.lineTo(size, mHeightMode); RectF rectF3 = new RectF(-size, mHeightMode - size, size, mHeightMode + size); mpath.arcTo(rectF3, 0, -90); mpath.lineTo(0, size); RectF rectF4 = new RectF(-size, -size, size, size); mpath.arcTo(rectF4, -270, -90); mpath.lineTo(size, 0); mpath.close(); canvas.drawPath(mpath, mPaint); }
addArc和arcTo都是添加圆弧到path中,不过他们之间还是有区别的:addArc是直接添加圆弧到path中,而arcTo会判断要绘制圆弧的起点与绘制圆弧之前path中最后的点是否是同一个点,如果不是同一个点的话,就会连接两个点。使用accTo可让白色填充。
完整代码 :
package com.example.myapplication.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.RectF; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.LinearLayout; /** * 反圆角 */ public class BGRelactLayout extends LinearLayout { private int mWidthMode; private int mHeightMode; private Paint mPaint; private Path mpath; public BGRelactLayout(Context context) { super(context); } public BGRelactLayout(Context context, AttributeSet attrs) { super(context, attrs); } public BGRelactLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); Log.i("yan", w + "," + h + "," + oldw + "," + oldh); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int measuredWidth = 0; int measuredHeight = 0; final int childCount = getChildCount(); measureChildren(widthMeasureSpec, heightMeasureSpec); int widthSpaceSize = MeasureSpec.getSize(widthMeasureSpec); int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); int heightSpaceSize = MeasureSpec.getSize(heightMeasureSpec); int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); if (childCount == 0) { setMeasuredDimension(0, 0); } else if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) { final View childView = getChildAt(0); measuredWidth = childView.getMeasuredWidth() * childCount; measuredHeight = childView.getMeasuredHeight(); setMeasuredDimension(measuredWidth, measuredHeight); } else if (heightSpecMode == MeasureSpec.AT_MOST) { final View childView = getChildAt(0); measuredHeight = childView.getMeasuredHeight(); setMeasuredDimension(widthSpaceSize, childView.getMeasuredHeight()); } else if (widthSpecMode == MeasureSpec.AT_MOST) { final View childView = getChildAt(0); measuredWidth = childView.getMeasuredWidth() * childCount; setMeasuredDimension(measuredWidth, heightSpaceSize); } mWidthMode = measuredWidth; mHeightMode = measuredHeight; Log.i("yan", "高度:" + mWidthMode + "宽度:" + mHeightMode); } @Override protected void dispatchDraw(Canvas canvas) { initDrawBg(canvas);//放在super前是后景,相反是前景,前景会覆盖子布局 super.dispatchDraw(canvas); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); } private void initDrawBg(Canvas canvas) { canvas.drawColor(Color.parseColor("#00FFFFFF"));//绘制透明色 int size = 26; mPaint = new Paint(); mpath = new Path(); mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(Color.WHITE); mPaint.setAntiAlias(true); mpath.lineTo(mWidthMode - size, 0); RectF rectF1 = new RectF(mWidthMode - size, -size, mWidthMode + size, size); mpath.arcTo(rectF1, -180, -90); mpath.lineTo(mWidthMode, mHeightMode - size); RectF rectF2 = new RectF(mWidthMode - size, mHeightMode - size, mWidthMode + size, mHeightMode + size); mpath.arcTo(rectF2, -90, -90); mpath.lineTo(size, mHeightMode); RectF rectF3 = new RectF(-size, mHeightMode - size, size, mHeightMode + size); mpath.arcTo(rectF3, 0, -90); mpath.lineTo(0, size); RectF rectF4 = new RectF(-size, -size, size, size); mpath.arcTo(rectF4, -270, -90); mpath.lineTo(size, 0); mpath.close(); canvas.drawPath(mpath, mPaint); } }