首页 > 代码库 > 每日总结 - android布局优化
每日总结 - android布局优化
1,使用<include /> 标签避免代码重复
设想一种情况:我们需要为应用程序中的每个视图都添加一个标题。为了简化问题,我们假设标题是一个显示应用程序标题的TextView。通常多个Activity 会对应多个XML 文件。难道我们需要把这个TextView 复制到每个XML 文件中吗?如果以后需要修改这个TextView 会出现什么情况?“复制/ 粘贴”的方式固然能够解决这个问题,但并不是高效的方法。解决上述问题的最简单方法是使用<include /> 标签。
我们可以通过<include /> 标签把在其他XML文件中定义的布局插入当前布局文件中。以其中一个Activity 为例,其XML 布局文件如下所示:
1 <RelativeLayout 2 xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent"> 5 <TextView 6 android:layout_width="fill_parent" 7 android:layout_height="wrap_content" 8 android:layout_centerInParent="true" 9 android:gravity="center_horizontal"10 android:text="@string/hello"/>11 <include layout="@layout/title"/>12 13 </RelativeLayout>
title布局如下所示:
1 <TextView xmlns:android="http://schemas.android.com/apk/res/android"2 android:layout_width="fill_parent"3 android:layout_height="wrap_content"4 android:layout_alignParentBottom="true"5 android:layout_marginBottom="30dp"6 android:gravity="center_horizontal"7 android:text="@string/title_text"/>
在上述示例代码中,我们使用了<include /> 标签,并且只需要指定该标签的layout 属性值。
但是也存在一个问题,这种方式之所以可行是因为Activity 在main 布局文件中使用的是RelativeLayout。如果其中一个Activity 的布局文件使用的是LinearLayout 呢?
虽然android:layout_alignParentBottom="true" 适用于RelativeLayout,但是并不适用于LinearLayout。”这个想法是正确的。接下来分析
使用<include /> 标签的第二种方法,在这种方法里,我们直接在<include /> 标签里使用android:layout_* 属性。
以下是修改后的main.xml 文件,其中使用了<include /> 标签的android:layout_* 属性,源码如下所示:
1 <RelativeLayout 2 xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent"> 5 <TextView 6 android:layout_width="fill_parent" 7 android:layout_height="wrap_content" 8 android:layout_centerInParent="true" 9 android:gravity="center_horizontal"10 android:text="@string/hello"/>11 <include12 layout="@layout/title"13 android:layout_width="fill_parent"14 android:layout_height="wrap_content"15 android:layout_alignParentBottom="true"16 android:layout_marginBottom="30dp"/>17 </RelativeLayout/>
修改后的标题布局文件如下:
1 <TextView xmlns:android="http://schemas.android.com/apk/res/android"2 android:layout_width="0dp"3 android:layout_height="0dp"4 android:gravity="center"5 android:text="@string/title"/>
2,通过ViewStub 实现View 的延迟加载
设计布局的时候,读者可能想过根据上下文或者用户交互情况显示一个视图。如果想要一个视图只在需要的时候显示,可以使用ViewStub 这个类。
Android 开发文档中有关于ViewStub 的介绍,主要内容如下:
“ViewStub 是一种不可视并且大小为0 的视图,可以延迟到运行时填充(inflate) 布局资源。当ViewStub 设置为可视或者inflate() 方法被调用后,就会填充布局资源,然后ViewStub 便会被填充的视图替代。”
既然已经清楚ViewStub 是什么, 接下来看看它能做什么。在下面的示例代码中,我们使用ViewStub 来延迟加载一个MapView。假设需要创建一个视图来显示地理位置的详细信息,先看两种可能情况:
? 一些场所没有 GPS 信息
? 用户可能并不需要地图信息
如果一个场所没有GPS 信息,开发者不需要在地图上显示标记信息。同样,如果用户不需要地图信息,也就无须加载地图。我们可以把MapView 放置在ViewStub 标签中,让用户自己决定是否显示地图信息。
要达到上述目的,需要使用下面的布局:
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent"> 5 <Button 6 android:layout_width="fill_parent" 7 android:layout_height="wrap_content" 8 android:text="@string/show_map" 9 android:onClick="onShowMap"/>10 <ViewStub11 android:id="@+id/map_stub"12 android:layout_width="fill_parent"13 android:layout_height="fill_parent"14 android:layout="@layout/map"15 andorid:inflatedId="@+id/map_view" />16 </RelativeLayout>
很显然,需要通过map_stub这个id从Activity获得ViewStub。同时layout属性指定需要填充的布局文件。对于本例,需要填充的是map.xml文件,源码如下:
1 <?xml version="1.0" encoding="utf-8"?>2 <com.google.android.maps.MapView xmlns:android="http://schemas.android.com/apk/res/android"3 android:layout_width="fill_parent"4 android:layout_height="fill_parent"5 android:clickable="true"6 android:apiKey="my_api_key"/>
最后一个需要说明的属性是inflatedId。inflatedId是调用ViewStub 的inflate() 方法或者setVisibility() 方法时返回的ID,这个ID 便是被填充的View 的ID。在本例中,我们不需要操作MapView,只需要调用setVisibility(View.VISIBLE) 方法即可。如果想获取被填充的视图的引用,inflate() 方法会直接返回该引用,这样避免了再次调用findViewById() 方法。Activity 的源码比较简单,如下所示:
1 public class MainActivity extends MapActivity { 2 private View mViewStub; 3 @Override 4 public void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 setContentView(R.layout.main); 7 mViewStub = findViewById(R.id.map_stub); 8 } 9 public void onShowMap(View v) {10 mViewStub.setVisibility(View.VISIBLE);11 }12 ...13 }
如上述代码所示,只需要改变ViewStub 的可视性便可控制map 的显示。
还可以通过View view = ((ViewStub) findViewById(R.id.map_stub)).inflate();
当调用inflate()函数的时候,ViewStub被引用的资源替代,并且返回引用的view。 这样程序可以直接得到引用的view而不用再次调用函数findViewById()来查找了。
每日总结 - android布局优化