效果图
事件传递机制
带码
- SwipeDeleteItem.java 自定义拖拽控件
public class SwipeDeleteItem extends FrameLayout {
private ViewDragHelper viewDragHelper;
private View contentView;
private View deleteView;
private int contentHeight;
private int contentWidth;
private int deleteWidth;
float downX, downY;
private float upX;
private float upY;
private float moveX;
private float moveY;
private float downIX;
private float downIY;
enum State {
close, open
}
private State state = State.close;
public SwipeDeleteItem(Context context) {
this(context, null);
}
public SwipeDeleteItem(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SwipeDeleteItem(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
viewDragHelper = ViewDragHelper.create(this, 1.0f, callback);
}
/**
* 此控件的结束标签读取完毕
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
contentView = getChildAt(0);
deleteView = getChildAt(1);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
contentView.layout(0, 0, contentWidth, contentHeight);
Log.e("", "content" + contentWidth);
deleteView.layout(contentWidth, 0, contentWidth + deleteWidth, deleteWidth);
}
/**
* onMeasure 已经执行完毕 可以直接获取孩子宽高
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
contentHeight = contentView.getMeasuredHeight();
contentWidth = contentView.getMeasuredWidth();
deleteWidth = deleteView.getMeasuredWidth();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
Log.e("进入","onInterceptTouchEvent");
boolean value = viewDragHelper.shouldInterceptTouchEvent(event);
if (!SwipeDeleteManager.getInstance().haveOpened(this)) {
SwipeDeleteManager.getInstance().close();
}
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
downIX = event.getX();
downIY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
moveX = event.getX();
moveY = event.getY();
if (Math.abs(moveX-downIX)>1||Math.abs(moveY-downIY)>1){
Log.e("onInterceptTouchEvent","不是点击拦截事件");
value = true;
}
break;
}
return value;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e("进入","onTouchEvent");
if (SwipeDeleteManager.getInstance().haveOpened(this)) {
Log.e("onTouchEvent","不允许父控件拦截");
requestDisallowInterceptTouchEvent(true);
} else if (SwipeDeleteManager.getInstance().haveOpened()) {
requestDisallowInterceptTouchEvent(true);
return true;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
downY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
float moveX = event.getX();
float moveY = event.getY();
float dx = Math.abs(moveX - downX);
float dy = Math.abs(moveY - downY);
if (dx > dy) {
Log.e("Touch","dx>dy");
requestDisallowInterceptTouchEvent(true);
}
downX = moveX;
downY = moveY;
break;
}
viewDragHelper.processTouchEvent(event);
return true;
}
private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child == contentView || child == deleteView;
}
@Override
public void onViewDragStateChanged(int state) {
super.onViewDragStateChanged(state);
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
/**伴随移动**/
if (changedView == contentView) {
deleteView.layout(deleteView.getLeft() + dx, deleteView.getTop() + dy,
deleteView.getRight() + dx, deleteView.getBottom() + dy);
} else if (changedView == deleteView) {
contentView.layout(contentView.getLeft() + dx, contentView.getTop() + dy,
contentView.getRight() + dx, contentView.getBottom() + dy);
}
if (contentView.getLeft() != 0)
SwipeDeleteManager.getInstance().setSwipeDeleteItem(SwipeDeleteItem.this);
else SwipeDeleteManager.getInstance().clear();
if (contentView.getLeft() == 0 && state != State.close) state = State.close;
else if (contentView.getLeft() == -deleteWidth && state != State.open)
state = State.open;
}
@Override
public int getViewHorizontalDragRange(View child) {
return deleteWidth;
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
if (child == contentView) {
if (left > 0) left = 0;
if (left < -deleteWidth) left = -deleteWidth;
} else if (child == deleteView) {
if (left > contentWidth) left = contentWidth;
if (left < contentWidth - deleteWidth) left = contentWidth - deleteWidth;
}
return left;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
if (xvel < -2000) {
open();
return;
}
if (xvel > 2000) {
close();
return;
}
if (contentView.getLeft() > -deleteWidth / 2) {
close();
} else {
open();
}
}
};
public void open() {
Log.e("item","动画打开");
viewDragHelper.smoothSlideViewTo(contentView, -deleteWidth, contentView.getTop());
state = State.open;
SwipeDeleteManager.getInstance().setSwipeDeleteItem(SwipeDeleteItem.this);
ViewCompat.postInvalidateOnAnimation(SwipeDeleteItem.this);
}
public void close() {
Log.e("item","动画关闭");
viewDragHelper.smoothSlideViewTo(contentView, 0, contentView.getTop());
ViewCompat.postInvalidateOnAnimation(SwipeDeleteItem.this);
}
/**
* 重写此方法刷新动画
*/
@Override
public void computeScroll() {
if (viewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
}
- SwipeDeleteManager.java 管理控件 用来判断是否有打开的item 关闭item
public class SwipeDeleteManager {
private SwipeDeleteManager() {
}
private static SwipeDeleteManager swipeDeleteManager = new SwipeDeleteManager();
public static SwipeDeleteManager getInstance() {
return swipeDeleteManager;
}
private SwipeDeleteItem swipeDeleteItem;
public void setSwipeDeleteItem(SwipeDeleteItem s) {
swipeDeleteItem = s;
}
public void clear() {
swipeDeleteItem = null;
}
public void close() {
Log.e("Manager","关闭请求");
if (swipeDeleteItem != null){
swipeDeleteItem.close();
Log.e("Manager","关闭");
}
}
/**
* 是否有item已经打开
*/
public boolean haveOpened() {
return swipeDeleteItem != null;
}
/**
* 是否有item已经打开
*/
public boolean haveOpened(SwipeDeleteItem s) {
return swipeDeleteItem != null && swipeDeleteItem == s;
}
}
public class MainActivity extends AppCompatActivity {
private ListView listView;
private ArrayList<String> dataList = new ArrayList<>();
private static Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
SwipeDeleteManager.getInstance().close();
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
});
mContext= this;
for (int i = 0; i < 10; i++) {
dataList.add("我是第" + i + "条数据");
}
listView.setAdapter(new MyAdapter());
}
private class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return dataList.size();
}
@Override
public Object getItem(int position) {
return dataList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = View.inflate(MainActivity.this, R.layout.item_swipe_delete, null);
}
ViewHolder holder = ViewHolder.getHolder(convertView);
holder.name.setText(dataList.get(position));
return convertView;
}
}
static class ViewHolder {
TextView name, top, delete;
ViewHolder(View convertView) {
name = (TextView) convertView.findViewById(R.id.tv_name);
top = (TextView) convertView.findViewById(R.id.tv_top);
delete = (TextView) convertView.findViewById(R.id.tv_delete);
top.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext,"top",Toast.LENGTH_SHORT).show();
SwipeDeleteManager.getInstance().close();
}
});
}
static ViewHolder getHolder(View convertView) {
ViewHolder holder = (ViewHolder) convertView.getTag();
if (holder == null) {
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}
return holder;
}
}
}
- 布局文件item_swipe_delete.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.reige.swipedeleteitem.SwipeDeleteItem
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="#11111111"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="15dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/ic_launcher"/>
<TextView
android:id="@+id/tv_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="名称"
android:textColor="#99000000"
android:textSize="20sp"/>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="80dp"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_top"
android:layout_width="100dp"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:background="#aaC7C7CD"
android:gravity="center"
android:text="置顶"
android:textColor="#ffffff"
android:textSize="18sp"/>
<TextView
android:id="@+id/tv_delete"
android:layout_width="100dp"
android:layout_height="match_parent"
android:background="#eeFF3A30"
android:gravity="center"
android:text="删除"
android:textColor="#ffffff"
android:textSize="18sp"/>
</LinearLayout>
</com.reige.swipedeleteitem.SwipeDeleteItem>
</LinearLayout>