美文网首页
自定义 View 实现 View 圆角的能力

自定义 View 实现 View 圆角的能力

作者: wuchao226 | 来源:发表于2020-04-21 23:04 被阅读0次

主要介绍通过自定义 View 实现 View 所有边都有圆角及某一边有圆角的功能,替代在 xml 中写 shape;

首先看效果图

1587479574658.jpg

1、加一个自定义的属性,某个边是圆角还是都是圆角以及圆角的大小

    <declare-styleable name="viewOutLineStrategy">
        <!--  圆角大小     -->
        <attr name="clip_radius" format="dimension" />
        <attr name="clip_side" format="enum">
            <enum name="all" value="0" />
            <!--     左边       -->
            <enum name="left" value="1" />
            <!--     上边       -->
            <enum name="top" value="2" />
            <!--     右边       -->
            <enum name="right" value="3" />
            <!--    下边        -->
            <enum name="bottom" value="4" />
        </attr>
    </declare-styleable>

布局不仅由 FrameLayout 还有 LinearLayout 和 RelativeLayout,都有可能通过这种方式实现圆角,所以自定义属性的解析,我们单独写个类来解析。

下面创建 ViewHelper 类来解析自定义属性:

import android.annotation.TargetApi;
import android.content.res.TypedArray;
import android.graphics.Outline;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;

/**
 * @desciption: View 帮助类,自定义属性解析
 */
public class ViewHelper {

    public static final int RADIUS_ALL = 0;
    public static final int RADIUS_LEFT = 1;
    public static final int RADIUS_TOP = 2;
    public static final int RADIUS_RIGHT = 3;
    public static final int RADIUS_BOTTOM = 4;

    public static void setViewOutline(View view, AttributeSet attributes, int defStyleAttr, int defStyleRes) {
        TypedArray array = view.getContext().obtainStyledAttributes(attributes, R.styleable.viewOutLineStrategy, defStyleAttr, defStyleRes);
        int radius = array.getDimensionPixelSize(R.styleable.viewOutLineStrategy_clip_radius, 0);
        int hideSide = array.getInt(R.styleable.viewOutLineStrategy_clip_side, 0);
        array.recycle();
        setViewOutline(view, radius, hideSide);
    }

    /**
     * 设置 view 带有边角的边线
     * @param owner view
     * @param radius 半径
     * @param radiusSide view 的边角
     */
    public static void setViewOutline(View owner, final int radius, final int radiusSide) {

        owner.setOutlineProvider(new ViewOutlineProvider() {
            @Override
            @TargetApi(21)
            public void getOutline(View view, Outline outline) {
                int w = view.getWidth(), h = view.getHeight();
                if (w == 0 || h == 0) {
                    return;
                }
                //某一边需要圆角        
                if (radiusSide != RADIUS_ALL) {
                    int left = 0, top = 0, right = w, bottom = h;
                    if (radiusSide == RADIUS_LEFT) {
                        right += radius;
                    } else if (radiusSide == RADIUS_TOP) {
                        bottom += radius;
                    } else if (radiusSide == RADIUS_RIGHT) {
                        left -= radius;
                    } else if (radiusSide == RADIUS_BOTTOM) {
                        top -= radius;
                    }
                    outline.setRoundRect(left, top, right, bottom, radius);
                    return;
                }
                //所有边需要圆角
                int top = 0, bottom = h, left = 0, right = w;
                if (radius <= 0) {
                    outline.setRect(left, top, right, bottom);
                } else {
                    outline.setRoundRect(left, top, right, bottom, radius);
                }
            }
        });
        owner.setClipToOutline(radius > 0);
        owner.invalidate();
    }
}

ViewHelper 类中裁剪代码分析如下:


1587481083065.jpg

红色区域左边被裁剪为圆角,右上角和右下角圆角没有被裁剪掉,因为右边的裁剪区域已经超过了 VIew 的大小。同理其它几边圆角裁剪原理一样。

接下来实现自定义带有 Corner 的 FrameLayout 和 LinearLayout

import android.content.Context;
import android.util.AttributeSet;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

/**
 * @desciption: 自定义带有 Corner 的 FrameLayout
 */
public class CornerFrameLayout extends FrameLayout {

    public CornerFrameLayout(@NonNull Context context) {
        this(context, null);
    }

    public CornerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CornerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public CornerFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        ViewHelper.setViewOutline(this, attrs, defStyleAttr, defStyleRes);
    }

    public void setViewOutline(int radius, int radiusSide) {
        ViewHelper.setViewOutline(this, radius, radiusSide);
    }
}

接下来实现自定义带有 Corner 的 FrameLayout

import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;

import androidx.annotation.Nullable;

/**
 * @desciption: 自定义带有 Corner 的 LinearLayout
 */
public class CornerLinearLayout extends LinearLayout {
    public CornerLinearLayout(Context context) {
        this(context, null);
    }

    public CornerLinearLayout(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CornerLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public CornerLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);

        ViewHelper.setViewOutline(this, attrs, defStyleAttr, defStyleRes);
    }
}

使用方式

和正常使用 View 方式一样,加上自定义的属性即可:

<com.....libcommon.view.CornerFrameLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="@dimen/dp_16"
        android:layout_marginRight="@dimen/dp_16"
        android:background="@color/color_gray"
        android:paddingLeft="@dimen/dp_10"
        android:paddingRight="@dimen/dp_10"
        android:paddingBottom="@dimen/dp_10"
        app:clip_radius="6dp"
        app:clip_side="all"/>

相关文章

网友评论

      本文标题:自定义 View 实现 View 圆角的能力

      本文链接:https://www.haomeiwen.com/subject/ysomihtx.html