注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。
原文链接:
http://developer.android.com/training/contacts-provider/display-contact-badge.html
这节课将会向你展示如何添加一个
QuickContactBadge
到你的UI中,以及如何将数据和它捆绑起来。一个
QuickContactBadge
是一个显示缩略图的空间。虽然你可以使用
Bitmap
显示任何缩略图,但是你必须要将联系人照片进行解码。
缩略图的作用类似于一个控制器:当用户点击缩略图时,
QuickContactBadge
会扩展成一个对话框,其中包含如下内容:
一个放大的图标
一个和该联系人关联的大图标,如果没有的话,就用一个默认的占位图片代替。
应用图标
每一个具体的联系人信息旁会有一个应用图标,它说明该数据可被此内置应用处理。例如,如果联系人的数据中有一个或多个email地址,那么就会出现一个email的图标。当用户点击这个图标,联系人的所有email地址会显示出来,之后用户如果点击了某一个email地址,会打开电子邮件应用,其中的收件人地址就是所选中的email地址。
QuickContactBadge
提供了一个指向联系人详细信息的即时访问,以及一个和联系人沟通的快速渠道。用户不需要查询联系人列表,寻找并拷贝信息,之后再把它粘贴到其它的应用界面中去。取而代之的,它们只需要在
QuickContactBadge
上进行点击,选择他们想要使用的沟通方式,并直接通过相关的应用发送消息即可。
一). 添加一个QuickContactBadge视图
要添加一个
QuickContactBadge
,在你的布局中插入一个
元素,例如:
<
RelativeLayout
xmlns:android
="http://schemas.android.com/apk/res/android"
android:layout_width
="match_parent"
android:layout_height
="match_parent"
>
...
<
QuickContactBadge
android:id
=@+id/quickbadge
android:layout_height
="wrap_content"
android:layout_width
="wrap_content"
android:scaleType
="centerCrop"
/>
...
RelativeLayout
>
二). 检索提供器的数据
要在
QuickContactBadge
中显示一个联系人,你需要一个联系人的内容URI还有缩略图的
Bitmap
对象。你从Contacts Provider搜索的列数据用来创建内容URI和
Bitmap
对象。指定这些列左右你在
Cursor
中用来加载数据的投影的一部分。
对Android 3.0(API版本11)及之后的版本,在你的投影中包含下面几列:
Contacts._ID
Contacts.LOOKUP_KEY
Contacts.PHOTO_THUMBNAIL_URI
对Android 2.3.3(API版本10)及之前的版本,在你的投影中包含下面几列:
Contacts._ID
Contacts.LOOKUP_KEY
我们假设在这节课之前,你已经加载了一个
Cursor
,它包含了上面的这些列,还有一些你已经选择了的列。要学习如何使用
Cursor
检索这些列数据,可以参阅:
Retrieving a List of Contacts
(博客链接:
http://www.cnblogs.com/jdneo/p/3674830.html
)
一旦你有了必要的列,你就可以将数据绑定到
QuickContactBadge
上。
要为联系人的内容URI,调用
getLookupUri(id,lookupKey)
来获取一个
CONTENT_LOOKUP_URI
,然后调用
assignContactUri()
来设置联系人。例如:
//
The Cursor that contains contact rows
Cursor mCursor;
//
The index of the _ID column in the Cursor
int
mIdColumn;
//
The index of the LOOKUP_KEY column in the Cursor
int
mLookupKeyColumn;
//
A content URI for the desired contact
Uri mContactUri;
//
A handle to the QuickContactBadge view
QuickContactBadge mBadge;
...
mBadge
=
(QuickContactBadge) findViewById(R.id.quickbadge);
/*
* Insert code here to move to the desired cursor row
*/
//
Gets the _ID column index
mIdColumn =
mCursor.getColumnIndex(Contacts._ID);
//
Gets the LOOKUP_KEY index
mLookupKeyColumn =
mCursor.getColumnIndex(Contacts.LOOKUP_KEY);
//
Gets a content URI for the contact
mCOntactUri=
Contacts.getLookupUri(
mCursor.getLong(mIdColumn),
mCursor.getString(mLookupKeyColumn)
);
mBadge.assignContactUri(mContactUri);
当用户点击了
QuickContactBadge
图标后,联系人的详细信息会自动显示在对话框中。
为
QuickContactBadge
设置联系人的URI并不会自动的加载他的照片。要加载照片,需要从联系人的
Cursor
行中获取照片的URI,使用它来打开包含有压缩后的照片缩略图文件,并将该文件读入一个
Bitmap
对象。
Note:
PHOTO_THUMBNAIL_URI
列在Android 3.0之前的版本中是没有的。对于那些较早的版本,你必须从
Contacts.Photo
自表中获取URI。
首先,为访问包含有
Contacts._ID
和
Contacts.LOOKUP_KEY
列的
Cursor
设置变量,如下所示:
//
The column in which to find the thumbnail ID
int
mThumbnailColumn;
/*
* The thumbnail URI, expressed as a String.
* Contacts Provider stores URIs as String values.
*/
String mThumbnailUri;
...
/*
* Gets the photo thumbnail column index if
* platform version >= Honeycomb
*/
if
(Build.VERSION.SDK_INT >=
Build.VERSION_CODES.HONEYCOMB) {
mThumbnailColumn
=
mCursor.getColumnIndex(Contacts.PHOTO_THUMBNAIL_URI);
//
Otherwise, sets the thumbnail column to the _ID column
}
else
{
mThumbnailColumn
=
mIdColumn;
}
/*
* Assuming the current Cursor position is the contact you want,
* gets the thumbnail ID
*/
mThumbnailUri
=
mCursor.getString(mThumbnailColumn);
...
定义一个方法,它获取联系人的照片数据,以及缩略图的目标大小,并将照片以一个适当尺寸的
Bitmap
形式返回。我们首先从构造一个指向该缩略图的URI开始:
/**
* Load a contact photo thumbnail and return it as a Bitmap,
* resizing the image to the provided image dimensions as needed.
*
@param
photoData photo ID Prior to Honeycomb, the contact's _ID value.
* For Honeycomb and later, the value of PHOTO_THUMBNAIL_URI.
*
@return
A thumbnail Bitmap, sized to the provided width and height.
* Returns null if the thumbnail is not found.
*/
private
Bitmap loadContactPhotoThumbnail(String photoData) {
//
Creates an asset file descriptor for the thumbnail file.
AssetFileDescriptor afd =
null
;
//
try-catch block for file not found
try
{
//
Creates a holder for the URI.
Uri thumbUri;
//
If Android 3.0 or later
if
(Build.VERSION.SDK_INT
>=
Build.VERSION_CODES.HONEYCOMB) {
//
Sets the URI from the incoming PHOTO_THUMBNAIL_URI
thumbUri =
Uri.parse(photoData);
}
else
{
//
Prior to Android 3.0, constructs a photo Uri using _ID
/*
* Creates a contact URI from the Contacts content URI
* incoming photoData (_ID)
*/
final
Uri cOntactUri=
Uri.withAppendedPath(
Contacts.CONTENT_URI, photoData);
/*
* Creates a photo URI by appending the content URI of
* Contacts.Photo.
*/
thumbUri
=
Uri.withAppendedPath(
contactUri, Photo.CONTENT_DIRECTORY);
}
/*
* Retrieves an AssetFileDescriptor object for the thumbnail
* URI
* using ContentResolver.openAssetFileDescriptor
*/
afd
=
getActivity().getContentResolver().
openAssetFileDescriptor(thumbUri,
"r"
);
/*
* Gets a file descriptor from the asset file descriptor.
* This object can be used across processes.
*/
FileDescriptor fileDescriptor
=
afd.getFileDescriptor();
//
Decode the photo file and return the result as a Bitmap
//
If the file descriptor is valid
if
(fileDescriptor !=
null
) {
//
Decodes the bitmap
return
BitmapFactory.decodeFileDescriptor(
fileDescriptor,
null
,
null
);
}
//
If the file isn't found
}
catch
(FileNotFoundException e) {
/*
* Handle file not found errors
*/
}
//
In all cases, close the asset file descriptor
}
finally
{
if
(afd !=
null
) {
try
{
afd.close();
}
catch
(IOException e) {}
}
}
return
null
;
}
在你的代码中调用
loadContactPhotoThumbnail()
来获取缩略图的
Bitmap
对象,将结果用来设置你的
QuickContactBadge
中的联系人缩略图:
...
/*
* Decodes the thumbnail file to a Bitmap.
*/
Bitmap mThumbnail
=
loadContactPhotoThumbnail(mThumbnailUri);
/*
* Sets the image in the QuickContactBadge
* QuickContactBadge inherits from ImageView, so
*/
mBadge.setImageBitmap(mThumbnail);
一个
QuickContactBadge
是一个ListView的非常有用的控件,它会显示联系人的列表。使用
QuickContactBadge
为每一个联系人显示他的缩略图;当用户点击缩略图后,
QuickContactBadge
对话框会出现。
首先,添加一个
QuickContactBadge
视图元素到你的列表项布局中。例如,如果你想要显示一个
QuickContactBadge
还有你检索的每个联系人的名字,将下列XML放置到一个布局文件中:
<
RelativeLayout
xmlns:android
="http://schemas.android.com/apk/res/android"
android:layout_width
="match_parent"
android:layout_height
="wrap_content"
>
<
QuickContactBadge
android:id
="@+id/quickcontact"
android:layout_height
="wrap_content"
android:layout_width
="wrap_content"
android:scaleType
="centerCrop"
/>
<
TextView
android:id
="@+id/displayname"
android:layout_width
="match_parent"
android:layout_height
="wrap_content"
android:layout_toRightOf
="@+id/quickcontact"
android:gravity
="center_vertical"
android:layout_alignParentRight
="true"
android:layout_alignParentTop
="true"
/>
RelativeLayout
>
在下面的章节中,这一文件我们称它为:
contact_item_layout.xml
。
要将一个
CursorAdapter
绑定到一个包含有
QuickContactBadge
的
ListView
上,自定义一个自定义的适配器,它继承自
CursorAdapter
。这一方法允许你在将
Cursor
绑定到
QuickContactBadge
之前,可以在
Cursor
内处理数据。同时这个方法还允许你将多个
Cursor
列绑定到
QuickContactBadge
上。这些方法对于一个传统的
CursorAdapter
而言是不可能做到的。
对于
CursorAdapter
的子类,你必须覆写下列方法:
CursorAdapter.newView()
填充一个新的
View
对象来显示列表项布局。在该方法的覆写版本中,保存布局中子
View
对象的句柄,包括子
QuickContactBadge
。通过使用这一方法,你可以避免每次你填充一个新的布局时去获取子
View
对象的句柄。
你必须要覆写这一方法,这样你才能获取每个自
View
对象的句柄。这一方法允许你在
CursorAdapter.bindView()
方法中控制他们的捆绑关系。
CursorAdapter.bindView()
将数据从当前的
Cursor
行移动到列表项布局中子
View
对象里。你必须覆写这一方法这样你就能同时将联系人URI和缩略图捆绑到
QuickContactBadge
上。而默认的实现值允许一列数据和一个
View
间一对一的对应关系。
下面的代码片段包含了自定义子类
CursorAdapter
的一个例子:
定义
CursorAdapter
的子类,包括它的构造函数,覆写
newView()
和
bindView()
:
/**
*
*
*/
private
class
ContactsAdapter
extends
CursorAdapter {
private
LayoutInflater mInflater;
...
public
ContactsAdapter(Context context) {
super
(context,
null
, 0
);
/*
* Gets an inflater that can instantiate
* the ListView layout from the file.
*/
mInflater
=
LayoutInflater.from(context);
...
}
...
/**
* Defines a class that hold resource IDs of each item layout
* row to prevent having to look them up each time data is
* bound to a row.
*/
private
class
ViewHolder {
TextView displayname;
QuickContactBadge quickcontact;
}
..
@Override
public
View newView(
Context context,
Cursor cursor,
ViewGroup viewGroup) {
/*
Inflates the item layout. Stores resource IDs in a
* in a ViewHolder class to prevent having to look
* them up each time bindView() is called.
*/
final
View itemView =
mInflater.inflate(
R.layout.contact_list_layout,
viewGroup,
false
);
final
ViewHolder holder =
new
ViewHolder();
holder.displayname
=
(TextView) view.findViewById(R.id.displayname);
holder.quickcontact
=
(QuickContactBadge)
view.findViewById(R.id.quickcontact);
view.setTag(holder);
return
view;
}
...
@Override
public
void
bindView(
View view,
Context context,
Cursor cursor) {
final
ViewHolder holder =
(ViewHolder) view.getTag();
final
String photoData =
cursor.getString(mPhotoDataIndex);
final
String displayName =
cursor.getString(mDisplayNameIndex);
...
//
Sets the display name in the layout
holder.displayname =
cursor.getString(mDisplayNameIndex);
...
/*
* Generates a contact URI for the QuickContactBadge.
*/
final
Uri cOntactUri=
Contacts.getLookupUri(
cursor.getLong(mIdIndex),
cursor.getString(mLookupKeyIndex));
holder.quickcontact.assignContactUri(contactUri);
String photoData
=
cursor.getString(mPhotoDataIndex);
/*
* Decodes the thumbnail file to a Bitmap.
* The method loadContactPhotoThumbnail() is defined
* in the section "Set the Contact URI and Thumbnail"
*/
Bitmap thumbnailBitmap
=
loadContactPhotoThumbnail(photoData);
/*
* Sets the image in the QuickContactBadge
* QuickContactBadge inherits from ImageView
*/
holder.quickcontact.setImageBitmap(thumbnailBitmap);
}
在你的代码中,设置变量,包括一个
Cursor
投影,它包含了必要的那些列。
Note:
下面的代码片段使用了
loadContactPhotoThumbnail()
方法,这在之前的章节中该方法已经详细叙述过了。
例如:
public
class
ContactsFragment
extends
Fragment
implements
LoaderManager.LoaderCallbacks
{
...
//
Defines a ListView
private
ListView mListView;
//
Defines a ContactsAdapter
private
ContactsAdapter mAdapter;
...
//
Defines a Cursor to contain the retrieved data
private
Cursor mCursor;
/*
* Defines a projection based on platform version. This ensures
* that you retrieve the correct columns.
*/
private
static
final
String[] PROJECTION =
{
Contacts._ID,
Contacts.LOOKUP_KEY,
(Build.VERSION.SDK_INT
>=
Build.VERSION_CODES.HONEYCOMB)
?
Contacts.DISPLAY_NAME_PRIMARY :
Contacts.DISPLAY_NAME
(Build.VERSION.SDK_INT
>=
Build.VERSION_CODES.HONEYCOMB)
?
Contacts.PHOTO_THUMBNAIL_ID :
/*
* Although it's not necessary to include the
* column twice, this keeps the number of
* columns the same regardless of version
*/
Contacts_ID
...
};
/*
* As a shortcut, defines constants for the
* column indexes in the Cursor. The index is
* 0-based and always matches the column order
* in the projection.
*/
//
Column index of the _ID column
private
int
mIdIndex = 0
;
//
Column index of the LOOKUP_KEY column
private
int
mLookupKeyIndex = 1
;
//
Column index of the display name column
private
int
mDisplayNameIndex = 3
;
/*
* Column index of the photo data column.
* It's PHOTO_THUMBNAIL_URI for Honeycomb and later,
* and _ID for previous versions.
*/
private
int
mPhotoDataIndex =
Build.VERSION.SDK_INT
>= Build.VERSION_CODES.HONEYCOMB ?
3
:
0
;
...
设置ListView
在
Fragment.onCreate()
中,实例化自定义的
cursor适配器,并获得一个
ListView
的句柄:
@Override
public
void
onCreate(Bundle savedInstanceState) {
...
/*
* Instantiates the subclass of
* CursorAdapter
*/
ContactsAdapter mContactsAdapter
=
new
ContactsAdapter(getActivity());
/*
* Gets a handle to the ListView in the file
* contact_list_layout.xml
*/
mListView
=
(ListView) findViewById(R.layout.contact_list_layout);
...
}
...
在
onActivityCreated()
中,将
ContactsAdapter
和
ListView
绑定起来:
@Override
public
void
onActivityCreated(Bundle savedInstanceState) {
...
//
Sets up the adapter for the ListView
mListView.setAdapter(mAdapter);
...
}
...
当你获取了一个包含有联系人数据的
Cursor
,通常是在
, D)">
onLoadFinished()
,调用
swapCursor()
将
Cursor
数据移动到
ListView
。这会为联系人列表中的每一个条目显示
QuickContactBadge
:
public
void
onLoadFinished(Loader
loader, Cursor cursor) {
//
When the loader has completed, swap the cursor into the adapter.
mContactsAdapter.swapCursor(cursor);
}
当你通过一个
CursorAdapter
(或它的子类)将一个
Cursor
绑定到
ListView
上,并且你使用
CursorLoader
加载
Cursor
,一定要记得在
)">
onLoaderReset()
的实现中清楚
Cursor
的引用,例如:
@Override
public
void
onLoaderReset(Loader
loader) {
//
Removes remaining reference to the previous Cursor
mContactsAdapter.swapCursor(
null
);
}
【Android Developers Training】 101. 显示快速联系人挂件(Quick Contact Badge)