[译]精通 Android 中的 tools 命名空间

作者: lovexiaov | 来源:发表于2016-05-16 22:08 被阅读5083次

    原文:Mastering tools namespace on Android
    作者:Alexandru Simonescu
    译者:lovexiaov

    你可能注意到了 tools 命名空间会出现在许多 Google 提供的样例布局 XML 文件中。此命名空间在开发阶段很有用而且不会影响用户体验。它包含了帮助我们在 Android Studio 设计视图中渲染布局的一套方便的属性。

    有时这些巧妙的属性会节约我们的构建时间。我并不是说会加快构建速度,而是构建相关的 UI 改变会减少。

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    
    

    tools 命名空间的 URI 是 http://schemas.android.com/tools,通常使用 tools 前缀绑定,但你也可以使用任何其他前缀。

    该命名空间中的所有属性都不会影响运行时或 apk 的大小,它们会在 Gradle 打包应用时被剥离出去。

    你可以使用 Android Studio 提供的快捷键快速添加 tools 命名空间。只需输入 toolsNS 然后按下 TAB 键。

    Quick add Tools namespace

    值得一提的是截止到写这篇文章时,Android Studio 并没有太多对此 xml 语法补全支持,不过别担心,即使 AS 没有语法提示,你仍然可以覆写 tools 属性。最简单的使用方式是:首先书写基于 android: 命名空间的属性,然后使用 CMD + D 复制这行,并替换它的前缀(为 tools)。

    Duplicate and replace namespace

    开始使用

    当我刚做 Android 开发时,曾使用 android:text="" 属性结合一些硬编码的假文本在 预览窗口 中查看 TextView 或 EditText 如何显示。但是 Lint 工具会检查出硬编码字符串的问题,最后我只能去定义 strings(来消除此问题),然而这样做对用户没有任何意义,还使我的 .apk 中包含了没用的资源。

    (解决上述问题的)技巧是使用 tools:text"@string" 来在预览窗口中查看预填充了数据的视图。你会得到类似如下的 xml 代码:

    <TextView
        tools:text="Mastering ToolsNs"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
    
    

    使用以上代码片段,在设计时你会看到 TextView 中的文字,而在运行时将不会有该属性存在。

    运行时和设计时的不同属性

    需要注意的是你可以同时使用 androidtools 命名空间。tools 命名空间将会用在设计阶段而前者会用在运行时。

    有时你希望在运行时开启某些特性在设计预览时关闭。Android 文档展示了 ListView 的例子:

    <ListView
        android:id="@+id/listView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:fastScrollAlwaysVisible="true"
        tools:fastScrollAlwaysVisible=""/>
    
    

    这里你可以看到:在运行时开启了 fastScrollAlwaysVisible 功能,而在设计时关闭了它。

    其实你可以覆盖所有已存在与 android 命名空间中的属性,但无法覆盖自定义属性。

    在XML 中指定目标 API 版本

    你可以在 XML 中执行 API 级别,就想在 Java 中使用 @TargetApi 一样。API 版本可以通过一个整形或它的代号指定。这将避免 Lint 上报版本特定 XML 属性的问题。

    <TextView
        tools:text="Mastering ToolsNs"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        tools:layout_height="match_parent"
        tools:targetApi="M"
        />
    
    

    告知 Lint 你的字符串是正确的

    由于 Android Studio / Lint 默认语言是英语,如果你有其他语言的字符串资源,它将会显示如下的排版警告。

    Language typos warnings

    告知 Lint 你本地化资源的技巧:

    <resources xmlns:tools="http://schemas.android.com/tools" 
        tools:locale="es"/>
    

    这样就不会显示排版警告了。

    在 fragment 和自定义视图上预览布局

    我发现这(tools 命名空间)在使用 Fragment 和自定义视图时非常有用。通过 tools:layout="@layout/your_layout" 属性你可以设置在预览窗口中显示一个布局。

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:paddingBottom="@dimen/activity_vertical_margin"
        tools:context=".MainActivity"
        >
    
        <fragment
            android:name="com.alexsimo.mastertoolsnamespace.BooksFragment"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            tools:layout="@layout/fragment_books"
            />
    
    </LinearLayout>
    
    

    上述代码使用了 tools:layout 属性来预览 BooksFragment 布局,而不用将工程运行在设备或模拟器上。

    我们来看一下视图结构:

    activity_main:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:paddingBottom="@dimen/activity_vertical_margin"
        tools:context=".MainActivity"
        >
    
        <fragment
            android:name="com.alexsimo.mastertoolsnamespace.BooksFragment"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            tools:layout="@layout/fragment_book"
            />
    
    </LinearLayout>
    
    

    fragment_book:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v7.widget.RecyclerView
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/list"
        android:name="com.alexsimo.mastertoolsnamespace.BooksFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        app:layoutManager="LinearLayoutManager"
        tools:context="com.alexsimo.mastertoolsnamespace.BooksFragment"
        tools:listitem="@layout/fragment_book_list_item"
        />
    
    

    fragment_book_list_item:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:orientation="horizontal"
                  xmlns:tools="http://schemas.android.com/tools"
        >
    
      <ImageView
          android:layout_width="150dp"
          android:layout_height="150dp"
          android:id="@+id/imageView"
          tools:src="@android:drawable/ic_media_play"
          />
      <LinearLayout
          android:orientation="vertical"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          >
        <TextView
            android:id="@+id/id"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/text_margin"
            android:textAppearance="?attr/textAppearanceListItem"
            tools:text="My book title"
            />
        <TextView
            android:id="@+id/content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/text_margin"
            android:textAppearance="?attr/textAppearanceListItem"
            tools:text="My book description"
            />
      </LinearLayout>
    
    </LinearLayout>
    
    

    打开 activity_main 的预览窗口,你将会看到如下界面:

    预览列表项布局

    如果你比较细心,你会看到上面 xml 代码片段中的 tools:listitem="" 一行。这在预览列表时会显示你自定义的列表项而不是默认的 @android:layout/list_content"

    还有更多相关的属性,但是 RecyclerView 没有 header 或 footer 属性(这两个属性只能用在 ListView 上)。这两个属性分别是 tools:listheadertools:listfooter

    带父容器上下文的视图

    假如你有一个自定义视图或可重用的布局会通过 <include> 标签被用在许多地方。当设计该视图时,预览它在想要包含它的父容器中如何显示将会很有帮助。

    在上面的 fragment_book_list_item 中,如果我们添加 tools:showIn="@layout/activity_main" 属性,将可以预览该列表条目如何显示在 activity_main 中。这没有多大意义,只是为了演示这个概念。

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:orientation="horizontal"
                  xmlns:tools="http://schemas.android.com/tools"
                  tools:showIn="@layout/activity_main"
        >
        <!-- Remaining views removed -->
    </LinearLayout>
    
    

    预览界面将类似于这样:

    该特性也依赖于 Android Studio 的版本。截止到写此文之时,我使用的是 Android Studio v2.1。

    关联 XML 到一个 activity

    我很确定你已经知道该属性了,当我们使用 Android Studio 引导创建一个 Activity 时,在默认生成的 XML 文件中你会找到该属性 tools:context=".MainActivity"。如你所知,单个 xml 布局可以被用在多个 ActivityFragment 中,使用此属性,你就告诉了 Android Studio 那个 .java Activity 类与之相关联。

    这将帮助布局修改这猜测 Activity 的主题,因为主题曾被定义在 AndroidManifest.xml 文件中。

    忽略 Lint 警告

    你应该谨慎使用此属性,因为忽略 Lint 警告不是一个好主意。如果 Lint 上报问题,你应该行动起来并修复错误和警告。但有时 Lint 给出的是错误警告,我们明确知道(或许不知道)我们在做什么。这种情况下你可以使用 tools:ignore=""

    想想一下我们有一个图标找不到它对应的像素密度文件夹,我们可能会使用 tools:ignore="IconMissingDensityFolder" 忽略 Lint 警告。你可以在 Android 官方文档 中阅读更多关于 Lint 的内容。

    带菜单预览布局

    默认情况下,定义在 Activity.onCreateOptionsMenu() 中的菜单会被渲染到预览窗口。但你可以使用 tools:menu="comma separated menu IDs" 覆盖此菜单。我个人不会使用该属性,但它可能会对你有用。

    设置 Toolbar 导航模式

    此属性很简单!使用 tools:actionBarNavMode="standard|list|tabs" 你可以设置 ActivityBar 的导航模式。

    收缩资源

    Android tools 命名空间中有许多关于收缩资源的属性,比如 tools:shrinkMode="strict|safe"tools:keep="@layout|layout_wildcard"tools:discard="@layout/unused" 等,但我不准备在此讨论它们,因为本文不是讨论收缩资源的,如果你感兴趣,可以在 Android Studio 官方文档中了解更多信息。

    引用:

    相关文章

      网友评论

      • 斑马搬码:请问ViewStub控件能用tools预览吗
        斑马搬码:没试出来,以为是inflateId这个属性,结果是Fragment使用的。别的属性试了几个也没试出来。
        lovexiaov:@七方 试一下咯
      • robinxdroid:写的不错,第一次看到关于tools用法文章
        lovexiaov:@robinxdroid 是不是有种相见恨晚的赶脚~
      • dalimaga:不知道是不是我刚学,文章看了一遍还是不懂。😞😞
        dalimaga: @lovexiaov 是这样的,不过还是博主谢谢分享。
        lovexiaov:@联盟热 等你写过几个项目之后再回来看看就懂啦:smile:
      • binglingziyu: :dog: :gun: ,作者你粗来,私藏到现在才说出来。
        lovexiaov:@binglingziyu :smiley:
      • 71caf019970b:真棒。。做了这么久 都没关心过这个功能。
        lovexiaov:@赛飞 :grin:
      • ec95b5891948:nice,讲真,我做Android开发这么久,第一次知道tools可以干吗用!感谢 :relaxed:
        lovexiaov: @D_clock爱吃葱花 哈哈,我也是≥﹏≤
      • 67d75c11e8a3:从微信公众号点进来 棒棒棒!对于开发时预览界面真的作用很大 省时省力
        lovexiaov:@meomeoChars_ 是的呢,之前一直都不知道它是干嘛的~
      • 囧_囧:再接再厉 :+1: :+1: :+1:
        lovexiaov:@囧_囧 谢谢支持 :kissing_heart: 哈哈
      • Ken_mmm:真是极好的,现在AS2.2.1支持的也基本够用了
        lovexiaov:@AndrWang 嗯嗯,开发期的利器哇…
      • 囧_囧:请收下我的膝盖
      • Marno:很实用的文章!太棒了!支持!!!
        lovexiaov:@Marno 哈哈,有用就好啊😊

      本文标题:[译]精通 Android 中的 tools 命名空间

      本文链接:https://www.haomeiwen.com/subject/uyobrttx.html