欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android自定義view系列之99.99%實(shí)現(xiàn)QQ側(cè)滑刪除效果實(shí)例代碼詳解

 更新時(shí)間:2016年09月08日 11:50:41   作者:qiang_xi  
這篇文章給大家介紹android自定義view系列之99.99%實(shí)現(xiàn)QQ側(cè)滑刪除效果,本文介紹的非常詳細(xì),具有參考借鑒價(jià)值,需要的朋友參考下吧

首先聲明本文是基于GitHub上"baoyongzhang"的SwipeMenuListView修改而來(lái),該項(xiàng)目地址:

https://github.com/baoyongzhang/SwipeMenuListView

可以說(shuō)這個(gè)側(cè)滑刪除效果是我見(jiàn)過(guò)效果最好且比較靈活的項(xiàng)目,沒(méi)有之一!!!

但是在使用它之前需要給大家提兩點(diǎn)注意事項(xiàng):

1,該項(xiàng)目支持Gradle dependence,但是目前作者提供的依賴地址對(duì)應(yīng)的項(xiàng)目不是最新的項(xiàng)目,依賴過(guò)后的代碼與demo中使用的不一致,會(huì)提示沒(méi)有BaseSwipeListAdapter這個(gè)類,因?yàn)檫@個(gè)類是其他的開(kāi)發(fā)者后來(lái)提交上去的,所以如果想使用最新的代碼,目前還是得把代碼下載下來(lái),然后把library文件拷貝到自己項(xiàng)目中使用.

下圖是目前作者提供的依賴地址,不是最新的,所以想用最新代碼的朋友還是直接下載代碼到本地吧.

2,第二點(diǎn)注意事項(xiàng)應(yīng)該算是一個(gè)bug吧,如果你測(cè)試過(guò)作者給的demo,你會(huì)發(fā)現(xiàn)如果某一項(xiàng)item已經(jīng)被拉出來(lái)了,這個(gè)時(shí)候你再把ListView向上或向下滑動(dòng),讓這個(gè)被拉出來(lái)的item移出屏幕,然后再移回來(lái),這個(gè)已經(jīng)被拉出來(lái)的item會(huì)直接恢復(fù)到未拉出的狀態(tài).這會(huì)讓用戶感覺(jué)很困惑,我明明已經(jīng)拉出了這個(gè)菜單,怎么又不見(jiàn)了,然后可能就會(huì)產(chǎn)生這個(gè)軟件做的真垃圾的想法,進(jìn)而可能把你的軟件卸載掉.如下圖:

對(duì)于上面兩個(gè)注意事項(xiàng),第一個(gè)倒是沒(méi)什么好說(shuō)的,第二個(gè)問(wèn)題怎么辦呢?別急,這正是我們今天要說(shuō)的內(nèi)容.

首先我們可以先研究一下QQ的側(cè)滑刪除效果,說(shuō)到這你可以打開(kāi)你的qq看看它的具體效果.

你會(huì)發(fā)現(xiàn),如果一個(gè)item被拉出來(lái)了,當(dāng)你的手指放到其他的item上時(shí),它會(huì)直接先把被拉出的那個(gè)item關(guān)閉掉,并且當(dāng)前動(dòng)作的后續(xù)的事件也都不再響應(yīng),除非你再次把手指放到屏幕上,他才會(huì)響應(yīng)相關(guān)事件,而如果你的手指放到當(dāng)前被拉出的item上,他不會(huì)隱藏這個(gè)item,并且可以正常響應(yīng)左右滑動(dòng)事件.

ok,QQ的效果我們分析完畢,我們探討一下它的實(shí)現(xiàn)原理:

1,如果一個(gè)item已經(jīng)被拉了出來(lái),當(dāng)你的手指放到其他的item上時(shí),它會(huì)直接先把被拉出的那個(gè)item關(guān)閉掉, 怎么實(shí)現(xiàn)呢?

首先我們需要判斷我們當(dāng)前所按下的這個(gè)item是不是被拉出來(lái)的那個(gè)item,不是的話,我們才需要關(guān)閉,是的話,則不用管.代碼如下:

if (view instanceof SwipeMenuLayout) { 
SwipeMenuLayout touchView = (SwipeMenuLayout) view; 
if (!touchView.isOpen()) { 
mTouchView.smoothCloseMenu(); 
} 
}

2,并且當(dāng)前動(dòng)作的后續(xù)的事件也都不再響應(yīng), 怎么實(shí)現(xiàn)呢?

