SwipeMenuListView类
涉及到的一些知识点,在onInterceptTouchEvent方法的down事件中的三个方法:
pointToPosition
getChildAt
inRangeOfView
SwipeMenuLayout类
涉及知识点:
GestureDetectorCompat手势类
以及
手势类的监听器OnGestureListener
平滑滑动的类ScrollerCompat
详细解释
1、pointToPosition
AbsListView类中的方法
/**
* Maps a point to a position in the list.
*
* @param x X in local coordinate
* @param y Y in local coordinate
* @return The position of the item which contains the specified point, or
* {@link #INVALID_POSITION} if the point does not intersect an item.
*/
public int pointToPosition(int x, int y) {
}
解释是:返回触摸到的点的position
listview.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int position = listview.pointToPosition((int)event.getX(), (int)event.getY());
return false;
}
});
可以打印下position的值,它不存在什么复用不复用的问题,实际得到的position值就是item的位置。
2、getChildAt
/**
* Returns the view at the specified position in the group.
*
* @param index the position at which to get the view from
* @return the view at the specified position or null if the position
* does not exist within the group
*/
public View getChildAt(int index) {
if (index < 0 || index >= mChildrenCount) {
return null;
}
return mChildren[index];
}
由于我们在使用listview的时候,都存在复用问题,所以在用getChildAt方法得到view时,得到的都是复用的那个view,所以需要用得到的position减去getFirstVisiblePosition
View view = getChildAt(position- getFirstVisiblePosition());
3、inRangeOfView
这个就是判断事件是否在某个view内部
这个是SwipMenuListView类中自己实现的方法,不是系统方法
/**
* 判断点击事件是否在某个view内
*
* @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;
}
4、GestureDetectorCompat
private GestureDetectorCompat mGestureDetector;
private OnGestureListener mGestureListener;
mGestureDetector = new GestureDetectorCompat(getContext(),
mGestureListener);
mGestureListener = new SimpleOnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
return super.onFling(e1, e2, velocityX, velocityY);
}
};
其实在这个接口中有很多关于手势的回调方法:
/**
* A convenience class to extend when you only want to listen for a subset
* of all the gestures. This implements all methods in the
* {@link OnGestureListener} and {@link OnDoubleTapListener} but does
* nothing and return {@code false} for all applicable methods.
*/
public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener {
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
public void onLongPress(MotionEvent e) {
}
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
return false;
}
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
return false;
}
public void onShowPress(MotionEvent e) {
}
public boolean onDown(MotionEvent e) {
return false;
}
public boolean onDoubleTap(MotionEvent e) {
return false;
}
public boolean onDoubleTapEvent(MotionEvent e) {
return false;
}
public boolean onSingleTapConfirmed(MotionEvent e) {
return false;
}
}
5、ScrollerCompat
跟Scroller一样,一般想要实现平滑过渡,可以使用
public static ScrollerCompat create(Context context, Interpolator interpolator) {
return new ScrollerCompat(context, interpolator);
}
这是个静态方法,直接用类可以调用,并且可以传入一个差值器,很有用的。
调用startScroll方法进行滑动
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
mImpl.startScroll(mScroller, startX, startY, dx, dy, duration);
}
最后需要覆写computeScroll方法完成
@Override
public void computeScroll() {
// ......
postInvalidate();
// ......
}
postInvalidate会调用view的draw方法,draw方法内部会调用computeScroll(源码中能找到),循环调用完成动画,computeScroll方法中需要有动画结束逻辑。