参考:http://blog.csdn.net/guolin_blog/article/details/48719871
Scroller是一个专门用于处理滚动效果的工具类,很多熟知的控件内部都用到了Scroller,例如Viewpager.本篇文章来自定义一个ViewGroup实现Viewpager的功能。
首先看几个方法:
scrollTo()方法是让View相对于初始的位置滚动某段距离,而scrollBy()方法是让View相对于当前的位置滚动某段距离。
其中参数均指的时偏移量而不是坐标,如果view向左移动,参数为正,向右移动参数为负。例如:
View有(10,10)移动到(110,110),偏移量即为10-110=-100.
再来看getScrollX()和getScrollY()方法,查了很多博客文章,发现有些文章说的略有模糊,下面时我的见解:
getScrollX 得到的值应该时手机屏幕左边缘在View坐标系的值,如下图,此时getScrollx()应该为100;
image同理,getScrollY也是一样的道理。
最后时代码实现:
package com.example.scrollview;
import android.content.Context;
import android.support.v4.view.ViewConfigurationCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;
/**
* Created by 张翔宇 on 2018/4/2.
*/
public class scrollgroupextends ViewGroup {
int leftborder;
int rightborder;
Scrollerscroller;
int scrollx;
int downx;
int firstx;
int lastx;
private int mTouchSlop;
public scrollgroup(Context context) {
super(context);
}
public scrollgroup(Context context, AttributeSet attrs) {
super(context, attrs);
scroller=new Scroller(context);
ViewConfiguration configuration = ViewConfiguration.get(context);
// 获取TouchSlop值
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
}
public scrollgroup(Context context, AttributeSet attrs,int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {
int size=getChildCount();
int measurwidth=0;
int measurheight=0;
for(int i=0;i
View childview=getChildAt(i);
measureChild(childview,widthMeasureSpec,heightMeasureSpec);
}
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),MeasureSpec.getSize(heightMeasureSpec));
}
@Override
protected void onLayout(boolean changed,int l,int t,int r,int b) {
for(int i=0;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:
downx= (int) ev.getRawX();
firstx=downx;
break;
case MotionEvent.ACTION_MOVE:
lastx= (int) ev.getRawX();
int movex=Math.abs(firstx-lastx);
if(movex>mTouchSlop){
return true;
}
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_MOVE:
lastx= (int) event.getRawX();
scrollx=firstx-lastx;
if(getScrollX()+scrollx
scrollTo(leftborder,0);
}else if(getScrollX()+getWidth()+scrollx>rightborder){
scrollTo(rightborder-getWidth(),0);
}
else
{
scrollBy(scrollx,0);
}
firstx=lastx;
break;
case MotionEvent.ACTION_UP:
int treasurex=(getScrollX()+getWidth()/2)/getWidth();
int dx=treasurex*getWidth()-getScrollX();
scroller.startScroll(getScrollX(),0,dx,0);
invalidate();
break;
}
return super.onTouchEvent(event);
}
@Override
public void computeScroll() {
if(scroller.computeScrollOffset()){
scrollTo(scroller.getCurrX(),scroller.getCurrY());
invalidate();
}
}
}
我们重写onInterceptTouchEvent函数,在手指移动时,判断当前View是否处于拖动状态,即是否大于了mTouchSlop,是的话,返回true,表明scrollview可以处理该事件。接下来就执行onTouchEvent里的逻辑,之间判断了是否超过了边界。在手指抬起时,使用Scroller来完成后续的滚动操作。首先这里我们先根据当前的滚动位置来计算布局应该继续滚动到哪一个子控件的页面,然后计算出距离该页面还需滚动多少距离。接下来我们就该进行上述步骤中的第二步操作,调用startScroll()方法来初始化滚动数据并刷新界面。startScroll方法执行需重复调用computeScroll方法,利用Scroller的computeScrollOffset()方法来进行判断滚动操作是否已经完成了,如果还没完成的话,那就继续调用scrollTo()方法,并把Scroller的curX和curY坐标传入,然后刷新界面从而完成平滑滚动的操作。
最后结果就不粘贴了,还是很完美的哈哈。
网友评论