- 浏览: 33009 次
文章分类
最新评论
参考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 674<?xml version="1.0" ... -
Eclipse Memory Analyzer 分析内存溢出
2016-10-19 11:37 0一 安装篇 1. eclipse 自 ... -
MSBuild命令行编译Xamarin 项目
2016-04-19 14:42 1221Xamarin 平台: C# language – 使用C ... -
Handler Thread
2016-03-21 16:42 473介绍 首先我们来看看为什么我们要使用HandlerThread ... -
Android Handler 作用
2016-03-21 15:31 402Android 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 530Listview 问题汇总: 1. it ... -
Intent与Activity启动模式相关的Flag
2015-11-27 16:08 405网上对于 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 41061. 使用relativeLayout 从右侧往左侧加,但是问 ... -
Android系统源码数据库(mmssms.db)(转)
2013-11-18 17:00 923论Android系统源码数据库(mmssms.db)中几个表之 ... -
Android SMS 数据库
2013-11-18 14:57 833$ adb shell $ cd data/data $ cd ... -
PC 操作Android手机
2013-11-15 18:10 626https://code.google.com/p/andro ... -
下载Android source 问题
2013-10-17 10:34 646fatal: '../platform/abi/cpp.git ... -
查看Android数据库
2013-03-19 15:26 6281. adb shell; 2. cd data/data 3 ...
相关推荐
总的来说,实现“Android仿微信对话列表滑动删除效果”涉及到自定义ListView、监听触摸事件、计算滑动距离、以及执行动画等多方面的技术。通过这种方式,开发者可以为自己的应用添加类似微信的交互体验,提高用户的...
这个"仿微信左划删除效果"是为了在自己的项目中实现与微信类似的交互体验,让用户能够方便地通过手势删除列表项。 在描述中提到的"仿微信左划删除效果"主要涉及JavaScript和jQuery特效。JavaScript是一种强大的...
本文将详细解析如何实现“Android仿微信SlideView聊天列表滑动删除效果”。这一效果允许用户在聊天列表中通过手势滑动条目来触发删除操作,提升了用户体验。 首先,我们要创建一个ListView或RecyclerView,它是...
"ListView 仿QQ微信侧滑出现删除按钮"这个主题涉及到的是如何实现一个类似QQ和微信聊天界面中,通过侧滑列表项来显示删除或其他操作的功能。这种交互设计不仅提高了用户体验,也使得操作更加直观。下面将详细讲解...
需要注意的是,这种方法并不适用于主动左滑删除或手动清理微信缓存后丢失的聊天记录。 如果微信内置的修复工具无法解决问题,或者你需要更专业的恢复服务,可以考虑使用第三方数据恢复软件。这里推荐“开心手机恢复...
可以访问这篇文章有完整介绍: ... 1.类似QQ、微信聊天界面 2.好友、群组、系统消息、添加申请通知等 3.含聊天表情符 4.左滑显示删除按钮,jquery实现 5.含交互,模拟ajax返回结果动态处理
在许多应用中,我们常常需要实现像微信聊天那样,通过左右滑动条目来执行不同的操作,如删除或选择。这个教程将详细介绍如何在RecyclerView中实现左侧滑动删除以及右侧滑动选择的功能。 首先,我们需要理解...
当需要实现类似微信聊天中的左滑删除或复制功能时,可以通过以下方法来完成。本文将详细介绍如何在UITableView中实现这一功能。 首先,要使UITableView的Cell可以被编辑,需要在`UITableViewDataSource`协议的代理...
而“qq左滑置顶删除组件”则是指模仿QQ聊天界面中,通过滑动聊天列表项来实现的快捷功能,比如置顶、删除等操作。 ### 描述知识点 描述部分首先提到了在进行小程序开发中遇到了难题,设计师要求实现类似QQ的左滑...
在Android开发中,滑动删除(Swipe to Delete)是一种常见的交互设计,广泛应用于聊天应用、邮件客户端等场景,如QQ和微信。滑动删除功能可以让用户通过简单的手势操作,快速地删除列表中的条目,提高了用户体验。本...
SwipeMenuListView是一款强大的Android开发工具,它为ListView提供了一个便捷的侧滑删除功能,类似于微信中的消息删除方式。这个开源项目包含两个版本,一个适用于Eclipse IDE,另一个适用于Android Studio (AS)。...
库中包含了预设的滑动操作样式,如左滑删除、右滑查看详细信息等,同时也支持自定义滑动视图。 6. 使用第三方库:引入和集成SWTableViewCell库到项目中,需要了解CocoaPods或Carthage等依赖管理工具的使用,以及...