一转眼就15年了,希望大家15年升职加薪走上人生巅峰
这篇博客是结合上一篇ListView滑动删除之Viewgroup打造滑动控件(修正版)博客所完成的,先上个效果图吧.
其实实现起来并不复杂
1,解决滑动冲突
因为我们的自定义滑动控件和ListView本身的滑动事件会产生各种冲突,所以我们可以自定义ListView并重写onInterceptTouchEvent方法。
我们先来了解一下android事件的分发,当用户触摸屏幕时会先去调用ViewGroup的dispatchTouchEvent方法。
而在dispathTouchEvent方法中又会调用onInterceptTouchEvent方法,这个方法主要的目的就是用来拦截用户的操作,具体的分发机制详情可以看郭神的博客 Android事件分发机制完全解析,带你从源码的角度彻底理解(下)。
我们这里就先知道如果这个方法返回false则是touch事件全部由子view完成就可以,看看代码。
/**
* 判断是否拦截事件
*/
public boolean onInterceptTouchEvent(MotionEvent ev) {
float lastX = ev.getX();
float lastY = ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mFirstX = lastX;
mFirstY = lastY;
int motionPosition = pointToPosition((int) mFirstX, (int) mFirstY);
if (motionPosition >= 0) {
currentItemView = getChildAt(motionPosition
- getFirstVisiblePosition());
mySwipeItem = (MySwipeItem) currentItemView
.findViewById(R.id.myitem);
}
break;
case MotionEvent.ACTION_MOVE:
float dx = lastX - mFirstX;
float dy = lastY - mFirstY;
Log.d("TAG", "DX:" + dx);
if (Math.abs(dx) >= 5 && Math.abs(dy) >= 5) {
return false;
}
if (Math.abs(dx) < 5 && Math.abs(dx) > 0) {
mySwipeItem.toOff();
}
break;
default:
break;
}
return super.onInterceptTouchEvent(ev);
}
在这里我就是在move的时候做判断,如果条件满足我们就认为用户是在进行横向滑动操作,而在down的时候获取到listview的子view,当move条件不满足开始进行纵向滑动的时候使控件关闭。
2,使用回调接口
我们的效果为如果滑开了这个控件下次再点击除button以外的地方就关闭滑动控件,我们可以使用接口回调来实现这个效果
public interface OnScrollState {
public void scrollView();
public void scrollOn(View view);
}
public void setOnScrollState(OnScrollState onScrollState) {
this.mOnScrollState = onScrollState;
}
自定义了一个接口然后在touch的时候进行判断
@Override
public boolean onTouchEvent(MotionEvent event) {
int scrollX = getScrollX();
int x = (int) event.getX();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
if (mOnScrollState != null) {
mOnScrollState.scrollView();
}
break;
}
case MotionEvent.ACTION_MOVE: {
int deltaX = x - lastX;
// 计算滑动终点是否合法,防止滑动越界
int newScrollX = scrollX - deltaX;
if (deltaX != 0) {
if (newScrollX < 0) {
newScrollX = 0;
} else if (newScrollX > mMaxDistancex) {
newScrollX = mMaxDistancex;
}
this.scrollTo(newScrollX, 0);
}
break;
}
case MotionEvent.ACTION_UP: {
int newScrollX = 0;
// 这里做了下判断,当松开手的时候,会自动向两边滑动,具体向哪边滑,要看当前所处的位置
if (scrollX > mMaxDistancex / 2) {
newScrollX = mMaxDistancex;
}
// 慢慢滑向终点
this.smoothScrollTo(newScrollX, 0);
if (mOnScrollState != null && newScrollX == mMaxDistancex) {
mOnScrollState.scrollOn(this);
}
break;
}
}
lastX = x;
return true;
}
在Main中进行调用控件的关闭方法
@Override
public void scrollView() {
if (mLastItem != null) {
mLastItem.toOff();
}
}
@Override
public void scrollOn(View view) {
mLastItem = (MySwipeItem) view;
}
3,缺点
很简单就实现了滑动效果不是么。。。。但是我们会发现我们自己的listview的onItemClick方法不起作用了!!,因为我们重写了onInterceptTouchEvent方法,但是我们的滑动控件中的textView以及button还是可以用onclick的,所以还有一种listview的滑动删除方法高仿微信对话列表滑动删除效果。
4,后记
不要问我为什么自己不写一个完美的,我才不会说是因为我写不出来又犯懒了。。。。新手可以学习借鉴了解一下android的分发机制,但要是真的要用到项目中,我还是建议去Github上down一个成熟的