Android系统中已经提供了非常多好用的控件,这让我们在编写布局的时候可以很轻松。但是有些时候我们可能需要反复利用某个已经写好的布局,如果你总是使用复制粘贴的方式来进行布局重用,这显然是一种很笨的做法。而Android当然也已经充分考虑到了布局重用的重要性,于是提供了
include
举个例子吧,我们应该都知道,目前几乎所有的软件都会有一个头布局,头布局中可以包含界面的标题、返回按钮、以及其它一些操作功能等。那这样的一个头布局,有些软件是使用ActionBar来实现的,但是由于ActionBar的灵活性不太好,因而也有很多软件会选择自己去编写实现。那如果自己去实现的话,由于这个头布局是在所有界面都要使用的,显然我们不可能在每个界面当中都去写一遍这个头布局的代码,因此这种情况下使用1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28<?xml version="1.0" encoding="utf-8"?>
<merge>
<android.support.design.widget.AppBarLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginLeft="?attr/actionBarSize"
android:layout_marginRight="?attr/actionBarSize"
android:singleLine="true"
android:textSize="18dp" />
</RelativeLayout>
</android.support.design.widget.AppBarLayout>
</merge>
merge
实例1
对于这样的布局view,在RecyclerView里面滑动时,一般会有infalte布局过多,type过多,混乱,代码不能很好的组织管理。图一的RecyclerView分为多Type,每个type自定义view,可以分开单独的view显示逻辑,见实例代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23@Override
public void onBindViewHolder(ViewHolder holder, Columns data, int position) {
switch (getItemViewType(position)) {
case TYPE_LIFE_SIR:
((ColumnLifeSirView) holder.getConvertView()).setData(data.getLife_sir_fav_list());
break;
case TYPE_LIFE:
((ColumnLifeView) holder.getConvertView()).setData(data.getLife_channel().get(0));
break;
case TYPE_TALENT:
((ColumnTalentView) holder.getConvertView()).setData(data.getTalent_channel().get(0));
break;
case TYPE_TOBE_TALENT:
((ColumnTobeTalentView) holder.getConvertView()).setData(data.getTo_be_talent());
break;
case TYPE_LIFE_HEADER:
((ColumnTalentLifeHeaderView) holder.getConvertView()).setType(ColumnTalentLifeHeaderView.TYPE_LIFE);
break;
case TYPE_TALENT_HEADER:
((ColumnTalentLifeHeaderView) holder.getConvertView()).setType(ColumnTalentLifeHeaderView.TYPE_TALENT);
break;
}
}
- 实例2
viewpager分页加载多个tab页,对于Android平台的内存问题来说是个严重考验,由于viewpager的预缓存机制,会自动加载上下的offset页,所以在图2中,处于对内存的性能考虑,我们需要让用户滑动到当前页以后,再去做数据加载,节省内存开销以及用户的流量。
代码如下,在setUserVisibleHint方法里判断是否用户可见:1
2
3
4
5
6@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser)
visibleLoadData();
}
图2中同样有多个type,和实例1类似,分为多type来操作。对于图2中的第一个view来说,可能很多开发者会选择用LinearLayout 嵌套RelativeLayout 然后再加横向ScrollView或者ListView或者Recyclerview来布局,但是多了一层viewGroup,提高了布局复杂度,在滑动过程中可能就会出现失帧的情况了。
如图所示,当前页面只有一层布局,只有一个最外层的RelativeLayout即可。
- 实例3
这个view涉及到viewpager嵌套viewpager,对于FragmentManager以及ChildFragmentManager不做过多叙述,不理解可自行搜索。
图3中因为要用到对当前viewpager中view的图片高斯模糊背景,用到了v8 Render,用法自行搜索,推荐500px的第三方库500px-android-blur。
善用merge标签
利用ViewHierarchy工具可以查看当前页面的布局逻辑。对于自定义复合view来说,很多人会inflate一个自定义布局。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<rec.ui.view.loopviewpager.LoopViewPager
android:id="@+id/banner"
android:layout_width="match_parent"
android:layout_height="200dp" />
<rec.ui.view.pageIndicator.CirclePageIndicator
android:id="@+id/banner_indicator"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/banner"
android:layout_centerHorizontal="true"
android:layout_marginBottom="5dp"
app:fillColor="#FFFFFFFF"
app:pageColor="#25000000"
app:radius="4dp"
app:strokeWidth="0dp" />
</RelativeLayout>
1 | public class HomeItemBannerView extends RelativeLayout{ |
很多开发者会这样去做复合view,这样是错误的,其实用ViewHierarchy一看就能知道,当前的view是继承自RelativeLayout,而infalte的root viewGroup也是RelativeLayout,重复嵌套同一层布局,在布局比较复杂的情况下, 这样的操作是很耗性能的。
正确的做法应该将布局文件中的RelativeLayout改为merge标签,对于xml的root节点的RelativeLayout的数据在
HomeItemBannerView中的init()方法通过代码设置即可。注意:如果是merge标签了,要注意merge的使用场景,merge标签的parent view 必须是一个ViewGroup,否则会运行报错哦。另外,在view 中inflate布局时要注意attachToRoot为true哦。如果不熟悉关于inflate的一些属性,可以自己搜索学习下。