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

5. KindSectionView

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

 <com.android.contacts.editor.KindSectionView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/raw_contact_sect_fields_margin_bottom"
android:orientation="vertical"> <include
android:id="@+id/kind_title_layout"
layout="@layout/edit_kind_title" /> <LinearLayout
android:id="@+id/kind_editors"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" /> <Button
android:id="@+id/add_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:text="@string/add_new_entry_for_section"
android:drawableStart="@drawable/spb_plus_icn" /> </com.android.contacts.editor.KindSectionView>

对照这图片我们分析:

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

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

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

 @Override
protected void onFinishInflate() {
setDrawingCacheEnabled(true);
setAlwaysDrawnWithCacheEnabled(true); mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); mTitle = (TextView) findViewById(R.id.kind_title);
mEditors = (ViewGroup) findViewById(R.id.kind_editors);
mAddFieldFooter = findViewById(R.id.add_text);
mAddFieldFooter.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mAddFieldFooter.setVisibility(View.GONE);
addItem();
}
});
super.onFinishInflate();
}

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

 private View createEditorView(ValuesDelta entry) {
final View view;
try {
view = mInflater.inflate(mKind.editorLayoutResourceId, mEditors, false);
} catch (Exception e) {
} view.setEnabled(isEnabled()); if (view instanceof Editor) {
Editor editor = (Editor) view;
editor.setDeletable(true);
editor.setValues(mKind, entry, mState, mReadOnly, mViewIdGenerator);
editor.setEditorListener(this);
}
mEditors.addView(view);
return view;
}

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

 public DataKind() {
editorLayoutResourceId = R.layout.text_fields_editor_view;
maxLinesForDisplay = 1;
} public DataKind(String mimeType, int titleRes, int weight, boolean editable,
int editorLayoutResourceId) {
this.mimeType = mimeType;
this.titleRes = titleRes;
this.weight = weight;
this.editable = editable;
this.typeOverallMax = -1;
this.editorLayoutResourceId = editorLayoutResourceId;
maxLinesForDisplay = 1;
}

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

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

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

 protected DataKind addDataKindNickname(
Context context) throws DefinitionException {
DataKind kind = addKind(new DataKind(Nickname.CONTENT_ITEM_TYPE,
R.string.nicknameLabelsGroup, 115, true,
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:

 <com.android.contacts.editor.TextFieldsEditorView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal"
android:gravity="center_vertical"
android:focusable="true"
android:clickable="true"> <include
layout="@layout/edit_spinner"
android:layout_width="@dimen/editor_type_label_width"
android:layout_height="@dimen/editor_min_line_item_height"
android:layout_gravity="top"
android:layout_marginEnd="@dimen/raw_contact_edit_spinner_margin_end"
android:visibility="gone" /> <include
layout="@layout/edit_field_list_with_anchor_view" /> <FrameLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"> <include
android:id="@+id/expansion_view_container"
layout="@layout/edit_expansion_view"
android:visibility="gone" /> <include
android:id="@+id/delete_button_container"
layout="@layout/edit_delete_button"
android:visibility="gone" /> </FrameLayout> </LinearLayout> </com.android.contacts.editor.TextFieldsEditorView>

edit_spinner:上图中“Home” Spinner;

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

delete_button_container:上图中的叉;

TextFieldsEditorView类的继承关系如图:

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

 @Override
public void setValues(DataKind kind, ValuesDelta entry, RawContactDelta state, boolean readOnly, ViewIdGenerator vig) {
super.setValues(kind, entry, state, readOnly, vig);
int fieldCount = kind.fieldList.size();
mFieldEditTexts = new EditText[fieldCount];
for (int index = 0; index < fieldCount; index++) {
final EditField field = kind.fieldList.get(index);
final EditText fieldView = createFieldView(field.column);
fieldView.setTextAppearance(getContext(), android.R.style.TextAppearance_Medium);
mFieldEditTexts[index] = fieldView; fieldView.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
// Trigger event for newly changed value
onFieldChanged(column, s.toString());
} }); mFields.addView(fieldView);
} }

首先调用了父类的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,如下:

 <LinearLayout
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1" android:orientation="vertical">
<LinearLayout
android:id="@+id/editors"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:focusable="true"
android:focusableInTouchMode="true"
android:descendantFocusability="afterDescendants" />
<View
android:id="@+id/anchor_view"
android:layout_width="match_parent"
android:layout_height="0px" />
</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的布局:

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

进入structured_name_editor_view.xml:

 <com.android.contacts.editor.StructuredNameEditorView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/editor_min_line_item_height"
android:orientation="vertical"> <include
layout="@layout/edit_spinner"
android:layout_width="@dimen/editor_type_label_width"
android:layout_height="@dimen/editor_min_line_item_height"
android:layout_gravity="top"
android:visibility="gone" /> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:clickable="true"> <include
layout="@layout/edit_field_list_with_anchor_view"/> <include
android:id="@+id/expansion_view_container"
layout="@layout/edit_expansion_view"
android:visibility="gone" /> <include
android:id="@+id/delete_button_container"
layout="@layout/edit_delete_button"
android:visibility="gone" />
</LinearLayout> </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设置背景,以及其他属性,来达到定制的需求。

