前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Android XML】Android XML 转 Java Code 系列之 style(3)

【Android XML】Android XML 转 Java Code 系列之 style(3)

作者头像
sickworm
发布2019-02-27 17:05:51
6300
发布2019-02-27 17:05:51
举报
文章被收录于专栏:sickworm

最近一个月把代码重构了一遍, 感觉舒服多了, 但总体开发进度没有变化.. 今天聊聊把style属性转换成Java代码的办法

先说结论: 引用系统style是无法完美的实现的, 我们如果有写成Java代码的需求, 请尽量避免使用系统style. 自定义style没问题.

style是什么?

(参考链接) http://developer.android.com/guide/topics/resources/style-resource.html

” A style resource defines the format and look for a UI. A style can be applied to an individual View (from within a layout file) or to an entireActivity or application (from within the manifest file).”

更通俗的理解是, style其实是放置一组attribute的宏, 在控件中指定这个style, 将在xml解析时将style的一组属性应用到该控件中. 举个栗子:

这里有个style, 定义在res/value中:

<span style="color: #0000ff;"><?</span><span style="color: #ff00ff;">xml version="1.0" encoding="utf-8"</span><span style="color: #0000ff;">?></span> <span style="color: #0000ff;"><</span><span style="color: #800000;">resources</span><span style="color: #0000ff;">></span> <span style="color: #0000ff;"><</span><span style="color: #800000;">style </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="CustomText"</span><span style="color: #ff0000;"> parent</span><span style="color: #0000ff;">="@style/Text"</span><span style="color: #0000ff;">></span> <span style="color: #0000ff;"><</span><span style="color: #800000;">item </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="android:textSize"</span><span style="color: #0000ff;">></span>20sp<span style="color: #0000ff;"></</span><span style="color: #800000;">item</span><span style="color: #0000ff;">></span> <span style="color: #0000ff;"><</span><span style="color: #800000;">item </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="android:textColor"</span><span style="color: #0000ff;">></span>#008<span style="color: #0000ff;"></</span><span style="color: #800000;">item</span><span style="color: #0000ff;">></span> <span style="color: #0000ff;"></</span><span style="color: #800000;">style</span><span style="color: #0000ff;">></span> <span style="color: #0000ff;"></</span><span style="color: #800000;">resources</span><span style="color: #0000ff;">></span>

1234567

<span style="color: #0000ff;"><?</span><span style="color: #ff00ff;">xml version="1.0" encoding="utf-8"</span><span style="color: #0000ff;">?></span><span style="color: #0000ff;"><</span><span style="color: #800000;">resources</span><span style="color: #0000ff;">></span>    <span style="color: #0000ff;"><</span><span style="color: #800000;">style </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="CustomText"</span><span style="color: #ff0000;"> parent</span><span style="color: #0000ff;">="@style/Text"</span><span style="color: #0000ff;">></span>        <span style="color: #0000ff;"><</span><span style="color: #800000;">item </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="android:textSize"</span><span style="color: #0000ff;">></span>20sp<span style="color: #0000ff;"></</span><span style="color: #800000;">item</span><span style="color: #0000ff;">></span>        <span style="color: #0000ff;"><</span><span style="color: #800000;">item </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="android:textColor"</span><span style="color: #0000ff;">></span>#008<span style="color: #0000ff;"></</span><span style="color: #800000;">item</span><span style="color: #0000ff;">></span>    <span style="color: #0000ff;"></</span><span style="color: #800000;">style</span><span style="color: #0000ff;">></span><span style="color: #0000ff;"></</span><span style="color: #800000;">resources</span><span style="color: #0000ff;">></span>

然后我们在layout中的某个控件引用了这个style:

<span style="color: #0000ff;"><?</span><span style="color: #ff00ff;">xml version="1.0" encoding="utf-8"</span><span style="color: #0000ff;">?></span> <span style="color: #0000ff;"><</span><span style="color: #800000;">EditText </span><span style="color: #ff0000;">style</span><span style="color: #0000ff;">="@style/CustomText"</span><span style="color: #ff0000;"> android:layout_width</span><span style="color: #0000ff;">="fill_parent"</span><span style="color: #ff0000;"> android:layout_height</span><span style="color: #0000ff;">="wrap_content"</span><span style="color: #ff0000;"> android:text</span><span style="color: #0000ff;">="Hello, World!"</span> <span style="color: #0000ff;">/></span>

12

<span style="color: #0000ff;"><?</span><span style="color: #ff00ff;">xml version="1.0" encoding="utf-8"</span><span style="color: #0000ff;">?></span><span style="color: #0000ff;"><</span><span style="color: #800000;">EditText </span><span style="color: #ff0000;">style</span><span style="color: #0000ff;">="@style/CustomText"</span><span style="color: #ff0000;"> android:layout_width</span><span style="color: #0000ff;">="fill_parent"</span><span style="color: #ff0000;"> android:layout_height</span><span style="color: #0000ff;">="wrap_content"</span><span style="color: #ff0000;"> android:text</span><span style="color: #0000ff;">="Hello, World!"</span> <span style="color: #0000ff;">/></span>

