一般而言,Android界面布局使用聚合的方式比較多,這種方式要求首先構(gòu)建一批能夠復(fù)用的組件,然后在Activity的布局文件中進(jìn)行聚合。盡管這種方式能夠完成組件的復(fù)用,但如果這些組件在不同Activity中的布局有很多相同點的時候,也還是會帶來很大程度的冗余(代碼)。本文介紹一種比聚合更加有效的界面布局方式——繼承式布局。
對于類的繼承和對象的聚合之間有哪些相同點和不同點,分別適用于哪種場景,相信大家已經(jīng)深有體會。在此就不多講了。其實類比過來,Android的界面布局也是如此。假設(shè)我們需要實現(xiàn)如下的三種布局:
![[Android]繼承式UI界面布局設(shè)計 - lvan - lvan GoGo 的世界](http://image93.360doc.com/DownloadImg/2016/01/1022/64287282_1.png) ![[Android]繼承式UI界面布局設(shè)計 - lvan - lvan GoGo 的世界](http://image93.360doc.com/DownloadImg/2016/01/1022/64287282_2.png) ![[Android]繼承式UI界面布局設(shè)計 - lvan - lvan GoGo 的世界](http://image93.360doc.com/DownloadImg/2016/01/1022/64287282_3.png)
每一個布局都是在前一個布局的基礎(chǔ)上增加自己的元素。這種形式多么像類的繼承呀!下面列出實現(xiàn)文件:
page_three_parts.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas./apk/res/android" android:id="@+id/page_three_parts_root_layout" android:layout_width="match_parent" android:layout_height="match_parent" >
<RelativeLayout android:layout_width="match_parent" android:layout_height="96dp" android:layout_alignParentTop="true" android:background="@color/main_blue" >
<ImageView android:id="@+id/image_logo" android:layout_width="120dp" android:layout_height="80dp" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_margin="10dp" android:gravity="center" android:src="@drawable/logo" /> </RelativeLayout>
<RelativeLayout android:layout_width="match_parent" android:layout_height="96dp" android:layout_alignParentBottom="true" android:background="@color/main_blue" > </RelativeLayout>
</RelativeLayout>
page_base_setting.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas./apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" >
<include android:layout_width="match_parent" android:layout_height="match_parent" layout="@layout/page_three_parts" />
<Button android:id="@+id/baseSettingButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_marginBottom="32dp" android:text="page_base_setting.xml" />
</RelativeLayout>
page_net_settting.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas./apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" >
<include android:layout_width="match_parent" android:layout_height="match_parent" layout="@layout/page_base_setting" />
<Button android:id="@+id/netSettingButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_marginBottom="32dp" android:text="page_net_settting.xml" />
</RelativeLayout>
繼承式布局在第一個節(jié)點處包含父布局文件,然后實現(xiàn)子布局。繼承式布局要求父布局和子布局的根布局大小必須一致。至于為什么這么要求,很簡單,想一想類繼承的特點——子類必須實現(xiàn)父類的所有內(nèi)容,或者說子類必須能夠代替父類。這樣的繼承方式與我們在C++、C#、Java中實現(xiàn)的繼承很不一樣,而與GObject、Lua等實現(xiàn)繼承的方式很相似。
這種布局方式能夠比聚合實現(xiàn)更簡單的設(shè)計,而且能夠更大程度的完成代碼和布局的解耦合。這里指的是有很多人會在聚合式布局中留出擴展點,然后在程序運行的時候?qū)?nèi)容填充到保留點。這種方式有一個很大的問題,就是只有當(dāng)程序運行起來之后才能看到頁面的完整信息。繼承式布局就不存在這樣的問題。而且,這種繼承關(guān)系也完全可以映射到代碼類的繼承。下面是代碼中關(guān)于布局的繼承關(guān)系:
ThreePartsActivity.java
package com.testui;
import android.app.Activity; import android.os.Bundle; import android.widget.ImageView;
/** * 該類和 page_three_parts.xml 布局文件對應(yīng) */ public class ThreePartsActivity extends Activity {
/** * 布局文件 */ protected int layoutRes;
/** * LOGO圖片 */ protected ImageView imageLogo;
protected ThreePartsActivity(int layoutRes) { this.layoutRes = layoutRes; }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
// 設(shè)置視圖內(nèi)容 setContentView(layoutRes);
imageLogo = (ImageView) findViewById(R.id.image_logo); }
}
BaseSettingActivity.java
package com.testui;
import android.os.Bundle; import android.widget.Button;
/** * 該類和 page_base_setting.xml 布局文件對應(yīng) */ public class BaseSettingActivity extends ThreePartsActivity {
/** * 基本配置按鈕 */ Button baseSettingButton;
protected BaseSettingActivity(int layoutRes) { super(layoutRes); }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
baseSettingButton = (Button) findViewById(R.id.baseSettingButton); }
}
NetSettingActivity.java
package com.testui;
import android.os.Bundle; import android.widget.Button;
/** * 該類和 page_net_settting.xml 布局文件對應(yīng) */ public class NetSettingActivity extends BaseSettingActivity {
/** * 網(wǎng)絡(luò)設(shè)置按鈕 */ Button netSettingButton;
public NetSettingActivity() { super(R.layout.page_net_settting); }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
netSettingButton = (Button) findViewById(R.id.netSettingButton); }
}
繼承式布局實際上是通過布局的層層疊加實現(xiàn)的,但這種疊加是邏輯上的,而不是渲染層次的。所以在實際運行中不會帶來太大的性能問題。下面這張圖應(yīng)該能夠?qū)⒗^承式布局形象的展示出來:
![[Android]繼承式UI界面布局設(shè)計 - lvan - lvan GoGo 的世界](http://image93.360doc.com/DownloadImg/2016/01/1022/64287282_4.png)
|