PS:初學Android,很多術語可能不甚嚴謹,希望大家積極指出,bill才好及時改正,以免誤人子弟。
今天在考慮一個RelativeLayout布局,整個螢幕分為兩個部分,上部分是一個ListView,下部分是兩個橫排的Button。欲實作這兩個Button始終置底,ListView在Button的上方占滿剩餘的空間。
Button置底這個方法還算簡單,直接将兩個Button包裹于一個LinearLayout,然後設定這個LinearLayout的屬性android:layout_alignParentBottom為true即可。
效果如下:
<a href="http://blog.51cto.com/attachment/201201/151705532.png" target="_blank"></a>
XML代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- Button 置底 -->
<LinearLayout android:id="@+id/test_bottom_buttons"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:orientation="horizontal" android:layout_alignParentBottom="true">
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="确定"></Button>
android:layout_height="wrap_content" android:text="取消"></Button>
</LinearLayout>
</RelativeLayout>
接下來就是要把剩餘的空間用一個ListView進行填充了。
最開始bill臆斷地認為,隻要在包裹Buttons的LinearLayout代碼上方加上一個ListView就OK了,這是我最開始錯誤的xml布局檔案:
<ListView android:id="@+id/lv_test" android:layout_width="fill_parent"
android:layout_height="fill_parent">
</ListView>
寫完後悲劇地發現Button倒是置底了,但是ListView卻并沒有在Button上方,而是充斥了整個螢幕。如下圖所示:
<a href="http://blog.51cto.com/attachment/201201/151903569.png" target="_blank"></a>
可以看到,ListView的Item 8清單項穿過了Buttons
相對布局是最靈活、最巧妙的“手工活兒”,出現這種情況,隻能怪bill自己疏忽大意,稍後我注意到這樣一條屬性android:layout_above="[viewid]",表示相對布局中的目前view處在viewid所指代view的上方。這可算是救星啊,迅速改正ListView的布局代碼如下:
<ListView android: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: 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++裡兩個類互相嵌套會産生編譯錯誤,提示找不到其中一個類的聲明。這裡會不會出現了類似于這種情況的錯誤呢?
于是我把ListView的XML代碼寫在了Buttons的後面:
android:layout_height="fill_parent" android:layout_above="@id/test_bottom_buttons">
不出所料,編譯通過并正常顯示如下:
<a href="http://blog.51cto.com/attachment/201201/152209965.png" target="_blank"></a>
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中編寫如下内容:
<resources>
<!-- 手動聲明資源ID,類似于C++中的前置聲明 -->
<item type="id" name="test_bottom_buttons"></item>
</resources>
這樣便手動向系統添加了一個ID test_bottom_buttons 系統會根據這條xml代碼在R類中生成對應的int型資源。
我們現在就可以按照實際布局的順序将xml代碼改寫如下了
<ListView android:id="@+id/lv_test" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_above="@id/test_bottom_buttons">
</ListView>
<LinearLayout android:id="@id/test_bottom_buttons"
<a href="http://blog.51cto.com/attachment/201201/152327549.png" target="_blank"></a>
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,如需轉載請自行聯系原作者