ImageVerifierCode 换一换
格式:DOCX , 页数:20 ,大小:294.40KB ,
资源ID:10564649      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/10564649.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Android 中 View移动总结ViewDragHelper学习及用法详解.docx)为本站会员(b****7)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Android 中 View移动总结ViewDragHelper学习及用法详解.docx

1、Android 中 View移动总结ViewDragHelper学习及用法详解Android 中 View移动总结:ViewDragHelper学习及用法详解如上图简单呈现出两个方块后,提出一个需求:1.拖动方块时,方块(即子View)可以跟随手指移动。2.一个方块移动时,另一个方块可以跟随移动。3.将方块移动到左边区域(右边区域)后放开(即手指离开屏幕),它会自动移动到左边界(右边界)。4.移动的时候给方块加点动画(duangduangduang)。View移动的相关方法总结:1. layout在自定义控件中,View绘制的一个重写方法layout(),用来设置显示的位置。所以,可以通过修改

2、View的坐标值来改变view在父View的位置,以此可以达到移动的效果!但是缺点是只能移动指定的View:/通过layout方法来改变位置view.layout(l,t,r,b);2.offsetLeftAndRight() 和offsetTopAndBottom()非常方便的封装方法,只需提供水平、垂直方向上的偏移量,展示效果与layout()方法相同。view.offsetLeftAndRight(offset);/同时改变left和rightview.offsetTopAndBottom(offset);/同时改变top和bottom3. LayoutParams此类保存了一个View

3、的布局参数,可通过LayoutParams动态改变一个布局的位置参数,以此动态地修改布局,达到View位置移动的效果!但是在获取getLayoutParams()时,要根据该子View对应的父View布局来决定自身的LayoutParams。所以一切的前提是:必须要有一个父View,否则无法获取LayoutParams!/必须获取父View的LayoutParamsLinearLayout.LayoutParamslayoutParams = (LinearLayout.LayoutParams)getLayoutParams();layoutParams.leftMargin = getLe

4、ft() + dx;layoutParams.topMargin = getTop() + dy;setLayoutParams(layoutParams);4. scrollTo和scrollBy通过改变scrollX和scrollY来移动,但是可以移动所有的子View。scrollTo(x,y)表示移动到一个具体的坐标点(x,y),而scrollBy(x,y)表示移动的增量为dx,dy。scrollTo(x,y);scrollBy(xOffset,yOffset);注意:这里使用scrollBy(xOffset,yOffset);,你会发现并没有效果,因为以上两个方法移动的是View的co

5、ntent。若在ViewGroup中使用,移动的是所有子View;若在View中使用,移动的是View的内容(比如TextView)。所以,不可在view中使用以上方法!应该在View所在的ViewGroup中使用:(View)getParent().scrollBy(offsetX, offsetY);【视图坐标系】:可是即使这样,你会发现view移动的效果与设想方向相反!这是Android试图移动原因,若参数为正值,content将向坐标轴负方向移动;参数为负值,content将向坐标轴正方向移动。所以要实现随手指移动而滑动的效果,应将偏移量设置为负值即可:(View)getParent(

6、).scrollBy(-offsetX, -offsetY);5. canvas通过改变Canvas绘制的位置来移动View的内容,用的少:canvas.drawBitmap(bitmap, left, top, paint)总结但是要完成最开始的提的需求,不管使用哪一种方法,都需要通过onTouchEvent方法来捕捉手势,自己手动计算移动距离,再改变子View的布局,不免有些麻烦,所以在这里引出正文,介绍一个强大的类来处理移动:ViewDragHelperViewDragHelper介绍:1. 产生:ViewDragHelper在高版本的v4包(android4.4以上的v4)中,于Goo

