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

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

[b]ListView 代码[/b]

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();
}
}
}


[b]touchListener 代码[/b]

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();
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值