Android开发技巧——自定义控件之使用style

简介: Android开发技巧——自定义控件之使用style回顾在上一篇《Android开发技巧——自定义控件之自定义属性》中,我讲到了如何定义属性以及在自定义控件中获取这些属性的值,也提到了关于这些属性除了可以在布局文件中指定之外,也可以在主题中指定。

Android开发技巧——自定义控件之使用style

回顾

在上一篇《Android开发技巧——自定义控件之自定义属性》中,我讲到了如何定义属性以及在自定义控件中获取这些属性的值,也提到了关于这些属性除了可以在布局文件中指定之外,也可以在主题中指定。接下来将分享我所了解的关于在主题中指定属性值的两种方式。

在主题中指定属性值

我们在开发过程中,虽然关于自定义控件学会了如何在布局文件中指定它的值,以应对不同的需求。但有时还会遇到这样一种情况:我们希望对某个控件的属性,能够做一个全局的配置,这样我在本项目中使用它的时候,都是同样的表现,而不需要每个布局文件都复制一次属性的值,而在另一个项目中,我们可以进行另一个全局的配置。

属性定义及关于实现的思考

在上一篇中,我们讲到了自定义属性,如下所示:

 <attr name="pwBorderWidth" format="dimension"/>

其中format定义了这个属性的格式,它支持以下这些方式:

  • boolean 布尔值
  • color 颜色
  • dimension 尺寸
  • enum 枚举
  • flag 位或运算
  • float 浮点值
  • fraction 百分数
  • integer 整型值
  • string 字符串
  • reference 引用某一资源ID

在定义格式时,还可以指定多种格式。比如

 <attr name="pwBorderWidth" format="dimension|reference"/>

而这里要说的就是reference,引用某一资源ID。

我们可以定义一个属性,格式为reference,然后在theme中配置它的值为某个style,这样我们就可以读取到这个style的属性。这是我们对这个实现过程的思考。

下面以我以前写的一个项目IconTabPageIndicator为例,全部代码见其develop分支。这是一个底部菜单指示器,其中每个tab(继承自TextView)的具体表现我们都希望能够在style中定义。所以首先我们先定义一个属性,用于指定这个tab的style:

    <attr name="tabView" format="reference"/>

下面分别说明对这个属性的两种使用方式。

在Java代码中获取

重写构造方法。在本例子中,我们的TabView是通过在java代码中自己new出来的,调用的是构造方法TabView(Context context),所以我们需要重写这个构造方法,在这个构造方法中调用this(context, null, R.attr.tabView),第三个参数传入的是R.attr.tabView,即我们定义的style属性。

        public TabView(Context context) {
            this(context, null, R.attr.tabView);
        }

然后我们重写所调用的这个带defStyle参数的构造方法,因为另外一个构造方法TextView(Context context, AttributeSet attrs)也是调用了它:

        public TabView(Context context, AttributeSet attr, int defStyle) {
            super(context, attr, defStyle);
            TypedArray a = context.obtainStyledAttributes(attr, R.styleable.TabView, defStyle, 0);
            iconWidth = a.getDimensionPixelSize(R.styleable.TabView_iconWidth, 0);
            iconHeight = a.getDimensionPixelSize(R.styleable.TabView_iconHeight, 0);
            a.recycle();
        }

在构造方法中,首先第一行是调用父构造方法。接下来,我们就需要获取我们自定义的其他属性了,比如在这个例子中的图标宽高,获取时调用的方法与昨天所使用的有点不同 ,我们调用的是
obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes),第三个参数是我们定义的style属性,第四个参数则是style资源。在确定一个属性最终的值的时候,优先级顺序是这样的:

  1. 首先获取给定的AttributeSet中的属性值
  2. 如果找不到,则去AttributeSet中style(你在写布局文件时定义的style="@style/xxxx")指定的资源获取
  3. 如果找不到,则去defStyleAttr以及defStyleRes中的默认style中获取。
  4. 最后去找的是当前theme下的基础值。

所以在上面的方法中,我们也可以给第四个参数传一个我们默认的style(R.style.xxx),当使用者没有在第三个属性所指定的style中声明一些属性时,就会使用我们第四个参数中的style里的属性。

在调用obtainStyledAttributes方法获取到属性之后,后面如何使用则可参考前一篇博客,或本项目。

别人如何使用

理论上,其他人使用的时候,只要写一个style,然后在他的应用的主题中指定,就可以了。但是通常我们会需要指定许多属性的值,而这些属性的值大部分情况下都是通用的。所以我们首先应提供一个良好的style,如下:

    <style name="TabView">
        <item name="android:gravity">bottom|center_horizontal</item>
        <item name="android:layout_width">0dp</item>
        <item name="android:background">@android:color/white</item>
        <item name="android:layout_height">match_parent</item>
        <item name="android:textColor">@color/tab_text_selector</item>
        <item name="android:textSize">12sp</item>
        <item name="iconWidth">27dp</item>
        <item name="iconHeight">27dp</item>
        <item name="android:paddingTop">4dp</item>
        <item name="android:paddingBottom">4dp</item>
        <item name="android:drawablePadding">2dp</item>
    </style>

在这个style中,我定义了tab文字居中,背景色,字体大小颜色,边距等。在不重写其中的属性的情况下,就能提供一个外观良好的效果。
然后写个theme,在其中指定这个style,算是作为一个给其他开发者学习的示例:

    <style name="Theme.IndicatorDefault" parent="android:Theme">
        <item name="tabView">@style/TabView</item>
    </style>