7、gle在2013年开发者大会提出的2. 作用:它主要用于处理ViewGroup中对子View的拖拽处理。3. 使用:它主要封装了对View的触摸位置,触摸速度,移动距离等的检测和Scroller,通过接口回调的方式通知我们。所以我们需要做的只是用接收来的数据指定这些子View是否需要移动,移动多少等。4. 本质:是一个对触摸事件的解析类。ViewDragHelper实现1. ViewDragHelper实例创建/* * Factory method to create a new ViewDragHelper. * * paramforParent Parent view to monitor

8、 * param sensitivity Multiplier for how sensitive the helper should be about detecting*the start of a drag. Larger values are more sensitive. 1.0f is normal. * paramcb Callback to provide information and receive events * return a new ViewDragHelper instance */viewDragHelper = ViewDragHelper.create(f

9、orParent, sensitivity, cb);create()就是创建ViewDragHelper实例的方法,代码中的注释是create()中参数的解释,来查看:(1)forParent:“用来监视的父View”。传入参数父View,即可监视该父View中的所有子View。(2)sensitivity:“检测时的敏感度;值越大越敏感,1是正常范围”。比如说手指在滑动屏幕时速度特别快,敏感度越大时,此时速度快也可以检测到,反之亦然。(3)Callback :“提供信息和接受的事件”。最重要的参数!可以从这个回调提供的信息获取到View滑动的距离、速度等。2. 自定义View继承Frame

10、Layout这里来个小提示:之前实现的布局中自定义DragLayout是继承于ViewGroup,并且实现重写了onMeasure()方法,如下:DragLayout.javapublicclassDragLayoutextendsViewGroup .OverrideprotectedvoidonMeasure(intwidthMeasureSpec, intheightMeasureSpec) super.onMeasure(widthMeasureSpec, heightMeasureSpec);/方法一:对子View的测量需求/*获取子View的宽度100dp 的两种方法:int si

11、ze = (int) getResources().getDimension(R.dimen.width);int size = readView.getLayoutParams().width;*/intmeasureSpec = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().width, MeasureSpec.EXACTLY);/具体指定宽高,为精确模式redView.measure(measureSpec,measureSpec);/当父控件测量完子控件,才可以填(0,0)blueView.measure(measureSp

12、ec,measureSpec);/* /方法二:如果说没有特殊的对子View的测量需求,可用如下方法measureChild(redView,widthMeasureSpec,heightMeasureSpec);measureChild(blueView,widthMeasureSpec,heightMeasureSpec);*/ 但是现在使DragLayout类继承于FrameLayout即可!publicclassDragLayoutextendsFrameLayout .因为在自定义ViewGroup的时候,如果对子View的测量没有特殊的需求,那么可以继承系统已有的布局(比如Fram

13、eLayout、RelativeLayout),目的是为了让已有的布局帮我们实现onMeasure()。所以在继承之后,我们无需实现onMeasure()方法,以上代码全部不需要(这里选择继承FrameLayout帧布局,原因是在Android源码中其实现最简单),所以重写继承的onLayout()方法其实是重写帧布局中的onLayout(),如果也注释的话,你会发现蓝色小方块覆盖红色,一起摆放在左上角(其实就是帧布局的摆放规则)3. callback回调创建privateViewDragHelper.Callback callback = new Callback() /必须要实现的方法Ov

14、erridepublicbooleantryCaptureView(View child, intpointerId) returnfalse; ;4. 触摸、拦截事件以上部分ViewDragHelper的创建部分已完成,可是还没结束。比如大家熟悉的一个类:GestureDetector手势识别器,想要它生效,必须传一个触摸事件,这样GestureDetector类才可以解析当前手势。道理相同,之前在介绍ViewDragHelper已提到,它只是一个对触摸事件的解析类,需要传一个触摸事件,才会生效。/处理是否拦截OverridepublicbooleanonInterceptTouchEven

15、t(MotionEventev) /由viewDragHelper来判断是否应该拦截此事件boolean result = viewDragHelper.shouldInterceptTouchEvent(ev);return result; OverridepublicbooleanonTouchEvent(MotionEvent event) /将触摸事件传给viewDragHelper来解析处理viewDragHelper.processTouchEvent(event);/消费掉此事件,自己来处理returntrue; 以上则viewDragHelper可以监视并解析我们的手势了,而且

