用户接口(UserInterfaces)

       活动通常显示用户界面。同时安卓为构建用户接口提供了很多类。

1. 视图(View)

绘制视图本身和处理事件。

       一些预定义的视图:

(1)按钮(Button)

       能够单击并表现行为的视图。

(2)状态按钮(ToggleButton)

       2-状态按钮,拥有检查/未检查状态,灯光指示器显示按钮当前的状态。

(3)检查框(CheckBox)

       另外一种2-状态按钮,拥有检查/未检查状态。

(4)评分条(RatingBar)

       包含一行星的视图。用户可以点击或拖动星来表示它们的等级。

(5)自动完成的文本视图(AutocompleteTextView)

       当用户输入文本时提供完成建议的可编辑文本区域。

2. 常见的视图操作

(1)设置可见:显示或隐藏视图;

(2)设置检查状态

(3)设置监听:当具体的事件发生时应该执行的代码;

(4)设置属性:透明度,背景和旋转;

(5)管理输入焦点:允许视图取得焦点和请求焦点。

3. 视图事件资源

(1)用户交互:触摸;键盘/轨迹球/方向键;

(2)系统控制:生命周期的改变。

4. 处理视图事件

       经常在监听器中处理事件。由视图类定义大量的监听接口。

(1)视图监听接口

       OnClickListener.onClick()——视图被单击;

       OnLongClickListener.onLongClick()——视图被按下并保持;

       OnFocusChangeListener.onFocuesChange()——视图获得或失去焦点;

       OnKeyListener.onKey()——视图接收到硬件的按键按下。

(2)显示视图

       视图的组织呈树状结构。显示视图包含多个步骤。

       测量——获得每个视图的大小;

       布局——定位每个视图;

       绘制——绘制每个视图。

       定制的视图子类会覆盖不同的视图方法。

       onMeasure()——确定视图及其子类的大小;

       onLayout()——视图必须对其所有的子视图分配大小和位置;

       onDraw()——显示视图的内容;

       onFocusChanged()——视图的焦点状态改变;

       onKeyUp(),onKeyDown()——硬件按键事件发生;

       onWindowVisibilityChanged()——包含视图的窗口的可见状态改变。

5. 视图组

       包含其它视图的不可见视图;用于组和组织视图集合;视图的容器(containers)和布局的基类。

预定义的视图组:

(1)单选组

       单选组包含一系列单选按钮。每次总是只有一个按钮被选择;

(2)时间选择器

       视图组允许用户去选择时间;

(3)日期选择器

       视图组允许用户去选择日期;

(4)网络视图

       显示网页的视图组;

(5)地图视图

       显示地图的视图组;

(6)画廊

       显示水平滚动的列表的视图组;由下拉列表适配器管理选项;

       a)适配器和适配器视图

适配器视图的子视图由适配器管理。适配器管理数据并向适配器视图提供数据视图;适配器视图显示数据视图。

       b)列表视图

       适配器视图显示选项的可滚动列表;由列表适配器管理选项;列表视图可以基于文本输入过滤选项列表。

(7)下拉列表

       提供选项的可滚动列表的适配器视图;用户可以从列表中选择一个选项;下拉列表适配器管理选项。

6. 布局

       为所包含的视图定义结构的通用视图组。

(1)线性布局

       子视图以单个水平或垂直的行出现;

(2)相对布局

       子视图的位置由其它视图或父视图决定;

(3)桌面布局

       子视图以行和列的形式安排。

7. 网格视图

       子视图安排在2维可滚动的网格中。

菜单和操作杆

       支持菜单的活动;活动可以在菜单中添加选项,处理在菜单选项上的单击事件。

1. 菜单类型

(1)选项

       用户按下菜单按钮后显示的菜单;

(2)上下文

       当用户触摸并保持视图时具体的视图菜单;

(3)子菜单

       当用户触摸可见菜单项时被激活的菜单。

2. 创建菜单

       在XML文件中定义菜单资源,保存在res/menu/filename.xml中。

onCreate…Menu()函数中填充菜单资源;在合适的on…ItemSelected()函数中处理选项的选择。

3. 菜单

       同时支持许多其他特征:将菜单项打成组;将菜单项与快捷键结合;将菜单项与意图结合。

4. 操作杆

       和很多桌面应用的操作杆相似。能够快速执行常见操作。

(1)带操作杆的片段动态布局

       显示选择的剧本的引用和剧本的标题;为操作杆提供动作;三个主要对象:

       QuoteViewerActivity

       TitleFragment

       QuoteFragment

(2)actionbar.tab

       在Tab和内容区域划分屏幕,允许多个片段共享单个内容区域;每个Tab都与一个片段相关联;同一时刻只有一个Tab被选中;选中的Tab对应的片段将在内容区域可见。

