Android 通过代码添加自定义Shape

时间:2021-7-21 作者:qvyue

简述

在Android 开发中,想必总会有人遇到奇葩的需求,比如颜色值要求通过后台来配置显示。这个时候,通过在drawable 文件夹新建xml 编写shape标签则无法控制颜色值了。于是引出了今天要讲的通过代码自定义shape 设置到我们想要的View中去。

老规矩先上图(思路说完最后再附上写的代码):

Android 通过代码添加自定义Shape
视频效果图.gif

先看看我这边主界面简单XML布局

Android 通过代码添加自定义Shape
activity_main.png

很简单,就是一个垂直线性布局,里面有两个TextView控件。

通过代码自定义Shape

接下来就来说说如何通过代码设置,最主要的就是通过GradientDrawable控制其相关属性,然后设置到我们的控件中去,来达到我们要的效果。
例如这里简单写一个黑色背景圆角矩形

       GradientDrawable drawable = new GradientDrawable();
        drawable.setCornerRadius(5);
        drawable.setColor( 0xFF000000);
        drawable.setStroke(1,0xFF000000);
        tv_view.setBackground(drawable);
  • setCornerRadius(float radius) : 圆角值
  • setColor(int argb) :argb 颜色值,即0x 开头的十六进制颜色 ,若是想用 RGB 颜色 则可以通过转换 Color.parseColor(String colorString),效果一样
drawable.setColor( 0xFF000000); //十六进制黑色
drawable.setColor(Color.parseColor("#000000"));//GRB 颜色
  • setStroke(int width, int color) width-线条宽度 color-argb颜色值

通过代码自定义选择器

设置两种不同GradientDrawable ,然后添加状态到我们设置StateListDrawable中去,即可实现在xml中的效果。
例如上面视频中的按下时一种图形,松开有显示一种图形

        StateListDrawable stateListDrawable = new StateListDrawable();
        stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, pressedDraw);
        stateListDrawable.addState(new int[]{}, normalDraw);
        tv_round.setBackground(stateListDrawable);

其中pressedDraw,normalDraw 是我们自定义的GradientDrawable
addState(int[] stateSet, Drawable drawable)是为控件添加状态
其属性状态和XML 中的一样多 ,通过android.R.attr.state_pressed 点击跳转到 attrs.xml 查看其相关属性,这里给下粗略截图,有兴趣的小伙伴可以自行查阅

Android 通过代码添加自定义Shape
android-29 attrs.xml.png

最后为了方便写,我稍微改成了工具类(小伙伴可以自行编写,这边只给出录制的两种)
ShapeSettingUtil

public class ShapeSettingUtil {
    /**
     * 设置背景选择器
     *
     * @param pressedDraw 按下时所定义的Drawable
     * @param normalDraw  正常显示的Drawable
     * @return
     */
    public static StateListDrawable getSelector(Drawable normalDraw, Drawable pressedDraw) {
        StateListDrawable stateListDrawable = new StateListDrawable();
        stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, pressedDraw);
        stateListDrawable.addState(new int[]{}, normalDraw);
        return stateListDrawable;
    }


    /**
     * 设置shape
     *
     * @param radius 半径长度
     * @param fillColor 填充颜色
     * @param storeWidth 线条宽度
     * @param strokeColor 线条颜色
     * @return
     */
    public  static GradientDrawable getDrawable(int radius, String fillColor, int storeWidth, String strokeColor) {
        GradientDrawable gradientDrawable = new GradientDrawable();
        gradientDrawable.setCornerRadius(radius);
        gradientDrawable.setColor(Color.parseColor(fillColor));
        gradientDrawable.setStroke(storeWidth,Color.parseColor(strokeColor) );
        return gradientDrawable;
    }
    
}

ScreenUtil

public class ScreenUtil {

    /**
     * dp 转 px
     */
    public static int dp2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * px 转 dp
     */
    public static int px2dp(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

}

主界面代码 MainActivity

public class MainActivity extends AppCompatActivity {

    private TextView tv_view, tv_round;
    private String color1="#9873EA",color2="#7B4BE4";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_view=findViewById(R.id.tv_view);
        tv_round=findViewById(R.id.tv_round);
        tv_view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this,"带有圆角的控件 点击!",Toast.LENGTH_SHORT).show();
            }
        });

        tv_round.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this,"圆形选择器 点击!",Toast.LENGTH_SHORT).show();
            }
        });



        setUI();
    }

    private void setUI() {

        /***
         * 设置带有圆角5dp的浅紫色矩形
         * */
        GradientDrawable drawable= ShapeSettingUtil.getDrawable(
                ScreenUtil.dp2px(this,5),color1,
                ScreenUtil.dp2px(this,1),color1);

        tv_view.setBackground(drawable);



        /***
         * 圆形选择器
         * */
        GradientDrawable normal= ShapeSettingUtil.getDrawable(
                ScreenUtil.dp2px(this,125),color1,
                0,color1);
        GradientDrawable press= ShapeSettingUtil.getDrawable(
                ScreenUtil.dp2px(this,125),color2,
                0,color2);
        tv_round.setBackground(ShapeSettingUtil.getSelector(normal,press));

    }
}

至此,Android 通过代码添加自定义Shape编写完毕。希望能对小伙伴提供到思路。

最后的最后,小伙伴们用代码而非XML来设置代码,可能不是我上面说到的奇葩问题,而是基于UI优化,通过代码创建,而不是把整个XML加载到内存中去。这样的优点是UI渲染更快性能更好,但是缺点是减少了可阅读性,对于后续迭代开发不友好,所以这边贴出了大佬们开源出来的库X2C ,是将XML 转换为 Java 代码的工具。
在针对性能要求非常高,但修改又不非常频繁的场景是可以使用使用。

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。