精通 Android 中的 tools 命名空间

本贴最后更新于 2785 天前,其中的信息可能已经时移世改

原文: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 官方文档中了解更多信息。

引用:

  • 开发
    38 引用 • 159 回帖 • 2 关注
  • 翻译
    58 引用 • 84 回帖 • 1 关注
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    334 引用 • 323 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...