1. 程式人生 > >android自定義viewgroup畫背景

android自定義viewgroup畫背景

設計部要求背景實現一個背景邊框帶圓弧的效果:

所以想著用自定義控制元件畫一個背景。

為了方便,繼承的是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,