在android中,可以很容易給一個視圖的外觀加上state,從而反映行為狀態比如:激活、選中、懸浮等。但是對於視圖布局的動態調整,比如說某一狀態,需要顯示按鈕,下一個狀態,不需要顯示這個按鈕,就顯得蒼白無力。
這種情況,大家會說我去改一下按鈕的可見度就ok了呀。的確是這樣,但是涉及到多個狀態、多個控件的時候是不是很麻煩?現有解決辦法主要問題有:
(1) 多狀態、多組件的難於管理。
(2) 沒用的組件只是看不見了,但是還存在,浪費資源。
有沒有更好的方法?有,那就是引入state。
點擊show clicked按鈕,變成:
最後,點擊show all,切換到all狀態:
這裡面有兩個組件: 按鈕和文本框,三種狀態:default、clicked、all。default下顯示文本框,clicked下顯示按鈕,all下顯示所有。
怎麼做的?
首先需要定義狀態
在狀態視圖的layout上用tractor:states定義所有狀態,tractor:currentState指定默認狀態。如下面代碼所示:
復制代碼
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tractor="http://schemas.tractorframework.com/tractor"
...
tractor:states="default,clicked,all"
tractor:currentState="default"
tractor:layout="activity_main" >
復制代碼
還有一個標簽是trantor:layout,這個是用來指定狀態視圖的layout的,在狀態切換的時候,需要這個參數來獲得layout,重新構造整個視圖。也就是說狀態視圖的layout都需要
一個單獨的layout文件來定義。有點小不方便,但是對於大量的可見度管理來說,可以接受,您說呢?
在控件上聲明對應狀態
在視圖控件上使用tractor:includeIn來表明該控件存在於哪些狀態下,或者用tractor:excludeFrom來指定不存在於哪些狀態。下面是例子程序的兩個控件的狀態聲明:
復制代碼
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tractor:includeIn="clicked,all"
android:text="hello clicked state"
/>
<EditText
android:id="@+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tractor:excludeFrom="clicked"
android:text="hello default state" />
復制代碼
按鈕存在於clicked,all兩個狀態,文本框不存在於clicked狀態,也就是說存在於default和all狀態。
狀態切換
上面都是定義和聲明,是不是很簡單?狀態切換也不復雜,在上面例子上,最上面的三個按鈕就是切換狀態用的,它們被點擊後,就會去切換對應狀態。比如show clicked按鈕點擊就會去切換到clicked狀態,代碼是這樣的:
public void switchToClicked(View v)
{
View root = findViewById(R.id.root);
sf.getViewState(root).setCurrentState("clicked");
}
首先得到狀態視圖,其次得到狀態試圖對應的ViewState去設置當前狀態。一切很容易操作的了,但是大家會說sf是什麼,看下面。
最核心的是加入狀態支持,在Activity設置視圖之前,重新設置LayoutInflater的Factory2工廠,這個在sdk版本11才有哦。這個sf就是加入了狀態支持的Factory2工廠實例。
例子程序的Activity是這樣構造的:
復制代碼
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
createInflator();
setContentView(R.layout.activity_main);
}
private void createInflator()
{
LayoutInflater inflater = LayoutInflater.from(this);
sf = new StateFactory(inflater);
inflater.setFactory2(sf);
}