Hacks布局篇-Hack2 使用标签避免代码重复

Hacks布局篇-Hack2 使用<include />标签避免代码重复_第1张图片

作者:李旺成

时间:2016年5月7日


在这个 Hack 中将详细介绍 标签的使用,以及一些注意事项。

一、每个页面添加页脚

Hacks布局篇-Hack2 使用<include />标签避免代码重复_第2张图片
添加页脚示意图

假设:现在有这样一个需求,为应用中的每个页面都添加一个页脚。这里简单处理,要添加的页脚就是一个显示应用名称的文本(使用 TextView 来显示),如上图所示。大多数的应用都是由多个 Activity 组成的,多个 Activity 一般对应多个布局文件。那是不是要把这个页脚 TextView 一个个拷贝到每个布局文件中?

听过这么一句话:当你的程序中出现大量的重复代码时你得小心了。(不是我杜撰的,大致是这个意思,没有找到出处...)

确实是这样,不要把一段相同的代码到处“复制/粘贴”,有一个很明显的弊端摆在眼前,如果以后需要修改这段代码就悲剧了。

所以,要实现上述需求“复制/粘贴”不是我们要的解决方案。解决该问题最简单的方法是使用 标签。当然,使用 style 来保证这些页脚都使用同一个样式也是可以的,但没有 标签简便,再说 style 的主要功能可不是用来解决重复代码问题的。

好了需求明确的,看看怎么实现。

使用 标签为页面添加页脚

首先,创建一个页脚布局 footer_app_name.xml:



然后,使用 为布局添加页脚 activity_hack2_1.xml:



    
    
    


上面的示例代码很简单,为 标签的 layout 属性指定一个表示页脚的布局即可。仔细一点的同学可能看到了:页脚布局中设置了 android:layout_alignParentBottom="true" 属性,那么问题来了,这个属性是 RelativeLayout 中子控件才有用,如果把 activity_hack2_1.xml 的根布局修改为 FrameLayout 那不就不行了吗?

Hacks布局篇-Hack2 使用<include />标签避免代码重复_第3张图片
根布局修改为 FrameLayout

上图中可以看到,将根布局修改为 FrameLayout 之后,“页脚”就不是在该页面的底部了,那要怎么做了?不急,下面会给出解决方案,且继续往下阅读。

二、 标签使用详解

标签使用虽然挺简单的,但也有一些细节要注意,这里做个简单的总结供大家参考。

include 属性有两种设置方式

1、在子布局中设置
就是上面的示例代码中使用的方式,直接在子布局中设置好所有的属性,使用的时候只需要在主布局中为 include 设置 layout 属性即可。

这样用很方便,但是 Android 中提供了很多布局技术,你在子布局中设置的属性可能只适用与某一个/某一类布局。上面的示例中就是这样,只有主布局为 RelativeLayout 的时候页面才能在指定位置显示,如果替换为 FrameLayout 就显示不正确了。这就反映了一个问题 —— 不灵活。那怎么解决呢?include 属性还有另外一种设置方式。

2、在 标签里设置
说到这里,那先把示例中遗留的问题解决了,就是将 RelativeLayout 替换为 FrameLayout 之后页面位置的问题。

先看解决后的效果:

Hacks布局篇-Hack2 使用<include />标签避免代码重复_第4张图片
标签里设置属性

解决方案代码:



    ...
    

上面的示例代码中与根布局为 RelativeLayout 对比的主要修改处是在 标签中添加了 android:layout_gravity 属性,并将其属性值设置为了 "bottom" ,这就可以保证页脚会在页面的底部显示了。

说明:其实和 style 的使用非常类似,你可以直接使用 style,也可以覆盖 style 中的一些属性。

标签里设置属性一般是这样用的,下面使用添加一个页眉作为示例:

  1. 创建页面 header_app_name.xml:


  1. 使用 标签添加页眉

效果如下:

Hacks布局篇-Hack2 使用<include />标签避免代码重复_第5张图片
添加页眉

注意:在示例中页面布局的宽度高度都设置为 0dp 了,这么做的目的就是由 header_app_name.xml 文件的使用者在 标签中指定 layout_width 和 layout_height 属性。如果使用者不指定这两个属性,它们的默认值都是 0dp,那便看不到页眉。

三、 标签注意事项

这里罗列了一些我在使用 标签的时候踩过的一些坑,希望大家以后可以绕过去。

findViewById 出现 NullPointerException

具体情况是这样的,如果 include 一个布局时,并没有给 标签设置 id 属性,那么你直接使用 findViewById 来找 include 指定布局中控件是没有问题的。

但是,一旦你为 标签设置了 id ,就不能直接把它里面的控件当成主布局文件中的控件来直接获取了,必须先获得这个 标签指定的布局文件,再通过该布局文件 findViewById 来获得其子控件。

标签失效了

Android 的缺陷(Issue)跟踪系统中报告过一个缺陷,缺陷的标题是:“ 标签失效了,如果想通过 标签的属性覆盖被包含的布局所指定的属性是行不通的。”。

这个 issue 描述的问题在一定程度上是正确的,问题出在如果想在 标签中覆盖被包含布局所指定的任何 android:layout_* 属性,必须在 标签中同时指定 android:layout_width 和 android:layout_height 这两个属性。(参考自:《50 Android Hacks》)

PS:话说如果你是用 AndroidStudio 的话,可能根本就不会遇到这个问题,因为,如果你在指定其他的 android:layout_* 属性时,如果没有同时指定 android:layout_width 和 android:layout_height 这两个属性,AndroidStudio 是会报错的:

提示添加 layout_width 和 layout_height

自定义控件与

如果是一些比较简单,include 进来之后不需要有过多操作的,使用 完全可以胜任了。对于一些比较复杂,而且要添加很多响应事件等的使用场景,建议使用自定义控件。如果还是使用 标签,那么不可避免在 Java 代码中又得写一堆类似的代码来添加相应逻辑。

项目地址

AndroidHacks合集
布局篇
个人博客
示例用到代码见:
Hack2Activity.java
activity_hack2_1.xml
activity_hack2_2.xml
header_app_name.xml
footer_app_name.xml

你可能感兴趣的:(Hacks布局篇-Hack2 使用标签避免代码重复)