一般而言,Android界面布局使用聚合的方式比較多,這種方式要求首先構(gòu)建一批能夠復(fù)用的組件,然后在Activity的布局文件中進(jìn)行聚合。盡管這種方式能夠完成組件的復(fù)用,但如果這些組件在不同Activity中的布局有很多相同點(diǎn)的時(shí)候,也還是會(huì)帶來很大程度的冗余(代碼)。本文介紹一種比聚合更加有效的界面布局方式——繼承式布局。
對(duì)于類的繼承和對(duì)象的聚合之間有哪些相同點(diǎn)和不同點(diǎn),分別適用于哪種場(chǎng)景,相信大家已經(jīng)深有體會(huì)。在此就不多講了。其實(shí)類比過來,Android的界面布局也是如此。假設(shè)我們需要實(shí)現(xiàn)如下的三種布局:
每一個(gè)布局都是在前一個(gè)布局的基礎(chǔ)上增加自己的元素。這種形式多么像類的繼承呀!下面列出實(shí)現(xiàn)文件:
page_three_parts.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/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.android.com/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.android.com/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>
繼承式布局在第一個(gè)節(jié)點(diǎn)處包含父布局文件,然后實(shí)現(xiàn)子布局。繼承式布局要求父布局和子布局的根布局大小必須一致。至于為什么這么要求,很簡(jiǎn)單,想一想類繼承的特點(diǎn)——子類必須實(shí)現(xiàn)父類的所有內(nèi)容,或者說子類必須能夠代替父類。這樣的繼承方式與我們?cè)贑++、C#、Java中實(shí)現(xiàn)的繼承很不一樣,而與GObject、Lua等實(shí)現(xiàn)繼承的方式很相似。
這種布局方式能夠比聚合實(shí)現(xiàn)更簡(jiǎn)單的設(shè)計(jì),而且能夠更大程度的完成代碼和布局的解耦合。這里指的是有很多人會(huì)在聚合式布局中留出擴(kuò)展點(diǎn),然后在程序運(yùn)行的時(shí)候?qū)?nèi)容填充到保留點(diǎn)。這種方式有一個(gè)很大的問題,就是只有當(dāng)程序運(yùn)行起來之后才能看到頁(yè)面的完整信息。繼承式布局就不存在這樣的問題。而且,這種繼承關(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 布局文件對(duì)應(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 布局文件對(duì)應(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 布局文件對(duì)應(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);
}
}
繼承式布局實(shí)際上是通過布局的層層疊加實(shí)現(xiàn)的,但這種疊加是邏輯上的,而不是渲染層次的。所以在實(shí)際運(yùn)行中不會(huì)帶來太大的性能問題。下面這張圖應(yīng)該能夠?qū)⒗^承式布局形象的展示出來:
聯(lián)系客服