实际上, 他是等于:

<span style="color: #0000ff;"><?</span><span style="color: #ff00ff;">xml version="1.0" encoding="utf-8"</span><span style="color: #0000ff;">?></span> <span style="color: #0000ff;"><</span><span style="color: #800000;">EditText </span><span style="color: #ff0000;">android:textSize</span><span style="color: #0000ff;">="20sp"</span><span style="color: #ff0000;"> android:textColor</span><span style="color: #0000ff;">="#008"</span><span style="color: #ff0000;"> android:layout_width</span><span style="color: #0000ff;">="fill_parent"</span><span style="color: #ff0000;"> android:layout_height</span><span style="color: #0000ff;">="wrap_content"</span><span style="color: #ff0000;"> android:text</span><span style="color: #0000ff;">="Hello, World!"</span> <span style="color: #0000ff;">/></span>

12

<span style="color: #0000ff;"><?</span><span style="color: #ff00ff;">xml version="1.0" encoding="utf-8"</span><span style="color: #0000ff;">?></span><span style="color: #0000ff;"><</span><span style="color: #800000;">EditText </span><span style="color: #ff0000;">android:textSize</span><span style="color: #0000ff;">="20sp"</span><span style="color: #ff0000;"> android:textColor</span><span style="color: #0000ff;">="#008"</span><span style="color: #ff0000;"> android:layout_width</span><span style="color: #0000ff;">="fill_parent"</span><span style="color: #ff0000;"> android:layout_height</span><span style="color: #0000ff;">="wrap_content"</span><span style="color: #ff0000;"> android:text</span><span style="color: #0000ff;">="Hello, World!"</span> <span style="color: #0000ff;">/></span>

有点宏替换的味道, 如果接触过html的同学可以很容易想到CSS这种东西, 两个想要做的基本是一样的.

需要指明的是: style的属性的优先级是最低的, 会被控件的其他相同属性覆盖掉. 这是理所当然的, 不然控件里的attribute要不服了(你都把我写出来了, 居然和我说我没用, 要被style那货覆盖掉?!)

让我们再回到这个被我们定义的style上, 会发现他还有一个叫parent的属性. 这里我们用面向对象的父类来理解, 就是子style会继承父类的属性. 同样的, 父类的属性要比子类属性优先级要低. (你都把我写出来了, 居然和我说我没用, 要被老爸的style覆盖掉?!)

style不是什么?

style不属于android Namespace中的属性 (不以android:开头), 没有对应的setStyle方法可以使用, 我的理解是它属于xml预加载的一种”机制”.

自定义style的翻译:

那么对于自定义的style, 翻译就很简单了.

对于一个style, 将其替换成style中的attribute集合, 并向上 (父类) 继续增加父类集合, 并注意优先级 (子类可以覆盖父类attribute).

系统style的翻译:

系统style的翻译主要存在两个问题:

