`

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

 
阅读更多
参考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();
    }
}

分享到:
评论

相关推荐

    仿微信左划删除效果

    这个"仿微信左划删除效果"是为了在自己的项目中实现与微信类似的交互体验,让用户能够方便地通过手势删除列表项。 在描述中提到的"仿微信左划删除效果"主要涉及JavaScript和jQuery特效。JavaScript是一种强大的...

    Android仿微信SlideView聊天列表滑动删除效果

    本文将详细解析如何实现“Android仿微信SlideView聊天列表滑动删除效果”。这一效果允许用户在聊天列表中通过手势滑动条目来触发删除操作,提升了用户体验。 首先,我们要创建一个ListView或RecyclerView,它是...

    ListView 仿QQ微信侧滑出现删除按钮

    "ListView 仿QQ微信侧滑出现删除按钮"这个主题涉及到的是如何实现一个类似QQ和微信聊天界面中,通过侧滑列表项来显示删除或其他操作的功能。这种交互设计不仅提高了用户体验,也使得操作更加直观。下面将详细讲解...

    如何恢复微信删除的聊天记录?用对方法,恢复只需三分钟.pdf

    需要注意的是,这种方法并不适用于主动左滑删除或手动清理微信缓存后丢失的聊天记录。 如果微信内置的修复工具无法解决问题,或者你需要更专业的恢复服务,可以考虑使用第三方数据恢复软件。这里推荐“开心手机恢复...

    html+css+aui实现消息聊天列表,好友、群组、公告、系统消息,好友申请,群组申请等含表情符.zip

    可以访问这篇文章有完整介绍: ... 1.类似QQ、微信聊天界面 2.好友、群组、系统消息、添加申请通知等 3.含聊天表情符 4.左滑显示删除按钮,jquery实现 5.含交互,模拟ajax返回结果动态处理

    实现RecyclerView左侧滑删除与右侧滑选择

    在许多应用中,我们常常需要实现像微信聊天那样,通过左右滑动条目来执行不同的操作,如删除或选择。这个教程将详细介绍如何在RecyclerView中实现左侧滑动删除以及右侧滑动选择的功能。 首先,我们需要理解...

    iOS实现UITableView左滑删除复制即用功能

    当需要实现类似微信聊天中的左滑删除或复制功能时,可以通过以下方法来完成。本文将详细介绍如何在UITableView中实现这一功能。 首先,要使UITableView的Cell可以被编辑,需要在`UITableViewDataSource`协议的代理...

    mpvue小程序仿qq左滑置顶删除组件

    而“qq左滑置顶删除组件”则是指模仿QQ聊天界面中,通过滑动聊天列表项来实现的快捷功能,比如置顶、删除等操作。 ### 描述知识点 描述部分首先提到了在进行小程序开发中遇到了难题,设计师要求实现类似QQ的左滑...

    android 滑动删除

    在Android开发中,滑动删除(Swipe to Delete)是一种常见的交互设计,广泛应用于聊天应用、邮件客户端等场景,如QQ和微信。滑动删除功能可以让用户通过简单的手势操作,快速地删除列表中的条目,提高了用户体验。本...

    eclipse和studio双版本:SwipeMenuListView-master

    SwipeMenuListView是一款强大的Android开发工具,它为ListView提供了一个便捷的侧滑删除功能,类似于微信中的消息删除方式。这个开源项目包含两个版本,一个适用于Eclipse IDE,另一个适用于Android Studio (AS)。...

    可以左右滑动的UITableView

    库中包含了预设的滑动操作样式,如左滑删除、右滑查看详细信息等,同时也支持自定义滑动视图。 6. 使用第三方库:引入和集成SWTableViewCell库到项目中,需要了解CocoaPods或Carthage等依赖管理工具的使用,以及...

Global site tag (gtag.js) - Google Analytics