PS:初学Android,很多术语可能不甚严谨,希望大家积极指出,bill才好及时改正,以免误人子弟。

今天在考虑一个RelativeLayout布局,整个屏幕分为两个部分,上部分是一个ListView,下部分是两个横排的Button。欲实现这两个Button始终置底,ListView在Button的上方占满剩余的空间。

Button置底这个方法还算简单,直接将两个Button包裹于一个LinearLayout,然后设置这个LinearLayout的属性android:layout_alignParentBottom为true即可。

效果如下:

XML代码如下:

        
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"android:layout_width="fill_parent"
  4. android:layout_height="fill_parent">
  5. <!--Button置底-->
  6. <LinearLayoutandroid:id="@+id/test_bottom_buttons"
  7. android:layout_width="fill_parent"android:layout_height="wrap_content"
  8. android:orientation="horizontal"android:layout_alignParentBottom="true">
  9. <Buttonandroid:layout_width="wrap_content"
  10. android:layout_height="wrap_content"android:text="确定"></Button>
  11. <Buttonandroid:layout_width="wrap_content"
  12. android:layout_height="wrap_content"android:text="取消"></Button>
  13. </LinearLayout>
  14. </RelativeLayout>

接下来就是要把剩余的空间用一个ListView进行填充了。

最开始bill臆断地认为,只要在包裹Buttons的LinearLayout代码上方加上一个ListView就OK了,这是我最开始错误的xml布局文件:

        
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"android:layout_width="fill_parent"
  4. android:layout_height="fill_parent">
  5. <ListViewandroid:id="@+id/lv_test"android:layout_width="fill_parent"
  6. android:layout_height="fill_parent">
  7. </ListView>
  8. <!--Button置底-->
  9. <LinearLayoutandroid:id="@+id/test_bottom_buttons"
  10. android:layout_width="fill_parent"android:layout_height="wrap_content"
  11. android:orientation="horizontal"android:layout_alignParentBottom="true">
  12. <Buttonandroid:layout_width="wrap_content"
  13. android:layout_height="wrap_content"android:text="确定"></Button>
  14. <Buttonandroid:layout_width="wrap_content"
  15. android:layout_height="wrap_content"android:text="取消"></Button>
  16. </LinearLayout>
  17. </RelativeLayout>

写完后悲剧地发现Button倒是置底了,但是ListView却并没有在Button上方,而是充斥了整个屏幕。如下图所示:

可以看到,ListView的Item8列表项穿过了Buttons

相对布局是最灵活、最巧妙的“手工活儿”,出现这种情况,只能怪bill自己疏忽大意,稍后我注意到这样一条属性android:layout_above="[viewid]",表示相对布局中的当前view处在viewid所指代view的上方。这可算是救星啊,迅速改正ListView的布局代码如下:

        
  1. <ListViewandroid:id="@+id/lv_test"android:layout_width="fill_parent"
  2. android:layout_height="fill_parent"
  3. android:layout_above="@id/test_bottom_buttons">
  4. </ListView>

这样理论上就表示ListView是位于Buttons的上方,原本以为这样就大功告成了,没想到却得到一个莫名其妙的编译错误:

error:Error:Noresourcefoundthatmatchesthegivenname(at'layout_above'withvalue

'@id/test_bottom_buttons').

说是在android:layout_above这条属性语句中,找不到@id/test_bottom_buttons所指的资源,但是我上面的xml文件明明添加了这个ID的啊(<LinearLayoutandroid:id="@+id/test_bottom_buttons"),怎么会找不到?

后来仔细一想,既然我认为“test_bottom_buttons这个ID资源肯定存在”是一个事实,而编译提示“找不到该ID所指的资源”也是一个事实,两个完全对立的事实不可能同时存在,那么总有一个“事实”是伪造的,而编译器99.99%是不会撒谎的。也就是说我自己把自己骗了,test_bottom_buttons这个ID资源并不存在。

但是这个ID的的确确已经被我写进XML布局文件里了啊?!

突然,我得到了一个灵感,我们知道,C++里两个类相互嵌套会产生编译错误,提示找不到其中一个类的声明。这里会不会出现了类似于这种情况的错误呢?

于是我把ListView的XML代码写在了Buttons的后面:

        
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"android:layout_width="fill_parent"
  4. android:layout_height="fill_parent">
  5. <!--Button置底-->
  6. <LinearLayoutandroid:id="@+id/test_bottom_buttons"
  7. android:layout_width="fill_parent"android:layout_height="wrap_content"
  8. android:orientation="horizontal"android:layout_alignParentBottom="true">
  9. <Buttonandroid:layout_width="wrap_content"
  10. android:layout_height="wrap_content"android:text="确定"></Button>
  11. <Buttonandroid:layout_width="wrap_content"
  12. android:layout_height="wrap_content"android:text="取消"></Button>
  13. </LinearLayout>
  14. <ListViewandroid:id="@+id/lv_test"android:layout_width="fill_parent"
  15. android:layout_height="fill_parent"android:layout_above="@id/test_bottom_buttons">
  16. </ListView>
  17. </RelativeLayout>

