【Android(安卓)如何置底一个View(附 前置声明layout布局文件中的资源ID)】
PS:初学Android,很多术语可能不甚严谨,希望大家积极指出,bill才好及时改正,以免误人子弟。
今天在考虑一个RelativeLayout布局,整个屏幕分为两个部分,上部分是一个ListView,下部分是两个横排的Button。欲实现这两个Button始终置底,ListView在Button的上方占满剩余的空间。
Button置底这个方法还算简单,直接将两个Button包裹于一个LinearLayout,然后设置这个LinearLayout的属性android:layout_alignParentBottom为true即可。
效果如下:
XML代码如下:
- <?xmlversion="1.0"encoding="utf-8"?>
- <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <!--Button置底-->
- <LinearLayoutandroid:id="@+id/test_bottom_buttons"
- android:layout_width="fill_parent"android:layout_height="wrap_content"
- android:orientation="horizontal"android:layout_alignParentBottom="true">
- <Buttonandroid:layout_width="wrap_content"
- android:layout_height="wrap_content"android:text="确定"></Button>
- <Buttonandroid:layout_width="wrap_content"
- android:layout_height="wrap_content"android:text="取消"></Button>
- </LinearLayout>
- </RelativeLayout>
接下来就是要把剩余的空间用一个ListView进行填充了。
最开始bill臆断地认为,只要在包裹Buttons的LinearLayout代码上方加上一个ListView就OK了,这是我最开始错误的xml布局文件:
- <?xmlversion="1.0"encoding="utf-8"?>
- <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <ListViewandroid:id="@+id/lv_test"android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- </ListView>
- <!--Button置底-->
- <LinearLayoutandroid:id="@+id/test_bottom_buttons"
- android:layout_width="fill_parent"android:layout_height="wrap_content"
- android:orientation="horizontal"android:layout_alignParentBottom="true">
- <Buttonandroid:layout_width="wrap_content"
- android:layout_height="wrap_content"android:text="确定"></Button>
- <Buttonandroid:layout_width="wrap_content"
- android:layout_height="wrap_content"android:text="取消"></Button>
- </LinearLayout>
- </RelativeLayout>
写完后悲剧地发现Button倒是置底了,但是ListView却并没有在Button上方,而是充斥了整个屏幕。如下图所示:
可以看到,ListView的Item8列表项穿过了Buttons
相对布局是最灵活、最巧妙的“手工活儿”,出现这种情况,只能怪bill自己疏忽大意,稍后我注意到这样一条属性android:layout_above="[viewid]",表示相对布局中的当前view处在viewid所指代view的上方。这可算是救星啊,迅速改正ListView的布局代码如下:
- <ListViewandroid:id="@+id/lv_test"android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_above="@id/test_bottom_buttons">
- </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的后面:
- <?xmlversion="1.0"encoding="utf-8"?>
- <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <!--Button置底-->
- <LinearLayoutandroid:id="@+id/test_bottom_buttons"
- android:layout_width="fill_parent"android:layout_height="wrap_content"
- android:orientation="horizontal"android:layout_alignParentBottom="true">
- <Buttonandroid:layout_width="wrap_content"
- android:layout_height="wrap_content"android:text="确定"></Button>
- <Buttonandroid:layout_width="wrap_content"
- android:layout_height="wrap_content"android:text="取消"></Button>
- </LinearLayout>
- <ListViewandroid:id="@+id/lv_test"android:layout_width="fill_parent"
- android:layout_height="fill_parent"android:layout_above="@id/test_bottom_buttons">
- </ListView>
- </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中编写如下内容:
- <?xmlversion="1.0"encoding="utf-8"?>
- <resources>
- <!--手动声明资源ID,类似于C++中的前置声明-->
- <itemtype="id"name="test_bottom_buttons"></item>
- </resources>
这样便手动向系统添加了一个IDtest_bottom_buttons系统会根据这条xml代码在R类中生成对应的int型资源。
我们现在就可以按照实际布局的顺序将xml代码改写如下了
- <?xmlversion="1.0"encoding="utf-8"?>
- <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <ListViewandroid:id="@+id/lv_test"android:layout_width="fill_parent"
- android:layout_height="fill_parent"android:layout_above="@id/test_bottom_buttons">
- </ListView>
- <!--Button置底-->
- <LinearLayoutandroid:id="@id/test_bottom_buttons"
- android:layout_width="fill_parent"android:layout_height="wrap_content"
- android:orientation="horizontal"android:layout_alignParentBottom="true">
- <Buttonandroid:layout_width="wrap_content"
- android:layout_height="wrap_content"android:text="确定"></Button>
- <Buttonandroid:layout_width="wrap_content"
- android:layout_height="wrap_content"android:text="取消"></Button>
- </LinearLayout>
- </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++的编译吗?如果是,那么其编译器是什么?如果不是,那么这个过程又叫做什么呢?
我想,这些谜题应该会随着自己学习的深入而一一解开吧。
更多相关文章
- 使用Ramdisk加速Android工程的编译 (AndroidStudio Gradle)
- Android(安卓)studio和Eclipse分别生成jar包并混淆jar包
- 写给Android开发者的混淆使用手册
- Android(安卓)应用瘦身,从 18MB 到 12.5MB
- Android反编译和二次打包实战
- 跟Google学习Android开发-起始篇-构建你的第一个应用程序(3)
- [置顶] android 从资源中获取数组
- 第3.2.2节 抽象布局与抽象样式
- Android字符串及字符串资源的格式化