当前位置:主页 > 查看内容

Style在Android中的继承关系

发布时间:2021-09-17 00:00| 位朋友查看

简介:Android的Styles(样式)和Themes(主题)非常类似Web开发里的CSS,方便开发者将页面内容和布局呈现分开。Style和Theme在Android里的定义方式是完全一样的,两者只是概念上的区别:Style作用在单个视图或控件上,而Theme用于Activity或整个应用程序。由于作用范……

Android的Styles(样式)和Themes(主题)非常类似Web开发里的CSS,方便开发者将页面内容和布局呈现分开。Style和Theme在Android里的定义方式是完全一样的,两者只是概念上的区别:Style作用在单个视图或控件上,而Theme用于Activity或整个应用程序。由于作用范围的不同,Theme也就需要比Style包含更多的定义属性值的项目(item)。不过本文,我将Style和Theme都归为Style来称呼。

Android的Style和Web的CSS相比,有一个缺陷就是只能针对一个对象只能通过android:theme="@style/AppTheme"或style="@style/MyStyle"指定一个值。而CSS则可以通过class属性在DOM元素上定义多个样式来达到组合的效果。不过Style也有CSS没有的功能,那就是继承(Inheritance)。(当然CSS通过LESS和SASS这些工具也获得继承的能力。)

Style继承简介

根据Android Developers官方文档的介绍,定义Style的继承有两种方式:一是通过parent标志父Style;

  1. <style name="GreenText" parent="@android:style/TextAppearance" 
  2.     <item name="android:textColor">#00FF00</item>  
  3. </style>  

另一种则是将父Style的名字作为前缀,然后通过“.”连接新定义Style的名字:

  1. <style name="CodeFont.Red"
  2. <item name="android:textColor">#FF0000</item> 
  3. </style>  

第二种方式可以***连接子Style来实践多层继承:

  1. <style name="CodeFont.Red.Big"
  2. <item name="android:textSize">30sp</item> 
  3. </style>  

相对***种,Android对第二种方式做出的限制就是Style必须是由自己定义的,或者说父Style和子Style必须是定义在同一个程序内,不能是引用第三方或系统的Style。毕竟对于系统的Style的引用是需要加上android:前缀作为命名空间。

其次在使用Style时,对于第二种方式定义的Style,必须引用其完全的名字,也就是说必须要包含完整的前缀和名字:

  1. <EditText 
  2. style="@style/CodeFont.Red.Big" 
  3. ... />  

Android对于***种定义方式并没用限制,所以所有以第二种方式定义的Style都可以转用***种:

  1. <style name="Big" parent="CodeFont.Red"
  2. <item name="android:textSize">30sp</item> 
  3. </style>  

只要parent中的名字对应上实际定义的Style名字即可。不过换成***种后Style的名字如果太简洁就容易冲突了。

两种继承方式混合的效果

前面说到Style的两种继承方式的效果是一致的,那假如将两种方式混在一起定义一个Style又会是什么样的效果呢?下边就用实际例子来分析一下。

首先定义一些实验所需的自定义属性(attr),(这样可以减少系统属性的干扰,因为系统总是会为它的属性定义值,那样可能无法分辨***的效果是来自系统还是定义的值)

  1. <?xml version="1.0" encoding="utf-8"?> 
  2.  
  3. <resources> 
  4.  
  5.     <declare-styleable name="CustomStyle"
  6.  
  7.         <attr name="customColor" format="color"/> 
  8.  
  9.         <attr name="customText" format="string"/> 
  10.  
  11.         <attr name="customSize" format="dimension"/> 
  12.  
  13.     </declare-styleable> 
  14.  
  15. </resources>  