不出所料,编译通过并正常显示如下:

Buttons已经置底,且ListView位于Buttons上方

这就说明,之前的错误是由于在xml编译期,ListView写在了LinearLayout的前面,编译ListView时,LinearLayout的ID@+id/test_bottom_buttons尚未添加到系统中,而ListView就提前使用了这条ID资源android:layout_above="@id/test_bottom_buttons"因此编译到此处时,由于找不到ID资源而导致编译错误并停止编译,于是就出现了上述“莫名其妙”的错误。解决办法之一是,严格遵循“先声明后使用”的原则办事。

问题虽然解决了,但是却解决得并不完美。我们一般习惯按照布局的排版顺序依次列写我们的xml代码,但是像上述这样的xml并没有按照布局的顺序编写,而是为了解决找不到ID这个问题,把本应该写在前面的ListView后置了。总觉得很别扭,有没有什么方法既能解决找不到ID的问题,又能按照实际布局的顺序编写XML布局代码呢?答案是肯定的。

就如同C++里解决两个相互嵌套类的方案——前置声明一样,布局文件中也有所谓的“前置声明”。

既然问题在于该ID的使用出现在声明之前,那么我们就试图把ID的声明提前。

这里用到了另一个xml配置文件,bill暂且将其命名为myids,在myids.xml中编写如下内容:

        
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <resources>
  3. <!--手动声明资源ID,类似于C++中的前置声明-->
  4. <itemtype="id"name="test_bottom_buttons"></item>
  5. </resources>

这样便手动向系统添加了一个IDtest_bottom_buttons系统会根据这条xml代码在R类中生成对应的int型资源。

我们现在就可以按照实际布局的顺序将xml代码改写如下了

        
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"android:layout_width="fill_parent"
  4. android:layout_height="fill_parent">
  5. <ListViewandroid:id="@+id/lv_test"android:layout_width="fill_parent"
  6. android:layout_height="fill_parent"android:layout_above="@id/test_bottom_buttons">
  7. </ListView>
  8. <!--Button置底-->
  9. <LinearLayoutandroid:id="@id/test_bottom_buttons"
  10. android:layout_width="fill_parent"android:layout_height="wrap_content"
  11. android:orientation="horizontal"android:layout_alignParentBottom="true">
  12. <Buttonandroid:layout_width="wrap_content"
  13. android:layout_height="wrap_content"android:text="确定"></Button>
  14. <Buttonandroid:layout_width="wrap_content"
  15. android:layout_height="wrap_content"android:text="取消"></Button>
  16. </LinearLayout>
  17. </RelativeLayout>

效果如下:

Buttons置底,且ListView位于其上方

ADDED(billhoo - 2013-3-18)

感谢网友gogo901的回复,他提到要实现上述行为还有更加简单的方式:

QUOTE[

可以不换顺序

List中定义:android:layout_above="@+id/test_bottom_buttons"

Button中定义:android:id="@id/test_bottom_buttons"

]

这下可以收工吃东西了~

写了这么多,bill知道,自己只是从表面实验了一下android资源文件编译期的一些特性。但是资源文件的编译顺序究竟是怎么样的?这个过程真的就像是C++的编译吗?如果是,那么其编译器是什么?如果不是,那么这个过程又叫做什么呢?

我想,这些谜题应该会随着自己学习的深入而一一解开吧。

更多相关文章

  1. 使用Ramdisk加速Android工程的编译 (AndroidStudio Gradle)
  2. Android(安卓)studio和Eclipse分别生成jar包并混淆jar包
  3. 写给Android开发者的混淆使用手册
  4. Android(安卓)应用瘦身,从 18MB 到 12.5MB
  5. Android反编译和二次打包实战
  6. 跟Google学习Android开发-起始篇-构建你的第一个应用程序(3)
  7. [置顶] android 从资源中获取数组
  8. 第3.2.2节 抽象布局与抽象样式
  9. Android字符串及字符串资源的格式化

随机推荐

  1. Android(安卓)翻牌动画 实现
  2. Android中判断网络是否连接实例详解
  3. Android实现画虚线的控件
  4. Mac无法编译android
  5. Android(安卓)之 网络访问服务器,解析JSON
  6. SmallActivity创建
  7. Android(安卓)AnimationSet详解
  8. COCOS2DX 安卓WIN32下配置手册
  9. Android所有系统资源图标android.R.drawa
  10. 2010.12.29——— android 可伸缩的listv