5. 对话

       用于与用户交流的活动的独立子窗口。

(1)对话子类

       警告对话;过程对话;日期选择器对话;时间选择器对话。

用户接口实验

1.    初始用户接口

(1)填入新视图层

       主活动存放在ToDoActivity.java中,本来主活动显示的视图为空白。现在需要将footerView填充进footer_view.xml文件。

       TextView footerView = (TextView)getLayoutInflater().inflate(R.layout.footer_view,getListView(), false);

       查看footerView.xml发现只有1个TextView,文本的内容为“AddNew ToDo Item”。这个界面在之前的空白界面中并未出现,所以需要用getLayoutInflater()查找res/layout下的xml文件,并且用xml布局实例化后的LayoutInflater对象调用inflate()函数载入footerView视图。正如许多人所说的,getLayoutInflater().inflate()是将Layout的xml布局文件实例化为View类对象。这里用到的函数形式为:

       public View inflate (int resource, ViewGrouproot, boolean attachToRoot)

       inflate函数:

       根据指定的XML资源添加新的视图层。函数发生错误时会返回填入异常(InflateException)。

       1)参数

       resource:需要加载的XML布局资源的ID号(比如,R.layout.main_page);

       root:产生的新视图层的父视图(如果attachToRoot为true),或者只是为返回的视图层的父图层提供一系列布局参数(LayoutParams)值的对象(如果attachToRoot为false)。

       attachToRoot:填入的图层是否应与根参数相关联?如果为false,仅用根来为XML根视图创建正确的布局参数子类。

如果提供了根视图并且attachToRoot为true,那么返回的视图为根视图,否则填入的XML文件为根视图。

ListView继承自View,也是一种视图。同时ListView为默认的布局元素。

(2)添加新视图层到列表视图

       此时仅仅是得到footer_view.xml对应的视图对象footerview,并且上面也将attachToRoot设置为false,所以与根视图暂时还一点关系扯不上。所以需要添加XML对应的视图对象至列表视图。

       getListView().addFooterView(footerView);

       这里我理解为如果没有根视图,那么可以选择添加新的视图层到列表视图。

       先看看这个函数addFooterView()到底怎么用的:

       voidandroid.widget.ListView.addFooterView(View v)

       addFooterView函数:

       在列表的底部添加一个固定的视图。如果addFooterView被多次调用,视图将会根据它们的添加顺序出现。根据用户需要可以通过调用该函数获取视图的焦点。

       第一次使用时,函数调用只能放在用setAdapter(ListAdapter)设置适配器之前。

       参数:需添加的视图。

(3)为新视图添加监听器

将新的视图强制转换成TextView后才赋值给了footerView,为footerView添加监听器。当检测到footerView被触摸时进入footerView对象的OnClickListener()函数,在该函数中从当前活动ToDoManagerActivity转换到另一个活动AddToDoActivity。然后启动从ToDoManagerActivity转换到AddToDoActivity的映射并向AddToDoActivity发送请求码ADD_TODO_ITEM_REQUEST。
       Intent intent = new Intent(getApplicationContext(),AddToDoActivity.class);
       startActivityForResult(intent, ADD_TODO_ITEM_REQUEST);
(4)显示新视图层
       到目前为止已经将新视图层添加进列表视图了,最后还需要在界面中显示更新后的列表视图。列表视图显示组件(TextView继承自视图,也是一种基本组件)还需要使用适配器将组件等数据映射到当前活动对应的界面上。
mAdapter);
setListAdapter (ListAdapter adapter) 
适配器管理数据并向适配器视图提供数据(这里为组件)更容易理解。
(5)接收目标活动的响应
       在当前活动ToDoManagerActivity中启动目标活动AddToDoActivity后,目标活动完成任务后会向当前活动返回结果。在onActivityResult()中处理响应结果:首先判断请求码是否为当前活动发送出去的请求码,然后判断结果码是否为完成任务(后面具体说明任务内容),两个条件同时满足后,根据返回的意图类data创建新的ToDoItem对象,最后添加到当前活动对应的适配器mAdapter中去。add函数添加数据至适配器并通知(Notify)映射数据的列表视图刷新界面。
       if (requestCode == ADD_TODO_ITEM_REQUEST) {
           if(resultCode == RESULT_OK){
mAdapter.add(new ToDoItem(data));
            }
      }
2. 适配器添加视图过程总结
(1)填充给定XML的布局文件至视类对象;
(2)视类对象添加进根视图;
(3)为视类对象添加监听函数;
(4)适配器显示添加入视类对象后的根视图。3. AddToDoActivity活动中添加的代码
(1)“取消”事件响应函数
       直接结束活动:finish();
