Android开发技巧——自定义控件之使用style
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资源。在确定一个属性最终的值的时候,优先级顺序是这样的:
- 首先获取给定的AttributeSet中的属性值
- 如果找不到,则去AttributeSet中style(你在写布局文件时定义的
style="@style/xxxx"
)指定的资源获取 - 如果找不到,则去
defStyleAttr
以及defStyleRes
中的默认style中获取。 - 最后去找的是当前
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,继承自我们的TabView
style,重写里面的属性值即可:
<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>
本篇到此结束,相关项目如下:
- IconPageIndicator 开发分支,学习自JakeWharton大神的ViewPagerIndicator
- ActionSheet,学习自哪个项目我也忘了。
下篇讲一下如何在自定义控件中增加状态state
。
本文原创,转载请注明在CSDN上的出处:http://blog.csdn.net/maosidiaoxian/article/details/50037371
Android开发技巧——自定义控件之使用style的更多相关文章
- Android开发技巧——自定义控件之增加状态
Android开发技巧--自定义控件之增加状态 题外话 这篇本该是上周四或上周五写的,无奈太久没写博客,前几段把我的兴头都用完了,就一拖再拖,直到今天.不想把这篇拖到下个月,所以还是先硬着头皮写了. ...
- Android开发技巧——自定义控件之自定义属性
Android开发技巧--自定义控件之自定义属性 掌握自定义控件是很重要的,因为通过自定义控件,能够:解决UI问题,优化布局性能,简化布局代码. 上一篇讲了如何通过xml把几个控件组织起来,并继承某个 ...
- Android开发技巧——自定义控件之组合控件
Android开发技巧--自定义控件之组合控件 我准备在接下来一段时间,写一系列有关Android自定义控件的博客,包括如何进行各种自定义,并分享一下我所知道的其中的技巧,注意点等. 还是那句老话,尽 ...
- Android开发技巧——写一个StepView
在我们的应用开发中,有些业务流程会涉及到多个步骤,或者是多个状态的转化,因此,会需要有相关的设计来展示该业务流程.比如<停车王>应用里的添加车牌的步骤. 通常,我们会把这类控件称为&quo ...
- Android开发技巧——实现可复用的ActionSheet菜单
在上一篇<Android开发技巧--使用Dialog实现仿QQ的ActionSheet菜单>中,讲了这种菜单的实现过程,接下来将把它改成一个可复用的控件库. 本文原创,转载请注明出处: h ...
- Android开发技巧——高亮的用户操作指南
Android开发技巧--高亮的用户操作指南 2015-12-15补记: 发现使用PopupWindow进行遮罩层的显示,在华为P7上会有问题.具体表现为:画出来的高亮部分会偏下.原因为:通过view ...
- 50个android开发技巧
50个android开发技巧 http://blog.csdn.net/column/details/androidhacks.html
- Android开发技巧——大图裁剪
本篇内容是接上篇<Android开发技巧--定制仿微信图片裁剪控件> 的,先简单介绍对上篇所封装的裁剪控件的使用,再详细说明如何使用它进行大图裁剪,包括对旋转图片的裁剪. 裁剪控件的简单使 ...
- Android开发技巧——使用PopupWindow实现弹出菜单
在本文当中,我将会与大家分享一个封装了PopupWindow实现弹出菜单的类,并说明它的实现与使用. 因对界面的需求,android原生的弹出菜单已不能满足我们的需求,自定义菜单成了我们的唯一选择,在 ...
随机推荐
- qq安全原理
故事总要有缘由,那么这个故事的缘由就是,当我以前写了一个获取其它进程密码框密码的时候(前几篇博客中有描述),我抱着试一试的心情去试探了一下能不能得到 QQ 的密码,当我抓到密码框的句柄,然后输入给程序 ...
- JavaEE介绍
相关术语 为什么需要JavaEE 我们编写的JSP代码中,由于大量的显示代码和业务逻辑混淆在一起,彼此嵌套,不利于程序的维护和扩展.当业务需求发生变化的时候,对于程序员和美工都是一个很重的负担.为了程 ...
- SQL Server 执行计划操作符详解(3)——计算标量(Compute Scalar)
接上文:SQL Server 执行计划操作符详解(2)--串联(Concatenation ) 前言: 前面两篇文章介绍了关于串联(Concatenation)和断言(Assert)操作符,本文介绍第 ...
- Cocos2D v3.4.9粒子效果不能显示的原因分析及解决办法
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 在游戏App中为了衬托气氛我们往往使用一些特殊的图形效果,粒子 ...
- Android的DatePicker和TimePicker-android学习之旅(三十八)
DatePicker和TimePicker简介 DatePicker和TimePicker是从FrameLayout继承而来,他们都是比较简单的组件.时间改变时间分别添加OnDateChangeLis ...
- ubuntu权限管理常用命令
1.chmod 第一种方式 chomd [{ugoa}{+-=}{rwx}] [文件或者目录] u 代表该文件所属用户 g 代表该文件所属用户组 o 代表访客 a 代表所有用户 +-=分别表示增加权限 ...
- JVM的内存区域模型
首先要明白一个概念,就是JVM的内存区域划分与java的内存区域模型是两个不同的概念,前者指的是在java中jvm会将一个程序划分为哪些块来存储对应的数据,后者是一个更宏观上的j概念,指的是java线 ...
- Dynamics CRM2013 ScLib::AccessCheckEx failed
今天在系统中做某一操作的时候报如下截图错误,把错误日志下载下来,根据AccessRights这:ReadAccess一提示确定是对某一实体没有读的权限. 那怎样知道是哪个实体呢,再看上面错误日志中给出 ...
- java中Error与Exception有什么区别
Error类和Exception类都继承自Throwable类. Error的继承关系: java.lang.Object java.lang.Throwable java.lang.Er ...
- Oracle生成查询包含指定字段名对应的所有数据表记录语句
应用场合:已知字段名字,查询数据库中所有数据表中包含该字段名的所有数据表 操作办法:指定字段名,数据库表用户,执行下面查询语句即可 --Oracle生成查询包含指定字段名对应的所有数据表记录语句 de ...