设计部要求背景实现一个背景边框带圆弧的效果:android自定义viewgroup画背景-LMLPHP

所以想着用自定义控件画一个背景。

为了方便,继承的是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);
    }
}
04-21 07:41