這就很簡(jiǎn)單了,根據(jù)view的事件分發(fā)原理,如果在某一個(gè)觸摸事件中返回了false,那么該事件后續(xù)的事件都不會(huì)再交給他處理,也就是說(shuō),如果我們?cè)贏CTION_DOWN的時(shí)候返回了false,那么后續(xù)的ACTION_MOVE,ACTION_UP等事件都不會(huì)響應(yīng),所以要實(shí)現(xiàn)這個(gè)效果,我們只需要在關(guān)閉菜單的后面,返回false就行了,完整的代碼如下:

/********新添加的內(nèi)容,當(dāng)按下的item不是當(dāng)前已經(jīng)打開(kāi)的item,則關(guān)閉已經(jīng)打開(kāi)的item,并返回false.不再響應(yīng)down以后的事件,仿qq效果********/ 
if (view instanceof SwipeMenuLayout) { 
SwipeMenuLayout touchView = (SwipeMenuLayout) view; 
if (!touchView.isOpen()) { 
mTouchView.smoothCloseMenu(); 
return false; 
} 
}

這樣的幾行代碼就實(shí)現(xiàn)了剛才分析的qq效果中的前半部分效果,即如果一個(gè)item被拉出來(lái)了,當(dāng)你的手指放到其他的item上時(shí),它會(huì)直接先把被拉出的那個(gè)item關(guān)閉掉,并且當(dāng)前動(dòng)作的后續(xù)的事件也都不再響應(yīng),除非你再次把手指放到屏幕上,他才會(huì)響應(yīng)相關(guān)事件.

上面的那幾行代碼是基于SwipeMenuListView類修改而來(lái),完整的修改之后的SwipeMenuListView代碼如下所示:

