- 浏览: 31800 次
文章分类
最新评论
微信聊天左滑显示删除实现
- 博客分类:
- Android
参考http://blog.csdn.net/xiaanming/article/details/18311877
使用https://github.com/JakeWharton/NineOldAndroids 第三方工程实现
1. 自定义view 继承ListView 添加OnScrollListener 和 实现View.OnTouchListener
2. 在OnTouchListener 中实现view动画
ListView 代码
touchListener 代码
使用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(); } }
发表评论
-
android页面布局 中间的listView填充剩余部分
2016-12-05 17:29 639<?xml version="1.0" ... -
Eclipse Memory Analyzer 分析内存溢出
2016-10-19 11:37 0一 安装篇 1. eclipse 自 ... -
MSBuild命令行编译Xamarin 项目
2016-04-19 14:42 1137Xamarin 平台: C# language – 使用C ... -
Handler Thread
2016-03-21 16:42 432介绍 首先我们来看看为什么我们要使用HandlerThread ... -
Android Handler 作用
2016-03-21 15:31 369Android handler 作用: 什 ... -
Android UI 线程和子线程通信
2016-03-18 18:24 0从主线程发送消息到子 ... -
数据库升级
2016-03-07 17:09 0转自: http://892848153.iteye.com/ ... -
Android ListView 问题汇总
2016-01-11 11:16 498Listview 问题汇总: 1. it ... -
Intent与Activity启动模式相关的Flag
2015-11-27 16:08 370网上对于 Intent 的 flag 做了很多介绍,都 ... -
android 让一个控件按钮居于底部的几种方法
2015-04-09 15:00 0android 让一个控件按钮居于底部的几种方法 1.采用li ... -
Service 理解
2015-03-11 19:08 01. Service 也是运行在主线程,和Activity级别 ... -
回调 同步 异步
2014-12-16 17:34 0回调 同步 异步 -
JSON
2014-12-16 17:33 0JSON 的使用场景 -
远程service
2014-12-16 17:32 0远程Service使用场景: 1. 远程Service-- ... -
Android 实现两个控件分别靠左侧边缘和右侧边缘,且不重叠
2014-12-11 16:02 40451. 使用relativeLayout 从右侧往左侧加,但是问 ... -
Android系统源码数据库(mmssms.db)(转)
2013-11-18 17:00 881论Android系统源码数据库(mmssms.db)中几个表之 ... -
Android SMS 数据库
2013-11-18 14:57 793$ adb shell $ cd data/data $ cd ... -
PC 操作Android手机
2013-11-15 18:10 557https://code.google.com/p/andro ... -
下载Android source 问题
2013-10-17 10:34 603fatal: '../platform/abi/cpp.git ... -
查看Android数据库
2013-03-19 15:26 5721. adb shell; 2. cd data/data 3 ...
相关推荐
模拟微信listview左滑出现删除按钮
主要为大家详细介绍了java仿微信实现左滑显示删除按钮功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
模仿QQ微信,在列表item左滑删除功能。本demo简单实现了在列表左滑出现删除按钮,点击按钮可删除该item,点击其他地方按钮就隐藏并且实现了惯性滑动。完美解决了滑动冲突和点击冲突。
高仿微信左滑删除效果
html5实现的仿网页版微信聊天界面效果源码
仿微信聊天软件-Socket实现.zip 仿微信聊天软件-Socket实现.zip
微信聊天消息列表的时间显示判断
Android仿qq,微信 滑动删除功能
基于iOS开发的微信聊天输入框的实现源码(下载即用).zip基于iOS开发的微信聊天输入框的实现源码(下载即用).zip基于iOS开发的微信聊天输入框的实现源码(下载即用).zip基于iOS开发的微信聊天输入框的实现源码...
仿微信聊天软件,Socket实现,给需要的同学
Android--仿微信聊天界面
仿微信聊天系统源码(基于WinForm实现),可供学习参考。
抖音微信聊天记录视频怎么做 微信聊天记录AE模板
仿微信聊天界面,聊天表情仿微信聊天界面,聊天表情仿微信聊天界面,聊天表情
使用Qt开发的微信聊天软件,单播,组播,文件传输,仅供学习使用哦
微信聊天微信小程序源码.zip
它还能够尝试恢复之前删除过的好友和聊天对话,不小心删除的聊天记录也会显示出来。 可按照联系人名称创建文件夹自动分类,包括:文字,语音,图片,视频,收发的文件,表情包等。导出的html格式文件通过浏览器打开...
Android仿微信聊天软件,Socket实现源码,包含服务端.zip
这是一款微信聊天内容制作生成小程序源码,该小程序支持制作多种内容。 支持单人聊天模式制作,支持群聊模式制作生成; 每一种模式都支持我们微信需要的功能都有,视频,语音,时间,内容等等,大家可以最后看演示图!...
html5仿微信聊天界面