实现的方式
1.使用scrollTo 或者 scrollBy
2.使用动画
3. 改变布局参数
三种实现方式对比
1.scrollToor scrollBy只会改变View里面的子View的位置,不会改变View的位置
2.动画:属性动画是真正的改变View的位置,但只有3.0以后的版本才支持属性动画,View动画只是改变View的影像
3.改变布局参数实现起来需要考虑对其他View位置的影响
实现
使用scrollTo 或者 scrollBy
scrollTo是基于所传递参数的绝对滑动 和 scrollBy是基于当前位置的相对滑动
publicvoidscrollBy(int x,int y) {
scrollTo(mScrollX + x,mScrollY + y);
}
可以看出scrollBy就是调用了scrollTo的实现相对滑动
另外需要注意的是scrollTo和scrollBy只能将View的内容进行移动,并不能将View本身进行移动。不会改变View在布局中的位置
relative1.scrollTo(0,-100);
仅仅移动relative1里面的View。
并且scrollTo(int x,int y)
参数x为正时 view向左移动
参数y为正时 view向上移动
反之,右,下。
ScrollTo和scrollBy这种方式,可以比较方便的实现滑动效果并且不影响内部元素的单击事件,但他的缺点就是不能滑动View本身,只能滑动View包含的View。
上述同样限制这种方式的使用范围
直接使用ScrollTo或者scrollby View会硬生生的瞬间完成滑动,而我们大多数时间是希望有一个弹性滑动的效果。
实现弹性滑动方式:
使用Scroller
Scrollerscroller = new Scroller(mContext);
//Interpolator插值器
Scrollerscroller = new Scroller(mContext, interpolator);
//缓慢滑动动指定的位置
Privatevoid smoothScrollTo(int destX,int destY){
intscrollX = getScrollX();
intdeltaX = destX – scrollX;
//1000ms内滑动向destX,效果慢慢滑动
mScoller.starScroll(scrollX,0,deltaX,0,1000);
invalidate();
}
//必须重写的方法
@Override
Public void computeScroll(){
If(mScroller.computeScrollOffset()){
scrollTo(mScroller.getCurrX(),mscroller.getCurrY());
postInvalidate();
}
}
如果分析Scroller的源码可以发现,Scroller本身并没有实现View 的滑动,她需要配合View的computeScroll方法才能完成弹性滑动的效果。computeScrollOffset根据时间流逝计算当前的scrollX和scrollY然后不断的调用ScrollTo,然后重绘。
借用动画
动画本身就是一个渐变的过程,因此通过动画当然可以实现弹性的滑动
ValueAnimator va = ObjectAnimator.ofInt(0,100).setDuration(500).start();
va.addUpdateListener(newAnimatorUpdateListener(){
@override
publicvoid onAnimationUpdate(ValueAnimator animator){
float flag = animator.getAnimatorFraction();
mButton1.scrollTo(startX+(int )(deltaX*flag),0);
}
});
动画就是充当一个计时工具。
自定义延时策略
final Runnable run = new Runnable() {
@Override
publicvoid run() {
count++;
floatflag = count/30f;
relative1.scrollTo(0,(int) (-100*flag));
}
};
Timertimer = new Timer();
timer.schedule(newTimerTask() {
@Override
publicvoid run() {
relative1.post(run);
}
},0, 10);
使用线程计时实现滑动。
使用动画
View动画和属性动画的最大区别就是 View动画只是改变View的影像的位置,而属性动画改变的是View的实际位置。
也就是说 如果一个button使用View动画后,点击动画后的位置的button不会触发事件,而点击butotn原来的位置则可以触发事件。而属性动画不存在这样的情况。
所以View动画只适用于没有事件绑定的View。当然可以人工处理比如:隐藏原来位置的view,在影像的位置生成新view并绑定事件(太麻烦)
属性动画没有什么缺点,但是只有android3.0以后支持
Android3.0以前想使用属性动画的话,可以引入nineoldandroids ,但是只是兼容代码,本质上在3.0以前还是属于view动画。
View动画的四种变换效果对应 Animation的四个子类:
TranslateAnimation
ScaleAnimation
RotateAnimation
AlphaAnimation
View动画可以动态创建也可以使用xml定义动画 一般会使用xml的形式
在anim文件夹下:
<?xmlversion="1.0"encoding="utf-8"?>
<setxmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true"
android:zAdjustment="normal"
>
<translate
android:duration="500"
android:fromXDelta="0"
android:fromYDelta="0"
android:interpolator="@android:anim/linear_interpolator"
android:toXDelta="100"
android:toYDelta="100"
/>
</set>
常用的属性效果需要多练习
在代码中使用:
Animation animation =AnimationUtils.loadAnimation(GesturetestActivity.this, R.anim.test_aaim);
button1.setAnimation(animation);
帧动画
在drawable目录下
<animation-list>
Btn.setbackground(animation-list);
AnimationDrawable = Btn.getBackground();
AnimationDrawable.start;
LayoutAnimation
作用于ViewGroup item的动画
Anim文件夹下
<layoutAnimation>
可以直接 xml引用android:layoutAnimation="@anim/anim_layout"
也可以
animation = AnimationUtil.loadAnimation
contorller = new LayoutAnimationCotroler(animation)
contorller.set
listView.setLayoutAnimation(controller);
Activity切换
overrideRedingTransition在startAcitivity 或者 finish之后调用
Fragment切换
FragmentTransaction setCustomAnimations
属性动画
API11新加入的特性
API11以下 支持库:nineoldandroids本质还是View动画
常用的几个动画类:
ValueAnimator
ObjectAnimator
AnimatorSet
ObjectAnimator继承自ValueAnimator,AnimatorSet是动画集合
ObjectAnimator anim =ObjectAnimator.ofFloat(button1,"translationY", 0,100).setDuration(1000);
anim.setInterpolator(new BounceInterpolator());
anim.setEvaluator(new FloatEvaluator());
anim.addListener(newAnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animatoranimation) {
// TODO Auto-generated method stub
super.onAnimationEnd(animation);
}
});
anim.start();
ObjectAnimator colorAnim =ObjectAnimator.ofInt(button1,"backgroundColor", Color.RED,Color.GREEN).setDuration(3000);
colorAnim.setRepeatCount(20);
colorAnim.setRepeatMode(ValueAnimator.REVERSE);
colorAnim.setEvaluator(new ArgbEvaluator());
//colorAnim.setInterpolator(new BounceInterpolator());
colorAnim.start();
AnimatorSetset = newAnimatorSet();
set.playTogether(
ObjectAnimator.ofFloat(button1,"rotationY",0,180),
ObjectAnimator.ofFloat(button1,"scale",1,2),
ObjectAnimator.ofFloat(button1,"translationX",0,200),
ObjectAnimator.ofFloat(button1,"translationY",0,200),
ObjectAnimator.ofFloat(button1,"alpha",1,0.25f,1)
);
set.setDuration(3000).start();
也可以在animator 目录下定义xml 实现属性动画
<set>
<objectAnimator>
<animator>
</set>
AnimatorSet set =AnimatorInflate.loadAnimator(myContext,R.anim.property);
set.setTarget(mbt);
set .start();
开发中属性动画很少会使用xml实现
使用属性动画对任意属性动画
属性动画要求动画作用的对象提供该属性的get和set方法,属性动画根据外界传递的该属性的初始值和最终值,以动画的效果多次去调用set方法,每次传递给set方法的值都不一样,确切的说是随着时间的推移,所传递的值越来越接近最终值。
所以我们对object的属性abc做动画,object就必须提供setAbc方法和getAbc方法
setAbc同时可以自己更新UI
当我们需要对一个不满足条件的view使用属性动画时,可以用一个原始对象,间接的提供get和set方法
ObjectAnimator.ofInt(newwrapper(view),"width",500).setduration(500).start();
private static class wrapper{
private view t;
wrapper( View view){
t =view
}
public int getT(){
return t.getLayoutParams().width;
}
public int setT(){
t.getLayoutParams().width = width;
t.requestLayout();
}
}
注意
帧动画容易出现oom
Activity退出时停止动画,防止内存泄露
3.0属性动画的兼容问题
View动画是对view的影像的动画,并不是真正的改变view的状态
尽量实用dp
MarginLayoutParams params =(MarginLayoutParams) button1.getLayoutParams();
params.width += 100;
params.height +=100;
params.topMargin+=100;
button1.requestLayout();
需要处理给其他View的位置带来的影响,只有在特殊的时候使用。
补充
插值器和估值器
TimeInterPolator
时间插值器,根据时间流逝的百分比来计算出当前属性值改变的百分比,系统预置的有LinearInterpolator AccelerateDecelerateInterpolator 等等
TypeEvaluator
类型估值算法
根据当前属性改变的百分比计算改变后的属性值,系统预置的有IntEvaluatorFloatEvaluator ArgbEvaluator(针对color 比较有实用)
他们是实现非匀速动画的重要手段
本文算是任玉刚大神《android开发艺术探索》的阅读笔记。感谢大神