天天看點

圓角矩形圓形圖檔簡單解決方案

一個圓角圖檔的解決方案,解決設計需要不同圓角圖檔時,避免重複讓設計師出不一樣的切圖。

廢話不多說,先上效果圖:

圓角矩形圓形圖檔簡單解決方案
屬性介紹
參數 屬性 介紹
round_rect_circle boolean 是否顯示圓形
round_rect_corner int 圓角大小
round_rect_corner_top_to_left int 左上角圓弧
round_rect_corner_top_to_right int 右上角圓弧
round_rect_corner_bottom_to_left int 左下角圓弧
round_rect_corner_bottom_to_right int 右下角圓弧
round_rect_stroke_color int 描邊顔色
round_rect_stroke_width int 描邊大小

* round_rect_circle:預設false,如果是true,直接繪制圓形。

* round_rect_corner:四個角圓弧屬性,預設為0。

* round_rect_corner_top_to_left:左上角圓弧,如果設定了該屬性,round_rect_corner的左上角設定不起作用。

* round_rect_corner_top_to_right:右上角圓弧,如果設定了該屬性,round_rect_corner的右上角設定不起作用。

* round_rect_corner_bottom_to_left:左下角圓弧,如果設定了該屬性,round_rect_corner的左下角設定不起作用。

* round_rect_corner_bottom_to_right:右下角圓弧,如果設定了該屬性,round_rect_corner的右下角設定不起作用。

* round_rect_stroke_color:描邊的顔色,預設是白色。

* round_rect_stroke_width:圓弧的描邊,預設描邊的寬度是0。

實作思路

先上完整代碼:

首先先定義圓角圖形所需要的屬性:

<declare-styleable name="RoundRectLayout">
        <attr name="round_rect_circle" format="boolean"/>
        <attr name="round_rect_corner" format="dimension"/>
        <attr name="round_rect_corner_top_to_left" format="dimension"/>
        <attr name="round_rect_corner_top_to_right" format="dimension"/>
        <attr name="round_rect_corner_bottom_to_left" format="dimension"/>
        <attr name="round_rect_corner_bottom_to_right" format="dimension"/>
        <attr name="round_rect_stroke_color" format="color"/>
        <attr name="round_rect_stroke_width" format="dimension"/>
    </declare-styleable>
           

然後在定義一個RoundRectLayout繼承RelativeLayout:完整代碼如下:

ublic class RoundRectLayout extends RelativeLayout {

    private RectF mRectF;//繪制畫布的大小
    public float[] mRadii = new float[];//繪制眼角矩形所需的8個角
    private boolean mCircle;//是否是繪制圓形
    private int mRectCorner; //圓角弧度
    private int mStrokeColor;// 描邊顔色
    private int mStrokeWidth;// 描邊寬度

    public RoundRectLayout(Context context) {
        this(context, null);
    }

    public RoundRectLayout(Context context, AttributeSet attrs) {
        this(context, attrs, );
    }

    public RoundRectLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context, attrs);
    }

    private void initView(Context context, AttributeSet attrs) {
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.RoundRectLayout);
        mCircle = array.getBoolean(R.styleable.RoundRectLayout_round_rect_circle, false);
        mRectCorner = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner, );
        int roundRectTopLeft = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner_top_to_left, -);
        int roundRectTopRight = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner_top_to_right, -);
        int roundRectBottomLeft = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner_bottom_to_left, -);
        int roundRectBottomRight = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner_bottom_to_right, -);

        mRadii[] = roundRectTopLeft == - ? mRectCorner : roundRectTopLeft;
        mRadii[] = roundRectTopLeft == - ? mRectCorner : roundRectTopLeft;
        mRadii[] = roundRectTopRight == - ? mRectCorner : roundRectTopRight;
        mRadii[] = roundRectTopRight == - ? mRectCorner : roundRectTopRight;
        mRadii[] = roundRectBottomLeft == - ? mRectCorner : roundRectBottomLeft;
        mRadii[] = roundRectBottomLeft == - ? mRectCorner : roundRectBottomLeft;
        mRadii[] = roundRectBottomRight == - ? mRectCorner : roundRectBottomRight;
        mRadii[] = roundRectBottomRight == - ? mRectCorner : roundRectBottomRight;

        mStrokeColor = array.getColor(R.styleable.RoundRectLayout_round_rect_stroke_color, Color.WHITE);
        mStrokeWidth = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_stroke_width, );
        array.recycle();

        mRectF = new RectF();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mRectF.left = getPaddingLeft();
        mRectF.top = getPaddingTop();
        mRectF.right = w - getPaddingRight();
        mRectF.bottom = h - getPaddingBottom();
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.saveLayer(mRectF, null, Canvas.ALL_SAVE_FLAG);
        super.dispatchDraw(canvas);
        Path path = new Path();
        path.reset();
        //判斷是否繪制圓
        if (mCircle) {
            float width = (mRectF.right - mRectF.left) > (mRectF.bottom - mRectF.top) ? mRectF.bottom - mRectF.top : mRectF.right - mRectF.left;
            path.addCircle((mRectF.right - mRectF.left) / , (mRectF.bottom - mRectF.top) / , (width - mStrokeWidth) / , Path.Direction.CW);
        } else {
            path.addRoundRect(mRectF, mRadii, Path.Direction.CW);
        }


        Paint paint = new Paint();
        paint.setAntiAlias(true);

        //繪制描邊
        if (mStrokeWidth > ) {
            paint.setColor(mStrokeColor);
            paint.setStrokeWidth(mStrokeWidth);
            paint.setStyle(Paint.Style.STROKE);
            canvas.drawPath(path, paint);
        }

        //剪切圓角矩形
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        paint.setStyle(Paint.Style.FILL);
        canvas.drawPath(path, paint);
    }
}
           

