• Android Phonebook编写联系人UI加载及联系人保存流程(四)


    2014-01-07 10:23:22 将百度空间里的东西移过来。

    5. KindSectionView

    KindSectionView是何方神圣呢?它又是怎么怎么和一个DataKind,以及一个RawContactDelta绑定到一起的呢?继续看,进入KindSectionView,其实KindSectionView就是一个普通的自定义View,他的作用还真的就是将DataKind中包含的数据变成UI显示出来,那么这个View是什么呢?它有自己的xml文件:item_kind_section.xml:

     1 <com.android.contacts.editor.KindSectionView
     2     xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:layout_width="match_parent"
     4     android:layout_height="wrap_content"
     5     android:layout_marginBottom="@dimen/raw_contact_sect_fields_margin_bottom"
     6     android:orientation="vertical">
     7    
     8     <include
     9         android:id="@+id/kind_title_layout"
    10         layout="@layout/edit_kind_title" />
    11    
    12     <LinearLayout
    13         android:id="@+id/kind_editors"
    14         android:layout_width="match_parent"
    15         android:layout_height="wrap_content"
    16         android:orientation="vertical" />
    17    
    18     <Button
    19         android:id="@+id/add_text"
    20         android:layout_width="wrap_content"
    21         android:layout_height="wrap_content"
    22         android:layout_gravity="start"
    23         android:text="@string/add_new_entry_for_section"
    24         android:drawableStart="@drawable/spb_plus_icn" />
    25    
    26 </com.android.contacts.editor.KindSectionView>

    对照这图片我们分析:

    kind_title_layout:就是上图中的Phone那个View;

    add_text:就是上图中的“Add new” Button;

    kind_editors:就是介于这两者之间的部分。当然,对add_text的点击事件处理也在KindSectionView类,如下:

     1 @Override
     2 protected void onFinishInflate() {
     3     setDrawingCacheEnabled(true);
     4     setAlwaysDrawnWithCacheEnabled(true);
     5    
     6     mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
     7    
     8     mTitle = (TextView) findViewById(R.id.kind_title);
     9     mEditors = (ViewGroup) findViewById(R.id.kind_editors);
    10     mAddFieldFooter = findViewById(R.id.add_text);
    11     mAddFieldFooter.setOnClickListener(new OnClickListener() {
    12         @Override
    13         public void onClick(View v) {
    14             mAddFieldFooter.setVisibility(View.GONE);
    15             addItem();
    16         }
    17     });
    18     super.onFinishInflate();
    19 }

    不过我们还是继续沿着KindSectionView类setState()方法往下分析,rebuildFromState()-->createEditorView(),createEditorView()方法具体加载了每一个DataKind,代码如下:

     1 private View createEditorView(ValuesDelta entry) {
     2     final View view;
     3     try {
     4         view = mInflater.inflate(mKind.editorLayoutResourceId, mEditors, false);
     5     } catch (Exception e) {
     6     }
     7    
     8     view.setEnabled(isEnabled());
     9    
    10     if (view instanceof Editor) {
    11         Editor editor = (Editor) view;
    12         editor.setDeletable(true);
    13         editor.setValues(mKind, entry, mState, mReadOnly, mViewIdGenerator);
    14         editor.setEditorListener(this);
    15     }
    16     mEditors.addView(view);
    17     return view;
    18 }

    首先是mKind,这个值就是section.setState(kind, state, false, vig)传过来的,它先取出editorLayoutResourceId,然后解析为View,并绑定在mEditors上,然后再操作,那么editorLayoutResourceId是什么?我们回过头去看DataKind:

     1 public DataKind() {
     2     editorLayoutResourceId = R.layout.text_fields_editor_view;
     3     maxLinesForDisplay = 1;
     4 }
     5    
     6 public DataKind(String mimeType, int titleRes, int weight, boolean editable,
     7         int editorLayoutResourceId) {
     8     this.mimeType = mimeType;
     9     this.titleRes = titleRes;
    10     this.weight = weight;
    11     this.editable = editable;
    12     this.typeOverallMax = -1;
    13     this.editorLayoutResourceId = editorLayoutResourceId;
    14     maxLinesForDisplay = 1;
    15 }

    DataKind有两个默认的构造器,无参构造器设置了默认的text_fields_editor_view,以LocalAccountType为例:

    1 protected DataKind addDataKindStructuredName(
    2     Context context) throws DefinitionException {
    3     DataKind kind = addKind(new DataKind(StructuredName.CONTENT_ITEM_TYPE,
    4             R.string.nameLabelsGroup, -1, true,
    5             R.layout.structured_name_editor_view));

    添加Name时,使用R.layout.structured_name_editor_view:

    1 protected DataKind addDataKindNickname(
    2     Context context) throws DefinitionException {
    3     DataKind kind = addKind(new DataKind(Nickname.CONTENT_ITEM_TYPE,
    4                 R.string.nicknameLabelsGroup, 115, true,
    5                 R.layout.text_fields_editor_view));

    添加NickName, Phone, Email等时都是R.layout.text_fields_editor_view。回来接着看createEditorView()方法,

    editorLayoutResourceId有了,剩下的就是把这个id对应的layout显示出来,看

    editor.setValues(mKind, entry, mState, mReadOnly, mViewIdGenerator);看两个xml文件:

    structured_name_editor_view.xml 这个是专门针对Name的,后面再说,先看text_fields_editor_view.xml:

     1 <com.android.contacts.editor.TextFieldsEditorView
     2     xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:layout_width="match_parent"
     4     android:layout_height="wrap_content"
     5     android:orientation="vertical">
     6    
     7     <LinearLayout
     8         android:layout_width="match_parent"
     9         android:layout_height="wrap_content"
    10         android:layout_weight="1"
    11         android:orientation="horizontal"
    12         android:gravity="center_vertical"
    13         android:focusable="true"
    14         android:clickable="true">
    15    
    16         <include
    17             layout="@layout/edit_spinner"
    18             android:layout_width="@dimen/editor_type_label_width"
    19             android:layout_height="@dimen/editor_min_line_item_height"
    20             android:layout_gravity="top"
    21             android:layout_marginEnd="@dimen/raw_contact_edit_spinner_margin_end"
    22             android:visibility="gone" />
    23    
    24         <include
    25             layout="@layout/edit_field_list_with_anchor_view" />
    26    
    27         <FrameLayout
    28             android:layout_width="wrap_content"
    29             android:layout_height="match_parent">
    30    
    31             <include
    32                 android:id="@+id/expansion_view_container"
    33                 layout="@layout/edit_expansion_view"
    34                 android:visibility="gone" />
    35    
    36             <include
    37                 android:id="@+id/delete_button_container"
    38                 layout="@layout/edit_delete_button"
    39                 android:visibility="gone" />
    40    
    41         </FrameLayout>
    42    
    43     </LinearLayout>
    44    
    45 </com.android.contacts.editor.TextFieldsEditorView>

    edit_spinner:上图中“Home” Spinner;

    expansion_view_container:展开或折叠Button,这个只有在Postal Address和Name中用到;

    delete_button_container:上图中的叉;

    TextFieldsEditorView类的继承关系如图:

    我们进入TextFieldsEditorView的setValues()方法:

     1 @Override
     2 public void setValues(DataKind kind, ValuesDelta entry, RawContactDelta state, boolean readOnly, ViewIdGenerator vig) {
     3     super.setValues(kind, entry, state, readOnly, vig);
     4     int fieldCount = kind.fieldList.size();
     5     mFieldEditTexts = new EditText[fieldCount];
     6     for (int index = 0; index < fieldCount; index++) {
     7         final EditField field = kind.fieldList.get(index);
     8         final EditText fieldView = createFieldView(field.column);
     9         fieldView.setTextAppearance(getContext(), android.R.style.TextAppearance_Medium);
    10         mFieldEditTexts[index] = fieldView;
    11    
    12    
    13         fieldView.addTextChangedListener(new TextWatcher() {
    14             @Override
    15             public void afterTextChanged(Editable s) {
    16                 // Trigger event for newly changed value
    17                 onFieldChanged(column, s.toString());
    18             }
    19    
    20         });
    21    
    22         mFields.addView(fieldView);
    23     }
    24    
    25 }

    首先调用了父类的setValues()方法,在父类的setValues()方法中对一些UI赋值,如Spinner mLabel,给他设置了一个Adapter,值就是kind.typeList中包含的内容,前文中提到过。

    我们继续看TextFieldsEditorView的setValues()方法,有个for循环,将kind.fieldList中所有的field取出来,并创建一个对应的EditText fieldView,然后添加到mFields,mFields = (ViewGroup) findViewById(R.id.editors),来自text_fields_editor_view.xml --> edit_field_list_with_anchor_view.xml,如下:

     1 <LinearLayout
     2     android:layout_width="0dip"
     3     android:layout_height="wrap_content"
     4     android:layout_weight="1"
     5    
     6     android:orientation="vertical">
     7     <LinearLayout
     8          android:id="@+id/editors"
     9          android:layout_width="match_parent"
    10          android:layout_height="wrap_content"
    11          android:orientation="vertical"
    12          android:focusable="true"
    13          android:focusableInTouchMode="true"
    14          android:descendantFocusability="afterDescendants" />
    15     <View
    16          android:id="@+id/anchor_view"
    17          android:layout_width="match_parent"
    18          android:layout_height="0px" />
    19 </LinearLayout>

    说白了,editors这个id对应的View就是用来添加一个EditText。

    稍微总结一下:

    最重要的是RawContactCommonEditorView类setState()方法,其中的for循环,作用就是将账户中的每一个kind取出来,然后生成一个KindSectionView,并显示出来。而每一个KindSectionView里面,又有可能包含多个field,这取决于kind中fieldlist中添加的EditField的个数,如下图,就包含2个EditField。

    至此,Phone UI的显示部分完成,具体的细节还得要仔细看代码,比如Spinner的点击事件,叉的点击事件,文中有提到,但是具体的还得研究代码,很简单,至于EditText添加的TextChangedListener的作用,这个设计到Save contact,我们先记住每个EditText都有一个TextChangedListener就好,到分析Save Contact流程时再说。

    6. 添加Name UI

    前面提到Name UI,我们这里仔细分析它。

    在raw_contact_editor_view.xml中,有专门添加Name相关UI的布局:

    1 <include
    2     android:id="@+id/edit_name"
    3     layout="@layout/structured_name_editor_view" />

    进入structured_name_editor_view.xml:

     1 <com.android.contacts.editor.StructuredNameEditorView
     2     xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:layout_width="match_parent"
     4     android:layout_height="wrap_content"
     5     android:minHeight="@dimen/editor_min_line_item_height"
     6     android:orientation="vertical">
     7    
     8     <include
     9         layout="@layout/edit_spinner"
    10         android:layout_width="@dimen/editor_type_label_width"
    11         android:layout_height="@dimen/editor_min_line_item_height"
    12         android:layout_gravity="top"
    13         android:visibility="gone" />
    14    
    15     <LinearLayout
    16         android:layout_width="match_parent"
    17         android:layout_height="wrap_content"
    18         android:orientation="horizontal"
    19         android:clickable="true">
    20    
    21         <include
    22             layout="@layout/edit_field_list_with_anchor_view"/>
    23    
    24         <include
    25             android:id="@+id/expansion_view_container"
    26             layout="@layout/edit_expansion_view"
    27             android:visibility="gone" />
    28    
    29         <include
    30             android:id="@+id/delete_button_container"
    31             layout="@layout/edit_delete_button"
    32             android:visibility="gone" />
    33     </LinearLayout>
    34    
    35 </com.android.contacts.editor.StructuredNameEditorView>

    发现这个文件和text_fields_editor_view.xml很像,当然了,看StructuredNameEditorView类的继承图,发现StructuredNameEditorView继承自TextFieldsEditorView,所以啊,他的逻辑其实也在TextFieldsEditorView里面,和Phone一样,只不过因为StructedName比较特殊,比如没有前面的Title, 后面的“Add new”和Spinner等。我以前做这块的UI定制的时候,需要改变页面中所有的EditText的效果,尤其是有多个EditText,比如Name, Address展开后的效果,其实改动还是在TextFieldsEditorView的setValues()方法中,对EditText设置背景,以及其他属性,来达到定制的需求。

  • 相关阅读:
    sharedCopy收藏夹代码
    执行EXE程序出现unable to locate suitable Java runtime Environment on this machine java解决方法
    点击combo激活下拉
    解决方案
    C++Builder中开发Activex
    BCB常见文件类型说明
    三款Json查看小工具
    oracel故障数据恢复 ora01033错误解决过程.
    fushioncharts破解
    基于注解的表单生成
  • 原文地址:https://www.cnblogs.com/wlrhnh/p/3508373.html
Copyright © 2020-2023  润新知