一 VelocityTracker
速度追踪,手指在滑动中的速度,包括水平和竖直方向。
计算公式: 速度 =(终点位置-起点位置)/ 时间段
使用:
VelocityTracker velocityTracker= VelocityTracker.obtain() ;
velocityTracker.addMovement(event);
velocityTracker.computeCurrentVelocity(1000);
int xVelocity = (int) velocityTracker.getXVelocity();
int yVelocity = (int) velocityTracker.getYVelocity();
最后需要重置和回收
velocityTracker.clear();
velocityTracker.recycle();
二 关于scroll
public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}
/**
* Move the scrolled position of your view. This will cause a call to
* {@link #onScrollChanged(int, int, int, int)} and the view will be
* invalidated.
* @param x the amount of pixels to scroll by horizontally
* @param y the amount of pixels to scroll by vertically
*/
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}
- scrollTo 绝对滑动(以画布为参照)
- scrollBy 相对滑动 (相对于自己上一次的位置)
mScrollX 通过getScrollX可获得 是 View左边缘和内容左边缘水平距离,单位像素
mScrollY 通过getScrollY可获得 是 View上边缘和内容上边缘竖直距离,单位像素
注意滑动的是View的内容,本身位置不变。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/linear"
android:layout_width="300dp"
android:layout_height="300dp"
android:background="#FFF68F"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFC1C1"
android:orientation="vertical">
<Button
android:id="@+id/btn_scollto"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:text="使用ScrollTo" />
<Button
android:id="@+id/btn_scollby"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:text="使用ScrollBy" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
LinearLayout linear = findViewById(R.id.linear);
findViewById(R.id.btn_scollto).setOnClickListener(v -> {
Log.i("scroll", "scrollTo移动前: scrollx= " + linear.getScrollX() + " scrollY= " + linear.getScrollY() );
linear.scrollTo(-50,-50);
Log.i("scroll", "scrollTo移动后: scrollx= " + linear.getScrollX() + " scrollY= " + linear.getScrollY() );
});
findViewById(R.id.btn_scollby).setOnClickListener(v -> {
Log.i("scroll", "scrollBy移动前: scrollx= " + linear.getScrollX() + " scrollY= " + linear.getScrollY() );
linear.scrollBy(-50,-50);
Log.i("scrolls", "scrollBy移动后: scrollx= " + linear.getScrollX() + " scrollY= " + linear.getScrollY() );
});
通过上述例子可以看到移动的是View的内容,本身位置没有改变。注意观察其scrollTo和scrollBy的区别。以及移动位置的正负值。
除了scroll方式以为还有动画和改变View的布局参数可以产生滑动的效果。三种方式的区别:
scroll 滑动View的内容,不能滑动View本身
动画:滑动后点击事件在新的位置无法点击,本身位置没有变。适用于没有交互,复杂动画效果。
三 弹性滑动
原理 将一次大的滑动分为若干次小的滑动并在一个时间段内完成
1.scroller的弹性滑动
public class MyScroller extends LinearLayout {
private final static String TAG ="MyScroller";
Scroller mScroller;
public MyScroller(Context context) {
super(context);
mScroller = new Scroller(context);
}
public MyScroller(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
}
public MyScroller(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mScroller = new Scroller(context);
}
public void smoothScrollerTo(int x){
int scrollX = getScrollX();
int deltaX = x -scrollX;
//1000ms内完成滑动
mScroller.startScroll(scrollX,0,deltaX,0,1000);
invalidate();
}
@Override
public void computeScroll() {
// super.computeScroll();
if(mScroller.computeScrollOffset()){
scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
postInvalidate();
}
}
}
MyScroller myScroller = findViewById(R.id.myScroller);
findViewById(R.id.btn_scollto).setOnClickListener(v -> {
myScroller.smoothScrollerTo(-400);
});
<?xml version="1.0" encoding="utf-8"?>
<com.example.scroll.MyScroller xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/myScroller"
android:orientation="vertical">
<Button
android:id="@+id/btn_scollto"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:text="scroller弹性滑动" />
</com.example.scroll.MyScroller>
效果:
如果把smoothScrollerTo里面的invalidate注释掉,是否还能滑动呢?不能
由于invalidate方法会导致View重绘,会调用draw方法,在draw里面会调用computeScroll方法。
2.利用动画实现弹性滑动
原理:在动画每一帧到来时获取动画完成的比例,根据这个比例计算当前View要滑动的距离。
LinearLayout myScroller = findViewById(R.id.linear);
findViewById(R.id.btn_scollto).setOnClickListener(v -> {
startAnimaScroll(myScroller);
});
private void startAnimaScroll(View view){
int startX = 0;
int deltaX = -500;
ValueAnimator animator = ValueAnimator.ofInt(0, 1).setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float fraction = animator.getAnimatedFraction();
view.scrollTo(
startX + (int) (deltaX * fraction), 0
);
}
});
animator.start();
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/linear"
android:orientation="vertical">
<Button
android:id="@+id/btn_scollto"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:text="scroller弹性滑动" />
</LinearLayout>
3.使用延时策略
通过发送一系列消息达到渐进式效果。
比如在Handler里面连续不断的发消息,然后接收到消息按比例滑动