Using Styles and Themes in Android(在Android中使用主题和样式)

来源:互联网 发布:javascript 第7版 pdf 编辑:程序博客网 时间:2024/06/05 14:48

Basics XML Attributes(基本的XML属性)

If you’ve written an Android app, you’ve seen them. They look like this:

如果你写过一个Android应用,那你一定见过他们。他们看起来像下面这样:

<TextView    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:textSize="64sp"    android:textColor="@color/green" />


The attribute compiler: AAPT(属性编译器:AAPT)


AAPT is the Android Assets Packaging Tool.AAPT is a kitchen sink of a tool. It parses the manifest, packages assets and resources, and validates the xml.It is one of the things that parses your resources.

AAPT 是Android的资产打包工具,类似厨房水槽。它的作用主要是转换manifest清单文件、app的资产和和资源文件,并且使xml文件有效。它是一种转换资源的工具。

  • It is written in C/C++(它是用c/c++语言编写的)

  • Uses eXpat as the parser(它使用eXpat作为转换器

  • Is amazingly complex(它非常复杂)

  • XML resources end up as compressed binary XML, in the APK(XML资源最终会被压缩成二进制数据在APK包中)


Where do predefined attributes come from?(系统预定义的属性是从哪来的?)


Documented in subclasses of View, e.g.:

对于这个问题的回答在下面这篇文章的view的子栏目里有记录:

http://developer.android.com/reference/android/view/View.html#lattrs

Defined in:(定义在下面这个文件里)

$ANDROID_HOME/frameworks/base/core/res/res/values/attrs.xml

Designed for extension: Views ignore attributes they don’t understand.

为了扩展,view会忽略那些他们不懂的属性。

Not so fast…

先别急...

The Android API is whitelisted. That includes attribute names.

Android  API  是有白名单的。它包含了属性名。

You can only use, e.g.,

你只能用下面这个

android:actionModeFindDrawable

…if it is whitelisted in:

如果他在下面这个文件中是白名单的话

$ANDROID_HOME/frameworks/base/api/<N>.{xml, txt}

…And it isn’t.

然而它并不是。

I don’t know exactly why… The white-list explains why the symbol is not available from Java, not why it isn’t visible to aapt

我真的不知道为什么会这样...白名单解释了为什么标识符不能通过java获取到,但不能解释为什么aapt里看不到它。


How to Package a Widget(如何打包一个控件)

You’ll see a fair amount of this:

你会看到一大坨这样的东西:

public abstract class FooView extends BarView {    private final int bgColor;    private final int fgColor;    private final int margin;    private final int padding;    protected FooView(        int bgColor, int fgColor,        int margin, int padding)    {        this.bgColor = bgColor;        this.fgColor = fgColor;        this.margin = margin;        this.padding = padding;    }
public class MyFooView extends BaseView {    public FooView(Context context) {        super(Color.RED, Color.GREEN, 7, 3);    }


Using Custom Attributes(使用自定义属性)

A much better approach, obviously, is to define new attributes and use them to configure your custom widget.

很显然,一个更好的办法是定义新的属性并用它们来配置你的自定义控件。

It’s a 3 step process (a waltz):

这需要以下三部曲(类似华尔兹):


  • define the attributes(定义属性)

  • parse them in your widget(在你的控件代码中解析这些属性)

  • use them in your widget layout.(在你的布局文件中使用他们)

Defining Custom Attributes(定义自定义属性)

Create a new resource file in the values directory, attrs.xml:

在values文件夹下创建一个名为attrs.xml的新资源文件:



Declare your attributes in a declare-stylable element, in the new file.The declare-styleable element is not a namespace. The attributes names must be globally unique!

在这个新文件中,在一个declare-stylable节点下声明你的属性。这个declare-stylable节点不是一个命名空间。你所定义的属性名称必须是全局唯一的。

<declare-styleable name="tag_view">    <attr name="tag_view_tag_drawable" format="reference" />    <attr name="tag_view_tag_margin" format="" />    <attr name="tag_view_tag_padding" format="dimension" />    <attr name="tag_view_text_size" format="dimension" />    <attr name="tag_view_text_color" format="color" />    <attr name="tag_view_text_face" format="enum">        <enum name="normal" value="0" />        <enum name="sans" value="1" />        <enum name="serif" value="2" />        <enum name="monospace" value="3" />    </attr></declare-styleable>


Custom Attribute Formats(自定义属性格式)

There are, currently, ten formats. They are undocumented but they are defined in the aapt source, here:

目前有10种格式可选。他们虽然未被正式明文规定,但他们却在aapt中被定义了,在这里:

$ANDROID_HOME/frameworks/base/tools/aapt/ResourceTable.cpp
  • reference

  • string

  • color

  • dimension

  • boolean

  • integer

  • float

  • fraction

  • enum

  • flag

Using Attribute Formats(使用属性格式)

Formats can be or-ed together.

不同格式可以用“或”符号连在一起使用。

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

Most of them already accept references, so adding reference is usually redundant.Note the syntax of the enumerated type, an attr containing enum elements:

大多数属性已经接受了引用格式,所以再添加引用格式通常是多此一举的。注意枚举类型的语法,一个attr节点可以包含多个枚举元素:

<attr name="tag_view_text_blink" format="enum">    <enum name="false" value="0" />    <enum name="true" value="1" /></attr>


Parsing Custom Attributes(解析自定义属性)

public TagView(Context context, AttributeSet attrs, int defStyle) {    super(context, attrs, defStyle);                                // #1    TypedArray atts = context.getTheme().obtainStyledAttributes(attrs, R.styleable.tag_view, defStyle, 0);    try {        final int n = atts.getIndexCount();        for (int i = 0; i < n; i++) {            try {                int attr = atts.getIndex(i);                switch (attr) {                    case R.styleable.tag_view_tag_view_text_color:                        textColor = atts.getColor(attr, textColor); // #3                        break;                    //// other cases...                }            }            catch (UnsupportedOperationException e) {                Log.w(TAG, "Failed parsing attribute: " + atts.getString(i), e);            }            catch (NotFoundException e) {                Log.w(TAG, "Failed parsing attribute: " + atts.getString(i), e);            }        }    }    finally { atts.recycle(); }                                     // #4}
    1. Be sure to let the super classes parse its attributes! Call the super constructor.

    1.一定要让父类解析它的属性!要调用父类的构造函数。

    2.While it is possible to get the attributes out of the AttributeSet, it is unnecessarily difficult. Styles have not been applied and @ references have not been resolved.
    2.虽然可以从AttributeSet中得到属性,但是没有必要搞的这么困难。样式还没有被应用,而且引用也尚未被解析。

    3.The TypedArray has getters for the above mentioned formats, plus a few more:
    3.对于上述格式TypedArray有专门的get方法来获取,甚至还有其他一些get方法:
            1.getDrawable
            2.getDimensionPixelOffset
            3.etc…

    4.Be sure to recycle the TypedArray when you are through with it.
    4.TypedArray用完之后一定记得要及时回收


More Parsing Custom Attributes(更多关于解析自定义属性)

A handy idiom, here, is:

这有一个很方便的习惯性写法:

attribute = defaultVal;//...case case R.styleable.tag:    attribute = atts.getAttribute(attr, attribute);//...finalAttribute = attribute;

If there are a lot of attributes, you might want to consider using a builder.

如果有很多属性要解析,您可能需要考虑使用一个builder。


Using Custom Attributes(使用自定义属性)

Add a new namespace to your layout and then use your new attributes like an others.

在你的布局文件中添加一个新的命名空间,然后像使用其他系统属性那样使用你的自定义属性。

xmlns:tagview="http://schemas.android.com/apk/res/<your package name>

Note that you add your package namespace, even if the attributes are defined in a library project!

注意在引用你的自定义属性时你需要加上刚才定义的命名空间,即使你的属性是定义在一个类库中!

<net.callmeike.android.sandbox.tagview.TagView        xmlns:android="http://schemas.android.com/apk/res/android"        xmlns:tagview="http://schemas.android.com/apk/res/net.callmeike.android.sandbox.tagview"        android:id="@+id/tags"        android:layout_width="match_parent"        android:layout_height="0dp"        android:layout_weight="1"        tagview:tag_view_tag_drawable="@drawable/tag"        tagview:tag_view_tag_margin="20dp"        tagview:tag_view_tag_padding_horizontal="10dp"        tagview:tag_view_tag_padding_vertical="6dp"        tagview:tag_view_text_style="bold" />


Introducing Styles(样式的介绍)

Styles bring a cascading-style-sheet-like capability to the Android UI. The syntax is very simple.

样式给Android 的 UI带来了类似网页设计中CSS样式表那样的能力。样式使用语法也很简单。

Translate:

android:attribute="value"

…in a layout, to:

<item name="android:attribute">value</item>

…in a style resource.

它把布局文件中的android:attribute="value" 翻译成了资源文件中的<item name="android:attribute">value</item>

Apply it using a style attribute:

像下面这样应用它:

<MyView  style="@style/mystyle"

Note that the style attribute is not in the android namespace.

注意这个样式属性不在“android”命名空间中。


Basic Styles(基础样式)

For instance, reorganize this:

例如长得像下面这些那样:

<TextView    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:textSize="64sp"    android:textColor="@color/green" />

as this:

<TextView    style="@style/big_green"    android:layout_width="wrap_content"    android:layout_height="wrap_content" />

and this:

<style name="big_green">    <item name="android:textSize">64sp</item>    <item name="android:textColor">@color/green</item></style>


Style Inheritance(样式继承)

These two style definitions are (roughly) equivalent:

这两种样式定义方式的效果是一样的:

<style name="Big">    <item name="android:textSize">64sp</item></style><style name="Big.Green">    <item name="android:textColor">@color/green</item></style>
<style name="Big">    <item name="android:textSize">64sp</item></style><style name="Big_Green" parent="Big">    <item name="android:textColor">@color/green</item></style>


Using Styles(使用样式)

The wins should be obvious.

优势应该是显而易见的。

  • A designer sets up standard styles for an application and applies them, as appropriate, to layouts.

  • 程序设计者为应用程序设计标准样式,并使他们适用于恰当的布局。

  • Factoring out styles makes the application less brittle.

  • 把样式提取出来能使应用程序不那么脆弱。

  • Like any other defined resource, styles are subject to resource qualifiers. Your app can look good on both a phone and a TV.

  • 像任何其他定义的资源一样,样式受到资源限定符的支配。你的应用可以在手机和电视上看起来不错。

Inheriting from - and then overriding - Android types is quite useful. You have to use the "parent" attribute: the "dot" trick won’t work:

继承然后复写Android类型是非常有用的。你必须使用“parent”属性,而用“点”的那个方法是行不通的:

<style name="MyButton" parent="android:Widget.Button">    <item name="android:background">@drawable/button_bg</item></style>


Slight aside: Resource Drawables(轻微的旁白: Drawable 资源)

If you haven’t met Resource Drawables, you should.

如果你还没有碰到过Drawable 资源,你会碰到的。

Perhaps the quickest thing you can do to customize the appearance of an application, is to give buttons custom backgrounds.

也许做给app定制外观最快的一件事就是给按钮搞个自定义背景。

Like this:

<shape android:shape="rectangle">        <corners android:radius="5dp" />        <gradient                android:angle="90"                android:centerColor="@color/mist"                android:endColor="@color/mist"                android:startColor="@color/mist" />        <stroke                android:width="2dp"                android:color="@color/charcoal" /></shape>


Where do predefined styles come from?(预定义的样式是哪来的?)

Android Styles are documented in:

android 的所有样式都记录在这里面:

http://developer.android.com/reference/android/R.style.html

Defined in:定义在这里:

$ANDROID_HOME/frameworks/base/core/res/res/values/styles.xml

Dots (".") in the definition are translated into underscores ("_") for Java symbols and in the documentation.

在文档中,定义中的点(“.”)被转换成了下划线(“_”)。

…and, again, though, their visiblity controlled in:

不过,他们的可见性被控制在下面这个文件里:

$ANDROID_HOME/frameworks/base/api/<N>.{xml, txt}


Introducing Themes(主题的介绍)

A theme is a collection of named references.

主题其实就是一堆已命名的引用。

Think of a function dispatch table…

联想一下函数调度表…

Here’s a tiny exerpt from Theme.Holo

这里是Theme.Holo的一小部分

<!-- AlertDialog attributes --><item name="alertDialogTheme">@android:style/Theme.Holo.Dialog.Alert</item><item name="alertDialogStyle">@android:style/AlertDialog.Holo</item><item name="alertDialogCenterButtons">false</item><item name="alertDialogIcon">@android:drawable/ic_dialog_alert_holo_dark</item>

It creates aliases for two styles, an (boolean) enum, and a drawable.

它为两种样式分别创建了别名,一个是boolean类型的枚举,一个是drawable的。


Themes backfit Android’s appearance(主题支撑Android的外观)


Themes can be assigned to individual application components. Android uses the theme to control its appearance.

主题可以分配给单独的某个app组件。Android系统使用主题来控制其外观。

Assigning a theme with overridden attributes to a component will customize the appearance of UI objects in the component — even those not managed by the component — without any other code!

给一个组件指定带复写属性的主题,将会重新定义这个组件的UI控件的外观——即使是那些不是由该组件来管理的ui控件——这个过程并不需要任何其他代码!

<style name="AppTheme.One">        <item name="android:background">@color/gatoraid</item></style><style name="AppTheme.Two">        <item name="android:background">@color/grapeaid</item></style>
<activity        android:name=".ActivityOne"        android:label="@string/title_activity_one"        android:theme="@style/AppTheme.One" ></activity><activity        android:name=".ActivityTwo"        android:label="@string/title_activity_two"        android:theme="@style/AppTheme.Two" ></activity>


Using foreign attributes Themed Styles(使用外部属性主题样式)

You can refer to an element of a theme, using question mark ("?") syntax.

通过使用问号(“?”)的语法形式,你可以引用一个主题的样式元素。

The style Theme.Holo defines a style buttonStyle. In your layout, you can say:

在Theme.Holo这个主题中定义了一个buttonStyle的样式,你可以在你的布局中这样引用:

<Button        style="?android:buttonStyle"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:text="@string/push_me" />

BE CAREFUL: question mark syntax will allow you to create things that will not run!

注意了:问号语法将允许你创建的一些不会运行的东西!

The referenced attribute must be part of a theme. 

被引用的属性必须是一个主题的一部分。

Themes and Resource Qualifiers(主题和资源限定符)

Themes are an even more powerful way adjust the appearance of your application, to different devices.

主题还是一个调整app的外观以适应不同设备的强有力工具。

Most important, you can use them to adjust to multiple versions of Android!

最重要的是,您可以使用它们来适应多个版本的安卓系统!



Building Custom Themes(构造自定义主题)

  • Define theme attributes(定义主题里的属性)

  • Create a parent theme that defines the attributes(创建一个定义了属性的父主题)

  • Use "?" syntax to refer to the theme styles.(使用“?”语法来引用这些主题样式)

Thanks!


译者注:
说实话这篇文章在介绍安卓的样式主题的用法时并不是特别的清晰,行文有点口语化,但还是能从中学到一些有用的东西。由于本人水平有限,难免会有错漏之处,如您有所发现,还请不吝指正,谢谢!

原文链接: https://newcircle.com/s/post/1444/styles_and_themes

0 0
原创粉丝点击