16、会把信息通过回调传递给callback。5. 处理computeScroll()该方法是Scroller类的核心,系统在绘制View的时候在draw()中调用此方法,实际与scrollTo()相同。 Overridepublic void computeScroll() puteScroll();if(puteScrollOffset()scrollTo(scroller.getCurrX(),scroller.getCurrY();invalidate(); 如上,Scroller类提供computeScrollOffset()方法来判断是否完成了整个滑动,同时getCurrX()和getC

17、urrY()来获得当前滑动坐标。重点是invalidate()方法,因为只能在computeScroll()方法中获取模拟过程中的scrollX和scrollY,但computeScroll()方法是不会自动调用的,只能通过invalidate() draw() computeScroll()来间接调用computeScroll()方法!模拟过程结束,if判断中computeScrollOffset()方法返回false,中断循环,完成整个平滑移动过程!但是!我们并不采取以上方法,之前介绍过ViewDragHelper已经封装好了Scroller,用另外一种:Overridepublicvoi

18、dcomputeScroll() puteScroll();if(viewDragHelper.continueSettling(true)ViewCompat.postInvalidateOnAnimation(DragLayout.this); continueSettling()方法判断是否结束,同Scroller的方法相似,主要是postInvalidateOnAnimation(),此方法不像Scroller的scrollTo,还需要传值,其实此方法体内已经封装好移动的方法,它会自动去测量当前位置进行移动,所以我们只需调用即可!(在手指抬起时回调的方法中也会用到它,后面介绍)6. 实

19、现callback回调中的方法之前在创建callback时,默认只实现了tryCaptureView()方法,完成需求仅仅不够,还需要其它方法,依次介绍:(1)tryCaptureView()此方法用于判断是否捕获当前child的触摸事件,可以指定ViewDragHelper移动哪一个子View。此例中,需要移动两个方块,则判断当前View是否是自己想移动的,返回boolean值。/*用于判断是否捕获当前child的触摸事件 * param child 当前触摸的子View * return true:捕获并解析 false:不处理 */OverridepublicbooleantryCapt

20、ureView(View child, intpointerId) return child = blueView | child = redView; (2)onViewCaptured()此方法在View被开始捕获和解析时回调,即当tryCaptureView()中的返回值为true的时候,此方法才会被调用。例如tryCaptureView()方法中只捕获红色方块,当移动红方快时,该方法会回调,移动蓝色方块时则不会!/* 当View被开始捕获和解析的回调(用处不大) * paramcapturedChild当前被捕获的子View */OverridepublicvoidonViewCapt

21、ured(View capturedChild, intactivePointerId) super.onViewCaptured(capturedChild, activePointerId);Log.e(tag,onViewCaptures); (3)clampViewPositionHorizontal() 和clampViewPositionVertical()这两个为具体滑动方法,分别对应水平和垂直方向上的移动。要想子View移动,此方法必须重写实现!而方法的返回值则是指定View在水平(left)或垂直(top)方向上变成的值,参数中的dx、dy则是代表相较于上一次位置的增量。/*

22、 控制child在水平方向的移动 * param child * param left ViewDragHelper会将当前child的left值改变成返回的值 * param dx 相较于上一次child在水平方向上移动的 * return */OverridepublicintclampViewPositionHorizontal(View child, int left, int dx) return left; /*控制child在垂直方向的移动 * param child * param top ViewDragHelper会将当前child的top值改变成返回的值 * paramd

23、y相较于上一次child在水平方向上移动的 * return */OverridepublicintclampViewPositionVertical(View child, int top, intdy) return top; ;显示效果:通过以上GIF动图和日志打印可以看出,仅将返回值设置成方法中的参数,方块就可以任意移动了。也证实了方法中提供的参数而dx或dy是每一次移动的距离,left或top 是指定View移动到的位置,这是计算好了的,相当于left = child.getLeft() + dx。若想要它不移动,则:return left - dx;将它计算好后的距离减去相较于上次

24、移动的距离即可,此时的View就不会移动。所以根据你的需求,可以任意改变此方法的返回值来移动View。(4)getViewHorizontalDragRange() 和getViewVerticalDragRange()看到以上GIF动图,你会发现我在移动方块时,它可以超过边界,没有任何限制!有些不合理,想限制它的移动范围,这两个方法就可以获取View的拖拽范围,将它的返回值设为:父控件的宽/高 - 子控件的宽/高,即控件可以移动的范围。/获取View水平方向的拖拽范围OverridepublicintgetViewHorizontalDragRange(View child) returng

25、etMeasuredWidth() - child.getMeasuredWidth(); / 获取View垂直方向的拖拽范围OverridepublicintgetViewVerticalDragRange(View child) returngetMeasuredHeight() - child.getMeasuredHeight(); 可是以上实现后,你会发现拖拽方块还是可以超出边界,此方法并没有起作用!是否代表此方法完全无用?这返回的值有何用?不是,它目前确实并不可以限制边界,但此方法返回的值会用在:比如说手指抬起时,View缓慢移动的动画时间的计算会用到此值,最好不要返回0(返回也不

26、会错)!但是我们还想要达到限制View拖拽边界的效果,这时在第三点介绍的clampViewPositionHorizontal() 和clampViewPositionVertical()发挥效果了,该方法是通过返回值来改变View移动的位置,这时可以在方法中加判断是否有越界:OverridepublicintclampViewPositionHorizontal(View child, int left, int dx) if(left (getMeasuredWidth() - child.getMeasuredWidth()/限制右边界left = getMeasuredWidth()

27、- child.getMeasuredWidth(); return left; 显示效果:(5)onViewPositionChanged()目前为止,需求已经完成可以任意拖拽View了,接下来完成拖拽View时,另一块跟随移动。这时介绍一个新的方法:onViewPositionChanged(),该方法在child(需要捕捉的View)位置改变时执行,参数left(top)跟之前介绍方法中含义相同,为child最新的left(top)位置,而dx(dy)是child相较于上一次移动时水平(垂直)方向上改变的距离。了解之后,就知道这个方法很强大了,在方法体中判断具体View,再根据方法提供的

28、参数设置另一View的位置,如下:/*当child位置改变时执行 * paramchangedView位置改变的子View * param left child最新的left位置 * param top child最新的top位置 * param dx 相较于上一次水平移动的距离 * paramdy相较于上一次垂直移动的距离 */OverridepublicvoidonViewPositionChanged(View changedView, int left, int top, int dx, intdy) super.onViewPositionChanged(changedView, l

29、eft, top, dx, dy);if(changedView = blueView)/拖动蓝色方块时,红色也跟随移动redView.layout(redView.getLeft()+dx , redView.getTop()+dy ,redView.getRight()+dx , redView.getBottom()+dy);elseif(changedView = redView)/拖动红色方块时,蓝色也跟随移动blueView.layout(blueView.getLeft()+dx , blueView.getTop()+dy ,blueView.getRight()+dx , b

30、lueView.getBottom()+dy); 显示效果:(6)onViewReleased()完成目前需求第三个:手指在左边(右边)区域离开屏幕后,方块自动移动到左边界(右边界)。接下来介绍最后一个方法onViewReleased(),手指抬起的时候执行该方法。这里有两个新参数:xvel:x方向移动的速度,若是正值,则代表向右移动,若是负值则向左移动;yvel:y方向移动的速度,若是正值则向下移动,若是负值则向上移动。/*手指抬起的时候执行该方法 * paramreleasedChild当前抬起的View * paramxvel x方向移动的速度:正值:向右移动负值:向左移动 * paramyvel y方向移动的速度:正值:向下移动负值:向上移动 */OverridepublicvoidonViewReleased(View releasedChild, floatxvel, floatyvel) super.onViewReleased(releasedChild, xvel, yvel);intcenterLeft = getMeasuredWidth()/2 - releasedChild.getMeasuredWidth()/2;if(releasedChild.getLeft(

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1