1.简介
Scroller是一个专门用于处理滚动效果的工具类,可能在大多数情况下,我们直接使用Scroller的场景并不多,但是很多大家所熟知的控件在内部都是使用Scroller来实现的,如ViewPager、ListView等。
2.View的scrollBy和scrollTo方法
2.1.图解
2.2.scrollBy方法
2.2.1.方法
public void scrollBy (int x, int y)
2.2.2.作用
移动你视图的滚动位置。这将导致对onScrollChanged(int, int, int, int)的调用,视图将被无效。
2.2.3.参数
x:X轴(水平)方向移动的距离。正值向左移动,负值向右移动,单位是像素。
y:Y轴(垂直)方向移动的距离。正值向上移动,负值向下移动,单位是像素。
2.3.scrollTo方法
2.3.1.方法
public void scrollTo (int x, int y)
2.3.2.作用
设置视图的滚动位置。这将导致对onScrollChanged(int, int, int, int)的调用,视图将被无效。
2.3.3.参数
x:X轴(水平)方向移动到目的坐标。正值向左移动,负值向右移动,单位是像素。
y:Y轴(垂直)方向移动到目的坐标。正值向上移动,负值向下移动,单位是像素。
2.3.scrollTo实现Demo
2.3.1.布局
2.3.2.Java代码
public class MarginLayoutParamsActivity extends AppCompatActivity {
private RelativeLayout layout;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_marginlayoutparams);
layout= (RelativeLayout) findViewById(R.id.activity_marginlayout_layout);
textView= (TextView) findViewById(R.id.activity_marginlayout_textview1);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
layout.scrollTo(-100, -100);
}
});
}
}
2.3.3.效果
原始:
点击(scrollTo到某某 所以点击一次到达指定目的地后再点击无效果)
2.4.scrollBy实现Demo
2.4.1.布局
2.4.2.Java代码
public class MarginLayoutParamsActivity extends AppCompatActivity {
private RelativeLayout layout;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_marginlayoutparams);
layout= (RelativeLayout) findViewById(R.id.activity_marginlayout_layout);
textView= (TextView) findViewById(R.id.activity_marginlayout_textview1);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
layout.scrollBy(-100, -100);
}
});
}
}
2.4.3.效果
原始:
点击
多次点击
3. Scroller工具类使用(参考:https://blog.csdn.net/guolin_blog/article/details/48719871)
3.1. Scroller使用步骤
3.1.1. 创建Scroller的实例。
3.1.2. 调用startScroll()方法来初始化滚动数据并刷新界面。
3.1.3. 重写computeScroll()方法,并在其内部完成平滑滚动的逻辑。
3.2.Demo实现仿ViewPager滑动
3.2.1.自定义View
public class ScrollerLayout extends ViewGroup {
/**
* 用于完成滚动操作的实例
*/
private Scroller mScroller;
/**
* 判定为拖动的最小移动像素数
*/
private int mTouchSlop;
/**
* 手机按下时的屏幕坐标
*/
private float mXDown;
/**
* 手机当时所处的屏幕坐标
*/
private float mXMove;
/**
* 上次触发ACTION_MOVE事件时的屏幕坐标
*/
private float mXLastMove;
/**
* 界面可滚动的左边界
*/
private int leftBorder;
/**
* 界面可滚动的右边界
*/
private int rightBorder;
public ScrollerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// 第一步,创建Scroller的实例
mScroller = new Scroller(context);
ViewConfiguration configuration = ViewConfiguration.get(context);
// 获取TouchSlop值
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
}
@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
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();
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mXDown = ev.getRawX();
mXLastMove = mXDown;
break;
case MotionEvent.ACTION_MOVE:
mXMove = ev.getRawX();
float diff = Math.abs(mXMove - mXDown);
mXLastMove = mXMove;
// 当手指拖动值大于TouchSlop值时,认为应该进行滚动,拦截子控件的事件
if (diff > mTouchSlop) {
return true;
}
break;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
mXMove = event.getRawX();
int scrolledX = (int) (mXLastMove - mXMove);
if (getScrollX() + scrolledX < leftBorder) {
scrollTo(leftBorder, 0);
return true;
} else if (getScrollX() + getWidth() + scrolledX > rightBorder) {
scrollTo(rightBorder - getWidth(), 0);
return true;
}
scrollBy(scrolledX, 0);
mXLastMove = mXMove;
break;
case MotionEvent.ACTION_UP:
// 当手指抬起时,根据当前的滚动值来判定应该滚动到哪个子控件的界面
int targetIndex = (getScrollX() + getWidth() / 2) / getWidth();
int dx = targetIndex * getWidth() - getScrollX();
// 第二步,调用startScroll()方法来初始化滚动数据并刷新界面
mScroller.startScroll(getScrollX(), 0, dx, 0);
invalidate();
break;
}
return super.onTouchEvent(event);
}
@Override
public void computeScroll() {
// 第三步,重写computeScroll()方法,并在其内部完成平滑滚动的逻辑
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();
}
}
}
3.2.2.布局
3.2.3.Java代码使用
public class MarginLayoutParamsActivity extends AppCompatActivity {
private ScrollerLayout scrollerLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_marginlayoutparams);
scrollerLayout= (ScrollerLayout) findViewById(R.id.activity_marginlayout_scrollerlayout);
scrollerLayout.removeAllViewsInLayout();
for(int i=0;i<3;i++){
TextView textView=new TextView(this);
textView.setBackgroundColor(Color.RED);
textView.setTextColor(Color.WHITE);
textView.setClickable(true);
ViewGroup.LayoutParams layoutParams=new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,300);
textView.setText("Scroller滑动Demo-"+"TextView-"+(i+1));
textView.setGravity(Gravity.CENTER);
textView.setLayoutParams(layoutParams);
scrollerLayout.addView(textView);
}
}
}