Android Phonebook编写联系人UI加载及联系人保存流程(四)的更多相关文章

  1. Android Phonebook编写联系人UI加载及联系人保存流程(一)

    2014-01-06 17:05:11 将百度空间里的东西移过来. 本文适合ROM定制做Phonebook的童鞋看,其他人飘过即可- Phonebook添加/编辑联系人UI加载及保存联系人流程,是一系 ...

  2. Android Phonebook编写联系人UI加载及联系人保存流程(三)

    2014-01-07 09:54:13  将百度空间里的东西移过来. 本文从点击“添加联系人”Button开始,分析新建联系人页面UI是如何加载,以及新的联系人信息是如何保存的,借此,我们一探Phon ...

  3. Android Phonebook编写联系人UI加载及联系人保存流程(五)

    2014-01-07 10:46:30 将百度空间里的东西移过来. 在前面的文章中我们分析了UI的加载,其中提到了一个重要的对象:RawContactDeltaList mState,我前面说过这个对 ...

  4. Android Phonebook编写联系人UI加载及联系人保存流程(二)

    2014-01-06 17:18:29 1. Phonebook中新建/编辑联系人的UI不是用xml文件写的,它是随着帐号类型的改变来加载不同的UI,比如SIM联系人,只有Name.Phone Num ...

  5. Android Phonebook编写联系人UI加载及联系人保存流程(六)

    2014-01-07 11:18:08 将百度空间里的东西移过来. 1. Save contact 我们前面已经写了四篇文章,做了大量的铺垫,总算到了这一步,见证奇迹的时刻终于到了. 用户添加了所有需 ...

  6. Android ViewPager Fragment使用懒加载提升性能

     Android ViewPager Fragment使用懒加载提升性能 Fragment在如今的Android开发中越来越普遍,但是当ViewPager结合Fragment时候,由于Androi ...

  7. Android三种基本的加载网络图片方式(转)

    Android三种基本的加载网络图片方式,包括普通加载网络方式.用ImageLoader加载图片.用Volley加载图片. 1. [代码]普通加载网络方式 ? 1 2 3 4 5 6 7 8 9 10 ...

  8. Android开发中如何解决加载大图片时内存溢出的问题

    Android开发中如何解决加载大图片时内存溢出的问题    在Android开发过程中,我们经常会遇到加载的图片过大导致内存溢出的问题,其实类似这样的问题已经屡见不鲜了,下面将一些好的解决方案分享给 ...

  9. Android引入高速缓存的异步加载全分辨率

    Android引进高速缓存的异步加载全分辨率 为什么要缓存 通过图像缩放,我们这样做是对的异步加载优化的大图,但现在的App这不仅是一款高清大图.图.动不动就是图文混排.以图代文,假设这些图片都载入到 ...

随机推荐

  1. 【Todo】Java要学的一些比较好的框架和系统

    commons-pool apache的通用线程池 可以看看这篇文章:<使用common-pool实现的一个简单的线程池> Jmeter 性能测试 Squid Link

  2. iOS开发之Xcode6 之手动添加Pch预编译文件

    参考文档 http://blog.csdn.net/crazyzhang1990/article/details/44243343 红色部分为本人自己补充注意事项 在Xcode6之前,创建一个新工程x ...

  3. Java中去除StringBuffer最后一个字符

    原文:http://www.cnblogs.com/shaozhiheng/p/3661714.html 由于编写了这么一段代码: Iterator it3 = set.iterator(); whi ...

  4. LCA模板

    /*********--LCA模板--***************/ //设置好静态参数并构建好图的邻接表,然后调用lca_setquery()设置查询 //最后调用lca_start(),在lca ...

  5. ITERATOR(迭代器)设计模式

    1 意图:提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示. 2 别名(Cursor) 3 动机:队列表的访问和遍历从列表对象中分离出来放入一个迭代器对象中.   多态迭代   ...

  6. RT-thread学习笔记(一)

    我的基础:能在现有C程序下做些修改,不会移植,不会写驱动,很难从头到尾自己写程序. RT-thread基础:之前看了一点rtthread_manual.zh.pdf(即RT-thread使用手册),发 ...

  7. 让页面滑动流畅得飞起的新特性:Passive Event Listeners

    版权声明:本文由陈志兴原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/153 来源:腾云阁 https://www.qclo ...

  8. C#基础:泛型委托

    泛型委托是委托的一种特殊形式,感觉看上去比较怪异,其实在使用的时候跟委托差不多,不过泛型委托更具有类型通用性. 就拿C#里最常见的委托EventHandler打比方.在.NET 2.0以前,也就是泛型 ...

  9. swiper轮播图--兼容IE8

    //引入idangerous.swiper.min.js var mySwiper = new Swiper ('.swiper-container', { loop: true, paginatio ...

  10. robotframework笔记22

    创建测试库 支持的编程语言 机器人框架本身是用写的 Python 和自然的测试 库扩展它可以使用相同的实现 语言. 运行时框架上 Jython ,图书馆也可以 实现使用 Java . 纯Python代 ...