使用步驟

在xml檔案直接引用

<com.android.round.weight.RoundRectLayout
                    android:layout_width="100dp"
                    android:layout_height="100dp"
                    android:layout_margin="30dp"
                    app:round_rect_circle="true">

                    <ImageView
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:scaleType="centerCrop"
                        android:src="@mipmap/club_bg"/>

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="40dp"
                        android:layout_alignParentBottom="true"
                        android:background="@mipmap/bottom_bg"
                        android:gravity="center"
                        android:textColor="@android:color/white"
                        android:textSize="10sp"/>

                </com.android.round.weight.RoundRectLayout>
           

具體的實作思路:

首先要擷取自定義的屬性:

TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.RoundRectLayout);
        mCircle = array.getBoolean(R.styleable.RoundRectLayout_round_rect_circle, false);
        mRectCorner = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner, );
        int roundRectTopLeft = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner_top_to_left, -);
        int roundRectTopRight = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner_top_to_right, -);
        int roundRectBottomLeft = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner_bottom_to_left, -);
        int roundRectBottomRight = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_corner_bottom_to_right, -);

        mRadii[] = roundRectTopLeft == - ? mRectCorner : roundRectTopLeft;
        mRadii[] = roundRectTopLeft == - ? mRectCorner : roundRectTopLeft;
        mRadii[] = roundRectTopRight == - ? mRectCorner : roundRectTopRight;
        mRadii[] = roundRectTopRight == - ? mRectCorner : roundRectTopRight;
        mRadii[] = roundRectBottomLeft == - ? mRectCorner : roundRectBottomLeft;
        mRadii[] = roundRectBottomLeft == - ? mRectCorner : roundRectBottomLeft;
        mRadii[] = roundRectBottomRight == - ? mRectCorner : roundRectBottomRight;
        mRadii[] = roundRectBottomRight == - ? mRectCorner : roundRectBottomRight;

        mStrokeColor = array.getColor(R.styleable.RoundRectLayout_round_rect_stroke_color, Color.WHITE);
        mStrokeWidth = array.getDimensionPixelSize(R.styleable.RoundRectLayout_round_rect_stroke_width, );
        array.recycle();
           

擷取到之後要及時關閉typeArray,這個不需要詳述,然後在onSizeChanged()方法中擷取目前view的大小屬性。onSizeChanged方法會在view有改動的時候調用,第一次建立view的時候也會調用一次。然後在dispatchDraw()方法中繪制圖形。

因為要使用setXfermode方法,是以首先要進行離屏緩沖,至于為什麼,請點選了解,行離屏緩沖很簡單,隻需要一行代碼:

然後判斷是繪制圓形還是圓角矩形,繪制畫布路徑

Path path = new Path();
        path.reset();
        //判斷是否繪制圓
        if (mCircle) {
            float width = (mRectF.right - mRectF.left) > (mRectF.bottom - mRectF.top) ? mRectF.bottom - mRectF.top : mRectF.right - mRectF.left;
            path.addCircle((mRectF.right - mRectF.left) / , (mRectF.bottom - mRectF.top) / , (width - mStrokeWidth) / , Path.Direction.CW);
        } else {
            path.addRoundRect(mRectF, mRadii, Path.Direction.CW);
        }
           

之後判斷是否需要描邊

//繪制描邊
        if (mStrokeWidth > ) {
            paint.setColor(mStrokeColor);
            paint.setStrokeWidth(mStrokeWidth);
            paint.setStyle(Paint.Style.STROKE);
            canvas.drawPath(path, paint);
        }
           

最後通過drawPath方法繪制需要的圖形

//剪切圓角矩形
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        paint.setStyle(Paint.Style.FILL);
        canvas.drawPath(path, paint);
           

代碼很簡單,如果有需要,可以直接引用git項目

PS:有問題可以加v1054353861,共同學習,提高!