會話編輯介面(三)記錄
1、前言
前文對接收者ui有一個簡單的瞭解,下面來看看簡訊記錄的載入以及介面更新。例如當我們發送一條簡訊,介面上顯示“正在發送”,發送完後變成“已發送”,以及接收的簡訊時顯示接收時間等等功能,只所以用單獨的篇幅來講解,主要考慮到該ui的重要性。2、功能分析2.1 初始化 簡訊記錄介面的初始仍然是在ComposeMessageActivity的onCreate方法中通過調用initMessageList方法:
private void initMessageList() { if (mMsgListAdapter != null) { return; } String highlightString = getIntent().getStringExtra("highlight"); Pattern highlight = highlightString == null ? null : Pattern.compile("\\b" + Pattern.quote(highlightString), Pattern.CASE_INSENSITIVE); // Initialize the list adapter with a null cursor. mMsgListAdapter = new MessageListAdapter(this, null, mMsgListView, true, highlight); mMsgListAdapter.setOnDataSetChangedListener(mDataSetChangedListener); mMsgListAdapter.setMsgListItemHandler(mMessageListItemHandler); mMsgListView.setAdapter(mMsgListAdapter); mMsgListView.setItemsCanFocus(false); mMsgListView.setVisibility(View.VISIBLE); mMsgListView.setOnCreateContextMenuListener(mMsgListMenuCreateListener); mMsgListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (view != null) { ((MessageListItem) view).onMessageListItemClick(); } } }); }
該方法初始化用於顯示歷程清單地的Listview,以及用於填充listView的adapter,並設定監聽器和長按menu。
2.2 UI分析2.2.1 UI 簡介 下面就來看看這個記錄是什麼樣的,有哪些介面元素組成,來初步認識一下這個介面。為簡訊記錄的ui,
記錄從可以看出記錄的ui至少包含以下ui組件:連絡人頭像、連絡人號碼或者姓名、內容、接收和發送時間,如果是多媒體訊息有對應附件、主題的顯示。當然除了這些還有一些錯誤顯示ui等等。2.2.2 ui布局分析 要窺探該介面怎麼布局,首先來看看MessageListAdapter類是如何綁定ui的?該類有兩個重要的方法來完成ui和資料的綁定bindView、newView;其中newView用於載入布局檔案,定義一個簡訊ui,bindview用於將從簡訊資料庫擷取的資料設定到newView上的ui上。這裡來看看系統怎麼定義這個ui的
@Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return mInflater.inflate(R.layout.message_list_item, parent, false); }
那該ui定義在布局檔案裡面,這裡簡短閑扯android ui的高明,之前有做過J2ME開發的同學可能對android的xml布局印象深刻,估計有很多同學疑問了J2ME為啥不引進這個xml布局,J2ME的ui實現完全靠一行一行的代碼,且複雜冗長,一言難盡哈。這裡來看看神秘的布局檔案。
<com.android.mms.ui.MessageListItem xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/msg_list_item" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/listitem_background" android:orientation="horizontal"> <LinearLayout android:id="@+id/mms_layout_view_parent" android:paddingLeft="5dip" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" > <ViewStub android:id="@+id/mms_layout_view_stub" android:layout="@layout/mms_layout_view" mms 附件ui,其還有自己的布局檔案,大家都可以查看多媒體訊息附件的ui,該ui包含一個iamgeview android:layout_width="match_parent" 另外就是一個playbutton android:layout_height="wrap_content"/> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <android.widget.QuickContactBadge android:layout_marginLeft="0dip" android:layout_marginRight="5dip" android:layout_marginTop="5dip" android:layout_marginBottom="5dip" android:id="@+id/avatar" style="?android:attr/quickContactBadgeStyleWindowSmall" /> 用於顯示連絡人表徵圖 <View android:layout_width="match_parent" android:layout_height="0dip" android:layout_below="@id/avatar" /> <LinearLayout android:id="@+id/status_icons" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@id/text_view" 簡訊內容包含、主題、時間 android:layout_alignParentRight="true" android:layout_marginBottom="8dip" android:orientation="horizontal" > <ImageView android:id="@+id/locked_indicator" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_lock_message_sms" 鎖定簡訊的image,鎖的表徵圖,該功能就是當你鎖定一條簡訊後,刪除該會話,該會話的 android:paddingRight="3dip" 其他簡訊都刪除,但是加鎖的簡訊不被刪除,這樣可以防止誤刪 android:visibility="gone" /> <ImageView android:id="@+id/delivered_indicator" android:layout_width="wrap_content" android:layout_height="wrap_content" 簡訊傳送報告,有可能是fail的表徵圖、以及開啟傳送報告後有一個傳送表徵圖 android:paddingRight="3dip" android:visibility="gone" /> <ImageView android:id="@+id/details_indicator" android:layout_width="wrap_content" 暫時不清楚 android:layout_height="wrap_content" android:src="@drawable/ic_sms_mms_details" android:visibility="gone" /> </LinearLayout> </RelativeLayout> </LinearLayout> <ViewStub android:id="@+id/mms_downloading_view_stub" android:layout="@layout/mms_downloading_view" 如果多媒體訊息未下載會顯示該ui,該ui有一個下載button,一個textview,當點擊button android:layout_gravity="center_vertical" 狀態更新為正在下載 android:layout_width="wrap_content" android:layout_height="wrap_content"/></com.android.mms.ui.MessageListItem>
基本上一條短多媒體訊息包含的ui就是上述,會根據當前短多媒體訊息的狀態來設定來設定對應UI 的值,顯示給使用者,至於如何設定,下回分解。2.2.3 資料的綁定綁定資料bindView方法來實現,核心的代碼如下
@Override public void bindView(View view, Context context, Cursor cursor) { if (view instanceof MessageListItem) { String type = cursor.getString(mColumnsMap.mColumnMsgType); long msgId = cursor.getLong(mColumnsMap.mColumnMsgId); MessageItem msgItem = getCachedMessageItem(type, msgId, cursor); if (msgItem != null) { MessageListItem mli = (MessageListItem) view; MessageItem oldMessageItem = mli.getMessageItem(); if (oldMessageItem != null) { String oldAddress = oldMessageItem.mAddress; if (oldAddress != null) { HashSet<MessageListItem> set = mAddressToMessageListItems.get(oldAddress); if (set != null) { set.remove(mli); } } } mli.bind(mAvatarCache, msgItem); 重要上面的代碼做的事情很簡單,將查詢到的簡訊綁定到ui,這裡的綁定涉藉助於MessageListItem的bind方法。對於每個欄位怎麼設定的這裡不做解析,有興趣的大家可以看看代碼,很簡單。2.4 長按按鈕對於每條簡訊,這裡給他們設定了一個長按事件,給使用者提供了以下功能。這裡沒有完全顯示,但我們可以通過代碼知道其具體有哪些功能。mMsgListMenuCreateListener該變數用於建立menu,menu的監聽的監聽事件處理MsgListMenuClickListener來完成。以下代碼是對每個menu的處理
private final class MsgListMenuClickListener implements MenuItem.OnMenuItemClickListener { public boolean onMenuItemClick(MenuItem item) { if (!isCursorValid()) { return false; } Cursor cursor = mMsgListAdapter.getCursor(); String type = cursor.getString(COLUMN_MSG_TYPE); long msgId = cursor.getLong(COLUMN_ID); MessageItem msgItem = getMessageItem(type, msgId, true); if (msgItem == null) { return false; } switch (item.getItemId()) { case MENU_EDIT_MESSAGE: 編輯簡訊 editMessageItem(msgItem); drawBottomPanel(); return true; case MENU_COPY_MESSAGE_TEXT: 複製簡訊文本 copyToClipboard(msgItem.mBody); return true; case MENU_FORWARD_MESSAGE: 轉寄簡訊 forwardMessage(msgItem); return true; case MENU_VIEW_SLIDESHOW: 查看投影片 MessageUtils.viewMmsMessageAttachment(ComposeMessageActivity.this, ContentUris.withAppendedId(Mms.CONTENT_URI, msgId), null); return true; case MENU_VIEW_MESSAGE_DETAILS: { 查看簡訊資訊:包含簡訊大小、發送和接收的時間 String messageDetails = MessageUtils.getMessageDetails( ComposeMessageActivity.this, cursor, msgItem.mMessageSize); new AlertDialog.Builder(ComposeMessageActivity.this) .setTitle(R.string.message_details_title) .setMessage(messageDetails) .setPositiveButton(android.R.string.ok, null) .setCancelable(true) .show(); return true; } case MENU_DELETE_MESSAGE: {刪除簡訊 DeleteMessageListener l = new DeleteMessageListener( msgItem.mMessageUri, msgItem.mLocked); confirmDeleteDialog(l, msgItem.mLocked); return true; } case MENU_DELIVERY_REPORT: 簡訊傳送報告 showDeliveryReport(msgId, type); return true; case MENU_COPY_TO_SDCARD: { 複製簡訊到sdcard String successMessage = getResources().getString(R.string.copy_to_sdcard_success, SAVED_ATTACHMENT_DIR); String resultMessage = copyMedia(msgId) ? successMessage : getResources() .getString(R.string.copy_to_sdcard_fail); Toast.makeText(ComposeMessageActivity.this, resultMessage, Toast.LENGTH_SHORT).show(); return true; } case MENU_COPY_TO_DRM_PROVIDER: { int resId = getDrmMimeSavedStringRsrc(msgId, copyToDrmProvider(msgId)); Toast.makeText(ComposeMessageActivity.this, resId, Toast.LENGTH_SHORT).show(); return true; } case MENU_LOCK_MESSAGE: { 鎖簡訊 lockMessage(msgItem, true); return true; } case MENU_UNLOCK_MESSAGE: {解鎖 lockMessage(msgItem, false); return true; } case MENU_COPY_TO_SIM: { 複製簡訊到sim卡 if (hasIccCardCount() > 1) { String[] items = new String[TelephonyManager.getPhoneCount()]; for (int i = 0; i < items.length; i++) { items[i] = getMultiSimName(i); } CopyToSimSelectListener listener = new CopyToSimSelectListener(msgItem); new AlertDialog.Builder(ComposeMessageActivity.this) .setTitle(R.string.copy_to_sim) .setIcon(android.R.drawable.ic_dialog_info) .setPositiveButton(android.R.string.ok, listener) .setSingleChoiceItems(items, 0, listener) .setCancelable(true) .show(); } else { copyToSimWithToast(msgItem); } return true; } default: return false; } } }3、總結
這裡對該ui做了一個簡單的介紹,至於其中一些具體的小細節,可以看一下代碼就明白了。