android自定義viewgroup畫背景
阿新 • • 發佈:2019-04-20
設計部要求背景實現一個背景邊框帶圓弧的效果:
所以想著用自定義控制元件畫一個背景。
為了方便,繼承的是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,