• 【Android Developers Training】 101. 显示快速联系人挂件(Quick Contact Badge)


    注:本文翻译自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,在你的布局中插入一个<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)及之后的版本,在你的投影中包含下面几列:

    对Android 2.3.3(API版本10)及之前的版本,在你的投影中包含下面几列:

    我们假设在这节课之前,你已经加载了一个Cursor,它包含了上面的这些列,还有一些你已经选择了的列。要学习如何使用Cursor检索这些列数据,可以参阅:Retrieving a List of Contacts(博客链接:http://www.cnblogs.com/jdneo/p/3674830.html


    三). 设置内容URI和缩略图

    一旦你有了必要的列,你就可以将数据绑定到QuickContactBadge上。

    设置内容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图标后,联系人的详细信息会自动显示在对话框中。

    设置照片缩略图

    QuickContactBadge设置联系人的URI并不会自动的加载他的照片。要加载照片,需要从联系人的Cursor行中获取照片的URI,使用它来打开包含有压缩后的照片缩略图文件,并将该文件读入一个Bitmap对象。

    Note:

    PHOTO_THUMBNAIL_URI列在Android 3.0之前的版本中是没有的。对于那些较早的版本,你必须从Contacts.Photo自表中获取URI。

    首先,为访问包含有Contacts._IDContacts.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是一个ListView的非常有用的控件,它会显示联系人的列表。使用QuickContactBadge为每一个联系人显示他的缩略图;当用户点击缩略图后,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

    要将一个CursorAdapter绑定到一个包含有QuickContactBadgeListView上,自定义一个自定义的适配器,它继承自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<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()中,实例化自定义的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()中,将ContactsAdapterListView绑定起来:

        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            ...
            // Sets up the adapter for the ListView
            mListView.setAdapter(mAdapter);
            ...
        }
        ...

    当你获取了一个包含有联系人数据的Cursor,通常是在onLoadFinished(),调用swapCursor()Cursor数据移动到ListView。这会为联系人列表中的每一个条目显示QuickContactBadge

        public void onLoadFinished(Loader<Cursor> 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<Cursor> loader) {
            // Removes remaining reference to the previous Cursor
            mContactsAdapter.swapCursor(null);
        }
  • 相关阅读:
    P3224 [HNOI2012]永无乡(平衡树合并)
    jquery的队列问题
    值得以后看的东西
    js的>>>
    js的set和get
    js数组的操作方法
    中文冒号检查了两个小时
    setintervalue传参数的三种方法
    js轮训
    npm全局安装
  • 原文地址:https://www.cnblogs.com/jdneo/p/3707278.html
Copyright © 2020-2023  润新知