这是我参与「第四届青训营 」笔记创作活动的第11天
View的滑动
方法有三:
1、scrollTo/scrollBy
scrollTo实现的是基于所传递参数的绝对滑动
scrollBy实际上也是调用了scrollTo方法,实现的是基于当前位置的相对滑动
scrollTo和scrollBy只能改变view中内容的位置,而不能改变view的位置
从左向右移是负值,反之是正值
从上向下移是负值,反之是正值
注:scrollTo/scrollBy只能移动View的内容,不是真的移动View
2、使用动画
主要是操作View的translationX和translationY属性,既可以使用传统的view动画,也可以使用属性动画,如果采用属性动画的 话,为了能够兼容3.0以下的版本,需要采用开源动画库nineoldandroids(nineoldandroids.com/)
TranslateAnimation是Andriod中的补间(Tween)动画中的位移变化的动画 使用时,需要在res下新建Android Resource Directtory,并选择anim。在anim文件夹下new一个Animation Resource File,并在Root element中填写translate即可。
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android">
</translate>
translate有duration(父类属性)、fromXDelta、fromYDelta、toXDelta、toYDelta自有属性。
duration:属性为动画持续时间,时间以毫秒为单位。 fromXDelta:属性为动画起始时,X坐标上的位置。 fromYDelta:属性为动画起始时,Y坐标上的位置。 toXDelta:属性为动画结束时,X坐标上的位置。 toYDelta:属性为动画结束时,Y坐标上的位置。 eg:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fromYDelta="100%p"
android:toYDelta="0%p"/>
上面代码表示动画时间为0.5秒,从父容器的底部开始到父容器的顶部结束。 android:fromYDelta=“100%”,表示自身的100%,也就是从View自己的位置开始。 android:fromYDelta=“100%p”,表示父层View的100%,是以它父层View为参照的。 注意: 没有指定,默认是以自己为相对参照物。
注:使用动画移动的是View的影像,也不是移动真正的view,所以如果设置有点击事件,点击原来View的位置反而可以响应
3、改变布局参数
比如我们想把一个Button向右平移100px,我们只需要将这个Button的LayoutParams里的marginLeft参数的值增加100px即可
还有一种方式,可以在button的四周比如左边放置一个空的View,这个空View的默认宽度是0,当我们需要向右移动Button,只需要重新设置空View的宽度即可,n的目的,我们可以在 Button的左边放置一个空的View,这个空View的默认宽度为0,当我们需要向右移动Button时,只需要重新设置空View的宽度即可,当空View的宽度增大时 (假设Button的父容器是水平方向的LinearLayout),Button就自动被挤向右边,即实现了向右平移的效果。
-
重新设置一个View的LayoutParams
MarginLayoutPararms params =(MarginLayoutParams)mButton1.getLayoutParams(); params.width+=100; params.leftMargin+=100; mButton1.requestLayout(); //或者mButton1.setLayoutParams(params);总结:
- scrollTo/scrollBy:操作简单,适合对View内容的滑动
- 动画:操作简单,主要适用于没有交互的View和实现复杂的动画效果
- 改变布局参数:操作稍微复杂,适用于有交互的View。
弹性滑动
在知道如何实现滑动之后,我们来学一下弹性滑动的实现,因为弹性滑动对用户的视觉效果更好,弹性滑动是一种渐进式滑动
实现方法的共同思想是将一个大的滑动分成若干小滑动,并在一定时间内完成
1、使用scroller
工作机制:scroll本身不能实现view的滑动,需要配合View的computeScroll方法来实现。调用invalidate()方法可以让view重绘,重绘的时候view的onDraw()方法又会去调用computeScroll方法,然后还是会向scroll获取scrollX和scrollY,然后就通过scrollTo方法实现滑动,最后再次调用postInvalidate()方法进行第二次重绘,重复上述步骤
invalidate();//会使View重绘,重绘之后View会通过onDraw()方法来调用computeScroll方法,在computeScroll方法里面通过scrollTo方法滑动到当前的位置
//作用是使视图无效,如果视图可见,onDraw(Canvas)将在将来的某个时间点被调用
//这必须从UI线程调用,从非UI线程调用需要使用postInvalidate()
postInvalidate();//非UI线程,也会导致view进行重绘,这里是第二次重绘
//导致在事件循环的后续循环中发生无效,使用这个方法来使来自非UI线程的视图无效
//仅当此视图附加到窗口时,才能从UI线程外部调用此方法
注:scrollTo和scrollBy是View类中的方法,不是Scroller类中的方法
2、通过动画
动画本身就是渐近的过程
ObjectAnimator.ofFloat(targetView,"translationX",0,100).setDuration
(100).start();//可以让一个View的内容在100ms内向左移动100像素。
们可以利用动画的特性来实现一些动画不能实现的效果。还拿scrollTo来说,我们也想模仿Scroller来实现View的弹性 滑动,那么利用动画的特性,我们可以采用如下方式来实现:
final int startX = 0;
final int deltaX = 100;
ValueAnimator animator =ValueAnimator.ofInt(0,1).setDuration(1000); animator.addUpdateListener( animator-> {
float fraction = animator.getAnimatedFraction(); mButton1.scrollTo(startX + (int) (deltaX * fraction),0);
//除了弹性滑动,还可以在这里实现其他的动画效果
});
animator.start()
动画本质上没有作用于任何对象,它只是在1000ms内完成了整个动画过程。利用这个特性,我们就可以在动画的每一帧到来 时获取动画完成的比例,然后再根据这个比例计算出当前View所要滑动的距离。注意,这里的滑动针对的是View的内容而非View本身。可以发现,这个方法 的思想其实和Scroller比较类似,都是通过改变一个百分比配合scrollTo方法来完成View的滑动
3、使用延时策略
核心思想是通过发送一系列延时消息从而达到一种渐近式的效果,具体来说可以使用 Handler或View的postDelayed方法,也可以使用线程的sleep方法。对于postDelayed方法来说,我们可以通过它来延时发送一个消息,然后在消息中来进行View 的滑动,如果接连不断地发送这种延时消息,那么就可以实现弹性滑动的效果。对于sleep方法来说,通过在while循环中不断地滑动View和sleep,就可以实现 弹性滑动的效果。