【Android 如何置底一个View(附 前置声明layout布局文件中的资源ID)】

简介:





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

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

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

效果如下:

 

 

 

XML代码如下:

 


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

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

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

 


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

 

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

 

可以看到,ListViewItem 8列表项穿过了Buttons

 

 

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

 


 
 
  1. <ListView android: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: No resource found that matches the given name (at 'layout_above' with value 

 '@id/test_bottom_buttons').

 

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

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

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

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

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

 


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

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

 

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

 

 

这就说明,之前的错误是由于在xml编译期,ListView写在了LinearLayout的前面,编译ListView时,LinearLayoutID @+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. <?xml version="1.0" encoding="utf-8"?> 
  2. <resources> 
  3.     <!-- 手动声明资源ID,类似于C++中的前置声明 --> 
  4.     <item type="id" name="test_bottom_buttons"></item> 
  5. </resources> 

 

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

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

 


 
 
  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:orientation="vertical" android:layout_width="fill_parent" 
  4.     android:layout_height="fill_parent"> 
  5.  
  6.   <ListView android:id="@+id/lv_test" android:layout_width="fill_parent" 
  7.     android:layout_height="fill_parent" android:layout_above="@id/test_bottom_buttons"> 
  8.   </ListView> 
  9.    
  10.     <!-- Button 置底 --> 
  11.     <LinearLayout android:id="@id/test_bottom_buttons" 
  12.         android:layout_width="fill_parent" android:layout_height="wrap_content" 
  13.         android:orientation="horizontal" android:layout_alignParentBottom="true"> 
  14.  
  15.         <Button android:layout_width="wrap_content" 
  16.             android:layout_height="wrap_content" android:text="确定"></Button> 
  17.  
  18.         <Button android:layout_width="wrap_content" 
  19.             android:layout_height="wrap_content" android:text="取消"></Button> 
  20.  
  21.     </LinearLayout> 
  22.  
  23. </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++的编译吗?如果是,那么其编译器是什么?如果不是,那么这个过程又叫做什么呢?

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






     本文转自Bill_Hoo 51CTO博客,原文链接:http://blog.51cto.com/billhoo/764788,如需转载请自行联系原作者



相关文章
|
缓存
若依 this.$router.push 同地址不同参,页面不刷新问题
若依 this.$router.push 同地址不同参,页面不刷新问题
1848 0
|
JSON 前端开发 Java
微服务——SpringBoot使用归纳——Spring Boot中的MVC支持——@RequestMapping
@RequestMapping 是 Spring MVC 中用于请求地址映射的注解,可作用于类或方法上。类级别定义控制器父路径,方法级别进一步指定处理逻辑。常用属性包括 value(请求地址)、method(请求类型,如 GET/POST 等,默认 GET)和 produces(返回内容类型)。例如:`@RequestMapping(value = &quot;/test&quot;, produces = &quot;application/json; charset=UTF-8&quot;)`。此外,针对不同请求方式还有简化注解,如 @GetMapping、@PostMapping 等。
830 0
|
IDE 开发工具 Windows
idea和webstorm性能优化
本文介绍了如何优化IDE(如IntelliJ IDEA和WebStorm)的性能。当IDE检测到启用实时保护的Microsoft Defender时,可能会影响性能。文章提供了自动或手动配置Defender排除列表的方法,通过将项目路径添加到排除列表中,可以显著提升IDE性能。按照步骤操作,确保以管理员身份运行IDE,以实现最佳效果。
724 1
idea和webstorm性能优化
|
前端开发 Java Spring
springbootWeb常用注解使用
本文概述了Spring Boot Web中处理HTTP请求的常用注解,包括`@PathVariable`、`@RequestHeader`、`@RequestParam`、`@RequestBody`、`@ModelAttribute`和`@CookieValue`的用法及其示例。
springbootWeb常用注解使用
|
存储 前端开发 安全
强化用户体验与安全性:前端单点登录和统一认证的最佳实践与区别
互联网发展了这么多年,各种更新皆为了提供更好更安全的上网环境。同时为了提供更好的用户体验、减少用户反复输入用户名和密码的繁琐操作,并确保账户安全,前端领域中的单点登录(SSO)和统一认证(Unified Authentication)成为了重要概念。
强化用户体验与安全性:前端单点登录和统一认证的最佳实践与区别
|
小程序 前端开发 生物认证
微信小程序如何将一个按钮放到页面的最底下?
微信小程序如何将一个按钮放到页面的最底下?
2380 5
|
小程序 前端开发 API
微信小程序 - 调用微信 API 回调函数内拿不到 this 问题(解决方案)
本文讨论了在微信小程序中调用API回调函数时无法获取到`this`上下文的问题,并提供了解决方案。在回调函数中,使用一个变量(如`that`)来保存当前的`this`引用,然后在回调内部使用这个变量来访问当前页面的数据和方法。
|
小程序 前端开发
【非常全】微信小程序下载图片到相册,微信小程序自动获取分享图片到相册
【非常全】微信小程序下载图片到相册,微信小程序自动获取分享图片到相册
1613 3
|
Unix Linux 异构计算
用于实时 Linux® 的 TwinCAT Runtime,基于 Linux® 的实时控制器开辟了新的应用可能性
**TwinCAT Runtime for Linux®** 打开了倍福实时控制的新领域,支持在同一PC上运行多个独立实例,促进硬件整合和效率提升。基于Debian的定制Linux发行版,内置实时内核,允许GPU驱动的高速应用如机器视觉。利用Docker等容器技术,实现模块化控制和资源优化,降低工程成本。此发行版将逐步扩展到更多倍福设备,为Linux用户提供熟悉的TwinCAT编程环境和增强的灵活性。
|
存储 Ubuntu Linux
xenomai3+linux构建linux实时操作系统-基于X86_64和arm
Xenomai是一个实时性解决方案,通过在Linux上添加实时内核Cobalt来增强实时性能。它有三个主要部分:libcobalt(用户空间实时库)、Cobalt(内核空间实时内核)和硬件架构特定层(ipipe-core或dovetail)。ipipe-core适用于Linux 5.4以下版本,而dovetail用于5.4及以上版本。本文介绍了在X86 Ubuntu环境下,如何编译Xenomai内核,搭建应用环境,包括配置、编译、安装和实时性测试。对于其他硬件架构,如ARM和ARM64,步骤类似。文章还提到了Xenomai与Linux内核版本的兼容性和实时性测试结果。
2538 0
xenomai3+linux构建linux实时操作系统-基于X86_64和arm