前言
以按钮点击效果举例,点击前后颜色变化,按钮形状可方可圆。
效果图
Android10以上调用相机 相册选择
这个视频的选择照片按钮就是用自定义Drawable设置背景的。
方法一:新增xml文件
编写Drawable目录下的xml文件,引入到组件中使用。
1、按钮形状、颜色
2、按钮点击变化
这种方法大多应该都会,后续补上两篇博客。
方法二:自定义Drawable资源
题外话:如上这样一个按钮需要三个xml文件。就当点击后默认颜色文件可以共用,后续每添加一种不同按钮,就需要添加两个xml文件;再好比按钮形状变了,此时要添加三个xml文件。以此类推,只要项目是需要那么多不同样式的组件,所需的xml文件越多。
于是,想着能不能自定义组件,传几个可变的参数来达到目的,这样子不就不需要创建xml文件。
1、设置背景资源
设置默认背景及点击背景,使用到GradientDrawable类
// 默认背景
GradientDrawable drawableDefault= new GradientDrawable();
drawableDefault.setShape(shape); // 设置形状
drawableDefault.setColor(colorDefault);// 设置颜色
drawableDefault.setCornerRadius(radius);// 设置弧度
// 点击背景
GradientDrawable drawableClick = new GradientDrawable();
drawableClick.setShape(shape); // 设置形状
drawableClick.setColor(Color.GRAY);// 设置颜色
drawableClick.setCornerRadius(radius);// 设置弧度
可以看出形状是共用的,弧度是共用的,点击背景设置默认灰色,那么要使用的参数也就是:
shape - 形状,例如: GradientDrawable.RECTANGLE
colorDefault - 颜色,组件默认颜色
这里有一点需要注意,drawableEnd.setColor(),这个方法里的参数是int型,可以看到点击背景的传入的是Color.GRAY,使用Color类的颜色是int型,像平常都是引用color.xml文件里设置好的颜色,也就是R.color.white这种形式,但是它是不可取的,只是引用了R类,不是int型,会报错。
radius - 弧度, 根据需要自行调整
要使用到的参数就这么多,可能有人会想,既然两个Drawable类都共用shape、radius,为啥不直接创建一个Drawable对象,这里前后两个对象Drawable是不能共用的,后一个会覆盖掉前一个对象,也就是最终只会显示一个Drawable对象,点击无效果的。
2、设置点击资源
设置点击操作,要使用到StateListDrawable类
// 创建StateListDrawable
StateListDrawable stateListDrawable = new StateListDrawale();
// 默认状态
stateListDrawable.addState(new int[]{-android.R.attr.state_pressed}, drawableDefault);
// 按下状态
stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, drawableClick);
把之前创建的两个Drawable对象添加到StateListDrawable对象里,这样就构成了同选择器xml文件功能。
到此为止,自定义的代码就写好了,把他们放在一个方法里,返回stateListDrawable对象,需要用的时候进行调用就OK了。
3、颜色转换
上文提到只能使用int型,也就是Color类的颜色,肯定是不方便的。
第一种方式:使用Color.parseColor(),将颜色值字符串用Color类进行转换成int型。
Color.parseColor("#FFFFFF");
第二种方式:使用ContextCompat.getColor(context, color),这种方式就可以把R.color.white传入color这种参数,然后ContextCompat就可以帮我们拿到这个颜色,得到的就是int型。
// 鼠标放在getColor上可以看到返回的是int类型, 传入的参数是上下文和资源id
ContextCompat.getColor(mContext,R.color.white);
tips: 我个人喜欢第二种方式,方便在color.xml文件中维护。
使用示例
// 首先建立一个方法,建议放在一个类里
public class DrawableUtil{
public static StateListDrawable setDrawable(int shape, int colorDefault, int radius){
// 把上文的代码放进来
return stateListDrawable;
}
}
// 在某个页面对某个按钮使用
public class MainActivity extends Activity{
// 我这里就简写onCreate方法了哈
onCreate(){
Button confrim_btn = findViewById(R.id.confirm_btn);
confrim_btn.setBackground(DrawableUtil.setDrawable(GradientDrawable.RECTANGLE,
ContextCompat.getColor(this, R.color.blue), 30);
}
}
自定义标题:后续放上
自定义列表:后续放上
Android Studio在创建Activity时,会默认继承AppCompatActivity,但这个类是默认使用了主题样式,会与自定义Drawable冲突,组件设置背景不会生效,所以要继承Activity类。
方法对比
【个人感受】
我在学习自定义Drawable资源这一块,最终目的就是不想创建过多xml文件,用一个方法搞定更简单化。
但在写这篇博客过程中,发现xml文件有一些优点是自定义没有的:
比如现在Android Studio是可以预览xml文件的图像的,eclipse不能,这样子的话,在使用xml文件时,文件过多,也可以去找出想要的样式;
再比如,一旦跟UI界面有关联,不必在逻辑代码中找,都在res目录下控制UI界面,相反写在逻辑代码里会混合逻辑与界面。
本来是想推荐使用自定义Drawable,避免使用xml文件,但现在看来,视情况而定吧,根据实际需求来选择使用哪一种方式作为资源。
【方法对比】
类型 | 优点 | 缺点 |
---|---|---|
自定义xml文件 | 1、逻辑代码与界面布局分离,提高代码可读性和可维护性 2、在AS中可以预览和编辑,方便快速调整样式 3、Android系统在加载xml布局时,会进行一定的优化处理 4、对于不需要动态改变的资源,使用xml文件更直观和方便。 | 1、缺乏灵活性,一旦被定义,除非重新加载布局,否则资源不能再运行时动态改变 2、代码量增加,需要在多个地方使用相同的资源,就需要复制粘贴xml代码,创建文件 |
自定义drawable资源 | 1、通过java代码可以动态设置和调整资源,灵活性高 2、代码复用,避免多个地方重复定义相同的资源 3、可以根据逻辑条件来决定使用那种资源 | 1、会混合逻辑和界面,降低代码可读性和维护性 2、相比xml文件,java代码设置资源会有一定的开销,特别是需要频繁改变资源情况下 3、不易预览和编辑,只能运行时看 |
总结
- 静态与动态:
- XML文件更适合定义静态的、不常改变的背景资源;
- Java代码则更适合动态地、根据应用状态或用户交互来改变背景资源。
- 可读性与可维护性:
- XML文件在描述UI界面时具有更好的可读性和可维护性;
- Java代码则可能在处理复杂逻辑和动态交互时更加灵活。
- 性能:
- 对于静态的背景资源,XML文件可能具有更好的性能;
- 对于需要频繁改变的背景资源,Java代码可能会带来一定的性能开销。