美文网首页android开发技巧
自定义View——ShapeTextView(可设置背景边框,S

自定义View——ShapeTextView(可设置背景边框,S

作者: 大灰狼zz | 来源:发表于2019-08-27 11:34 被阅读0次

    简介

    日常项目开发中,经常会遇到把TextView设置成一个按钮,就像下面这个:


    按钮.png

    而一般的实现方式就是在res/drawable目录下定义一个drawable.xml文件:

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
        <corners android:radius="10dp" />
        <solid android:color="@color/blue" />
    </shape>
    

    然后设置为TextView的背景,如果需要选中时改变状态,可以这么设置:

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@drawable/bule" android:state_pressed="false" />
        <item android:drawable="@drawable/red" android:state_pressed="true" />
        <item android:drawable="@drawable/bule" />
    </selector>
    

    这样写的好处是简单易懂,但是如果项目中用到了很多不同风格的边框背景时,就会创建非常多的相似的资源文件,比较麻烦。为了避免这种麻烦,这里使用Java代码来创建Drawable。


    状态说明.png

    自定义ShapeTextView

    使用自定义view继承TextView来实现上面说的效果

    定义属性

    在res/values/attrs.xml中添加自定义属性

    <!--自定义矩形边框的TextView-->
        <declare-styleable name="ShapeTextView">
            <!--是否使用Selector选择器-->
            <attr name="openSelector" format="boolean" />
            <!--填充色-->
            <attr name="solidColor" format="color" />
            <!--边框色-->
            <attr name="strokeColor" format="color" />
            <!--按下填充色-->
            <attr name="solidTouchColor" format="color" />
            <!--按下边框色-->
            <attr name="strokeTouchColor" format="color" />
            <!--边框宽度-->
            <attr name="strokeWidth" format="dimension" />
            <!--圆角弧度-->
            <attr name="radius" format="dimension" />
            <!--四个角的圆角弧度-->
            <attr name="topLeftRadius" format="dimension" />
            <attr name="topRightRadius" format="dimension" />
            <attr name="bottomLeftRadius" format="dimension" />
            <attr name="bottomRightRadius" format="dimension" />
            <!--虚线边框宽度-->
            <attr name="dashWidth" format="dimension" />
            <!--虚线边框间隙-->
            <attr name="dashGap" format="dimension" />
        </declare-styleable>
    

    自定义View继承TextView

    /**
     * @author Lin
     * @date 2019/8/22
     * @description 实现自定义圆角背景
     * 支持
     * 1.四边圆角
     * 2.指定边圆角
     * 3.支持填充色以及边框色,边框虚线
     * 4.支持按下效果
     */
    @SuppressLint("AppCompatCustomView")
    public class ShapeTextView extends TextView {
        private boolean openSelector;
        //自定背景边框Drawable
        private GradientDrawable gradientDrawable;
        //按下时的Drawable
        private GradientDrawable selectorDrawable;
        //填充色
        private int solidColor = 0;
        //边框色
        private int strokeColor = 0;
        //按下填充色
        private int solidTouchColor = 0;
        //按下边框色
        private int strokeTouchColor = 0;
        //按下字体色
        private int textTouchColor = 0;
        //边框宽度
        private int strokeWidth = 0;
        //四个角的弧度
        private float radius;
        private float topLeftRadius;
        private float topRightRadius;
        private float bottomLeftRadius;
        private float bottomRightRadius;
        //边框虚线的宽度
        float dashWidth = 0;
        //边框虚线的间隙
        float dashGap = 0;
        //字体色
        private int textColor = 0;
    
    
        public ShapeTextView(Context context) {
            this(context, null);
        }
    
        public ShapeTextView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public ShapeTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context, attrs);
            //默认背景
            gradientDrawable = getNeedDrawable(new float[]{topLeftRadius, topLeftRadius, topRightRadius, topRightRadius,
                            bottomRightRadius, bottomRightRadius, bottomLeftRadius, bottomLeftRadius},
                    solidColor, strokeWidth, strokeColor, dashWidth, dashGap);
            //如果设置了选中时的背景
            if (openSelector) {
                selectorDrawable = getNeedDrawable(new float[]{topLeftRadius, topLeftRadius, topRightRadius, topRightRadius,
                                bottomRightRadius, bottomRightRadius, bottomLeftRadius, bottomLeftRadius},
                        solidTouchColor, strokeWidth, strokeTouchColor, dashWidth, dashGap);
    
                //动态生成Selector
                StateListDrawable stateListDrawable = new StateListDrawable();
                //是否按下
                int pressed = android.R.attr.state_pressed;
    
                stateListDrawable.addState(new int[]{pressed}, selectorDrawable);
                stateListDrawable.addState(new int[]{}, gradientDrawable);
    
                setBackground(stateListDrawable);
            } else {
                setBackground(gradientDrawable);
            }
        }
    
        /**
         * 初始化参数
         *
         * @param context
         * @param attrs
         */
        private void init(Context context, AttributeSet attrs) {
            TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ShapeTextView, 0, 0);
    
            openSelector = ta.getBoolean(R.styleable.ShapeTextView_openSelector, false);
    
            solidColor = ta.getInteger(R.styleable.ShapeTextView_solidColor, 0x00000000);
            strokeColor = ta.getInteger(R.styleable.ShapeTextView_strokeColor, 0x00000000);
    
            solidTouchColor = ta.getInteger(R.styleable.ShapeTextView_solidTouchColor, 0x00000000);
            strokeTouchColor = ta.getInteger(R.styleable.ShapeTextView_strokeTouchColor, 0x00000000);
            textTouchColor = ta.getInteger(R.styleable.ShapeTextView_textTouchColor, 0x00000000);
            textColor = getCurrentTextColor();
            strokeWidth = (int) ta.getDimension(R.styleable.ShapeTextView_strokeWidth, 0);
    
            //四个角单独设置会覆盖radius设置
            radius = ta.getDimension(R.styleable.ShapeTextView_radius, 0);
            topLeftRadius = ta.getDimension(R.styleable.ShapeTextView_topLeftRadius, radius);
            topRightRadius = ta.getDimension(R.styleable.ShapeTextView_topRightRadius, radius);
            bottomLeftRadius = ta.getDimension(R.styleable.ShapeTextView_bottomLeftRadius, radius);
            bottomRightRadius = ta.getDimension(R.styleable.ShapeTextView_bottomRightRadius, radius);
    
            dashGap = ta.getDimension(R.styleable.ShapeTextView_dashGap, 0);
            dashWidth = ta.getDimension(R.styleable.ShapeTextView_dashWidth, 0);
    
            ta.recycle();
        }
    
        /**
         * @param radius      四个角的半径
         * @param colors      渐变的颜色
         * @param strokeWidth 边框宽度
         * @param strokeColor 边框颜色
         * @return
         */
        public static GradientDrawable getNeedDrawable(float[] radius, int[] colors, int strokeWidth, int strokeColor) {
            //TODO:判断版本是否大于16  项目中默认的都是Linear散射 都是从左到右 都是只有开始颜色和结束颜色
            GradientDrawable drawable;
            if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                drawable = new GradientDrawable();
                drawable.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT);
                drawable.setColors(colors);
            } else {
                drawable = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, colors);
            }
    
            drawable.setCornerRadii(radius);
            drawable.setStroke(strokeWidth, strokeColor);
            drawable.setGradientType(GradientDrawable.LINEAR_GRADIENT);
            return drawable;
        }
    
        /**
         * @param radius      四个角的半径
         * @param bgColor     背景颜色
         * @param strokeWidth 边框宽度
         * @param strokeColor 边框颜色
         * @return
         */
        public static GradientDrawable getNeedDrawable(float[] radius, int bgColor, int strokeWidth, int strokeColor) {
            GradientDrawable drawable = new GradientDrawable();
            drawable.setShape(GradientDrawable.RECTANGLE);
            drawable.setCornerRadii(radius);
            drawable.setStroke(strokeWidth, strokeColor);
            drawable.setColor(bgColor);
            return drawable;
        }
    
        /**
         * @param radius      四个角的半径
         * @param bgColor     背景颜色
         * @param strokeWidth 边框宽度
         * @param strokeColor 边框颜色
         * @param dashWidth   虚线边框宽度
         * @param dashGap     虚线边框间隙
         * @return
         */
        public static GradientDrawable getNeedDrawable(float[] radius, int bgColor, int strokeWidth, int strokeColor, float dashWidth, float dashGap) {
            GradientDrawable drawable = new GradientDrawable();
            drawable.setShape(GradientDrawable.RECTANGLE);
            drawable.setCornerRadii(radius);
            drawable.setStroke(strokeWidth, strokeColor, dashWidth, dashGap);
            drawable.setColor(bgColor);
            return drawable;
        }
    }
    

    使用示例

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingTop="50dp">
    
        <com.lin.module_base.view.ShapeTextView
            android:id="@+id/text1"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_margin="5dp"
            android:gravity="center"
            android:text="@string/about"
            app:openSelector="true"
            app:radius="10dp"
            app:solidColor="@color/white"
            app:solidTouchColor="@color/gray_light"
            app:strokeColor="@color/blue"
            app:strokeTouchColor="@color/red"
            app:strokeWidth="1dp"
            app:textTouchColor="@color/red" />
    
        <com.lin.module_base.view.ShapeTextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_margin="5dp"
            android:gravity="center"
            android:text="@string/about"
            app:bottomRightRadius="20dp"
            app:openSelector="true"
            app:solidColor="@color/white"
            app:solidTouchColor="@color/gray_light"
            app:strokeColor="@color/blue"
            app:strokeTouchColor="@color/red"
            app:strokeWidth="1dp"
            app:textTouchColor="@color/red"
            app:topLeftRadius="20dp" />
    
        <com.lin.module_base.view.ShapeTextView
            android:id="@+id/text2"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_margin="5dp"
            android:gravity="center"
            android:text="@string/about"
            app:dashGap="1dp"
            app:dashWidth="2dp"
            app:openSelector="true"
            app:radius="10dp"
            app:solidColor="@color/white"
            app:strokeColor="@color/blue"
            app:strokeTouchColor="@color/red"
            app:strokeWidth="0.5dp"
            app:textTouchColor="@color/red" />
    
        <com.lin.module_base.view.ShapeTextView
            android:id="@+id/text3"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_gravity="center_horizontal"
            android:layout_margin="5dp"
            android:gravity="center"
            android:text="@string/about"
            app:openSelector="true"
            app:radius="25dp"
            app:solidColor="@color/blue"
            app:strokeColor="@color/blue"
            app:strokeTouchColor="@color/red"
            app:strokeWidth="1dp"
            app:textTouchColor="@color/red" />
    
    </LinearLayout>
    
    

    效果如下图:


    image.png

    踩坑

    如果需要selector选择器的效果,需要在xml中设置app:openSelector="true"
    然后要给View设置监听事件

     text1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                }
            });
    

    总结

    这里我们使用了Java代码来创建Drawable,可以把常用方法提取到工具类中。
    日常开发中也有其他类似的需要定义CheckBox、RadioButton等背景的,也可以参考这种做法。

    参考:
    Drawable子类之——StateListDrawable (选择器)

    相关文章

      网友评论

        本文标题:自定义View——ShapeTextView(可设置背景边框,S

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