Scroller的fling方法详解
2016-05-27 15:11
555 查看
Scroller概述
scroller的作用:作为一个developer,要有看官方文档的习惯,文档链接。
关于scroller的作用我就不叙述了,google一下有太多的介绍
案例分析
自定义一个viewgroup,在viewgroup里面有一个能滑动的view,且手指必须按在view上才能生效,松手后能缓慢的停下来;分析:滑动view首先想到的是使用Scrooler(ViewDragHelper及属性动画咱先不考虑)。滑动,首先想到的是startScroll方法。
咱们来看看这个方法
startScroll(int startX, int startY, int dx, int dy)
startScroll(int startX, int startY, int dx, int dy, int duration)
这两个方法的区别就是多了个duration,即需要滑动到目的位置需要的时间,类似animation里面的duration
看源码:
public void startScroll(int startX, int startY, int dx, int dy) { startScroll(startX, startY, dx, dy, DEFAULT_DURATION); }
其实最后调用的还是第二个方法,默认的滑动时间为250ms;
调用如下方法:
view.startScroll(getScroolX(), getScrollY(), -50, -50, )
代码意思为:从当前的scroolX scroolY,x轴移动50个像素,y轴移动50个像素。
但是我们的需求是需要松开手指后能继续滑动
所以,这里就得使用fling方法了,我们来看看fling方法的具体内容:
fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) Start scrolling based on a fling gesture.
由官网的解释来看,就知道了这是基于一个滑动手势的滑动
OK,这里我们需要用到另外一个计算速度的类VelocityTracker,关于使用方法请自行google
定位view的具体位置:
如果我们只是如下操作:
按下—>滑动—->抬起手指 —–>再按下—->滑动……
这类操作的话,那么我们很容易定位到view的具体位置,但是,我们需要的是在手指抬起后还能滑动,那么,此时我们怎么定位view的位置呢;
这里我们就需要了解下Scroller的坐标系问题了
一般来说,对于viewgroup,我们我获取里面的子view的坐标只需要getLeft和getTop来就能知道当前view的x,y坐标。
那么Scroller的
getScrollX(),
getScrollY()和
getFinalX(),
getFinalY(),这里的获取的X和Y到底是什么呢,通过初次打印log信息,发现得到的x,y值有点莫名其妙,跟view的坐标系好像没什么关系,但是通过滑动我们来看获取的scrolllX坐标的规律,不难明白,这里获取的scrolllX和scrollY是基于你需要滑动的那个view的位置的。
光说可能不好明白,有图为证:
到了这里,咱们就能很容易的搞定fling的状态下view的定位问题
贴上全部代码:
public class HoodleGroupView extends ViewGroup { private PointF mDownPoint; private RectF mChildeRectF; private VelocityTracker velocityTracker; private Scroller mScroller; private int mMaxFlintVelocity, mMinFlintVelocity; private int mChildMeasuredWidth,mChildMeasuredHeight; private View chileView; private boolean isFirPoint = true; private float lastX, lastY; public HoodleGroupView(Context context) { this(context, null); } public HoodleGroupView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public HoodleGroupView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initData(context); } private void initData(Context context) { mDownPoint = new PointF(); mChildeRectF = new RectF(); mScroller = new Scroller(context, null, true); ViewConfiguration viewConfiguration = ViewConfiguration.get(context); mMaxFlintVelocity = viewConfiguration.getScaledMaximumFlingVelocity(); mMinFlintVelocity = viewConfiguration.getScaledMinimumFlingVelocity(); mMinFlintVelocity = 600; } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { LogUtil.e("onLayout"); chileView = getChildAt(0); int measuredWidth = getMeasuredWidth(); int measuredHeight = getMeasuredHeight(); mChildMeasuredWidth = chileView.getMeasuredWidth(); mChildMeasuredHeight = chileView.getMeasuredHeight(); mChildeRectF.set(measuredWidth / 2 - mChildMeasuredWidth / 2, measuredHeight / 2 - mChildMeasuredHeight / 2, measuredWidth / 2 + mChildMeasuredWidth / 2, measuredHeight / 2 + mChildMeasuredHeight / 2); chileView.layout(measuredWidth / 2 - mChildMeasuredWidth / 2, measuredHeight / 2 - mChildMeasuredHeight / 2, measuredWidth / 2 + mChildMeasuredWidth / 2, measuredHeight / 2 + mChildMeasuredHeight / 2); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { measureChildren(widthMeasureSpec,heightMeasureSpec); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override public void onHoverChanged(boolean hovered) { LogUtil.e("onHoverChanged"); super.onHoverChanged(hovered); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { LogUtil.e("onScrollChanged,l=" + l + ",t=" + t + ",oldl=" + oldl + ",oldt=" + oldt); // mChildeRectF.set(mChildeRectF.left - l, mChildeRectF.top - t, mChildeRectF.right - l, mChildeRectF.bottom - t); super.onScrollChanged(l, t, oldl, oldt); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { // return super.onTouchEvent(event); if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain(); } velocityTracker.addMovement(event); int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: mDownPoint.x = event.getX(); mDownPoint.y = event.getY(); lastX = event.getX(); lastY = event.getY(); LogUtil.e("down_x=" + lastX + ",down_y=" + lastY); //判断按下的手指是否在图片上面 if(!isViewUnderPoint(mDownPoint)){ return false; } if(!mScroller.isFinished()){ mScroller.abortAnimation(); } break; case MotionEvent.ACTION_MOVE: float ev_x = event.getX(); float ev_y = event.getY(); scrollBy((int) (-ev_x + lastX), (int) (-ev_y + lastY)); // mChildeRectF.set(mChildeRectF.left + ev_x - lastX, mChildeRectF.top + ev_y - lastY, mChildeRectF.right + ev_x - lastX, mChildeRectF.bottom + ev_y - lastY); lastX = ev_x; lastY = ev_y; break; case MotionEvent.ACTION_UP: //手指抬起,计算当前速率 float up_x = event.getX(); float up_y = event.getY(); velocityTracker.computeCurrentVelocity(1000, mMaxFlintVelocity); int xVelocity = (int) velocityTracker.getXVelocity(); int yVelocity = (int) velocityTracker.getYVelocity(); int scrollX = getScrollX(); int scrollY = getScrollY(); LogUtil.e("mMinFlintVelocity=" + mMinFlintVelocity + ",xVelocity=" + xVelocity + ",yVelocity=" + yVelocity); if (Math.abs(xVelocity) > mMinFlintVelocity && Math.abs(yVelocity) > mMinFlintVelocity) { mScroller.fling(scrollX, scrollY, -xVelocity, -yVelocity, 0, getWidth() - chileView.getWidth(), 0, getHeight() - chileView.getHeight()); LogUtil.e("up_x=" + up_x + ",up_y=" + up_y + "scrollX=" + scrollX + ",scrollY=" + scrollY + ", startX=" + mScroller.getStartX() + ", startY=" + mScroller.getStartY() + ", width=" + getWidth() + ",childWidth=" + chileView.getWidth() + ",height=" + getHeight() + ",childheight=" + chileView.getHeight()); int startX = mScroller.getStartX(); int startY = mScroller.getStartY(); int finalX = mScroller.getFinalX(); int finalY = mScroller.getFinalY(); mChildeRectF.set(chileView.getLeft() - finalX, chileView.getTop() -finalY, chileView.getRight() - finalX, chileView.getBottom() -finalY); int dex_x, dex_y; LogUtil.e("upx=" + up_x + ",upy=" + up_y + ",pontX=" + mDownPoint.x + ",pontY=" + mDownPoint.y); if(up_x > mDownPoint.x) { //证明往右滑动 dex_x = finalX - startX; }else { dex_x = startX - finalX; } if (up_y > mDownPoint.y) { dex_y = finalY - startY; }else { dex_y = startY - finalY; } LogUtil.e("dex="+dex_x+",dey="+dex_y+"left="+mChildeRectF.left+",top="+mChildeRectF.top+"finalX=" + mScroller.getFinalX() + ",finalY=" + mScroller.getFinalY()); // mChildeRectF.set(mChildeRectF.left + dex_x, mChildeRectF.top + dex_y, mChildeRectF.right + dex_x, mChildeRectF.bottom + dex_y); LogUtil.e("left="+mChildeRectF.left+",top="+mChildeRectF.top); awakenScrollBars(mScroller.getDuration()); invalidate(); }else { mChildeRectF.set(chileView.getLeft() - scrollX, chileView.getTop() -scrollY, chileView.getRight() - scrollX, chileView.getBottom() -scrollY); } if (velocityTracker != null) { velocityTracker.clear(); } break; case MotionEvent.ACTION_CANCEL: LogUtil.e("-----ACTION_CANCEL"); break; } return true; } private boolean isViewUnderPoint(PointF pointF) { return mChildeRectF.contains(pointF.x, pointF.y); } @Override public void computeScroll() { super.computeScroll(); if (mScroller.computeScrollOffset()) { LogUtil.e("computeScroll---"+mScroller.getCurrX()+","+mScroller.getCurrY()); scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } } }
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories