android_99_自定义View_侧滑删除
2017-01-25 08:13
288 查看
效果:
静态导入
平滑移动到指定位置的模板代码
布局:
activity_main
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.sg31.sgslidecell.MainActivity" >
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/lv"
></ListView>
</RelativeLayout>
item_list
<?xml version="1.0" encoding="utf-8"?>
<com.sg31.sgslidecell.SGSlideCellLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sl"
android:layout_width="match_parent"
android:layout_height="60dp"
android:minHeight="60dp"
android:background="#fff" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal" >
<TextView
android:id="@+id/tv_call"
android:layout_width="60dp"
android:layout_height="match_parent"
android:background="#666666"
android:gravity="center"
android:text="Call"
android:textColor="#ffffff" />
<TextView
android:id="@+id/tv_del"
android:layout_width="60dp"
android:layout_height="match_parent"
android:background="#ff0000"
android:gravity="center"
android:text="Delete"
android:textColor="#ffffff" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#44ffffff"
android:gravity="center_vertical"
android:orientation="horizontal" >
<ImageView
android:id="@+id/iv_image"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="15dp"
android:src="@drawable/head_1" />
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:text="beyond" />
</LinearLayout>
</com.sg31.sgslidecell.SGSlideCellLayout>
主控制器
package com.sg31.sgslidecell;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView mList = (ListView) findViewById(R.id.lv);
mList.setAdapter(new SGAdapter(MainActivity.this));
}
}
工具类
package com.sg31.sgslidecell;
import android.content.Context;
import android.graphics.Rect;
import android.support.v4.view.MotionEventCompat;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
public class Utils {
public static Toast mToast;
public static void showToast(Context mContext, String msg) {
if (mToast == null) {
mToast = Toast.makeText(mContext, "", Toast.LENGTH_SHORT);
}
mToast.setText(msg);
mToast.show();
}
/**
* dip 转换成 px
*
* @param dip
* @param context
* @return
*/
public static float dip2Dimension(float dip, Context context) {
DisplayMetrics displayMetrics = context.getResources()
.getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip,
displayMetrics);
}
/**
* @param dip
* @param context
* @param complexUnit
* {@link TypedValue#COMPLEX_UNIT_DIP}
* {@link TypedValue#COMPLEX_UNIT_SP}
* @return
*/
public static float toDimension(float dip, Context context, int complexUnit) {
DisplayMetrics displayMetrics = context.getResources()
.getDisplayMetrics();
return TypedValue.applyDimension(complexUnit, dip, displayMetrics);
}
/**
* 获取状态栏高度
*
* @param v
* @return
*/
public static int getStatusBarHeight(View v) {
if (v == null) {
return 0;
}
Rect frame = new Rect();
v.getWindowVisibleDisplayFrame(frame);
return frame.top;
}
public static String getActionName(MotionEvent event) {
String action = "unknow";
switch (MotionEventCompat.getActionMasked(event)) {
case MotionEvent.ACTION_DOWN:
action = "ACTION_DOWN";
break;
case MotionEvent.ACTION_MOVE:
action = "ACTION_MOVE";
break;
case MotionEvent.ACTION_UP:
action = "ACTION_UP";
break;
case MotionEvent.ACTION_CANCEL:
action = "ACTION_CANCEL";
break;
case MotionEvent.ACTION_SCROLL:
action = "ACTION_SCROLL";
break;
case MotionEvent.ACTION_OUTSIDE:
action = "ACTION_SCROLL";
break;
default:
break;
}
return action;
}
}
package com.sg31.sgslidecell;
public class Cheeses {
public static final String[] NAMES = new String[] { "宋江", "卢俊义", "吴用",
"公孙胜", "关胜", "林冲", "秦明", "呼延灼", "花荣", "柴进", "李应", "朱仝", "鲁智深",
"武松", "董平", "张清", "杨志", "徐宁", "索超", "戴宗", "刘唐", "李逵", "史进", "穆弘",
"雷横", "李俊", "阮小二", "张横", "阮小五", " 张顺", "阮小七", "杨雄", "石秀", "解珍",
" 解宝", "燕青", "朱武", "黄信", "孙立", "宣赞", "郝思文", "韩滔", "彭玘", "单廷珪",
"魏定国", "萧让", "裴宣", "欧鹏", "邓飞", " 燕顺", "杨林", "凌振", "蒋敬", "吕方",
"郭 盛", "安道全", "皇甫端", "王英", "扈三娘", "鲍旭", "樊瑞", "孔明", "孔亮", "项充",
"李衮", "金大坚", "马麟", "童威", "童猛", "孟康", "侯健", "陈达", "杨春", "郑天寿",
"陶宗旺", "宋清", "乐和", "龚旺", "丁得孙", "穆春", "曹正", "宋万", "杜迁", "薛永", "施恩",
"周通", "李忠", "杜兴", "汤隆", "邹渊", "邹润", "朱富", "朱贵", "蔡福", "蔡庆", "李立",
"李云", "焦挺", "石勇", "孙新", "顾大嫂", "张青", "孙二娘", " 王定六", "郁保四", "白胜",
"时迁", "段景柱" };
}
适配器
package com.sg31.sgslidecell;
import static com.sg31.sgslidecell.Cheeses.NAMES;
import java.util.ArrayList;
import com.sg31.sgslidecell.SGSlideCellLayout.OnSlideCellLayoutStateChangeListener;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class SGAdapter extends BaseAdapter {
protected static final String TAG = "TAG";
public SGAdapter(Context context) {
super();
this.context = context;
opendItems = new ArrayList<SGSlideCellLayout>();
}
private Context context;
private ArrayList<SGSlideCellLayout> opendItems;
@Override
public int getCount() {
return NAMES.length;
}
@Override
public Object getItem(int position) {
return NAMES[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if(convertView == null){
view = View.inflate(context, R.layout.item_list, null);
}
ViewHolder mHolder = ViewHolder.getHolder(view);
mHolder.tv_name.setText(NAMES[position]);
SGSlideCellLayout sl = (SGSlideCellLayout)view;
sl.setSwipeLayoutListener(new OnSlideCellLayoutStateChangeListener() {
@Override
public void onStartOpen(SGSlideCellLayout mSwipeLayout) {
Log.d(TAG, "onStartOpen");
// 要去开启时,先遍历所有已打开条目, 逐个关闭
for (SGSlideCellLayout layout : opendItems) {
layout.close();
}
opendItems.clear();
}
@Override
public void onStartClose(SGSlideCellLayout mSwipeLayout) {
Log.d(TAG, "onStartClose");
}
@Override
public void onOpen(SGSlideCellLayout mSwipeLayout) {
Log.d(TAG, "onOpen");
// 添加进集合
opendItems.add(mSwipeLayout);
}
@Override
public void onDraging(SGSlideCellLayout mSwipeLayout) {
}
@Override
public void onClose(SGSlideCellLayout mSwipeLayout) {
Log.d(TAG, "onClose");
// 移除集合
opendItems.remove(mSwipeLayout);
}
});
return view;
}
static class ViewHolder {
TextView tv_name;
TextView tv_call;
TextView tv_del;
public static ViewHolder getHolder(View view) {
Object tag = view.getTag();
if(tag == null){
ViewHolder viewHolder = new ViewHolder();
viewHolder.tv_name = (TextView)view.findViewById(R.id.tv_name);
viewHolder.tv_call = (TextView)view.findViewById(R.id.tv_call);
viewHolder.tv_del = (TextView)view.findViewById(R.id.tv_del);
tag = viewHolder;
view.setTag(tag);
}
return (ViewHolder)tag;
}
}
}
自定义Layout
package com.sg31.sgslidecell;
import android.content.Context;
import android.graphics.Rect;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
/**
* 侧拉删除控件
* @author poplar
*
*/
public class SGSlideCellLayout extends FrameLayout {
private Status status = Status.Close;
private OnSlideCellLayoutStateChangeListener swipeLayoutListener;
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public OnSlideCellLayoutStateChangeListener getSwipeLayoutListener() {
return swipeLayoutListener;
}
public void setSwipeLayoutListener(OnSlideCellLayoutStateChangeListener swipeLayoutListener) {
this.swipeLayoutListener = swipeLayoutListener;
}
public static enum Status{
Close, Open, Draging
}
public static interface OnSlideCellLayoutStateChangeListener {
void onClose(SGSlideCellLayout mSwipeLayout);
void onOpen(SGSlideCellLayout mSwipeLayout);
void onDraging(SGSlideCellLayout mSwipeLayout);
// 要去关闭
void onStartClose(SGSlideCellLayout mSwipeLayout);
// 要去开启
void onStartOpen(SGSlideCellLayout mSwipeLayout);
}
public SGSlideCellLayout(Context context) {
this(context, null);
}
public SGSlideCellLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SGSlideCellLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mDragHelper = ViewDragHelper.create(this, 1.0f, mCallback);
}
ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() {
// c. 重写监听
public boolean tryCaptureView(View view, int id) {
return true;
}
// 限定移动范围
public int clampViewPositionHorizontal(View child, int left, int dx) {
// left
if(child == mFrontView){
if(left > 0){
return 0;
}else if(left < -mRange){
return -mRange;
}
}else if (child == mBackView) {
if(left > mWidth){
return mWidth;
}else if (left < mWidth - mRange) {
return mWidth - mRange;
}
}
return left;
};
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
// 传递事件
if(changedView == mFrontView){
mBackView.offsetLeftAndRight(dx);
}else if (changedView == mBackView) {
mFrontView.offsetLeftAndRight(dx);
}
dispatchSwipeEvent();
// 兼容老版本
invalidate();
};
public void onViewReleased(View releasedChild, float xvel, float yvel) {
if (xvel == 0 && mFrontView.getLeft() < -mRange / 2.0f) {
open();
}else if (xvel < 0) {
open();
}else {
close();
}
};
};
private ViewDragHelper mDragHelper;
private View mBackView;
private View mFrontView;
private int mHeight;
private int mWidth;
private int mRange;
// b. 传递触摸事件
@Override
public boolean onInterceptTouchEvent(android.view.MotionEvent ev) {
return mDragHelper.shouldInterceptTouchEvent(ev);
};
protected void dispatchSwipeEvent() {
if(swipeLayoutListener != null){
swipeLayoutListener.onDraging(this);
}
// 记录上一次的状态
Status preStatus = status;
// 更新当前状态
status = updateStatus();
if (preStatus != status && swipeLayoutListener != null) {
if (status == Status.Close) {
swipeLayoutListener.onClose(this);
} else if (status == Status.Open) {
swipeLayoutListener.onOpen(this);
} else if (status == Status.Draging) {
if(preStatus == Status.Close){
swipeLayoutListener.onStartOpen(this);
}else if (preStatus == Status.Open) {
swipeLayoutListener.onStartClose(this);
}
}
}
}
private Status updateStatus() {
int left = mFrontView.getLeft();
if(left == 0){
return Status.Close;
}else if (left == -mRange) {
return Status.Open;
}
return Status.Draging;
}
public void close() {
Utils.showToast(getContext(), "Close");
close(true);
}
public void close(boolean isSmooth){
int finalLeft = 0;
if(isSmooth){
//开始动画
if(mDragHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)){
ViewCompat.postInvalidateOnAnimation(this);
}
}else {
layoutContent(false);
}
}
public void open() {
Utils.showToast(getContext(), "Open");
open(true);
}
public void open(boolean isSmooth){
int finalLeft = -mRange;
if(isSmooth){
//开始动画
if(mDragHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)){
ViewCompat.postInvalidateOnAnimation(this);
}
}else {
layoutContent(true);
}
}
public void computeScroll() {
super.computeScroll();
if(mDragHelper.continueSettling(true)){
ViewCompat.postInvalidateOnAnimation(this);
}
}
public boolean onTouchEvent(MotionEvent event) {
try {
mDragHelper.processTouchEvent(event);
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
// 摆放位置
layoutContent(false);
}
private void layoutContent(boolean isOpen) {
// 摆放前View
Rect frontRect = computeFrontViewRect(isOpen);
mFrontView.layout(frontRect.left, frontRect.top, frontRect.right, frontRect.bottom);
// 摆放后View
Rect backRect = computeBackViewViaFront(frontRect);
mBackView.layout(backRect.left, backRect.top, backRect.right, backRect.bottom);
// 调整顺序, 把mFrontView前置
bringChildToFront(mFrontView);
}
private Rect computeBackViewViaFront(Rect frontRect) {
int left = frontRect.right;
return new Rect(left, 0, left + mRange, 0 + mHeight);
}
private Rect computeFrontViewRect(boolean isOpen) {
int left = 0;
if(isOpen){
left = -mRange;
}
return new Rect(left, 0, left + mWidth, 0 + mHeight);
}
protected void onFinishInflate() {
super.onFinishInflate();
// 当xml被填充完毕时调用
mBackView = getChildAt(0);
mFrontView = getChildAt(1);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mHeight = mFrontView.getMeasuredHeight();
mWidth = mFrontView.getMeasuredWidth();
mRange = mBackView.getMeasuredWidth();
}
}
静态导入
平滑移动到指定位置的模板代码
布局:
activity_main
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.sg31.sgslidecell.MainActivity" >
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/lv"
></ListView>
</RelativeLayout>
item_list
<?xml version="1.0" encoding="utf-8"?>
<com.sg31.sgslidecell.SGSlideCellLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sl"
android:layout_width="match_parent"
android:layout_height="60dp"
android:minHeight="60dp"
android:background="#fff" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal" >
<TextView
android:id="@+id/tv_call"
android:layout_width="60dp"
android:layout_height="match_parent"
android:background="#666666"
android:gravity="center"
android:text="Call"
android:textColor="#ffffff" />
<TextView
android:id="@+id/tv_del"
android:layout_width="60dp"
android:layout_height="match_parent"
android:background="#ff0000"
android:gravity="center"
android:text="Delete"
android:textColor="#ffffff" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#44ffffff"
android:gravity="center_vertical"
android:orientation="horizontal" >
<ImageView
android:id="@+id/iv_image"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="15dp"
android:src="@drawable/head_1" />
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:text="beyond" />
</LinearLayout>
</com.sg31.sgslidecell.SGSlideCellLayout>
主控制器
package com.sg31.sgslidecell;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView mList = (ListView) findViewById(R.id.lv);
mList.setAdapter(new SGAdapter(MainActivity.this));
}
}
工具类
package com.sg31.sgslidecell;
import android.content.Context;
import android.graphics.Rect;
import android.support.v4.view.MotionEventCompat;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
public class Utils {
public static Toast mToast;
public static void showToast(Context mContext, String msg) {
if (mToast == null) {
mToast = Toast.makeText(mContext, "", Toast.LENGTH_SHORT);
}
mToast.setText(msg);
mToast.show();
}
/**
* dip 转换成 px
*
* @param dip
* @param context
* @return
*/
public static float dip2Dimension(float dip, Context context) {
DisplayMetrics displayMetrics = context.getResources()
.getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip,
displayMetrics);
}
/**
* @param dip
* @param context
* @param complexUnit
* {@link TypedValue#COMPLEX_UNIT_DIP}
* {@link TypedValue#COMPLEX_UNIT_SP}
* @return
*/
public static float toDimension(float dip, Context context, int complexUnit) {
DisplayMetrics displayMetrics = context.getResources()
.getDisplayMetrics();
return TypedValue.applyDimension(complexUnit, dip, displayMetrics);
}
/**
* 获取状态栏高度
*
* @param v
* @return
*/
public static int getStatusBarHeight(View v) {
if (v == null) {
return 0;
}
Rect frame = new Rect();
v.getWindowVisibleDisplayFrame(frame);
return frame.top;
}
public static String getActionName(MotionEvent event) {
String action = "unknow";
switch (MotionEventCompat.getActionMasked(event)) {
case MotionEvent.ACTION_DOWN:
action = "ACTION_DOWN";
break;
case MotionEvent.ACTION_MOVE:
action = "ACTION_MOVE";
break;
case MotionEvent.ACTION_UP:
action = "ACTION_UP";
break;
case MotionEvent.ACTION_CANCEL:
action = "ACTION_CANCEL";
break;
case MotionEvent.ACTION_SCROLL:
action = "ACTION_SCROLL";
break;
case MotionEvent.ACTION_OUTSIDE:
action = "ACTION_SCROLL";
break;
default:
break;
}
return action;
}
}
package com.sg31.sgslidecell;
public class Cheeses {
public static final String[] NAMES = new String[] { "宋江", "卢俊义", "吴用",
"公孙胜", "关胜", "林冲", "秦明", "呼延灼", "花荣", "柴进", "李应", "朱仝", "鲁智深",
"武松", "董平", "张清", "杨志", "徐宁", "索超", "戴宗", "刘唐", "李逵", "史进", "穆弘",
"雷横", "李俊", "阮小二", "张横", "阮小五", " 张顺", "阮小七", "杨雄", "石秀", "解珍",
" 解宝", "燕青", "朱武", "黄信", "孙立", "宣赞", "郝思文", "韩滔", "彭玘", "单廷珪",
"魏定国", "萧让", "裴宣", "欧鹏", "邓飞", " 燕顺", "杨林", "凌振", "蒋敬", "吕方",
"郭 盛", "安道全", "皇甫端", "王英", "扈三娘", "鲍旭", "樊瑞", "孔明", "孔亮", "项充",
"李衮", "金大坚", "马麟", "童威", "童猛", "孟康", "侯健", "陈达", "杨春", "郑天寿",
"陶宗旺", "宋清", "乐和", "龚旺", "丁得孙", "穆春", "曹正", "宋万", "杜迁", "薛永", "施恩",
"周通", "李忠", "杜兴", "汤隆", "邹渊", "邹润", "朱富", "朱贵", "蔡福", "蔡庆", "李立",
"李云", "焦挺", "石勇", "孙新", "顾大嫂", "张青", "孙二娘", " 王定六", "郁保四", "白胜",
"时迁", "段景柱" };
}
适配器
package com.sg31.sgslidecell;
import static com.sg31.sgslidecell.Cheeses.NAMES;
import java.util.ArrayList;
import com.sg31.sgslidecell.SGSlideCellLayout.OnSlideCellLayoutStateChangeListener;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class SGAdapter extends BaseAdapter {
protected static final String TAG = "TAG";
public SGAdapter(Context context) {
super();
this.context = context;
opendItems = new ArrayList<SGSlideCellLayout>();
}
private Context context;
private ArrayList<SGSlideCellLayout> opendItems;
@Override
public int getCount() {
return NAMES.length;
}
@Override
public Object getItem(int position) {
return NAMES[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if(convertView == null){
view = View.inflate(context, R.layout.item_list, null);
}
ViewHolder mHolder = ViewHolder.getHolder(view);
mHolder.tv_name.setText(NAMES[position]);
SGSlideCellLayout sl = (SGSlideCellLayout)view;
sl.setSwipeLayoutListener(new OnSlideCellLayoutStateChangeListener() {
@Override
public void onStartOpen(SGSlideCellLayout mSwipeLayout) {
Log.d(TAG, "onStartOpen");
// 要去开启时,先遍历所有已打开条目, 逐个关闭
for (SGSlideCellLayout layout : opendItems) {
layout.close();
}
opendItems.clear();
}
@Override
public void onStartClose(SGSlideCellLayout mSwipeLayout) {
Log.d(TAG, "onStartClose");
}
@Override
public void onOpen(SGSlideCellLayout mSwipeLayout) {
Log.d(TAG, "onOpen");
// 添加进集合
opendItems.add(mSwipeLayout);
}
@Override
public void onDraging(SGSlideCellLayout mSwipeLayout) {
}
@Override
public void onClose(SGSlideCellLayout mSwipeLayout) {
Log.d(TAG, "onClose");
// 移除集合
opendItems.remove(mSwipeLayout);
}
});
return view;
}
static class ViewHolder {
TextView tv_name;
TextView tv_call;
TextView tv_del;
public static ViewHolder getHolder(View view) {
Object tag = view.getTag();
if(tag == null){
ViewHolder viewHolder = new ViewHolder();
viewHolder.tv_name = (TextView)view.findViewById(R.id.tv_name);
viewHolder.tv_call = (TextView)view.findViewById(R.id.tv_call);
viewHolder.tv_del = (TextView)view.findViewById(R.id.tv_del);
tag = viewHolder;
view.setTag(tag);
}
return (ViewHolder)tag;
}
}
}
自定义Layout
package com.sg31.sgslidecell;
import android.content.Context;
import android.graphics.Rect;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
/**
* 侧拉删除控件
* @author poplar
*
*/
public class SGSlideCellLayout extends FrameLayout {
private Status status = Status.Close;
private OnSlideCellLayoutStateChangeListener swipeLayoutListener;
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public OnSlideCellLayoutStateChangeListener getSwipeLayoutListener() {
return swipeLayoutListener;
}
public void setSwipeLayoutListener(OnSlideCellLayoutStateChangeListener swipeLayoutListener) {
this.swipeLayoutListener = swipeLayoutListener;
}
public static enum Status{
Close, Open, Draging
}
public static interface OnSlideCellLayoutStateChangeListener {
void onClose(SGSlideCellLayout mSwipeLayout);
void onOpen(SGSlideCellLayout mSwipeLayout);
void onDraging(SGSlideCellLayout mSwipeLayout);
// 要去关闭
void onStartClose(SGSlideCellLayout mSwipeLayout);
// 要去开启
void onStartOpen(SGSlideCellLayout mSwipeLayout);
}
public SGSlideCellLayout(Context context) {
this(context, null);
}
public SGSlideCellLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SGSlideCellLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mDragHelper = ViewDragHelper.create(this, 1.0f, mCallback);
}
ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() {
// c. 重写监听
public boolean tryCaptureView(View view, int id) {
return true;
}
// 限定移动范围
public int clampViewPositionHorizontal(View child, int left, int dx) {
// left
if(child == mFrontView){
if(left > 0){
return 0;
}else if(left < -mRange){
return -mRange;
}
}else if (child == mBackView) {
if(left > mWidth){
return mWidth;
}else if (left < mWidth - mRange) {
return mWidth - mRange;
}
}
return left;
};
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
// 传递事件
if(changedView == mFrontView){
mBackView.offsetLeftAndRight(dx);
}else if (changedView == mBackView) {
mFrontView.offsetLeftAndRight(dx);
}
dispatchSwipeEvent();
// 兼容老版本
invalidate();
};
public void onViewReleased(View releasedChild, float xvel, float yvel) {
if (xvel == 0 && mFrontView.getLeft() < -mRange / 2.0f) {
open();
}else if (xvel < 0) {
open();
}else {
close();
}
};
};
private ViewDragHelper mDragHelper;
private View mBackView;
private View mFrontView;
private int mHeight;
private int mWidth;
private int mRange;
// b. 传递触摸事件
@Override
public boolean onInterceptTouchEvent(android.view.MotionEvent ev) {
return mDragHelper.shouldInterceptTouchEvent(ev);
};
protected void dispatchSwipeEvent() {
if(swipeLayoutListener != null){
swipeLayoutListener.onDraging(this);
}
// 记录上一次的状态
Status preStatus = status;
// 更新当前状态
status = updateStatus();
if (preStatus != status && swipeLayoutListener != null) {
if (status == Status.Close) {
swipeLayoutListener.onClose(this);
} else if (status == Status.Open) {
swipeLayoutListener.onOpen(this);
} else if (status == Status.Draging) {
if(preStatus == Status.Close){
swipeLayoutListener.onStartOpen(this);
}else if (preStatus == Status.Open) {
swipeLayoutListener.onStartClose(this);
}
}
}
}
private Status updateStatus() {
int left = mFrontView.getLeft();
if(left == 0){
return Status.Close;
}else if (left == -mRange) {
return Status.Open;
}
return Status.Draging;
}
public void close() {
Utils.showToast(getContext(), "Close");
close(true);
}
public void close(boolean isSmooth){
int finalLeft = 0;
if(isSmooth){
//开始动画
if(mDragHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)){
ViewCompat.postInvalidateOnAnimation(this);
}
}else {
layoutContent(false);
}
}
public void open() {
Utils.showToast(getContext(), "Open");
open(true);
}
public void open(boolean isSmooth){
int finalLeft = -mRange;
if(isSmooth){
//开始动画
if(mDragHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)){
ViewCompat.postInvalidateOnAnimation(this);
}
}else {
layoutContent(true);
}
}
public void computeScroll() {
super.computeScroll();
if(mDragHelper.continueSettling(true)){
ViewCompat.postInvalidateOnAnimation(this);
}
}
public boolean onTouchEvent(MotionEvent event) {
try {
mDragHelper.processTouchEvent(event);
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
// 摆放位置
layoutContent(false);
}
private void layoutContent(boolean isOpen) {
// 摆放前View
Rect frontRect = computeFrontViewRect(isOpen);
mFrontView.layout(frontRect.left, frontRect.top, frontRect.right, frontRect.bottom);
// 摆放后View
Rect backRect = computeBackViewViaFront(frontRect);
mBackView.layout(backRect.left, backRect.top, backRect.right, backRect.bottom);
// 调整顺序, 把mFrontView前置
bringChildToFront(mFrontView);
}
private Rect computeBackViewViaFront(Rect frontRect) {
int left = frontRect.right;
return new Rect(left, 0, left + mRange, 0 + mHeight);
}
private Rect computeFrontViewRect(boolean isOpen) {
int left = 0;
if(isOpen){
left = -mRange;
}
return new Rect(left, 0, left + mWidth, 0 + mHeight);
}
protected void onFinishInflate() {
super.onFinishInflate();
// 当xml被填充完毕时调用
mBackView = getChildAt(0);
mFrontView = getChildAt(1);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mHeight = mFrontView.getMeasuredHeight();
mWidth = mFrontView.getMeasuredWidth();
mRange = mBackView.getMeasuredWidth();
}
}
相关文章推荐
- Android开发-自定义View-AndroidStudio(十六)侧滑删除
- Android自定义View,ViewGroup(一)的一些原理与细节,RecyclerView版侧滑删除
- Android开发-自定义View-AndroidStudio(十六)侧滑删除
- Android自定义可编辑、删除的侧滑LisitView
- Android-详解RecyclerView+BGARefreshLayout实现自定义下拉刷新、上拉加载和侧滑删除效果
- android自定义View之自定义侧滑删除效果
- android自定义侧滑LisitView(包含编辑、删除)
- Android自定义view系列之99.99%实现QQ侧滑删除效果实例代码详解
- 手势冲突---UITableView删除, 自定义侧滑返回,UIScroll的手势冲突
- Android自定义组件系列【3】自定义ViewGroup实现侧滑
- 自定义View学习之12/5(侧滑删除实现,ViewDragHelper)
- Android实现RecyclerView侧滑删除和长按拖拽-ItemTouchHelper
- Android自定义View示例(一)—带有删除按钮的EditText
- Android自定义组件系列【3】——自定义ViewGroup实现侧滑
- Android自定义ViewGroup之子控件的自动换行和添加删除
- 详解RecyclerView+BGARefreshLayout实现自定义下拉刷新、上拉加载和侧滑删除效果
- Android 自定义View修炼-打造完美的自定义侧滑菜单/侧滑View控件(转)
- Android自定义View之ListView条目滑动删除(仿QQ5.1)
- 【Android开源项目解析】RecyclerView侧滑删除粒子效果实现——初探Android开源粒子库 Leonids
- Android 自定义侧滑ViewGroup