package com.lanma.swipemenulistviewdemo.swipemenulistview; 
import android.content.Context; 
import android.util.AttributeSet; 
import android.util.TypedValue; 
import android.view.MotionEvent; 
import android.view.View; 
import android.view.animation.Interpolator; 
import android.widget.ListAdapter; 
import android.widget.ListView; 
/** 
* @author baoyz 
* @date 2014-8-18 
* qiang_xi修改于2016-09-07(新增qq的效果) 
*/ 
public class SwipeMenuListView extends ListView { 
private static final int TOUCH_STATE_NONE = 0; 
private static final int TOUCH_STATE_X = 1; 
private static final int TOUCH_STATE_Y = 2; 
public static final int DIRECTION_LEFT = 1; 
public static final int DIRECTION_RIGHT = -1; 
private int mDirection = 1;//swipe from right to left by default 
private int MAX_Y = 5; 
private int MAX_X = 3; 
private float mDownX; 
private float mDownY; 
private int mTouchState; 
private int mTouchPosition; 
private SwipeMenuLayout mTouchView; 
private OnSwipeListener mOnSwipeListener; 
private SwipeMenuCreator mMenuCreator; 
private OnMenuItemClickListener mOnMenuItemClickListener; 
private OnMenuStateChangeListener mOnMenuStateChangeListener; 
private Interpolator mCloseInterpolator; 
private Interpolator mOpenInterpolator; 
public SwipeMenuListView(Context context) { 
super(context); 
init(); 
} 
public SwipeMenuListView(Context context, AttributeSet attrs, int defStyle) { 
super(context, attrs, defStyle); 
init(); 
} 
public SwipeMenuListView(Context context, AttributeSet attrs) { 
super(context, attrs); 
init(); 
} 
private void init() { 
MAX_X = dp2px(MAX_X); 
MAX_Y = dp2px(MAX_Y); 
mTouchState = TOUCH_STATE_NONE; 
} 
@Override 
public void setAdapter(ListAdapter adapter) { 
super.setAdapter(new SwipeMenuAdapter(getContext(), adapter) { 
@Override 
public void createMenu(SwipeMenu menu) { 
if (mMenuCreator != null) { 
mMenuCreator.create(menu); 
} 
} 
@Override 
public void onItemClick(SwipeMenuView view, SwipeMenu menu, 
int index) { 
boolean flag = false; 
if (mOnMenuItemClickListener != null) { 
flag = mOnMenuItemClickListener.onMenuItemClick( 
view.getPosition(), menu, index); 
} 
if (mTouchView != null && !flag) { 
mTouchView.smoothCloseMenu(); 
} 
} 
}); 
} 
public void setCloseInterpolator(Interpolator interpolator) { 
mCloseInterpolator = interpolator; 
} 
public void setOpenInterpolator(Interpolator interpolator) { 
mOpenInterpolator = interpolator; 
} 
public Interpolator getOpenInterpolator() { 
return mOpenInterpolator; 
} 
public Interpolator getCloseInterpolator() { 
return mCloseInterpolator; 
} 
@Override 
public boolean onInterceptTouchEvent(MotionEvent ev) { 
//在攔截處處理,在滑動(dòng)設(shè)置了點(diǎn)擊事件的地方也能swip,點(diǎn)擊時(shí)又不能影響原來(lái)的點(diǎn)擊事件 
int action = ev.getAction(); 
switch (action) { 
case MotionEvent.ACTION_DOWN: 
mDownX = ev.getX(); 
mDownY = ev.getY(); 
boolean handled = super.onInterceptTouchEvent(ev); 
mTouchState = TOUCH_STATE_NONE; 
mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY()); 
View view = getChildAt(mTouchPosition - getFirstVisiblePosition()); 
//只在空的時(shí)候賦值 以免每次觸摸都賦值,會(huì)有多個(gè)open狀態(tài) 
if (view instanceof SwipeMenuLayout) { 
//如果有打開(kāi)了 就攔截. 
if (mTouchView != null && mTouchView.isOpen() && !inRangeOfView(mTouchView.getMenuView(), ev)) { 
return true; 
} 
mTouchView = (SwipeMenuLayout) view; 
mTouchView.setSwipeDirection(mDirection); 
} 
//如果摸在另外個(gè)view 
if (mTouchView != null && mTouchView.isOpen() && view != mTouchView) { 
handled = true; 
} 
if (mTouchView != null) { 
mTouchView.onSwipe(ev); 
} 
return handled; 
case MotionEvent.ACTION_MOVE: 
float dy = Math.abs((ev.getY() - mDownY)); 
float dx = Math.abs((ev.getX() - mDownX)); 
if (Math.abs(dy) > MAX_Y || Math.abs(dx) > MAX_X) { 
//每次攔截的down都把觸摸狀態(tài)設(shè)置成了TOUCH_STATE_NONE 只有返回true才會(huì)走onTouchEvent 所以寫(xiě)在這里就夠了 
if (mTouchState == TOUCH_STATE_NONE) { 
if (Math.abs(dy) > MAX_Y) { 
mTouchState = TOUCH_STATE_Y; 
} else if (dx > MAX_X) { 
mTouchState = TOUCH_STATE_X; 
if (mOnSwipeListener != null) { 
mOnSwipeListener.onSwipeStart(mTouchPosition); 
} 
} 
} 
return true; 
} 
} 
return super.onInterceptTouchEvent(ev); 
} 
@Override 
public boolean onTouchEvent(MotionEvent ev) { 
if (ev.getAction() != MotionEvent.ACTION_DOWN && mTouchView == null) 
return super.onTouchEvent(ev); 
int action = ev.getAction(); 
switch (action) { 
case MotionEvent.ACTION_DOWN: 
int oldPos = mTouchPosition; 
mDownX = ev.getX(); 
mDownY = ev.getY(); 
mTouchState = TOUCH_STATE_NONE; 
mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY()); 
/*******把這句代碼提前*********/ 
View view = getChildAt(mTouchPosition - getFirstVisiblePosition()); 
if (mTouchPosition == oldPos && mTouchView != null 
&& mTouchView.isOpen()) { 
/********新添加的內(nèi)容,當(dāng)按下的item不是當(dāng)前已經(jīng)打開(kāi)的item,則關(guān)閉已經(jīng)打開(kāi)的item,并返回false.不再響應(yīng)down以后的事件,仿qq效果********/ 
if (view instanceof SwipeMenuLayout) { 
SwipeMenuLayout touchView = (SwipeMenuLayout) view; 
if (!touchView.isOpen()) { 
mTouchView.smoothCloseMenu(); 
return false; 
} 
} 
/***************************/ 
mTouchState = TOUCH_STATE_X; 
mTouchView.onSwipe(ev); 
return true; 
} 
if (mTouchView != null && mTouchView.isOpen()) { 
mTouchView.smoothCloseMenu(); 
mTouchView = null; 
// return super.onTouchEvent(ev); 
// try to cancel the touch event 
MotionEvent cancelEvent = MotionEvent.obtain(ev); 
cancelEvent.setAction(MotionEvent.ACTION_CANCEL); 
onTouchEvent(cancelEvent); 
if (mOnMenuStateChangeListener != null) { 
mOnMenuStateChangeListener.onMenuClose(oldPos); 
} 
return true; 
} 
if (view instanceof SwipeMenuLayout) { 
mTouchView = (SwipeMenuLayout) view; 
mTouchView.setSwipeDirection(mDirection); 
} 
if (mTouchView != null) { 
mTouchView.onSwipe(ev); 
} 
break; 
case MotionEvent.ACTION_MOVE: 
//有些可能有header,要減去header再判斷 
mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY()) - getHeaderViewsCount(); 
//如果滑動(dòng)了一下沒(méi)完全展現(xiàn),就收回去,這時(shí)候mTouchView已經(jīng)賦值,再滑動(dòng)另外一個(gè)不可以swip的view 
//會(huì)導(dǎo)致mTouchView swip 。 所以要用位置判斷是否滑動(dòng)的是一個(gè)view 
if (!mTouchView.getSwipEnable() || mTouchPosition != mTouchView.getPosition()) { 
break; 
} 
float dy = Math.abs((ev.getY() - mDownY)); 
float dx = Math.abs((ev.getX() - mDownX)); 
if (mTouchState == TOUCH_STATE_X) { 
if (mTouchView != null) { 
mTouchView.onSwipe(ev); 
} 
getSelector().setState(new int[]{0}); 
ev.setAction(MotionEvent.ACTION_CANCEL); 
super.onTouchEvent(ev); 
return true; 
} else if (mTouchState == TOUCH_STATE_NONE) { 
if (Math.abs(dy) > MAX_Y) { 
mTouchState = TOUCH_STATE_Y; 
} else if (dx > MAX_X) { 
mTouchState = TOUCH_STATE_X; 
if (mOnSwipeListener != null) { 
mOnSwipeListener.onSwipeStart(mTouchPosition); 
} 
} 
} 
break; 
case MotionEvent.ACTION_UP: 
if (mTouchState == TOUCH_STATE_X) { 
if (mTouchView != null) { 
boolean isBeforeOpen = mTouchView.isOpen(); 
mTouchView.onSwipe(ev); 
boolean isAfterOpen = mTouchView.isOpen(); 
if (isBeforeOpen != isAfterOpen && mOnMenuStateChangeListener != null) { 
if (isAfterOpen) { 
mOnMenuStateChangeListener.onMenuOpen(mTouchPosition); 
} else { 
mOnMenuStateChangeListener.onMenuClose(mTouchPosition); 
} 
} 
if (!isAfterOpen) { 
mTouchPosition = -1; 
mTouchView = null; 
} 
} 
if (mOnSwipeListener != null) { 
mOnSwipeListener.onSwipeEnd(mTouchPosition); 
} 
ev.setAction(MotionEvent.ACTION_CANCEL); 
super.onTouchEvent(ev); 
return true; 
} 
break; 
} 
return super.onTouchEvent(ev); 
} 
public void smoothOpenMenu(int position) { 
if (position >= getFirstVisiblePosition() 
&& position <= getLastVisiblePosition()) { 
View view = getChildAt(position - getFirstVisiblePosition()); 
if (view instanceof SwipeMenuLayout) { 
mTouchPosition = position; 
if (mTouchView != null && mTouchView.isOpen()) { 
mTouchView.smoothCloseMenu(); 
} 
mTouchView = (SwipeMenuLayout) view; 
mTouchView.setSwipeDirection(mDirection); 
mTouchView.smoothOpenMenu(); 
} 
} 
} 
public void smoothCloseMenu() { 
if (mTouchView != null && mTouchView.isOpen()) { 
mTouchView.smoothCloseMenu(); 
} 
} 
private int dp2px(int dp) { 
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, 
getContext().getResources().getDisplayMetrics()); 
} 
public void setMenuCreator(SwipeMenuCreator menuCreator) { 
this.mMenuCreator = menuCreator; 
} 
public void setOnMenuItemClickListener( 
OnMenuItemClickListener onMenuItemClickListener) { 
this.mOnMenuItemClickListener = onMenuItemClickListener; 
} 
public void setOnSwipeListener(OnSwipeListener onSwipeListener) { 
this.mOnSwipeListener = onSwipeListener; 
} 
public void setOnMenuStateChangeListener(OnMenuStateChangeListener onMenuStateChangeListener) { 
mOnMenuStateChangeListener = onMenuStateChangeListener; 
} 
public static interface OnMenuItemClickListener { 
boolean onMenuItemClick(int position, SwipeMenu menu, int index); 
} 
public static interface OnSwipeListener { 
void onSwipeStart(int position); 
void onSwipeEnd(int position); 
} 
public static interface OnMenuStateChangeListener { 
void onMenuOpen(int position); 
void onMenuClose(int position); 
} 
public void setSwipeDirection(int direction) { 
mDirection = direction; 
} 
/** 
* 判斷點(diǎn)擊事件是否在某個(gè)view內(nèi) 
* 
* @param view 
* @param ev 
* @return 
*/ 
public static boolean inRangeOfView(View view, MotionEvent ev) { 
int[] location = new int[2]; 
view.getLocationOnScreen(location); 
int x = location[0]; 
int y = location[1]; 
if (ev.getRawX() < x || ev.getRawX() > (x + view.getWidth()) || ev.getRawY() < y || ev.getRawY() > (y + view.getHeight())) { 
return false; 
} 
return true; 
} 
}

