1,联系人详情界面
ContactDetailFragment中处理,ViewAdapter装载数据显示头像
1 private final class ViewAdapter extends BaseAdapter { 2 ...... 3 4 public View getView(int position, View convertView, ViewGroup parent) { 5 switch (getItemViewType(position)) { 6 case VIEW_TYPE_HEADER_ENTRY://获取头像,name等 7 return getHeaderEntryView(convertView, parent); 8 case VIEW_TYPE_SEPARATOR_ENTRY://同类data,多个item之间分割线 9 return getSeparatorEntryView(position, convertView, parent); 10 case VIEW_TYPE_KIND_TITLE_ENTRY://data类别标题以及下划线 11 return getKindTitleEntryView(position, convertView, parent); 12 case VIEW_TYPE_DETAIL_ENTRY://data详情 13 return getDetailEntryView(position, convertView, parent); 14 case VIEW_TYPE_NETWORK_TITLE_ENTRY: 15 return getNetworkTitleEntryView(position, convertView, parent); 16 case VIEW_TYPE_ADD_CONNECTION_ENTRY: 17 return getAddConnectionEntryView(position, convertView, parent); 18 default: 19 throw new IllegalStateException("Invalid view type ID " + 20 getItemViewType(position)); 21 } 22 }
构建OnClickListener,并注册启用
1 private View getHeaderEntryView(View convertView, ViewGroup parent) { 2 final int desiredLayoutResourceId = R.layout.detail_header_contact_without_updates; 3 ...... 4 5 // Set the photo if it should be displayed 6 if (viewCache.photoView != null) { 7 final boolean expandOnClick = mContactData.getPhotoUri() != null; 8 //构造OnClickListener 9 final OnClickListener listener = mPhotoSetter.setupContactPhotoForClick( 10 mContext, mContactData, viewCache.photoView, expandOnClick); 11 12 RawContact rawContact = mContactData.getRawContacts().get(0); 13 final String accountType = rawContact.getAccountTypeString(); 14 15 if ((expandOnClick || mContactData.isWritableContact(mContext)) 16 && !(SimAccountType.ACCOUNT_TYPE.equals(accountType))) { 17 ///启用OnClickListener 18 viewCache.enablePhotoOverlay(listener); 19 } 20 }
public class ContactDetailPhotoSetter extends ImageViewDrawableSetter { public OnClickListener setupContactPhotoForClick(Context context, Contact contactData, ImageView photoView, boolean expandPhotoOnClick) { Bitmap bitmap = setupContactPhoto(contactData, photoView); return setupClickListener(context, contactData, bitmap, expandPhotoOnClick); } ...... private OnClickListener setupClickListener(Context context, Contact contactData, Bitmap bitmap, boolean expandPhotoOnClick) { final ImageView target = getTarget(); if (target == null) return null; return new PhotoClickListener( context, contactData, bitmap, getCompressedImage(), expandPhotoOnClick); } ...... private static final class PhotoClickListener implements OnClickListener { ...... public PhotoClickListener(Context context, Contact contactData, Bitmap photoBitmap, byte[] photoBytes, boolean expandPhotoOnClick) { ...... } @Override public void onClick(View v) { ...... Intent photoSelectionIntent = PhotoSelectionActivity.buildIntent(mContext, photoUri, mPhotoBitmap, mPhotoBytes, rect, delta, mContactData.isUserProfile(), mContactData.isDirectoryEntry(), mExpandPhotoOnClick); ...... mContext.startActivity(photoSelectionIntent); } } }
onClick会启动PhotoSelectionActivity
public class PhotoSelectionActivity extends Activity { ...... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.photoselection_activity); ...... / Wait until the layout pass to show the photo, so that the source bounds will match up. SchedulingUtils.doAfterLayout(mBackdrop, new Runnable() { @Override public void run() { displayPhoto(); } }); ...... private void displayPhoto() { ...... attachPhotoHandler(); } private void attachPhotoHandler() { ...... mPhotoHandler = new PhotoHandler(this, mPhotoView, mode, mState); if (mPendingPhotoResult != null) { ...... } else { SchedulingUtils.doAfterLayout(mBackdrop, new Runnable() { @Override public void run() { animatePhotoOpen(); } }); } } private void animatePhotoOpen() { mAnimationListener = new AnimatorListenerAdapter() { private void capturePhotoPos() { ...... } @Override public void onAnimationEnd(Animator animation) { capturePhotoPos(); if (mPhotoHandler != null) { //又一个onClick被调用 mPhotoHandler.onClick(mPhotoView); } } @Override public void onAnimationCancel(Animator animation) { capturePhotoPos(); } }; animatePhoto(getPhotoEndParams()); }
mPhotoHandler.onClick(mPhotoView)处理
public abstract class PhotoSelectionHandler implements OnClickListener { ...... @Override public void onClick(View v) { final PhotoActionListener listener = getListener(); if (listener != null) { if (getWritableEntityIndex() != -1) { mPopup = PhotoActionPopup.createPopupMenu( mContext, mPhotoView, listener, mPhotoMode); mPopup.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss() { listener.onPhotoSelectionDismissed(); } }); mPopup.show();//显示弹出框ListPopupWindow } } } }
PhotoActionPopup创建ListPopupWindow
1 public static ListPopupWindow createPopupMenu(Context context, View anchorView, 2 final Listener listener, int mode) { 3 // Build choices, depending on the current mode. We assume this Dialog is never called 4 // if there are NO choices (e.g. a read-only picture is already super-primary) 5 final ArrayList<ChoiceListItem> choices = new ArrayList<ChoiceListItem>(4); 6 // Use as Primary 7 if ((mode & Flags.ALLOW_PRIMARY) > 0) { 8 choices.add(new ChoiceListItem(ChoiceListItem.ID_USE_AS_PRIMARY, 9 context.getString(R.string.use_photo_as_primary))); 10 } 11 // Remove 12 if ((mode & Flags.REMOVE_PHOTO) > 0) { 13 choices.add(new ChoiceListItem(ChoiceListItem.ID_REMOVE, 14 context.getString(R.string.removePhoto))); 15 } 16 // Take photo or pick one from the gallery. Wording differs if there is already a photo. 17 if ((mode & Flags.TAKE_OR_PICK_PHOTO) > 0) { 18 boolean replace = (mode & Flags.TAKE_OR_PICK_PHOTO_REPLACE_WORDING) > 0; 19 final int takePhotoResId = replace ? R.string.take_new_photo : R.string.take_photo; 20 final String takePhotoString = context.getString(takePhotoResId); 21 final int pickPhotoResId = replace ? R.string.pick_new_photo : R.string.pick_photo; 22 final String pickPhotoString = context.getString(pickPhotoResId); 23 if (PhoneCapabilityTester.isCameraIntentRegistered(context)) { 24 choices.add(new ChoiceListItem(ChoiceListItem.ID_TAKE_PHOTO, takePhotoString)); 25 } 26 choices.add(new ChoiceListItem(ChoiceListItem.ID_PICK_PHOTO, pickPhotoString)); 27 } 28 29 final ListAdapter adapter = new ArrayAdapter<ChoiceListItem>(context, 30 R.layout.select_dialog_item, choices); 31 32 final ListPopupWindow listPopupWindow = new ListPopupWindow(context); 33 final OnItemClickListener clickListener = new OnItemClickListener() { 34 @Override 35 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 36 final ChoiceListItem choice = choices.get(position); 37 switch (choice.getId()) { 38 case ChoiceListItem.ID_USE_AS_PRIMARY: 39 listener.onUseAsPrimaryChosen(); 40 break; 41 case ChoiceListItem.ID_REMOVE: 42 listener.onRemovePictureChosen(); 43 break; 44 case ChoiceListItem.ID_TAKE_PHOTO: 45 listener.onTakePhotoChosen(); 46 break; 47 case ChoiceListItem.ID_PICK_PHOTO: 48 listener.onPickFromGalleryChosen(); 49 break; 50 } 51 52 UiClosables.closeQuietly(listPopupWindow); 53 } 54 }; 55 56 listPopupWindow.setAnchorView(anchorView); 57 listPopupWindow.setAdapter(adapter); 58 listPopupWindow.setOnItemClickListener(clickListener); 59 listPopupWindow.setModal(true); 60 listPopupWindow.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED); 61 final int minWidth = context.getResources().getDimensionPixelSize( 62 R.dimen.photo_action_popup_min_width); 63 if (anchorView.getWidth() < minWidth) { 64 listPopupWindow.setWidth(minWidth); 65 } 66 return listPopupWindow; 67 }
----------------------------------------------------
2,联系人编辑界面
ContactEditorFragment处理, bindEditors()加载编辑界面
private void bindEditors() { ...... editor = (RawContactEditorView) inflater.inflate(R.layout.raw_contact_editor_view, mContent, false); editor.setState(rawContactDelta, type, mViewIdGenerator, isEditingUserProfile()); // Set up the photo handler. bindPhotoHandler(editor, type, mState); ...... }
bindPhotoHandler(...) 构建Listener
1 private void bindPhotoHandler(BaseRawContactEditorView editor, AccountType type, 2 RawContactDeltaList state) { 3 ...... 4 final PhotoHandler photoHandler = new PhotoHandler(mContext, editor, mode, state); 5 editor.getPhotoEditor().setEditorListener( 6 (PhotoHandler.PhotoEditorListener) photoHandler.getListener()); 7 ...... 8 } 9 private final class PhotoHandler extends PhotoSelectionHandler { 10 11 final long mRawContactId; 12 private final BaseRawContactEditorView mEditor; 13 private final PhotoActionListener mPhotoEditorListener; 14 15 public PhotoHandler(Context context, BaseRawContactEditorView editor, int photoMode, 16 RawContactDeltaList state) { 17 super(context, editor.getPhotoEditor(), photoMode, false, state); 18 mEditor = editor; 19 mRawContactId = editor.getRawContactId(); 20 mPhotoEditorListener = new PhotoEditorListener(); 21 } 22 23 @Override 24 public PhotoActionListener getListener() { 25 return mPhotoEditorListener; 26 } 27 28 @Override 29 public void startPhotoActivity(Intent intent, int requestCode, Uri photoUri) { 30 mRawContactIdRequestingPhoto = mEditor.getRawContactId(); 31 mCurrentPhotoHandler = this; 32 mStatus = Status.SUB_ACTIVITY; 33 mCurrentPhotoUri = photoUri; 34 ContactEditorFragment.this.startActivityForResult(intent, requestCode); 35 } 36 37 private final class PhotoEditorListener extends PhotoSelectionHandler.PhotoActionListener 38 implements EditorListener { 39 40 @Override 41 public void onRequest(int request) { 42 if (!hasValidState()) return; 43 44 if (request == EditorListener.REQUEST_PICK_PHOTO) { 45 onClick(mEditor.getPhotoEditor()); 46 } 47 } 48 49 @Override 50 public void onDeleteRequested(Editor removedEditor) { 51 // The picture cannot be deleted, it can only be removed, which is handled by 52 // onRemovePictureChosen() 53 } 54 55 /** 56 * User has chosen to set the selected photo as the (super) primary photo 57 */ 58 @Override 59 public void onUseAsPrimaryChosen() { 60 // Set the IsSuperPrimary for each editor 61 int count = mContent.getChildCount(); 62 for (int i = 0; i < count; i++) { 63 final View childView = mContent.getChildAt(i); 64 if (childView instanceof BaseRawContactEditorView) { 65 final BaseRawContactEditorView editor = 66 (BaseRawContactEditorView) childView; 67 final PhotoEditorView photoEditor = editor.getPhotoEditor(); 68 photoEditor.setSuperPrimary(editor == mEditor); 69 } 70 } 71 bindEditors(); 72 } 73 74 /** 75 * User has chosen to remove a picture 76 */ 77 @Override 78 public void onRemovePictureChosen() { 79 mEditor.setPhotoBitmap(null); 80 81 // Prevent bitmap from being restored if rotate the device. 82 // (only if we first chose a new photo before removing it) 83 mUpdatedPhotos.remove(String.valueOf(mRawContactId)); 84 bindEditors(); 85 } 86 87 @Override 88 public void onPhotoSelected(Uri uri) throws FileNotFoundException { 89 final Bitmap bitmap = ContactPhotoUtils.getBitmapFromUri(mContext, uri); 90 setPhoto(mRawContactId, bitmap, uri); 91 mCurrentPhotoHandler = null; 92 bindEditors(); 93 } 94 95 @Override 96 public Uri getCurrentPhotoUri() { 97 return mCurrentPhotoUri; 98 } 99 100 @Override 101 public void onPhotoSelectionDismissed() { 102 // Nothing to do. 103 } 104 } 105 }
RawContactEditorView加载PhotoEditorView,PhotoEditorView注册Listener
public class RawContactEditorView extends BaseRawContactEditorView { ...... @Override protected void onFinishInflate() { super.onFinishInflate(); ...... } ...... } public abstract class BaseRawContactEditorView extends LinearLayout { ...... Override protected void onFinishInflate() { super.onFinishInflate(); mBody = findViewById(R.id.body); mDivider = findViewById(R.id.divider); mPhoto = (PhotoEditorView)findViewById(R.id.edit_photo); mPhoto.setEnabled(isEnabled()); } ...... } public class PhotoEditorView extends LinearLayout implements Editor { ...... @Override protected void onFinishInflate() { super.onFinishInflate(); mPhotoImageView = (ImageView) findViewById(R.id.photo); mFrameView = findViewById(R.id.frame); mFrameView.setOnClickListener(new OnClickListener() { @Override//响应点击onClick public void onClick(View v) { if (mListener != null) {
mListener.onRequest(EditorListener.REQUEST_PICK_PHOTO); } } }); } ...... }
mListener.onRequest就是ContactEditorFragment中bindPhotoHandler中定义的
private final class PhotoHandler extends PhotoSelectionHandler { ...... public PhotoHandler(Context context, BaseRawContactEditorView editor, int photoMode, RawContactDeltaList state) { super(context, editor.getPhotoEditor(), photoMode, false, state); mEditor = editor; mRawContactId = editor.getRawContactId(); mPhotoEditorListener = new PhotoEditorListener(); } ...... private final class PhotoEditorListener extends PhotoSelectionHandler.PhotoActionListener implements EditorListener { @Override public void onRequest(int request) { if (!hasValidState()) return; if (request == EditorListener.REQUEST_PICK_PHOTO) { onClick(mEditor.getPhotoEditor());//调用PhotoSelectionHandler 中定义的onClick方法。
} } ...... } ...... }
PhotoSelectionHandler中的onClick
public abstract class PhotoSelectionHandler implements OnClickListener { ...... @Override public void onClick(View v) { final PhotoActionListener listener = getListener(); if (listener != null) { if (getWritableEntityIndex() != -1) { mPopup = PhotoActionPopup.createPopupMenu( mContext, mPhotoView, listener, mPhotoMode); mPopup.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss() { listener.onPhotoSelectionDismissed(); } }); mPopup.show(); } } } ...... }
然后又是PhotoActionPopup.createPopupMenu处理。
---------------------------------------------------------
综上:联系人详情 and 联系人编辑界面响应头像点击过程都是:
先构建并注册OnClickListener,——>Listener处理——>调用PhotoSelectionHandler中的onClick——>PhotoActionPopup.createPopupMenux 显示弹出框PopupWindow
区别在于Listener的构建,和传递的参数。