`

微信聊天左滑显示删除实现

阅读更多
参考http://blog.csdn.net/xiaanming/article/details/18311877
使用https://github.com/JakeWharton/NineOldAndroids 第三方工程实现
1. 自定义view 继承ListView 添加OnScrollListener 和 实现View.OnTouchListener
2. 在OnTouchListener  中实现view动画

ListView 代码

public class CustListView extends ListView {

    private CustViewTouchListener touchListener;
    private boolean mIsScrolling = false;

    public CustListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        final ViewConfiguration configuration = ViewConfiguration.get(getContext());
        final int touchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
        touchListener = new CustViewTouchListener(context, this, touchSlop);
        setOnTouchListener(touchListener);
        setOnScrollListener(new OnScrollListener() {
            
            @Override
            public void onScrollStateChanged(AbsListView arg0, int scrollState) {
                if (OnScrollListener.SCROLL_STATE_IDLE == scrollState) {
                    mIsScrolling = false;
                } else {
                    mIsScrolling = true;
                }
                touchListener.setScrollStatus(mIsScrolling);
            }
            
            @Override
            public void onScroll(AbsListView arg0, int arg1, int arg2, int arg3) {
                
            }
        });
    }

    public void initListView() {
        if (null != touchListener) {
            touchListener.initSlidedItemView();
        }
    }

    public void resetView() {
        if (null != touchListener) {
            touchListener.resetView();
        }
    }
}


touchListener 代码

public class CustListViewTouchListener implements View.OnTouchListener {

    private static final String TAG = CustListViewTouchListener.class.getSimpleName();

    private int mMaxMotionWidth = 0;
    private float mMotionWidthThreshold = 0.10f;  // ten percent.

    //The touch X,Y when action down.
    private float mActionDownX = 0;
    private float mActionDownY = 0;

    private float mMoveX = 0;
    private boolean mIsMove =false;

    private int mTouchSlop = 0;

    private CustListView mCustListView = null;
    private CustListAdapter mCustListAdapter = null;

    private View mItemView = null;
    //The list view item layout except delete button
    private View mShowView = null;
    //Delete view
    private View mHideView = null;
    //Last slided item view
    private View mLastItemView = null;
    //The showView of last slided item
    private View mLastShowView = null;
    //The HideView of last slided item
    private View mLastHideView = null;
    //The current action down position
    private int mCurrentPosition = -1;
    //Last slided action view position
    private int mLastPosition = -1;
    //The Touch view rectangle
    private Rect mRect = new Rect();

    private Button mBtnDelete = null;

    private Context mContext;

    private boolean mIsScrolling;
    
    private int mGroup;
    private String mPeer;
    private int mId;
    private AlertDialog mDialog;
    private Handler mHandler = new Handler(); // do something in main(UI) thread.

    public CustListViewTouchListener(Context context, CustListView slideListView, int touchSlop) {
        this.mContext = context;
        this.mCustListView = slideListView;
        this.mTouchSlop = touchSlop;
    }

    public void initSlidedItemView() {
        if(mShowView != null && mHideView != null) {
            ViewPropertyAnimator.animate(mShowView).translationX(0).setDuration(0);
            ViewPropertyAnimator.animate(mHideView).translationX(0).setDuration(0);
        }
    }

    public void resetView() {
        if (mDialog != null && mDialog.isShowing()){
            mDialog.dismiss();
        }
    }
    private void restoreLastSlidedItemView() {
        if (mLastPosition >= 0 && mLastPosition != mCurrentPosition) {
            mLastItemView = mCustListView.getChildAt(mLastPosition
                    - mCustListView.getFirstVisiblePosition());
            if (mLastItemView != null) {
                mLastShowView = mLastItemView.findViewById(R.id.show_item);
                mLastHideView = mLastItemView.findViewById(R.id.hide_item);
                ViewPropertyAnimator.animate(mLastShowView).translationX(0).setDuration(200);
                ViewPropertyAnimator.animate(mLastHideView).translationX(0).setDuration(200);
            }
            mLastItemView = null;
        }
            mLastPosition = mCurrentPosition;
    }

    @Override
    public boolean onTouch(View v, MotionEvent motionEvent) {
        mCustListAdapter = (CustListAdapter) mCustListView.getAdapter();
        if (mIsScrolling)
            return false;
        switch (motionEvent.getActionMasked()) {
            case MotionEvent.ACTION_DOWN: {
                //Get action down x,y,position and itemView
                mMoveX = 0;
                mIsMove = false;
                mActionDownX = motionEvent.getRawX();
                mActionDownY = motionEvent.getRawY();
                mCurrentPosition = getPosition();
                if (-1 == mCurrentPosition) {
                    return false;
                }
                restoreLastSlidedItemView();
               mItemView = mCustListView.getChildAt(mCurrentPosition
                        - mCustListView.getFirstVisiblePosition());
                if (mItemView != null) {
                    mShowView = mItemView.findViewById(R.id.show_item);
                    mHideView = mItemView.findViewById(R.id.hide_item);
                    mBtnDelete = (Button) mHideView;
                    // TODO jhj case 1: group; case 2: not group
                    Object object = mCustListAdapter.getItem(mCurrentPosition);
                    int friendStatus = -1;
                    if (null != object && object instanceof Cursor) {
                        Cursor cursor = (Cursor) object;
                        if (!cursor.isClosed()) {
                            try {
                                int index = cursor.getColumnIndex(DBViewMessageThreads.FRIEND_STATE);
                                if (index >= 0 && index < cursor.getColumnCount()){
                                    friendStatus = cursor.getInt(index);
                                }
                                mId = cursor.getInt(cursor.getColumnIndex(DBViewMessageThreads._ID));
                                mGroup = cursor.getInt(cursor.getColumnIndex(DBViewMessageThreads.GROUP));
                                mPeer = cursor.getString(cursor.getColumnIndex(DBViewMessageThreads.PEER));
                            } catch (Exception e) {
                                PaLog.e(TAG, "get friend status failed");
                            }

                        }
                    }
                    PaLog.d(TAG, "freind status  " + friendStatus);
                   if (friendStatus == AgentElements.FriendStatus.INVITED.ordinal()){
                       ((Button)mHideView).setText(R.string.request_accept);
                       mHideView.setBackgroundColor(0xFF1AA2E2);
                   }else{
                       ((Button)mHideView).setText(R.string.delete_single_thread);
                       mHideView.setBackgroundColor(Color.RED);
                   }
//                  mBtnDelete.setClickable(false);
                }
                return true;
            }
            case MotionEvent.ACTION_UP: {
                if (!mIsMove ||  mCurrentPosition == -1 || mItemView == null) {
                    return false;
                }
                float translationX = 0;
                if (mMoveX < -mMaxMotionWidth / 2) {
                    //If the x slide to left is more than half a width,auto slide to left a full width.
                    translationX = -mMaxMotionWidth;
                } else {
                    translationX = 0;
                }
                ViewPropertyAnimator.animate(mShowView).translationX(translationX)
                        .setDuration(200);
                ViewPropertyAnimator.animate(mHideView).translationX(translationX)
                        .setDuration(200).setListener(new AnimatorListener() {
                            @Override
                            public void onAnimationStart(Animator animation) {
                                // TODO Auto-generated method stub
                            }

                            @Override
                            public void onAnimationEnd(Animator animation) {
                                final int delPostion = mCurrentPosition;
                                mBtnDelete.setOnClickListener(new OnClickListener() {
                                    @Override
                                    public void onClick(View v) {
                                    if (-1 != delPostion) {

                                        //use to delete group message
                                        ViewPropertyAnimator.animate(mShowView).translationX(0).setDuration(10);
                                        ViewPropertyAnimator.animate(mHideView).translationX(0).setDuration(10);

                                        if (1 == mGroup) {
                                            showLeaveGroupDialog(delPostion, mCustListAdapter.getItemId(delPostion));
                                            return;
                                        } else {
                                            mMoveX = 0;
                                            // Delete notification of this
                                            // thread.
                                            NotificationProxy.getInstance().deleteNotificationByRelativeKey(
                                                    SubType.NEW_AVTMSG.getInt(), mPeer);

                                            //use delete friend message
                                            PaLog.d(TAG, "mGroup 0 ..................");
                                            deleteThreadById(delPostion, mCustListAdapter.getItemId(delPostion));
                                        }
                                    }
                                    }
                                });
                            }

                            @Override
                            public void onAnimationCancel(Animator animation) {
                                // TODO Auto-generated method stub
                            }

                            @Override
                            public void onAnimationRepeat(Animator animation) {
                                // TODO Auto-generated method stub

                            }
                        });
                return true;
            }
            case MotionEvent.ACTION_MOVE: {
                if (mCurrentPosition == -1 || mItemView == null) {
                    mIsMove = false;
                    return false;
                }

                if (IsYScroll(motionEvent.getRawX(), motionEvent.getRawY())) {
                    if (mIsMove){
                        initSlidedItemView();//need reset the hide view since user can move Y then move X
                    }
                    mIsMove = false;
                    return false;
                }
                mMoveX = motionEvent.getRawX() - mActionDownX;

                float translationX = mShowView.getTranslationX();
                if (mMaxMotionWidth == 0) {
                    mMaxMotionWidth = mHideView.getWidth();
                }
                // Move to right
                if (mMoveX > (mMaxMotionWidth*mMotionWidthThreshold) && translationX < 0) {
                    if (mMoveX > mMaxMotionWidth) {
                        mMoveX = mMaxMotionWidth;
                    }
                    ViewHelper.setTranslationX(mShowView, mMoveX - mMaxMotionWidth);
                    ViewHelper.setTranslationX(mHideView, mMoveX - mMaxMotionWidth);
                    mIsMove = true;
                }
                // Move to left
                if (mMoveX < -(mMaxMotionWidth*mMotionWidthThreshold) && translationX > -mMaxMotionWidth) {
                    if (mMoveX < -mMaxMotionWidth) {
                        mMoveX = -mMaxMotionWidth;
                    }
                    ViewHelper.setTranslationX(mShowView, mMoveX);
                    ViewHelper.setTranslationX(mHideView, mMoveX);
                    mIsMove = true;
                }
                return true;
            }
            default: {
                return true;
            }
        }
    }

    private boolean IsYScroll(float x, float y) {
        final int xDiff = (int) Math.abs(x - mActionDownX);
        final int yDiff = (int) Math.abs(y - mActionDownY);
        final int touchSlop = this.mTouchSlop;
        if (xDiff == 0) {
            return true;
        }
        if ((yDiff / xDiff >= 1) && (yDiff > touchSlop)) {
            return true;
        } else {
            return false;
        }
    }

    //Get the item index in ListView when touch.
    private int getPosition() {
        final int childCount = mCustListView.getChildCount();
        int[] listViewCoords = new int[2];
        mCustListView.getLocationOnScreen(listViewCoords);
        final int x = (int) mActionDownX - listViewCoords[0];
        final int y = (int) mActionDownY - listViewCoords[1];
        View child;
        int childPosition = -1;
        for (int i = 0; i < childCount; i++) {
            child = mCustListView.getChildAt(i);
            child.getHitRect(mRect);
            if (mRect.contains(x, y)) {
                childPosition = mCustListView.getPositionForView(child);
                return childPosition;
            }
        }
        return childPosition;
    }

    public boolean deleteThreadById(int position, long id) {
        if (-1 == id) {
            return true;
        }

        
        Object object = mCustListAdapter.getItem(position);
        String peer = null;
        int friendStatus = -1, friendSize = 1;
        if (null != object && object instanceof Cursor) {
            Cursor cursor = (Cursor) object;
            if (!cursor.isClosed()) {
                peer = cursor.getString(cursor.getColumnIndex(DBViewMessageThreads.PEER));
                friendStatus = cursor.getInt(cursor.getColumnIndex(DBViewMessageThreads.FRIEND_STATE));
                friendSize =  1; 
                //mCustListAdapter.getMessagesDbAdapter().getInstance(mContext).getMessageThreads().getCount();
                //mCustListAdapter.getCount();//cursor.getInt(cursor.getColumnIndex(DBViewMessageThreads.UNREAD_COUNT));
                // TODO find out how to get the total count....
            }
        }
        final String peerJid = peer;

        // show a dialog to confirm whether delete the item.
        final int threadId = (int) id;
        if (mDialog != null && mDialog.isShowing()){
            mDialog.dismiss();
        }
        if (friendStatus == AgentElements.FriendStatus.INVITED.ordinal()) {
            ViewPropertyAnimator.animate(mShowView).translationX(0).setDuration(10);
            ViewPropertyAnimator.animate(mHideView).translationX(0).setDuration(10);
            mMoveX = 0;
            mCustListAdapter.acceptFriendRequest(peerJid, threadId);
            return true;
        }
        final int count = friendSize;
        mDialog = new AlertDialog.Builder(this.mContext, AlertDialog.THEME_HOLO_DARK)
                .setTitle(R.string.archive_delete_dialog_title)
                .setMessage(R.string.archive_delete_dialog_message)
                .setPositiveButton(R.string.alert_dialog_btn_ok,
                        new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                // Delete the thread.
                                ViewPropertyAnimator.animate(mShowView).translationX(0)
                                        .setDuration(10);
                                ViewPropertyAnimator.animate(mHideView).translationX(0)
                                        .setDuration(10);
                                mCustListAdapter.getMessagesDbAdapter().deleteMessageThreadById(
                                        threadId);
                                // Delete notification of this thread.
                                NotificationProxy.getInstance().deleteNotificationByRelativeKey(
                                        SubType.NEW_AVTMSG.getInt(), peerJid);
                                mMoveX = 0;
                                Analytics.getInstance().tagEventSingleStepAttribute(AnalyticsStrings.EventMSGMessageThreadDeleted, AnalyticsStrings.AttrMessageCountThread, 
                                        count, Analytics.IntStep0121416181101);
                            }
                        })
                .setNegativeButton(R.string.alert_dialog_btn_cancel,
                        new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.cancel();
                            }
                        }).create();
        mDialog.show();
        return true;
    }

    /**
     * @param mIsScrolling
     */
    public void setScrollStatus(boolean isScrolling) {
        mIsScrolling = isScrolling;
        
    }

    private AlertDialog mLeaveGroupDialog;

    private void showLeaveGroupDialog(int position, long id) {
        PaLog.d(TAG, "CustListViewTouchListener: showLeaveGroupDialog: position: " + position + ", id: " + id);
        if (-1 == id) {
            return;
        }

        if (mLeaveGroupDialog != null && mLeaveGroupDialog.isShowing()){
            return;
        }
        Object object = mCustListAdapter.getItem(position);
        String peer = null;
        int friendStatus = -1;
        if (null != object && object instanceof Cursor) {
            Cursor cursor = (Cursor) object;
            if (!cursor.isClosed()) {
                peer = cursor.getString(cursor.getColumnIndex(DBViewMessageThreads.PEER));
                friendStatus = cursor.getInt(cursor.getColumnIndex(DBViewMessageThreads.FRIEND_STATE));
            }
        }
        final String peerJid = peer;

        // show a dialog to confirm whether delete the item.
        final int threadId = (int) id;

        View view = LayoutInflater.from(mContext).inflate(R.layout.leave_group, null);
        mLeaveGroupDialog =
                new AlertDialog.Builder(mContext, AlertDialog.THEME_HOLO_LIGHT).setCancelable(false)
                        .setPositiveButton(R.string.dialog_leave_group_ok, new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                if (!TextUtils.isEmpty(peerJid)) {
                                    mCustListAdapter.showWaitingDlg();
                                    XmppProxy.getInstance(mContext).leaveGroupRoom(peerJid,
                                            new IGroupChatStatusCallback.Stub() {

                                                @Override
                                                public void onSended(long msgId, String roomName)
                                                        throws RemoteException {
                                                    PaLog.d(TAG, "leave group room call back: onSended() ");
                                                    mCustListAdapter.deleteGroupRequest(threadId);
                                                    Analytics.getInstance().tagEventSingleAttribute(AnalyticsStrings.EventGRPLeftGroup, 
                                                            AnalyticsStrings.AttrOutcome, AnalyticsStrings.ValueSucceeded);
                                                }

                                                @Override
                                                public void onError(long msgId, String roomName, int errType) throws RemoteException {
                                                    PaLog.d(TAG, "leave group room call back: onError() errType: "
                                                            + errType);
                                                    if (errType == XmppErrorCode.ROOM_NOT_EXIST
                                                            ||errType == XmppErrorCode.GROUP_SERVER_NOT_ALLOWED) {
                                                        mCustListAdapter.deleteGroupRequest(threadId);
                                                    } else {
                                                        mCustListAdapter.deleteGroupFailed();
                                                    }
                                                    Analytics.getInstance().tagEventSingleAttribute(AnalyticsStrings.EventGRPLeftGroup, 
                                                            AnalyticsStrings.AttrOutcome, AnalyticsStrings.ValueFailed);
                                                }

                                            });
                                }
                            }
                        }).setNegativeButton(R.string.dialog_leave_group_cancel, new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {

                            }
                        }).create();
        mLeaveGroupDialog.setView(view);
        mLeaveGroupDialog.show();
    }
}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics