public class DeleteView
extends FrameLayout {
private View contentView;
private View deleteView;
private int contentWidth;
private int deleteWidth;
private ViewDragHelper dragHelper;
private int dragWidth;
private int STATE_OPEN = 0;
private int STATE_CLOSE = 1;
private int mState = STATE_CLOSE;
float touchSlop;
public DeleteView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
dragHelper = ViewDragHelper.create(this,callback);
// 獲取系統認爲的滑動的臨界值
touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
}
/** 將攔截事件交給ViewDragHelper處理 */
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// 這裏只是爲了保證onTouchEvent可以執行
if(!SwipeLayoutManager.getInstance().isCouldSwipe(DeleteView.this)) {
return true;
}
return dragHelper.shouldInterceptTouchEvent(ev);
}
float downX, downY;
long downTime;
/** 將觸摸事件交給ViewDragHelper處理 */
@Override
public boolean onTouchEvent(MotionEvent event) {
// SwipeLayout不可以側滑時,關閉已經打開的SwipeLayout
if(!SwipeLayoutManager.getInstance().isCouldSwipe(DeleteView.this)) {
SwipeLayoutManager.getInstance().closeOpenInstance();
return false; // 這裏返回true崩潰什麼鬼 。
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
downY = event.getY();
// 記錄按下的時間
downTime = System.currentTimeMillis();
break;
case MotionEvent.ACTION_MOVE:
float moveX = event.getX();
float moveY = event.getY();
// 水平滑動,不讓listView攔截事件
if(Math.abs(moveY-downY) < Math.abs(moveX-downX)) {
// 請求父View不攔截事件
requestDisallowInterceptTouchEvent(true);
}
break;
case MotionEvent.ACTION_UP:
// 記錄擡起的時間點
long upTime = System.currentTimeMillis();
// 計算擡起的座標
float upX = event.getX();
float upY = event.getY();
// 計算按下和擡起的時間差
long touchDuration = upTime-downTime;
// 計算按下點和擡起點的距離
float touchD = getDistanceBetween2Points(new PointF(downX, downY), new PointF(upX, upY));
// 模擬點擊事件
if(touchDuration < 400 && touchD < touchSlop){
// 打開狀態則關閉,否則執行點擊事件
if(SwipeLayoutManager.getInstance().isOpenInstance(DeleteView.this)) {
SwipeLayoutManager.getInstance().closeOpenInstance();
} else {
if(listener!=null){
listener.onClick();
}
}
}
break;
}
dragHelper.processTouchEvent(event);
return true;
}
ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
/** 確定需要觸摸的View */
@Override
public boolean tryCaptureView(View child, int pointerId) {
//Toast.makeText(getContext(), "事件捕獲", Toast.LENGTH_SHORT).show();
return child == contentView || child == deleteView;
}
/** View在水平方向的拖拽範圍,不要返回0 */
@Override
public int getViewHorizontalDragRange(View child) {
return dragWidth;
}
/**
* 控制子View在水平方向移動
* @param child 拖拽的View
* @param left 手指滑動之後子ViewDragHelper認爲的View的left
* @param dx 手指在水平方向移動的距離
* @return 子View最終的left
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
if(child == contentView) {
left = left > 0 ? 0 : left;
left = left < -dragWidth ? -dragWidth : left;
} else if(child == deleteView) {
left = left > contentWidth ? contentWidth : left;
left = left < contentWidth - deleteWidth ? contentWidth - deleteWidth
: left;
}
return left;
}
/**
* View位置改變時調用,一般用來做伴隨移動和判斷狀態執行相應的操作
* @param changedView
* @param left View當前的left
* @param top View當前的top
* @param dx View的水平移動距離
* @param dy View的豎直移動距離
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
if(changedView == contentView) {
int newLeft = deleteView.getLeft() + dx;
deleteView.layout(newLeft,getTop(), newLeft+deleteWidth,getBottom());
} else if(changedView == deleteView) {
contentView.layout(left - contentWidth,contentView.getTop(),
left, contentView.getBottom());
}
// 處理打開與關閉的邏輯
if(contentView.getLeft() == -deleteWidth && mState == STATE_CLOSE) {
mState = STATE_OPEN;
// 記錄打開的SwipeLayout
SwipeLayoutManager.getInstance().setOpenInstance(DeleteView.this);
} else if(contentView.getLeft() == 0 && mState == STATE_OPEN) {
mState = STATE_CLOSE;
SwipeLayoutManager.getInstance().closeOpenInstance();
}
}
/** 手指擡起的時候執行 */
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
int width = contentWidth - dragWidth/2;
if(contentView.getRight() < width) {
openDeleteMenu();
} else {
closeDeleteMenu();
}
}
};
public void closeDeleteMenu() {
dragHelper.smoothSlideViewTo(contentView,0,contentView.getTop());
ViewCompat.postInvalidateOnAnimation(DeleteView.this);
}
public void openDeleteMenu() {
dragHelper.smoothSlideViewTo(contentView,-dragWidth,contentView.getTop());
ViewCompat.postInvalidateOnAnimation(DeleteView.this);
}
@Override
public void computeScroll() {
if(dragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(DeleteView.this);
}
}
/** 對contentView和deleteView重新排版 */
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
contentView.layout(left, top, right, bottom);
deleteView.layout(right, top, right + deleteWidth, bottom);
}
/** 獲取contentView和deleteView */
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// 做簡單的異常處理
if(getChildCount() != 2) {
throw new IllegalArgumentException("the swipelayout only have 2 children!");
}
contentView = getChildAt(0);
deleteView = getChildAt(1);
}
/** 獲取contentView和deleteView的測量大小 */
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
contentWidth = contentView.getMeasuredWidth();
deleteWidth = deleteView.getMeasuredWidth();
dragWidth = deleteWidth;
}
/** 獲取刪除區域 */
public View getDeleteView() {
return deleteView;
}
/** 獲取內容區域 */
public View getContentView() {
return contentView;
}
private OnSwipeLayoutClickListener listener;
public void setOnSwipeLayoutClickListener(OnSwipeLayoutClickListener listener){
this.listener = listener;
}
/** 點擊事件回調接口 */
public interface OnSwipeLayoutClickListener{
void onClick();
}
/**
* 獲得兩點之間的距離
* @param p0
* @param p1
* @return
*/
public static float getDistanceBetween2Points(PointF p0, PointF p1) {
return (float) Math.sqrt(Math.pow(p0.y - p1.y, 2) + Math.pow(p0.x - p1.x, 2));
}
}
使用方法
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
>
<view.DeleteView
android:id="@+id/delete_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
//顯示區域
<RelativeLayout
android:id="@+id/rl_item"
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
</RelativeLayout>
//刪除區域
<LinearLayout
android:gravity="center_vertical"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:orientation="horizontal" >
<TextView
android:id="@+id/swipe_call"
android:layout_width="10dp"
android:layout_height="match_parent"
android:textSize="18sp"
android:textColor="#ffffff"
android:gravity="center"
android:background="#00000000"
android:text=""/>
<TextView
android:layout_gravity="center_vertical"
android:id="@+id/tv_delete"
android:layout_width="80dp"
android:layout_height="35dp"
android:textSize="18sp"
android:textColor="#ffffff"
android:gravity="center"
android:background="@drawable/delete_bg"
android:text="刪除"/>
</LinearLayout>
</view.DeleteView>
</RelativeLayout>