這樣看來(lái)實(shí)現(xiàn)qq的那個(gè)效果是不是很簡(jiǎn)單,不過(guò)也多虧了原作者寫(xiě)的好,我修改起來(lái)才更容易.

話說(shuō)回來(lái),當(dāng)按下的item不是已經(jīng)被拉出來(lái)的那個(gè)item時(shí),相應(yīng)的效果我們已經(jīng)實(shí)現(xiàn),如果按下的item正好是那個(gè)已經(jīng)被拉出來(lái)的item,效果怎么實(shí)現(xiàn)呢?

其實(shí)對(duì)于這個(gè)效果原作者其實(shí)已經(jīng)實(shí)現(xiàn)了,只不過(guò)實(shí)現(xiàn)的不夠好,存在一些問(wèn)題,我這里把這個(gè)問(wèn)題修復(fù)了.

存在的問(wèn)題就是:如果在當(dāng)前被拉出的item上左右滑動(dòng)時(shí),當(dāng)你在抬起手指的那一刻并且滑動(dòng)方向是向著拉開(kāi)的方向滑動(dòng),有很大幾率,這個(gè)被拉開(kāi)的item會(huì)被關(guān)閉,舉個(gè)栗子,比如你設(shè)定的是向左滑動(dòng)是拉開(kāi)的方向,當(dāng)你在已經(jīng)被拉開(kāi)的item上左右滑動(dòng),并且在抬起手指的前一刻你是向左滑動(dòng)的,講道理的話這個(gè)item應(yīng)該是處于被拉開(kāi)的狀態(tài),但是實(shí)際上有很大幾率當(dāng)你抬起手指時(shí),這個(gè)item卻被關(guān)閉了,所以這是一個(gè)相當(dāng)影響用戶體驗(yàn)問(wèn)題,一個(gè)item的其實(shí)就是一個(gè)SwipeMenuLayout,在SwipeMenuLayout類中,有一個(gè)onSwipe方法,該方法的參數(shù)MotionEvent就是從SwipeMenuListView的onTouchEvent方法中傳遞過(guò)來(lái)的,之前說(shuō)過(guò),當(dāng)手指抬起時(shí)才會(huì)出問(wèn)題,那么我們直接就看ACTION_UP當(dāng)中的實(shí)現(xiàn)代碼,

