您的位置:首页 > 其它

通过下拉来学习Scroller的内容滑动原理

2015-10-27 22:24 267 查看
首先介绍位置参数

View的位置top,left,right,bottom,四个参数是相对于父容器来说的。
translationX和translationY是View左上角相对于父容器的偏移量,也只能在父控件里移动,若超过范围,刚无法看到,translationX= 最后的相对于父容器的偏移量X - left,所以如果往左移,translationX为负值;translationY= 最后的相对于父容器的偏移量Y - top,所以如果往上移,translationY 为负值。
x = left + translationX;
y = top + translationY;
还有两个移动的重要参数:mScroolerX和mScrollerY

mScrollerX = 父容器的左边界-View的X,所以当View左边缘在View内容左边缘的右边时,mScrollerX为正值,否则为负值。同理,当View上边缘在View内容上边缘的下边时,mScrollerY为正值,否则为负值。

Scroller的滑动原理是将一次大的滑动分成若干次小的滑动,并在一个时间段内完成。

通过调用mScroller.startScroller()->invalidate()->导致界面重绘->View的computeScroll()方法执行,需要重写这个方法,并调用scrollTo完成一次小的滑动,并postInvalidate();

具体例子如下:

package com.luoxf.drag.view;

import android.content.Context;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.widget.RelativeLayout;
import android.widget.Scroller;

/**
* Created by luoxf on 2015/10/27.
*/
public class MyRelativeLayout extends RelativeLayout{
private final String TAG = MyRelativeLayout.class.getSimpleName();
private int screenHeight;
private int screenWidth;
private Context mContext;
private Scroller mScroller;
private int mLastX;
private int mLastY;
private int touchSlop; //最小滑动距离
private boolean isNeedToUp = false;
public MyRelativeLayout(Context context) {
super(context);
initView(context);
}

public MyRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}

public MyRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}

private void initView(Context context) {
this.mContext = context;
this.mScroller = new Scroller(context);
touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
Point point = new Point();
wm.getDefaultDisplay().getSize(point);
screenWidth = point.x;
screenHeight = point.y;
}

//调用此方法滚动到目标位置
public void smoothScrollTo(int fx, int fy) {
int dx = fx - mScroller.getFinalX();
int dy = fy - mScroller.getFinalY();
smoothScrollBy(dx, dy);
}

//调用此方法设置滚动的相对偏移
public void smoothScrollBy(int dx, int dy) {
//设置mScroller的滚动偏移量
mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy);
invalidate();//这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果
}
@Override
public void computeScroll() {
//先判断mScroller滚动是否完成
if (mScroller.computeScrollOffset()) {
//这里调用View的scrollTo()完成实际的滚动
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
//必须调用该方法,否则不一定能看到滚动效果
postInvalidate();
}
}

@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
int deltaY = y - mLastY;
//滑到顶部
if(mScroller.getFinalY() - deltaY >= 0) {
smoothScrollTo(0, 0);
isNeedToUp = false;
}
//下滑大于屏幕三分之一
else if(mScroller.getFinalY() - deltaY < -screenHeight / 3) {
smoothScrollTo(0, -screenHeight / 3);
isNeedToUp = true;
} else {
smoothScrollBy(0, -deltaY);
isNeedToUp = true;
}
break;
case MotionEvent.ACTION_UP:
//自动滑到顶部
if(isNeedToUp) {
smoothScrollTo(0, 0);
}
break;
default:
break;
}
mLastX = x;
mLastY = y;
return true;
}
}


布局文件:

<com.luoxf.drag.view.MyRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/myRelativiLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
tools:context=".MainActivity">

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white">
<TextView
android:id="@+id/drag_demo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="ScrollDEMO"
android:layout_centerInParent="true"/>
</RelativeLayout>

</com.luoxf.drag.view.MyRelativeLayout>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: