【Android Developers Training】 101. 显示快

系统 1896 0

注:本文翻译自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._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 是一个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 绑定到一个包含有 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
      
      <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() 中,将 ContactsAdapter ListView 绑定起来:

      
            @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
      
      
        );

    }
      
    

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


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论