以下代碼是有問(wèn)題的:

if ((isFling || Math.abs(mDownX - event.getX()) > (mMenuView.getWidth() / 2)) && 
Math.signum(mDownX - event.getX()) == mSwipeDirection) { 
// open 
smoothOpenMenu(); 
} else { 
// close 
smoothCloseMenu(); 
return false; 
} 

我們來(lái)分析一下,isFliing不用看,問(wèn)題不是出在這里,我們看后面的判斷邏輯:X軸方向上滑動(dòng)距離的絕對(duì)值大于菜單寬度的一半并且滑動(dòng)方向是向著拉開(kāi)的方向滑動(dòng)時(shí),一個(gè)item才會(huì)被拉開(kāi),不然其他所有情況都會(huì)直接進(jìn)else語(yǔ)句關(guān)閉item,問(wèn)題就是出現(xiàn)在這里,而上面說(shuō)的問(wèn)題也是由這個(gè)導(dǎo)致的,試想一種情況,由于當(dāng)前的item是已經(jīng)被拉出來(lái)過(guò)的,如果我們的滑動(dòng)距離絕對(duì)值沒(méi)有超過(guò)菜單寬度的一半但是我們滑動(dòng)的方向是向著item被拉出來(lái)的方向,講道理的話我們的item是應(yīng)該繼續(xù)以被拉出的狀態(tài)顯示才對(duì),但是根據(jù)代碼中的判斷邏輯,這種情況是直接進(jìn)else語(yǔ)句的,也就是直接關(guān)閉這個(gè)item的,所以這里的邏輯判斷有大問(wèn)題,我們要的效果是:既然你已經(jīng)被拉出來(lái)了只要你是繼續(xù)往拉出的方向滑動(dòng),我就不會(huì)進(jìn)else,而是直接再在if中進(jìn)行判斷滑動(dòng)的距離,這樣的邏輯才是正確的,而為了在第一次滑動(dòng)時(shí),不出現(xiàn)問(wèn)題,我們還得為第一次滑動(dòng)做相應(yīng)操作.

