Android UI绘制 -- 滑动
来源:互联网 发布:如何做网络舆情监测员 编辑:程序博客网 时间:2024/05/17 11:04
基础
scrollBy()、scrollTo()的本质都是修改View中的mScrollY、mScrollX;而修改这两个参数的效果就是View在绘制的时候会将整个View的坐标进行平移。
详见 不再迷惑,也许之前你从未真正懂得 Scroller 及滑动机制
Scroller
Scroller 只是一个普通的类,它封装了滚动事件,可用于View的平滑滚动效果。但是,它只是提供滚动时的数据变化,它本身不控制对于 View 的滚动动画。如何制作的平滑的滚动效果,这个责任在于开发者自己,Scroller 能做的就是提供数值及时间在一个滚动动画周期中的值。所以它只是一个辅助类。
当我们利用scrollBy()、scrollTo()来使得view移动时因为是瞬移会有迟钝感,Scroller可以类似属性动画一样让滑动变得平滑,同时提供快速滑动(即ListView用力滑动时会自动滚动一段距离后停下,即有一个初速度)。
public class CustomView extends LinearLayout { private static final String TAG = "Scroller"; private Scroller mScroller; public CustomView(Context context, AttributeSet attrs) { super(context, attrs); //Step 1. 创建一个Scroller mScroller = new Scroller(context); } //调用此方法滚动到目标位置 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) { //Step 2.设置要滑动的距离 mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy); invalidate();//这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果 } //Step 3.重写computeScroll,Scroller只是为我们计算了下一帧应该移动到哪里(这样才平滑,且可设置插值器),实际的移动需要我们在这里设置scrollTo @Override public void computeScroll() { //先判断mScroller滚动是否完成 if (mScroller.computeScrollOffset()) { //这里调用View的scrollTo()完成实际的滚动 scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); //必须调用该方法,否则不一定能看到滚动效果 postInvalidate(); } super.computeScroll(); } }
同时Scroller提供fling来支持快速滚动
//startX 开始滚动时 X 坐标//startY 开始滚动时 Y 坐标//velocityX 开始滚动时 X 方向的初始速度//velocityY 开始滚动时 Y 方向的初始速度//minX 滚动过程,X 坐标不能小于这个数值//maxX 滚动过程,X 坐标不能大于这个值//minY 滚动过程,Y 坐标不能小于这个数值//maxY 滚动过程,Y 坐标不能大于这个数值public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) {}
ViewDragHelper
适合实现View的拖拽效果
public class VDHLayout extends LinearLayout{ private ViewDragHelper mDragger; public VDHLayout(Context context, AttributeSet attrs) { super(context, attrs); //Step 1.创建一个ViewDragHelper mDragger = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() { //如何返回ture则表示可以捕获该view,根据传入的第一个view参数决定哪些可以捕获 @Override public boolean tryCaptureView(View child, int pointerId) { return true; } //可以在该方法中对child移动的边界进行控制,left为即将移动到的位置 @Override public int clampViewPositionHorizontal(View child, int left, int dx) { return left; } //可以在该方法中对child移动的边界进行控制,top为即将移动到的位置 @Override public int clampViewPositionVertical(View child, int top, int dy) { return top; } //手指释放回调,可以做回滚 @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { //手指释放时可以自动回去 if (releasedChild == XXXView) { mDragger.settleCapturedViewAt(初始位置X,初始位置Y); invalidate(); } } //在边界拖动时回调, @Override public void onEdgeDragStarted(int edgeFlags, int pointerId) { mDragger.captureChildView(XXXView, pointerId); } }); //边界回调要生效需要设置边界 mDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { //Step 2.将onInterceptTouchEvent是否拦截交给ViewDragHelper return mDragger.shouldInterceptTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { //Step 3.将touch事件传递给ViewDragHelper mDragger.processTouchEvent(event); return true; }}
这样VDHLayout里的子View就可以随意的拖拽了
Callback中未用到的方法
内部View可点击需重写下面两个方法
@Overridepublic int getViewHorizontalDragRange(View child){ return getMeasuredWidth()-child.getMeasuredWidth();}@Overridepublic int getViewVerticalDragRange(View child){ return getMeasuredHeight()-child.getMeasuredHeight();}
onViewDragStateChanged
当ViewDragHelper状态发生变化时回调(IDLE,DRAGGING,SETTING[自动滚动时])
onViewPositionChanged
当captureview的位置发生改变时回调
onViewCaptured
当captureview被捕获时回调
GestureDetector
用来辅助处理触摸事件,可以理解为是onTouchEvent的增强,为我们识别了各种手势事件:单击、双击、滑动、快速滑动、长按等等…
GestureDetectorm_gestur eDetector = new GestureDetector(context, onGestureListener);m_gestureDetector.setOnDoubleTapListener(onDoubleTapListener); @Override public boolean onTouchEvent(MotionEvent event) { //将touch事件交给gesture处理 m_gestureDetector.onTouchEvent(event); return super.onTouchEvent(event); }
GestureDetector包括的监听有
GesturetDetector.OnGestureListener 接口
GesttureDetector.OnDoubleTapListener 接口
GesttureDetector.SimpleOnGestureListener 类
ItemTouchHelper
ItemTouchHelper是一个强大的工具,它处理好了关于在RecyclerView上添加拖动排序与滑动删除的所有事情。它是RecyclerView.ItemDecoration的子类,也就是说它可以轻易的添加到几乎所有的LayoutManager和Adapter中。它还可以和现有的item动画一起工作,提供受类型限制的拖放动画等等
创建一个ItemTouchHelper.Callback实现下面几个方法
getMovementFlags
@Overridepublic int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END; return makeMovementFlags(dragFlags, swipeFlags);}
ItemTouchHelper可以让你轻易得到一个事件的方向。你需要重写getMovementFlags()方法来指定可以支持的拖放和滑动的方向。使用helperItemTouchHelper.makeMovementFlags(int, int)来构造返回的flag。这里我们启用了上下左右两种方向。注:上下为拖动(drag),左右为滑动(swipe)。
isLongPressDragEnabled是否允许长按拖动 isItemViewSwipeEnabled是否允许滑动
接下来是拖动/滑动结束后的回调,需要在这里处理数据
onMove onSwiped
@Overridepublic boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { return true;}@Overridepublic void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {}
搞定后记得notifyItemMoved(from, to);下 提醒控件更新。
ps:ItemTouchHelper原理:监听RecyclerView的ItemTouchListener,判断手指的滑动来为Item添加一个跟随手指移动的移动动画(补间动画),该动画会持续到手指松开;而当移动到它原位置的±1个位置的时候该位置的Item也发生一个单位位置的移动动画并调用onMove由我们主动设置两个Item的位置顺序(如果我们没有设置位置则只会有Item跟随手指移动的动画且释放后会回到原位)。
- Android UI绘制 -- 滑动
- android UI绘制
- Android-UI-绘制
- Android UI绘制
- Android UI绘制流程
- Android UI绘制之独立线程绘制
- Android UI 绘制之Skia
- Android UI绘制原理(一)
- Android UI绘制原理(二)
- Android UI的绘制流程
- Android UI绘制流程(一)
- Android UI绘制流程(二)
- Android-UI绘制分析01
- Android-UI绘制分析02
- Android UI 界面绘制原理分析
- Android UI绘制之View重绘
- Android UI详解之View绘制原理
- Android UI测量、布局、绘制过程探究
- 设计模式学习笔记(三)- -装饰者模式
- 关于GCD的一些技巧笔记
- Android gradle和gradle插件配置
- java的日志方案分析
- ubuntu常用命令 -- 用于查找
- Android UI绘制 -- 滑动
- 知识学习——Java文档注释
- dubbo源码分析(二):超时原理以及应用场景
- Java内存区域和GC机制
- 为什么马氏距离是与尺度无关的
- 物联网卡+“两轮车”开启防盗的新模式
- Spring定时任务,本地正常, Linux服务器跑两次的问题 。。
- AutoCAD 2018 for Mac(CAD三维设计绘图软件) v2018最新破解版
- 前端学习资源分享