在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); }
核心代码就是StateFactory。这个地方可以下载整个例子程序,里面有StateFactory的代码。整个例子只是演示用的,StateFactory实现的也有不妥的地方,但是我们可以看到android支持视图状态的可能性。有了state,android 视图代码又会好写很多,一切目标:简单。您说呢 ?