1. 系统style是内置在系统内部的, 不同的系统style并不一样, 特别是深度定制化的如MIUI, Flyme等操作系统. 如果只是使用一些简单的比较标准的style, 如progressbar等, 可以通过SDK Manager下载最新Android版本的API, 然后在路径platformsandroid-20dataresvalues中找到标准的系统style, 或直接下载ASOP(路径framework/base/core/res/res/values/styles.xml. (我在项目中用到的是4.4的style文件, 5.0的sytle文件分成了多个, 而且里面的命名有点不规范)

有些同学会发现, 如progressbar里面的style: android:attr/progressBarStyleSmall, 是用android:attr索引的. android:attr其实是在theme中定义的属性, apk的theme在AndroidManifest.xml中定义. 在解析xml过程中, 遇到android:attr的时候, 他就会在apk指定的theme中找到相应的item. 这个item对应的值就是style的值, 如:

<span style="color: #000000;">style=?android:attr/progressBarStyleSmall 对应 最基本的Theme中的 </span><span style="color: #0000ff;"><</span><span style="color: #800000;">item </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="progressBarStyleSmall"</span><span style="color: #0000ff;">></span>@android:style/Widget.ProgressBar.Small<span style="color: #0000ff;"></</span><span style="color: #800000;">item</span><span style="color: #0000ff;">></span>

1

<span style="color: #000000;">style=?android:attr/progressBarStyleSmall 对应 最基本的Theme中的 </span><span style="color: #0000ff;"><</span><span style="color: #800000;">item </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="progressBarStyleSmall"</span><span style="color: #0000ff;">></span>@android:style/Widget.ProgressBar.Small<span style="color: #0000ff;"></</span><span style="color: #800000;">item</span><span style="color: #0000ff;">></span>

然后你再去styles.xml中寻找Widget.ProgressBar.Small. (这里还有个要注意的是, 就是系统的style不会声明parent属性, 但是以点”.”做层级, 比如这里的Widget.ProgressBar.Small父类是Widget.ProgressBar)

这样带来的另一个问题, 深度定制的操作系统各种主题也会有改动, 这样造成更大的偏差.

2. 系统style用到的资源, 有些是我们从外部无法获取的. 还是举Widget.ProgressBar.Small的例子:

<span style="color: #0000ff;"><</span><span style="color: #800000;">style </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="Widget.ProgressBar.Small"</span><span style="color: #0000ff;">></span> <span style="color: #0000ff;"><</span><span style="color: #800000;">item </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="android:indeterminateDrawable"</span><span style="color: #0000ff;">></span>@android:drawable/progress_small_white<span style="color: #0000ff;"></</span><span style="color: #800000;">item</span><span style="color: #0000ff;">></span> <span style="color: #0000ff;"><</span><span style="color: #800000;">item </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="android:minWidth"</span><span style="color: #0000ff;">></span>16dip<span style="color: #0000ff;"></</span><span style="color: #800000;">item</span><span style="color: #0000ff;">></span> <span style="color: #0000ff;"><</span><span style="color: #800000;">item </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="android:maxWidth"</span><span style="color: #0000ff;">></span>16dip<span style="color: #0000ff;"></</span><span style="color: #800000;">item</span><span style="color: #0000ff;">></span> <span style="color: #0000ff;"><</span><span style="color: #800000;">item </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="android:minHeight"</span><span style="color: #0000ff;">></span>16dip<span style="color: #0000ff;"></</span><span style="color: #800000;">item</span><span style="color: #0000ff;">></span> <span style="color: #0000ff;"><</span><span style="color: #800000;">item </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="android:maxHeight"</span><span style="color: #0000ff;">></span>16dip<span style="color: #0000ff;"></</span><span style="color: #800000;">item</span><span style="color: #0000ff;">></span> <span style="color: #0000ff;"></</span><span style="color: #800000;">style</span><span style="color: #0000ff;">></span>

1234567

<span style="color: #0000ff;"><</span><span style="color: #800000;">style </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="Widget.ProgressBar.Small"</span><span style="color: #0000ff;">></span>        <span style="color: #0000ff;"><</span><span style="color: #800000;">item </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="android:indeterminateDrawable"</span><span style="color: #0000ff;">></span>@android:drawable/progress_small_white<span style="color: #0000ff;"></</span><span style="color: #800000;">item</span><span style="color: #0000ff;">></span>        <span style="color: #0000ff;"><</span><span style="color: #800000;">item </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="android:minWidth"</span><span style="color: #0000ff;">></span>16dip<span style="color: #0000ff;"></</span><span style="color: #800000;">item</span><span style="color: #0000ff;">></span>        <span style="color: #0000ff;"><</span><span style="color: #800000;">item </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="android:maxWidth"</span><span style="color: #0000ff;">></span>16dip<span style="color: #0000ff;"></</span><span style="color: #800000;">item</span><span style="color: #0000ff;">></span>        <span style="color: #0000ff;"><</span><span style="color: #800000;">item </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="android:minHeight"</span><span style="color: #0000ff;">></span>16dip<span style="color: #0000ff;"></</span><span style="color: #800000;">item</span><span style="color: #0000ff;">></span>        <span style="color: #0000ff;"><</span><span style="color: #800000;">item </span><span style="color: #ff0000;">name</span><span style="color: #0000ff;">="android:maxHeight"</span><span style="color: #0000ff;">></span>16dip<span style="color: #0000ff;"></</span><span style="color: #800000;">item</span><span style="color: #0000ff;">></span>    <span style="color: #0000ff;"></</span><span style="color: #800000;">style</span><span style="color: #0000ff;">></span>

他里面用到了@android:drawable/progress_small_white这个系统资源, 但是这个资源不是public的, 我们实现的时候没办法把这个资源调用出来. 有些同学会想到反射, 但反射也是不行的. 因为所有的系统资源在ASOP编译的时候会生成类似于R.java这样的资源索引文件, 这些文件用于我们使用系统资源的id来调用系统资源. 而非public是不会声明出来的, 也就是说你连id都无法知道, 也就无法获取对应资源了. 我曾大致阅读了一下xml的解析实现, 发现到最后都进入了native层, 在native层用c/c++实现, 这让我望code兴叹..

不过ProgressBar的各种样式应该可以通过api来设置出来, 这个我还没证实. 可以参考: [Android实例] Android 在Java代码中设置style属性–使用代码创建ProgressBar对象

对这个非public系统资源获取有经验的同学欢迎交流.

项目代码:

我在项目中实现了构建style元素, 使用style元素替换为attritutes, 以及style元素之间的关系, 包括对theme的android:attr寻找:

https://github.com/SickWorm/AndroidXMLToJava/blob/master/src/com/excelsecu/androidx2j/AX2JStyle.java

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016年2月1日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • style是什么?
  • style不是什么?
  • 自定义style的翻译:
  • 系统style的翻译:
  • 项目代码:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档