Contact Badge的使用
QuickContactBadge 是一个如下图所示的组件。该组件最初显示为一张缩略图:
点击后显示为一个包含以下信息的对话框:
-大图片:与联系人关联的图片或占位图(如果没有图片提供的话)
-应用程序icon:可以处理联系人中的具体信息的内置应用程序的icon,如信息中包含电子邮件地址的话,会有一个email icon。一般情况下,会显示电话icon和短信icon,如上图所示。
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>
获取provider中的数据
在QuickContactBadge中显示联系人,需要提供联系人的URI和图片。通过获取Contacts Provider中的相应列的数据可以构造上述信息。因此,需要将这些列添加到加载Cursor的规划中。
在Android3.0(API 11)及以后,需要添加这些列:
- Contacts._ID
- Contacts.LOOKUP_KEY
Contacts.PHOTO_THUMBNAIL_URI
在Android2.3.3(API 10)及以前,需要添加这些列:Contacts._ID
Contacts.LOOKUP_KEY
设置联系人URI和缩略图
设置联系人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图标时,联系人的具体信息都自动加载到对话框中了。
设置图片
联系人的图片不会自动加载,因此需要先获取联系人图片的URI,然后将文件读入到一个Bitmap对象中。
**需要注意的是,在Android3.0之前,PHOTO_THUMBNAIL_URI是不存在的,需要使用Contacts.Photo表来获取相应的URI。
首先,定义获取Cusor中信息的变量,如下:
// 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:
/**
* 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()返回的结果设置给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添加到ListView中各项的布局文件中,如contact_item_layout.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>
设置自定义的CursorAdapter
定义继承CursorAdapter的自定义适配器。该适配器需要重写如下方法:
-CursorAdapter.newView()
创建View对象保存上面的布局,将该View对象保存起来以便复用。
-CusorAdapter.bindView()
复用上述View对象,重写填充新的信息。
示例代码如下:
/**
*
*
*/
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 );
}
设置变量
如下所示:
public class ContactsFragment extends Fragment implements
LoaderManager .LoaderCallbacks< Cursor> {
...
// 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()中实例化cusor adapter并获取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);
...
}
...
最后需要实现 onLoadFinished()和 onLoaderReset():
public void onLoadFinished(Loader <Cursor> loader, Cursor cursor) {
// When the loader has completed, swap the cursor into the adapter.
mContactsAdapter. swapCursor(cursor);
}
@Override
public void onLoaderReset(Loader <Cursor> loader) {
// Removes remaining reference to the previous Cursor
mContactsAdapter. swapCursor(null );
}