接着定义一个TextView的子类,并在其中获取上边自定义属性的值并赋予TextView去呈现:

  1. import android.util.TypedValue; 
  2.  
  3. import android.widget.TextView; 
  4.  
  5. /** 
  6.  
  7. * @author Ider 
  8.  
  9. */ 
  10.  
  11. public class StyledTextView extends TextView { 
  12.  
  13.     public StyledTextView(Context context) { 
  14.  
  15.         this(context, null); 
  16.  
  17.     } 
  18.  
  19.     public StyledTextView(Context context, AttributeSet attrs) { 
  20.  
  21.         this(context, attrs, 0); 
  22.  
  23.     } 
  24.  
  25.     public StyledTextView(Context context, AttributeSet attrs, int defStyleAttr) { 
  26.  
  27.         super(context, attrs, defStyleAttr); 
  28.  
  29.         final TypedArray a = context.getTheme() 
  30.  
  31.                 .obtainStyledAttributes(attrs, R.styleable.CustomStyle, defStyleAttr, 0); 
  32.  
  33.         final CharSequence text = a.getText(R.styleable.CustomStyle_customText); 
  34.  
  35.         final int color = a.getColor(R.styleable.CustomStyle_customColor, Color.RED); 
  36.  
  37.         final float size = a.getDimensionPixelSize(R.styleable.CustomStyle_customSize, 70); 
  38.  
  39.         a.recycle(); 
  40.  
  41.         setText(text); 
  42.  
  43.         setTextColor(color); 
  44.  
  45.         setTextSize(TypedValue.COMPLEX_UNIT_PX, size); 
  46.  
  47.     } 
  48.  
  49.  

然后就是定义研究所需的Style

  1. <resources> 
  2.  
  3.     <style name="SuperStyleOne"
  4.  
  5.         <item name="customColor">@android:color/holo_orange_dark</item> 
  6.  
  7.         <item name="customText">Hello World</item> 
  8.  
  9.         <item name="customSize">30dp</item> 
  10.  
  11.     </style> 
  12.  
  13.     <style name="SuperStyleTwo"
  14.  
  15.         <item name="customText">www.iderzheng.com</item> 
  16.  
  17.     </style> 
  18.  
  19.     <style name="SuperStyleOne.SubOne"
  20.  
  21.         <item name="customColor">@android:color/holo_blue_dark</item> 
  22.  
  23.     </style> 
  24.  
  25.     <style name="SuperStyleOne.SubTwo" parent="SuperStyleTwo"
  26.  
  27.     </style> 
  28.  
  29.     <style name="SuperStyleOne.SubThree" parent="SuperStyleTwo"
  30.  
  31.         <item name="customText">blog.iderzheng.com</item> 
  32.  
  33.     </style> 
  34.  
  35. </resources>  

上边定义的Style里,SuperStyleOne将通过添加前缀的方式作用到子Style上,而SuperStyleTwo则通过指定到parent来其作用。可以看到SubTwo和SubThree混合了两种方式。

***在Activity的布局视图里使用自定类并设定上不同的Style

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  2.  
  3.               xmlns:tools="http://schemas.android.com/tools" 
  4.  
  5.               android:orientation="vertical" 
  6.  
  7.               android:layout_width="match_parent" 
  8.  
  9.               android:layout_height="match_parent" 
  10.  
  11.               android:paddingLeft="@dimen/activity_horizontal_margin" 
  12.  
  13.               android:paddingRight="@dimen/activity_horizontal_margin" 
  14.  
  15.               android:paddingTop="@dimen/activity_vertical_margin" 
  16.  
  17.               android:paddingBottom="@dimen/activity_vertical_margin" 
  18.  
  19.               tools:context=".MainActivity"
  20.  
  21.     <com.ider.trial.styles.StyledTextView 
  22.  
  23.             style="@style/SuperStyleOne" 
  24.  
  25.             android:layout_width="wrap_content" 
  26.  
  27.             android:layout_height="wrap_content"/> 
  28.  
  29.     <com.ider.trial.styles.StyledTextView 
  30.  
  31.             style="@style/SuperStyleOne.SubOne" 
  32.  
  33.             android:layout_width="wrap_content" 
  34.  
  35.             android:layout_height="wrap_content"/> 
  36.  
  37.     <com.ider.trial.styles.StyledTextView 
  38.  
  39.             style="@style/SuperStyleOne.SubTwo" 
  40.  
  41.             android:layout_width="wrap_content" 
  42.  
  43.             android:layout_height="wrap_content"/> 
  44.  
  45.     <com.ider.trial.styles.StyledTextView 
  46.  
  47.             style="@style/SuperStyleOne.SubThree" 
  48.  
  49.             android:layout_width="wrap_content" 
  50.  
  51.             android:layout_height="wrap_content"/> 
  52.  
  53. </LinearLayout>  

运行之后得到效果如下:

***个和第二个都是Style标准的使用方式,也看到它们正确地获得了定义的属性值,子Style也正确的继承和覆盖了父Style的属性值。

对于第三个和第四个,它们呈现的颜色是代码中使用的默认红色(Color.RED),字体的值也是源自代码中的使用值,所以明显比前两者要小。这也就是说它们并没用继承下SuperStyleOne中定义的字体大小和颜色。但是SuperStyleTwo中定义的内容被第三个正确的显示了出来,也说明SubTwo成功继承通过parent指定的父Style的内容。而第四个呈现出来内容则说明覆盖的效果也是正确的。

在做这个试验之前,我一直以为两种方式会同时其作用,只是用parent指定比用前缀有高优先级。也就是说Android会先从当前Style定义中找某个属性的值,如果没有找到就转到parent指定的父Style中找,还没有则转到前缀指定的父Style中找。但是通过上边的结果表明:当使用parent指定父Style后,前缀方式则不在其作用,只是作为Style的名字。也就是说:Android的Style不支持多继承。Style的继承只能单线一层层下来。

反过来在看看系统定义的Style也更容易懂了,比如打开themes_holo.xml,会看到很多一样的内容被”冗余”地定义在Theme.Holo和Theme.Holo.Light两个Style下。但因为Theme.Holo.Light用parent指定了其父Style是Theme.Light,所以Theme.Holo.Light并没有从Theme.Holo继承任何属性值,也因此这样的冗余是必须的。

  1. <style name="Theme.Holo.Light" parent="Theme.Light"
  2.  
  3. ... ... ... ... 
  4.  
  5. </style>  

使用Theme.Holo.Light作为Style的名字只是为了名字更加的清晰明了。

References:

  1. Styles and Themes | Android Developers
  2. Android XML theme inheriting from two parent themes? – Stack Overflow
  3. xml – Reason why style attribute does not use the android: namespace prefix – Stack Overflow 

本文转载自网络,原文链接:http://mp.weixin.qq.com/s?__biz=MzA3MDMyMjkzNg==&mid=2652262231&idx=1&sn=ed917f4c5dcb22e60f959fba886d9097&chksm=84dc70c0b3abf9d6ab3df2c62a91bde93c552b8f97f2c9daf1120916129d3b3b1ea631abdf4f&mpshare=1&s
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!
上一篇:Bluepill:LinkedIn开源的iOS并行UI测试工具 下一篇:没有了

推荐图文

  • 周排行
  • 月排行
  • 总排行

随机推荐