美文网首页
自定义 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