这里的tabView就是我们所定义的style属性,也是我们在构造方法中指定的R.attr.tabView
如果库的使用者需求对这style进行修改,只需要写一个style,继承自我们的TabViewstyle,重写里面的属性值即可:

    <style name="MyTabView" parent="TabView">
        <item name="iconWidth">28dp</item>
        <item name="iconHeight">28dp</item>
    </style>

当然,还有最重要的一步:必须在自己的项目的主题中指定

    <style name="AppTheme" parent="Theme.AppCompat.Light">
        <item name="tabView">@style/MyTabView</item>
    </style>

此例子的完整项目请参考Github项目IconTabPageIndicator

在布局文件中指定style属性

我们定义的style属性,除了通过Java代码来获取使用之外,也可以直接通过布局文件来使用。需要使用到的是style属性。
我们对一个控件的style属性,通常的写法都是:style="@style/xxxxx",或者是指定android系统中的属性:style="@android:style/xxxx",除此之外,我们也可以用来指定我们所定义的style属性。
我另一个练习的项目ActionSheet就是使用了这种方式。完整代码请参见github上该项目地址,这里仅摘取部分相关的代码。
ActionSheet是我写的一个和qq菜单有点像的菜单,我希望菜单的每一项都是可以配置的。由于菜单是通过Dialog来加载,而Dialog是在Java代码中new出来,所以不能通过在xml中定义各个属性来完成菜单外观的配置,因此采用了这种方式。
首先同样是定义一些属性,和上面的一样:

    <attr name="ActionSheetList" format="reference"/>
    <attr name="ActionSheetCancel" format="reference"/>
    <attr name="ActionSheetItem" format="reference"/>

这里表示的是菜单列表的属性,取消按钮的样式,以及每一项菜单的样式。然后在我们的菜单布局文件中,除了不允许配置的属性我们进行了声明之外,其他的都是用style属性来指定,写法是style="?attr/你所定义的属性名",如下:

    <ListView
        android:id="@+id/menu_items"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="?attr/ActionSheetList"
        android:listSelector="@android:color/transparent"/>

    <Button
        android:id="@+id/menu_cancel"
        style="?attr/ActionSheetCancel"/>

同样在我们的style.xml文件中,需要定义这几个style:

    <style name="ActionSheetList">
        <item name="android:divider">#c9dddddd</item>
        <item name="android:dividerHeight">1px</item>
    </style>
    下面代码略...

而库的使用者,在使用的时候,也需要指定这几个属性值:

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="ActionSheetList">@style/ActionSheetList</item>
        <item name="ActionSheetItem">@style/ActionSheetItem</item>
        <item name="ActionSheetCancel">@style/ActionSheetCancel</item>
    </style>

本篇到此结束,相关项目如下:

下篇讲一下如何在自定义控件中增加状态state

本文原创,转载请注明在CSDN上的出处:http://blog.csdn.net/maosidiaoxian/article/details/50037371

目录
相关文章
|
1月前
|
移动开发 前端开发 Android开发
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
236 12
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
1月前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
203 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
1月前
|
移动开发 Rust JavaScript
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
516 4
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
2月前
|
开发工具 Android开发
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
482 11
X Android SDK file not found: adb.安卓开发常见问题-Android SDK 缺少 `adb`(Android Debug Bridge)-优雅草卓伊凡
|
1月前
|
移动开发 Android开发
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【03】建立隐私关于等相关页面和内容-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
120 0
|
2月前
|
Java 开发工具 Maven
【01】完整的安卓二次商业实战-详细的初级步骤同步项目和gradle配置以及开发思路-优雅草伊凡
【01】完整的安卓二次商业实战-详细的初级步骤同步项目和gradle配置以及开发思路-优雅草伊凡
196 6
|
4月前
|
安全 数据库 Android开发
在Android开发中实现两个Intent跳转及数据交换的方法
总结上述内容,在Android开发中,Intent不仅是活动跳转的桥梁,也是两个活动之间进行数据交换的媒介。运用Intent传递数据时需注意数据类型、传输大小限制以及安全性问题的处理,以确保应用的健壯性和安全性。
354 11
|
4月前
|
移动开发 Java 编译器
Kotlin与Jetpack Compose:Android开发生态的演进与架构思考
本文从资深Android工程师视角深入分析Kotlin与Jetpack Compose在Android系统中的技术定位。Kotlin通过空安全、协程等特性解决了Java在移动开发中的痛点,成为Android官方首选语言。Jetpack Compose则引入声明式UI范式,通过重组机制实现高效UI更新。两者结合不仅提升开发效率,更为跨平台战略和现代架构模式提供技术基础,代表了Android开发生态的根本性演进。
180 0
|
8月前
|
JavaScript Linux 网络安全
Termux安卓终端美化与开发实战:从下载到插件优化,小白也能玩转Linux
Termux是一款安卓平台上的开源终端模拟器,支持apt包管理、SSH连接及Python/Node.js/C++开发环境搭建,被誉为“手机上的Linux系统”。其特点包括零ROOT权限、跨平台开发和强大扩展性。本文详细介绍其安装准备、基础与高级环境配置、必备插件推荐、常见问题解决方法以及延伸学习资源,帮助用户充分利用Termux进行开发与学习。适用于Android 7+设备,原创内容转载请注明来源。
1990 77
|
5月前
|
安全 Java Android开发
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡
265 0
为什么大厂要求安卓开发者掌握Kotlin和Jetpack?深度解析现代Android开发生态优雅草卓伊凡