前言
我们在list view或者recycle view当中的某个item向左滑动时,可以显示出删除的按钮,这种交互方式使用的非常多,今天就来学习一下它的实现原理。
Scroller的使用
首先我们需要知道view 当中的2个与scroll相关的方法:scrollTo(x,y),scrollBy(x,y),
这个两个方法的区别就是,to是相对的是view的原始坐标,而by是相对view的当前坐标。
- scrollBy是基于view内容当前位置进行增量式的相对滑动
-
而scrollTo则是相对于view的绝对坐标进行滑动。
下面是2种实现的区别效果:
scrollTo()方法是让View相对于初始的位置滚动某段距离,由于View的初始位置是不变的,因此不管我们点击多少次scrollTo按钮滚动到的都将是同一个位置。而scrollBy()方法则是让View相对于当前的位置滚动某段距离,那每当我们点击一次scrollBy按钮,View的当前位置都进行了变动,因此不停点击会一直向右下方移动。
下面是一个自定义的viewgrop的示例,通过运用scrollTo和scrollBy,类似于viewpage效果。
package com.example.daixin.a3dtest;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewConfigurationCompat;
import android.text.SpanWatcher;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;
/**
* TODO: document your custom view class.
*/
public class ScrollerLayout extends ViewGroup{
private Scroller scroller;
private int touchSlop;
private float xDown;
private float xMove;
private float xLastMove;
private int leftBorder;
private int rightBorder;
String TAG = "ScrollerLayout";
public ScrollerLayout(Context context) {
super(context);
init(context);
}
public ScrollerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ScrollerLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context){
scroller = new Scroller(context);
ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
touchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(viewConfiguration);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
// 为ScrollerLayout中的每一个子控件测量大小
measureChild(childView, widthMeasureSpec, heightMeasureSpec);
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
xDown = ev.getRawX();
xLastMove = ev.getRawX();
//Log.e(TAG,"onInterceptTouchEvent ACTION_DOWN xLastMove:"+xLastMove);
break;
case MotionEvent.ACTION_MOVE:
xLastMove = ev.getRawX();
//Log.e(TAG,"onInterceptTouchEvent ACTION_MOVE xLastMove:"+xLastMove);
float diff = Math.abs(xMove - xDown);
if (diff > touchSlop) {
return true;
}
break;
case MotionEvent.ACTION_UP:
break;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG,"ACTION_MOVE getScrollX:"+getScrollX());
xMove = event.getRawX();
//Log.e(TAG,"xMove:"+xMove);
//Log.e(TAG,"xLastMove:"+xLastMove);
int scrolledX = (int) (xLastMove - xMove);
Log.e(TAG,"scrolledX:"+scrolledX);
if (getScrollX() + scrolledX < leftBorder) {
scrollTo(leftBorder, 0);
return true;
} else if (getScrollX() + getWidth() + scrolledX > rightBorder) {
scrollTo(rightBorder - getWidth(), 0);
return true;
}
scrollBy(scrolledX, 0);
xLastMove = xMove;
break;
case MotionEvent.ACTION_UP:
//Log.e(TAG,"getScrollX:"+getScrollX());
//Log.e(TAG,"getWidth:"+getWidth());
//判断当前处于哪个view的界面,得到targetIndex的值
int targetIndex = (getScrollX() + getWidth() / 2) / getWidth();
Log.e(TAG,"targetIndex:"+targetIndex);
int dx = targetIndex * getWidth() - getScrollX();
//Log.e(TAG,"dx:"+dx);
// 第二步,调用startScroll()方法来初始化滚动数据并刷新界面,会不断调用computeScroll来更新。
scroller.startScroll(getScrollX(), 0, dx, 0);
invalidate();
break;
}
return super.onTouchEvent(event);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
// 为ScrollerLayout中的每一个子控件在水平方向上进行布局
childView.layout(i * childView.getMeasuredWidth(), 0, (i + 1) * childView.getMeasuredWidth(), childView.getMeasuredHeight());
}
// 初始化左右边界值
leftBorder = getChildAt(0).getLeft();
rightBorder = getChildAt(getChildCount() - 1).getRight();
}
Log.e(TAG,"leftBorder:"+leftBorder);
Log.e(TAG,"rightBorder:"+rightBorder);
}
@Override
public void computeScroll() {
//super.computeScroll();
if (scroller.computeScrollOffset()) {
scrollTo(scroller.getCurrX(), scroller.getCurrY());
invalidate();
}
}
}