(2)“复位”事件响应函数
       设置默认的组件数据:设置标题的字符串为为空,设置默认的状态和优先级,设置默认的日期和时间:
mTitleText.setText("");
mStatusRadioGroup.check(mDefaultStatusButton.getId());
mPriorityRadioGroup.check(mDefaultPriorityButton.getId());
setDefaultDateTime();
       上面的成员变量在当前活动的视图中有对应关系,其中对我而言比较新的为RadioButton类型和RadioGroup类型的组件。看看check()函数的用法:
check
       设置将传入其标识符(ID)的单选按钮选中。选择标识符为-1时表示清空选择,这种操作等价于调用clearCheck()函数。
       1)参数
       id:组中需要选择的按钮的唯一标识符。
       Check中获得标识符的方式(mDefaultStatusButton.getId())等价于getCheckedRadioButtonId()函数。
(3)“提交”事件响应函数
       如程序中提示,获得优先级、当前状态和标题,将获得的数据打包进意图类data。这里自定义的packageIntent函数中都是由putExtra组成的,和前面自定义的add函数是成对的。如果将packageIntent相当于打包数据,add相当于解析数据(除此还有显示数据到视图)。至此,活动AddToDoActivity任务完成,最后向活动ToDoManagerActivity返回请求码、结果码和数据。
       // TODO - Get the current Priority
       Priority priority =getPriority();
       // TODO - Get the current Status
       Status status= getStatus();
       // TODO - Get the current ToDoItem Title
       StringtitleString = getToDoTitle();
       // Package ToDoItem data into anIntent
       Intent data =new Intent();
       ToDoItem.packageIntent(data,titleString, priority, status, fullDate);
       // TODO- return data Intent and finish
       setResult(RESULT_OK,data);
       finish();
4. 适配器显示视图
       我大概知道在这个函数中,具体看看getView()函数的说明也就清楚了:
 View getView (int position,  View convertView,  ViewGroup
     (1)getView函数
inflate(int,android.view.ViewGroup, boolean)来指定根视图并防止与根视图关联。
       1)参数
       position:期望的视图在适配器数据集中的选项位置;
       convertView:重利用的旧视图;
       parent:最终关联的俯视图;
       返回值:指定位置的数据对应的视图。
(2)get()函数获得列表中指定位置返回的元素,ToDoItem类中包含很多数据;
(3)从todo_item.xml布局文件中填入视图得到相对布局对象itemView;
(4)在itemView中显示数据。
       public View getView(intposition, View convertView, ViewGroup parent) {
 
// TODO - Get the current ToDoItem
              final ToDoItem toDoItem = mItems.get(position);
// TODO - Inflate the View for this ToDoItem
//from todo_item.xml
itemView= LayoutInflater.from(mContext).inflate(R.layout.todo_item, parent, false);
 
// TODO - Fill in specific ToDoItem data
//Remember that the data that goes in this View
//corresponds to the user interface elements defined
//in the layout file
 
// TODO - Display Title in TextView
              final TextView titleView = (TextView) itemView.findViewById(R.id.titleView);
              titleView.setText(toDoItem.getTitle());
// TODO - Set up Status CheckBox
              final CheckBox statusView = (CheckBox) itemView.findViewById(R.id.statusCheckBox);
setChecked(toDoItem.getStatus().equals(ToDoItem.Status.DONE));
 
              statusView.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
                     public void onCheckedChanged(CompoundButton buttonView,
                                   booleanisChecked) {
                            Log.i(TAG, "Entered onCheckedChanged()");
 
//  TODO - set up an OnCheckedChangeListener, which
// is called when the user toggles the status checkbox
                            if(isChecked) {
                                   toDoItem.setStatus(Status.DONE);
                            } else {
                                   toDoItem.setStatus(Status.NOTDONE);
                            }
                     }
              });
 
// TODO - Display Priority in a TextView
              final TextView priorityView = (TextView) itemView.findViewById(R.id.priorityView);
              priorityView.setText(toDoItem.getPriority().toString());
// TODO - Display Time and Date.
//Hint - use ToDoItem.FORMAT.format(toDoItem.getDate()) to get date and
//time String
              final TextView dateView = (TextView) itemView.findViewById(R.id.dateView);
ToDoItem.FORMAT.format(toDoItem.getDate()));
 
//Return the View you just created
              return itemView;
       }
}

5. 适配器显示视图过程总结

(1)获得视图位置返回的数据; (2)将数据对应的布局文件填入新视图; (3)在新视图中显示数据。

结语

       篇幅有限,日期和时间的设置和解析等部分这里暂时不追究了