我们知道,在 Android 开发过程中,我们的数据常常来自于服务端,只有在运行时才能获得数据展示,因此在布局 XML 的编写过程中,由于缺少数据,我们很难直接看到填充数据后的布局效果,那这个时候你一般是怎么做的呢?
经常看到一些小伙伴的做法是在布局文件中临时写死一些数据来查看布局展示效果,在查看结束后,再手动将这些数据进行删除。
是不是很麻烦,那我们有没有更简单点的方案呢?
针对上述的问题,Google 官方其实早就考虑到了,因此在开发工具中提供了 tools 命名空间的支持。
在布局 XML 文件中使用
tools:
命名空间添加的属性,在项目构建成 过程中,tools 属性会被构建工具自动移除,最终不会对构建程序产生任何的影响。
而除去在编写布局时的预览功能外,tools:
命名空间属性还提供了很多有用的功能,那么接下来我们就来详细介绍下 tools 属性的这些功能。
按照官方的定义, tools 属性划分为了三种类型:
错误控制属性(Error handling attributes)
主要用来帮助我们控制一些由 lint 产生的错误警告。
tools:ignore
适合于任意元素
我们知道,在 Android 开发工具中提供了 lint 工具,可以帮助您轻松地识别并纠正问题与结构质量的代码。
而 lint 中针对不同的问题警告定义了不同的 ID,该属性则可以通过设置 lint 中对应的问题 ID 来让 lint 忽略该种警告,同时也可以通过逗号分隔符的方式设置多个问题 ID 来忽略多种警告。
例:
<string name="show_all_apps" tools:ignore="MissingTranslation">All</string>
一般在存在多国语言资源包的情况下, 如果 strings.xml 里某个String 没有给出其他语言版本的翻译, 那么 lint 会给出 MissingTranslation 的警告提示,
而通过 tools:ignore="MissingTranslation"
我们就可以让 Lint 针对这条 String 忽略这个警告。
再例如我们开发中更常见的一个问题:
在使用 ImageView 标签时,如果不加 android:contentDescription
那么 lint 会给出 contentDescription 的相关警告,
此时,我们可以通过给 ImageView 标签添加 tools:ignore="contentDescription"
来忽略这个警告。
<ImageView ...
tools:ignore="contentDescription"
/>
tools:targetApi
适用于任何元素
这个属性类似我们在代码中使用 @TargetApi
注解
当我们使用的组件元素支持的 Android 最低版本大于我们项目所指定的最低版本 minSdkVersion 时, lint 会给出相应的版本警告。
该属性则可以通过给指定的布局设置对应的 API 版本来通知 lint 忽略警告。
例:
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:targetApi="14" >
如果我们不使用 v4 包下的 GridLayout , 那么 GridLayout 则只支持 API LEVEL 14 以上系统,此时如果我们项目的 minSdkVersion 低于14 ,那么 lint 会给出版本警告
当添加了 tools:targetApi="14"
之后,Lint 就会停止对应的版本警告了。
tools:locale
适用于 <resources>
元素
这个属性用来指定默认的资源文件所使用的语言环境,从而避免 Lint 在拼写检测的时候带来不必要的警告提示。
默认情况下,开发工具会假设我们的语言环境为英语,因此单词检测器(spell checker)在检测过程中会对一些英文字母产生警告。
例如,我的 app_name 叫TRSDK, 默认情况下 TRSDK 下会产生波浪线的警告提示:
此时如果我通过 tools:locale
设置默认环境为中文 zh,那么警告就会消失了
设计时预览属性(Design-time view attributes)
这类属性主要是针对于 Android layout 布局的特征属性的,通过设置这类属性可以在 Android Studio 的布局预览界面快速预览布局展示效果。
tools: instead of android:(可替代任何 android:
开头的属性)
适用于 <view>
类视图元素
你可以针对视图组件的属性,通过使用 tools :
前缀来替换 android:
前缀,从而提前在布局预览界面预览属性设置的效果。
并且在代码构建的时候,构建工具会自动移除这些属性,不对最终打包的 APK 产生任何影响。
例如:
如果 TextView 的数据需要在运行时才能获取,那我们可以通过设置 tool:text
的值,在布局预览界面预览数据填充后的效果,如图:
我们可以同时设置 android: 属性(运行时才能显示) 和匹配的 tools: 属性(只会在布局预览界面显示),构建项目时最终 tools 属性会被移除,只以 android: 属性的值显示。
假设 FrameLyout 中有多个子布局,并且我们只想预览有一个布局时的效果,此时,我们也可以通过设置 tools 属性来预览一个子布局时的显示效果:
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="First" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Second"
tools:visibility="invisible" />
tools:context
适用于部分 <view>
根布局
该属性用于设置布局文件相关的 Activity,从而使用开发工具的快速修复功能( quick fix )时能自动关联 Activity 上下文生成对应的代码。
例如:
<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:orientation="vertical"
tools:context=".MainActivity">
<Button
android:text="Button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/button"
android:layout_weight="1"
android:onClick="onButtonClicked"/>
</LinearLayout>
这里我们给根布局 LinearLayout 设置了 tools:context = ".MainActivity",当我们使用 Android Studio 的快速修复功能时,则会关联相关的 Activity 进行提示:
tools:layout
适用于 <fragment>
该属性用来定义需要在 fragment 内进行绘制的布局 layout ,从而在布局预览界面预览 fragment 的显示视图。
例如:
<fragment android:name="com.example.master.ItemListFragment"
tools:layout="@layout/list_content" />
tools:listitem / tools:listheader / tools:listfooter
适用于 <AdapterView>
还有 <ListView>
的子类
我们知道,在编写列表的时候,列表的 item 布局都是在 adapter 的 getView 里通过代码来进行设置的,在非运行时的环境下,无法看到列表的直接预览效果。
这几个属性便提供了这样的功能,通过直接设置对应的 layout 布局,我们可以在开发工具的布局预览界面直接看到显示效果:
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/sample_list_item"
tools:listheader="@layout/sample_list_header"
tools:listfooter="@layout/sample_list_footer" />
tools:showIn
适用于被 <include>
标签引用的布局根 <view>
假设 TextView 在 activity_main 布局中被 <include> 引用了,此时如果通过 tools:showIn 指向 activity_main, 则此时在布局预览界面能看到 TextView 在 activity_main 中的显示效果。
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:text="@string/hello_world"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:showIn="@layout/activity_main" />
tools:menu
适用于部分根 <view>
这个属性用来指定需要在 app bar 中显示的 menu 布局,可以使用逗号分隔符来指定多个 menu 布局。
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:menu="menu1,menu2" />
不过目前在 toolbar 下测试并未有效,如果有小伙伴知道该属性具体如何使用的,欢迎在评论中留言哈。
资源筛减属性(Resource shrinking attributes)
该类型属性允许你启用严格关联检测
并且决定在项目构建的时候是否保留或丢弃指定的资源文件。
使用该属性需要在 build.gradle 中设置 shinkResources 为 true 来开启资源压缩功能。
开启资源压缩后,在代码中或资源文件中未被引用的资源会在构建过程中被移除。
android {
...
buildTypes {
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}
tools:shrinkMode
适用于 <resources>
资源标签
该属性允许你指定构建工具是否使用 "safe mode" 安全模式 (该模式会保留所有明确引用的资源以及可能被 [Resources.getIdentifier()
](https://developer.android.google.cn/reference/android/content/res/Resources.html#getIdentifier(java.lang.String, java.lang.String, java.lang.String))动态引用的资源)
或是 "strict mode" 严格模式 (该模式只保留在代码或者资源文件中明确引用的资源)
默认情况下 shrinkMode="safe",如果需要使用严格模式,则在 <resources> 中设置 tools:shrinkMode="strict"
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:shrinkMode="strict" />
tools:keep
适用于 <resources>
资源标签
当开启了资源压缩(shrinking resource)功能时,这个属性允许你指定哪些资源需要被保留。
因为开启了资源压缩功能后,未被引用的资源文件会在构建过程中被移除,而部分使用 [Resources.getIdentifier()
](https://developer.android.google.cn/reference/android/content/res/Resources.html#getIdentifier(java.lang.String, java.lang.String, java.lang.String)) 进行引用的资源文件可能被误删。
此时我们可以使用该属性指定哪些资源需要保留,不能被移除:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@layout/used_1,@layout/used_2,@layout/*_3" />
tools:discard
适用于 <resources>
资源标签
当使用资源压缩功能移除没用的资源文件时,有些资源虽然被引用了,但移除对 app 不会产生任何影响,或者因为 Gradle plugin 错误地移除了关联的资源。
此时,我们可以通过这个属性来指定需要移除的资源:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:discard="@layout/unused_1" />