所以修改之后的代碼邏輯如下所示:

if ((isFling || Math.signum(mDownX - event.getX()) == mSwipeDirection)) { 
// open 
/**************新添加內(nèi)容****防止在已被拉開(kāi)的item上向拉開(kāi)的方向滑動(dòng)然后抬起手指時(shí),item有很大幾率關(guān)閉的問(wèn)題******************/ 
if (Math.abs(mDownX - event.getX()) > (mMenuView.getWidth() / 2)) { 
smoothOpenMenu(); 
} else { 
//沒(méi)有item打開(kāi)時(shí),且滑動(dòng)距離不滿足打開(kāi)的條件才進(jìn)行關(guān)閉 
if (!isOpen()) { 
smoothCloseMenu(); 
} 
} 
/*******************************************/ 
} else { 
// close 
smoothCloseMenu(); 
return false; 
} 

這樣,我們就完美實(shí)現(xiàn)了qq的第二個(gè)效果,即如果你的手指放到當(dāng)前被拉出的item上,他不會(huì)隱藏這個(gè)item,并且可以正常響應(yīng)左右滑動(dòng)事件.

完整的修改之后的SwipeMenuLayout類的代碼如下所示:

package com.lanma.swipemenulistviewdemo.swipemenulistview; 
import android.content.Context; 
import android.support.v4.view.GestureDetectorCompat; 
import android.support.v4.widget.ScrollerCompat; 
import android.util.AttributeSet; 
import android.util.Log; 
import android.util.TypedValue; 
import android.view.GestureDetector.OnGestureListener; 
import android.view.GestureDetector.SimpleOnGestureListener; 
import android.view.MotionEvent; 
import android.view.View; 
import android.view.animation.Interpolator; 
import android.widget.AbsListView; 
import android.widget.FrameLayout; 
/** 
* @author baoyz 
* @date 2014-8-23 
* qiang_xi修改于2016-09-07 
*/ 
public class SwipeMenuLayout extends FrameLayout { 
private static final int CONTENT_VIEW_ID = 1; 
private static final int MENU_VIEW_ID = 2; 
private static final int STATE_CLOSE = 0; 
private static final int STATE_OPEN = 1; 
private int mSwipeDirection; 
private View mContentView; 
private SwipeMenuView mMenuView; 
private int mDownX; 
private int state = STATE_CLOSE; 
private GestureDetectorCompat mGestureDetector; 
private OnGestureListener mGestureListener; 
private boolean isFling; 
private int MIN_FLING = dp2px(15); 
private int MAX_VELOCITYX = -dp2px(500); 
private ScrollerCompat mOpenScroller; 
private ScrollerCompat mCloseScroller; 
private int mBaseX; 
private int position; 
private Interpolator mCloseInterpolator; 
private Interpolator mOpenInterpolator; 
private boolean mSwipEnable = true; 
public SwipeMenuLayout(View contentView, SwipeMenuView menuView) { 
this(contentView, menuView, null, null); 
} 
public SwipeMenuLayout(View contentView, SwipeMenuView menuView, 
Interpolator closeInterpolator, Interpolator openInterpolator) { 
super(contentView.getContext()); 
mCloseInterpolator = closeInterpolator; 
mOpenInterpolator = openInterpolator; 
mContentView = contentView; 
mMenuView = menuView; 
mMenuView.setLayout(this); 
init(); 
} 
// private SwipeMenuLayout(Context context, AttributeSet attrs, int 
// defStyle) { 
// super(context, attrs, defStyle); 
// } 
private SwipeMenuLayout(Context context, AttributeSet attrs) { 
super(context, attrs); 
} 
private SwipeMenuLayout(Context context) { 
super(context); 
} 
public int getPosition() { 
return position; 
} 
public void setPosition(int position) { 
this.position = position; 
mMenuView.setPosition(position); 
} 
public void setSwipeDirection(int swipeDirection) { 
mSwipeDirection = swipeDirection; 
} 
private void init() { 
setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT, 
LayoutParams.WRAP_CONTENT)); 
mGestureListener = new SimpleOnGestureListener() { 
@Override 
public boolean onDown(MotionEvent e) { 
isFling = false; 
return true; 
} 
@Override 
public boolean onFling(MotionEvent e1, MotionEvent e2, 
float velocityX, float velocityY) { 
// TODO 
if (Math.abs(e1.getX() - e2.getX()) > MIN_FLING 
&& velocityX < MAX_VELOCITYX) { 
isFling = true; 
} 
// Log.i("byz", MAX_VELOCITYX + ", velocityX = " + velocityX); 
return super.onFling(e1, e2, velocityX, velocityY); 
} 
}; 
mGestureDetector = new GestureDetectorCompat(getContext(), 
mGestureListener); 
// mScroller = ScrollerCompat.create(getContext(), new 
// BounceInterpolator()); 
if (mCloseInterpolator != null) { 
mCloseScroller = ScrollerCompat.create(getContext(), 
mCloseInterpolator); 
} else { 
mCloseScroller = ScrollerCompat.create(getContext()); 
} 
if (mOpenInterpolator != null) { 
mOpenScroller = ScrollerCompat.create(getContext(), 
mOpenInterpolator); 
} else { 
mOpenScroller = ScrollerCompat.create(getContext()); 
} 
LayoutParams contentParams = new LayoutParams( 
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); 
mContentView.setLayoutParams(contentParams); 
if (mContentView.getId() < 1) { 
mContentView.setId(CONTENT_VIEW_ID); 
} 
mMenuView.setId(MENU_VIEW_ID); 
mMenuView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, 
LayoutParams.WRAP_CONTENT)); 
addView(mContentView); 
addView(mMenuView); 
// if (mContentView.getBackground() == null) { 
// mContentView.setBackgroundColor(Color.WHITE); 
// } 
// in android 2.x, MenuView height is MATCH_PARENT is not work. 
// getViewTreeObserver().addOnGlobalLayoutListener( 
// new OnGlobalLayoutListener() { 
// @Override 
// public void onGlobalLayout() { 
// setMenuHeight(mContentView.getHeight()); 
// // getViewTreeObserver() 
// // .removeGlobalOnLayoutListener(this); 
// } 
// }); 
} 
@Override 
protected void onAttachedToWindow() { 
super.onAttachedToWindow(); 
} 
@Override 
protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
super.onSizeChanged(w, h, oldw, oldh); 
} 
public boolean onSwipe(MotionEvent event) { 
mGestureDetector.onTouchEvent(event); 
switch (event.getAction()) { 
case MotionEvent.ACTION_DOWN: 
mDownX = (int) event.getX(); 
isFling = false; 
break; 
case MotionEvent.ACTION_MOVE: 
// Log.i("byz", "downX = " + mDownX + ", moveX = " + event.getX()); 
int dis = (int) (mDownX - event.getX()); 
if (state == STATE_OPEN) { 
dis += mMenuView.getWidth() * mSwipeDirection; 
} 
swipe(dis); 
break; 
case MotionEvent.ACTION_UP: 
if ((isFling || Math.signum(mDownX - event.getX()) == mSwipeDirection)) { 
// open 
/**************新添加內(nèi)容****防止在已被拉開(kāi)的item上向拉開(kāi)的方向滑動(dòng)然后抬起手指時(shí),item有很大幾率關(guān)閉的問(wèn)題******************/ 
if (Math.abs(mDownX - event.getX()) > (mMenuView.getWidth() / 2)) { 
smoothOpenMenu(); 
} else { 
//沒(méi)有item打開(kāi)時(shí),且滑動(dòng)距離不滿足打開(kāi)的條件才進(jìn)行關(guān)閉 
if (!isOpen()) { 
smoothCloseMenu(); 
} 
} 
/*******************************************/ 
} else { 
// close 
smoothCloseMenu(); 
return false; 
} 
break; 
} 
return true; 
} 
public boolean isOpen() { 
return state == STATE_OPEN; 
} 
@Override 
public boolean onTouchEvent(MotionEvent event) { 
return super.onTouchEvent(event); 
} 
private void swipe(int dis) { 
if (!mSwipEnable) { 
return; 
} 
if (Math.signum(dis) != mSwipeDirection) { 
dis = 0; 
} else if (Math.abs(dis) > mMenuView.getWidth()) { 
dis = mMenuView.getWidth() * mSwipeDirection; 
} 
mContentView.layout(-dis, mContentView.getTop(), 
mContentView.getWidth() - dis, getMeasuredHeight()); 
if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) { 
mMenuView.layout(mContentView.getWidth() - dis, mMenuView.getTop(), 
mContentView.getWidth() + mMenuView.getWidth() - dis, 
mMenuView.getBottom()); 
} else { 
mMenuView.layout(-mMenuView.getWidth() - dis, mMenuView.getTop(), 
-dis, mMenuView.getBottom()); 
} 
} 
@Override 
public void computeScroll() { 
if (state == STATE_OPEN) { 
if (mOpenScroller.computeScrollOffset()) { 
swipe(mOpenScroller.getCurrX() * mSwipeDirection); 
postInvalidate(); 
} 
} else { 
if (mCloseScroller.computeScrollOffset()) { 
swipe((mBaseX - mCloseScroller.getCurrX()) * mSwipeDirection); 
postInvalidate(); 
} 
} 
} 
public void smoothCloseMenu() { 
state = STATE_CLOSE; 
if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) { 
mBaseX = -mContentView.getLeft(); 
mCloseScroller.startScroll(0, 0, mMenuView.getWidth(), 0, 350); 
} else { 
mBaseX = mMenuView.getRight(); 
mCloseScroller.startScroll(0, 0, mMenuView.getWidth(), 0, 350); 
} 
postInvalidate(); 
} 
public void smoothOpenMenu() { 
if (!mSwipEnable) { 
return; 
} 
state = STATE_OPEN; 
if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) { 
mOpenScroller.startScroll(-mContentView.getLeft(), 0, mMenuView.getWidth(), 0, 350); 
} else { 
mOpenScroller.startScroll(mContentView.getLeft(), 0, mMenuView.getWidth(), 0, 350); 
} 
postInvalidate(); 
} 
public void closeMenu() { 
if (mCloseScroller.computeScrollOffset()) { 
mCloseScroller.abortAnimation(); 
} 
if (state == STATE_OPEN) { 
state = STATE_CLOSE; 
swipe(0); 
} 
} 
public void openMenu() { 
if (!mSwipEnable) { 
return; 
} 
if (state == STATE_CLOSE) { 
state = STATE_OPEN; 
swipe(mMenuView.getWidth() * mSwipeDirection); 
} 
} 
public View getContentView() { 
return mContentView; 
} 
public SwipeMenuView getMenuView() { 
return mMenuView; 
} 
private int dp2px(int dp) { 
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, 
getContext().getResources().getDisplayMetrics()); 
} 
@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
mMenuView.measure(MeasureSpec.makeMeasureSpec(0, 
MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec( 
getMeasuredHeight(), MeasureSpec.EXACTLY)); 
} 
@Override 
protected void onLayout(boolean changed, int l, int t, int r, int b) { 
mContentView.layout(0, 0, getMeasuredWidth(), 
mContentView.getMeasuredHeight()); 
if (mSwipeDirection == SwipeMenuListView.DIRECTION_LEFT) { 
mMenuView.layout(getMeasuredWidth(), 0, 
getMeasuredWidth() + mMenuView.getMeasuredWidth(), 
mContentView.getMeasuredHeight()); 
} else { 
mMenuView.layout(-mMenuView.getMeasuredWidth(), 0, 
0, mContentView.getMeasuredHeight()); 
} 
} 
public void setMenuHeight(int measuredHeight) { 
Log.i("byz", "pos = " + position + ", height = " + measuredHeight); 
LayoutParams params = (LayoutParams) mMenuView.getLayoutParams(); 
if (params.height != measuredHeight) { 
params.height = measuredHeight; 
mMenuView.setLayoutParams(mMenuView.getLayoutParams()); 
} 
} 
public void setSwipEnable(boolean swipEnable) { 
mSwipEnable = swipEnable; 
} 
public boolean getSwipEnable() { 
return mSwipEnable; 
} 
} 

那么.由于我們的標(biāo)題名字起的是99.99%實(shí)現(xiàn)側(cè)滑刪除效果,那么我們就來(lái)看下效果圖,看看到底是不是99.99%的一樣:

QQ效果圖:

 

修改后的效果圖:

上面的兩張效果圖可能看不出什么,特別是我們上面說(shuō)的那幾個(gè)效果,主要是視屏轉(zhuǎn)成gif之后又卡播放速度又快,所以想比較qq的效果和我們自己的效果,還是下載demo自己比較吧.我只能說(shuō)改過(guò)之后的效果和QQ的效果基本就是一樣的.嘎嘎~~

相關(guān)文章

最新評(píng)論