在翻译中,我尽量的保持了原来语句的语义,但是受“chinese english”的影响,也难免有偏差,希望大家批评指正。凡是android涉及到的词汇,我一般就不译成中文了,以免出现偏差,比如View,一般情况下我没有翻译成“视图”,以免中文丰富的近义词影响阅读。另外,我只翻译了文章的主体,即技巧,其他部分(目录,前沿,序...)都没有翻译,如果有小伙伴想看这部分,可以自行翻译。
技巧2 使用快捷导入来避免重复
当你在创建一个复杂的布局时,你会发现你增加了很多的ViewGroups和Views。但是你的视图树越高,软件将越慢。创建优化的层级结构是创建运行速度快、与用户良好交互的程序基础。
在本技巧中,你将学到在XML中如何使用<include/>标签来避免重复,还有如何使用ViewStub类来快捷导入视图。
2.1 使用<include />标签避免重复
让我们想一下,如果我们要在每一个视图下加一个脚标--简单的一个例子,比如要在应用程序中一个用TextView显示应用程序的名字。如果我们有很多个Activity,可能有几个XML文件,我们要把这个TextView复制到每一个xml中吗?如果我们将来需要编辑这个内容会怎么样?复制并黏贴可能解决问题,但是这看起来不高效。最简单的办法是用<include/>在程序中增加一个脚标。让我们看看这会怎么帮助我们。
在一个的XML文件中使用<include />来加入一个另外的layout。在我们的例子中,我们将创建完整的视图,在底部,我们增加了<include/>标签指向脚标层。其中一个Activity的xml文件如下描述:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center_horizontal"
android:text="@string/hello" />
<include layout="@layout/footer_with_layout_properties"/>
</RelativeLayout>
Footer_with_layout_properties如下描述:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="30dp"
android:gravity="center_horizontal"
android:text="@string/footer_text" />
在第一个例子中,我们使用标签<include />引入唯一需要的layout。你可能会想,“好吧,之所以会起作用,因为主XML使用了RelativeLayout布局。如果其中一个XML是LinearLayout会怎么样?android:layout_alignParentBottom=”true”将不会起作用,因为它是相对布局的一个属性。”是的,是这样。让我们看看第二种使用includes的方法,这里我们将在<include />中放置android:layout_*属性。
以下是修改了的main.xml,在<include />中使用了android:layout_*属性。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center_horizontal"
android:text="@string/hello" />
<include
layout="@layout/footer"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginTop="30dp"/>
</RelativeLayout>
以下是修改了的footer.xml
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="0dp"
android:layout_height="0dp"
android:gravity="center"
android:text="@string/footer_text" />
在第二个例子中,我们将让包含footer的容器决定在什么地方放置它。安卓的事件跟踪器报告了一件事情,它说<include />标签奔溃了(引用的层参数没有其作用)。有时是这样的。问题在于,如果我们想引用任何android:layout_*属性,<include />标签必须同时指定android:layout_width和android:layout_height。
注意在该技巧里一个我们做过了的细节。正如在第二个例子中看到的,我们把每一个android:layout_*挪到了<include />里。看看footer.xml里我们设定的宽度和高度—都是0dp。我们这样做是确保当使用<include />时指定了一个宽度和高度。如果使用者不加这些,他们将看不到footer,因为都是0.
2.2 使用ViewStub类快捷导入视图
当设计布局时,你可能考虑过依赖内容或用户的交互来显示一个视图。如果你曾经让一个视图不可见,然后让它可见,你应该读下去-----你将会喜欢上ViewStub类。
让我们看看Android文档(2.4节),里面对ViewStub类做了介绍。
ViewStub是一个不可见的、0尺寸的视图,它能在运行时导入布局资源。当设置ViewStub可见时,或当inflate()被激发时,布局资源被显示。ViewStub然后用显示了布局资源的View或Views替换自己。
你已经知道了ViewStub是什么了,所以我们看看能用它做些什么。接下来的例子,你会使用ViewStub快捷导入一个MapView。想想创建位置视图的细节。看看下面两个可能的情形:
●一些地方没有GPS信号。
●使用者可能不需要地图。
如果该地没有GPS信号,你不可能在地图上放置标记,如果使用者不需要地图,为什么要加载?我们把MapView放入ViewStub里,让用户决定是否加载地图。
用以下布局实现来实现:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:onClick="onShowMap"
android:text="@string/show_map" />
<ViewStub
android:id="@+id/map_stub"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:inflatedId="@+id/map_view"
android:layout="@layout/map" />
</RelativeLayout>
很明显,我们使用map_stubID从Activity获取ViewStub,layout属性告诉了ViewStub加载哪个布局。在该示例中,我们使用以下的地图布局:
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.maps.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true"
android:apiKey="my_api_key"/>
我们需要讨论最后一个属性inflatedID。inflatedId是加载了布局的视图的ID,该加载过程发生在ViewStub类里的infalte()或setVisibility()方法调用之后。在该示例中,我们使用了setVisibility(View.VISIBLE),因为我们除了MapView不做其他任何事情。如果我们想获取视图的引用,inflate()方法会返回视图,并避免二次调用findViewById()。
Activity的代码比较简单:
publicclass MainActivity extends MapActivity {
private View mViewStub;
@Override
publicvoid onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mViewStub = findViewById(R.id.map_stub);
}
publicvoid onShowMap(View v) {
mViewStub.setVisibility(View.VISIBLE);
}
...
}
正如你看到的,当我们需要显示地图时,只要改变ViewStub的可视性就行了。
2.3 概述
<include/>是规范布局的一个有用工具。如果你用Fragment类创建了一些东西,你会发现使用包含可以做同样的事情。和用Fragment需要做的一样,你的完整的视图应该是一些列的包含(includes)。
<include/>标签提供了很好的方法来组织XML文件的内容。如果你正在制作一个复杂的布局,XML将会很大,试试用包含(include)创建不同的部分。XML会变得简单易读,组织性更强。
ViewStub是用来导入视图的极好的类。无论何时你要根据内容隐藏一个视图、还是使它变得可见、试试用ViewStub。或许当只有一个视图时,你注意不到性能上的表现,但是如果你有很多视图时会发现。