这篇文章的源码以及效果在github。
实现墨迹天气向上滑动的viewpager使用的开源库ViewPager-Android。ViewPager-Android开源库设置app:orientation定义滑动方向。
墨迹天气引导界面共有4个视图,先看一下:(这里引入的图片都是实现后的,截图都是静态图,运行程序看动画效果)。
图一 图二
图三 图四
墨迹天气的引导界面使用的无非是移动、渐变、缩放、转动或者其中几个的组合。我们介绍其中的部分实现。
1、缩放动画
首先是图一的“极低耗电”使用了一个缩放效果,使用Property Animation实现如下:
xml动画文件:
- <?xml version="1.0" encoding="utf-8"?>
- <set xmlns:android="http://schemas.android.com/apk/res/android"
- android:ordering="together" >
- <objectAnimator
- android:duration="1000"
- android:interpolator="@android:anim/accelerate_decelerate_interpolator"
- android:propertyName="scaleX"
- android:valueFrom="1.0"
- android:valueTo="1.1"
- android:valueType="floatType" >
- </objectAnimator>
- <objectAnimator
- android:duration="1000"
- android:interpolator="@android:anim/accelerate_decelerate_interpolator"
- android:propertyName="scaleY"
- android:valueFrom="1.0"
- android:valueTo="1.1"
- android:valueType="floatType" >
- </objectAnimator>
- </set>
java使用:
- animation1=(AnimatorSet)AnimatorInflater.loadAnimator(PropertyAnimActivity.this,
- R.animator.tutorail_rotate);
- LinearInterpolator lin = new LinearInterpolator();
- animation1.setInterpolator(lin);
- t1_icon2.setVisibility(View.VISIBLE);
- animation1.setTarget(t1_icon2);
- animation1.start();
2、移动渐变组合动画
图一中下面的箭头使用了移动渐变组合动画,实现如下:
xml文件:
- <?xml version="1.0" encoding="utf-8"?>
- <set xmlns:android="http://schemas.android.com/apk/res/android"
- android:ordering="together" >
- <!--
- 可以包含<objectAnimator>, <valueAnimator>,<set>项
- 属性:android:ordering=["together" | "sequentially"],子集执行顺序
- sequentially Play animations in this set sequentially
- together (default) Play animations in this set at the same time.
- -->
- <set
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:ordering="together" >
- <objectAnimator
- android:duration="1000"
- android:propertyName="translationX"
- android:repeatCount="infinite"
- android:repeatMode="reverse"
- android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType" >
- </objectAnimator>
- <objectAnimator
- android:duration="1000"
- android:propertyName="translationY"
- android:repeatCount="infinite"
- android:repeatMode="reverse"
- android:valueFrom="-15"
- android:valueTo="20"
- android:valueType="floatType" >
- </objectAnimator>
- </set>
- <objectAnimator
- android:duration="1000"
- android:propertyName="alpha"
- android:repeatCount="infinite"
- android:valueFrom="1.0"
- android:valueTo="0.3"
- android:valueType="floatType" >
- </objectAnimator>
- <!--
- objectAnimator:
- android:propertyName
- 对view可以设置一下值:
- translationX and translationY:
- These properties control where the View is located
- as a delta from its left and top coordinates which
- are set by its layout container.
- rotation, rotationX, and rotationY:
- These properties control the rotation
- in 2D (rotation property) and 3D around the pivot point.
- scaleX and scaleY:
- These properties control the 2D scaling of a View around
- its pivot point.
- pivotX and pivotY:
- These properties control the location of the pivot point,
- around which the rotation and scaling transforms occur.
- By default, the pivot point is located at the center of
- the object.
- x and y:
- These are simple utility properties to describe
- the final location of the View in its container,
- as a sum of the left and top values and translationX
- and translationY values.
- alpha:
- Represents the alpha transparency on the View.
- This value is 1 (opaque) by default, with a value of 0
- representing full transparency (not visible).
- 还可以设置"backgroundColor"等值
- android:valueTo
- float, int, or color. Required. The value where the animated property ends.
- Colors are represented as six digit hexadecimal numbers (for example, #333333).
- android:valueFrom
- float, int, or color. The value where the animated property starts. If not specified,
- the animation starts at the value obtained by the property‘s get method.
- Colors are represented as six digit hexadecimal numbers (for example, #333333).
- android:duration
- int. The time in milliseconds of the animation. 300 milliseconds is the default.
- android:startOffset
- int. The amount of milliseconds the animation delays after start() is called.
- android:repeatCount:重复次数
- 说明:
- infinite:循环执行,
- 具体正整数表示循环次数
- android:repeatMode:重复模式,
- 说明:
- restart:重新从头开始执行
- reverse:反方向执行
- android:valueType
- Keyword. Do not specify this attribute if the value is a color.
- The animation framework automatically handles color values
- intType: Specifies that the animated values are integers
- floatType (default): Specifies that the animated values are floats
- -->
- </set>
Java调用动画资源和前面是一样的,不做过多说明。
3、旋转缩放组合动画
图1中间使用了旋转缩放组合动画,,实现如下:
- <?xml version="1.0" encoding="utf-8"?>
- <set xmlns:android="http://schemas.android.com/apk/res/android"
- android:ordering="together" >
- <set
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:ordering="together" >
- <objectAnimator
- android:duration="800"
- android:interpolator="@android:anim/accelerate_decelerate_interpolator"
- android:propertyName="scaleX"
- android:valueFrom="0.0"
- android:valueTo="1.2"
- android:valueType="floatType" >
- </objectAnimator>
- <objectAnimator
- android:duration="800"
- android:interpolator="@android:anim/accelerate_decelerate_interpolator"
- android:propertyName="scaleY"
- android:valueFrom="0.0"
- android:valueTo="1.2"
- android:valueType="floatType" >
- </objectAnimator>
- </set>
- <objectAnimator
- android:duration="3000"
- android:propertyName="rotation"
- android:repeatCount="-1"
- android:valueFrom="0.0"
- android:valueTo="359.0"
- android:valueType="floatType" >
- </objectAnimator>
- </set>
Java调用动画资源和前面是一样的,不做过多说明。
4、平移动画
图三更多的使用了平移动画,因为要计算位置,没有使用xml资源文件,Java实现:
- transAnimationX2=ObjectAnimator.ofFloat(t3_icon2, "translationX", fx1, tx1);
- transAnimationX2.setDuration(800);
- transAnimationX2.setRepeatCount(Animation.INFINITE);// Animation.INFINITE
- transAnimationX2.setRepeatMode(Animation.RESTART);
- transAnimationX2.setInterpolator(new LinearInterpolator());
- transAnimationY2=ObjectAnimator.ofFloat(t3_icon2, "translationY", fy1, ty1);
- transAnimationY2.setDuration(800);
- transAnimationY2.setRepeatCount(Animation.INFINITE);// Animation.INFINITE
- transAnimationY2.setRepeatMode(Animation.RESTART);
- transAnimationY2.setInterpolator(new LinearInterpolator());
- PropertyValuesHolder pvhX3 = PropertyValuesHolder.ofFloat("translationX", fx2, tx2);
- PropertyValuesHolder pvhY3 = PropertyValuesHolder.ofFloat("translationY", fy2, ty2);
- transAnimation3=ObjectAnimator.ofPropertyValuesHolder(t3_icon3, pvhX3, pvhY3);
- transAnimation3.setDuration(1200);
- transAnimation3.setRepeatCount(Animation.INFINITE);
- transAnimation3.setRepeatMode(Animation.RESTART);
- transAnimation3.setInterpolator((new LinearInterpolator()));
- PropertyValuesHolder pvhX4 = PropertyValuesHolder.ofFloat("translationX", fx3, tx3);
- PropertyValuesHolder pvhY4 = PropertyValuesHolder.ofFloat("translationY", fy3, ty3);
- transAnimation4=ObjectAnimator.ofPropertyValuesHolder(t3_icon4, pvhX4, pvhY4);
- transAnimation4.setDuration(1200);
- transAnimation4.setRepeatCount(Animation.INFINITE);
- transAnimation4.setRepeatMode(Animation.RESTART);
- transAnimation4.setInterpolator((new LinearInterpolator()));
- PropertyValuesHolder pvhX5 = PropertyValuesHolder.ofFloat("translationX", fx4, tx4);
- PropertyValuesHolder pvhY5 = PropertyValuesHolder.ofFloat("translationY", fy4, ty4);
- transAnimation5=ObjectAnimator.ofPropertyValuesHolder(t3_icon5, pvhX5, pvhY5);
- transAnimation5.setDuration(800);
- transAnimation5.setRepeatCount(Animation.INFINITE);
- transAnimation5.setRepeatMode(Animation.RESTART);
- transAnimation5.setInterpolator((new LinearInterpolator()));
- flag3=true;
- // 延迟1秒
- new Handler() {
- @Override
- public void dispatchMessage(Message msg) {
- // TODO Auto-generated method stub
- if(flag3)
- super.dispatchMessage(msg);
- }
- public void handleMessage(android.os.Message msg) {
- if (msg.what == 1) {
- t3_icon2.setVisibility(View.VISIBLE);
- t3_icon3.setVisibility(View.VISIBLE);
- t3_icon4.setVisibility(View.VISIBLE);
- t3_icon5.setVisibility(View.VISIBLE);
- transAnimationX2.start();
- transAnimationY2.start();
- transAnimation3.start();
- transAnimation4.start();
- transAnimation5.start();
- t3_icon6_animationDrawable.start();
- }
- };
- }.sendEmptyMessageDelayed(1, 1000);// 1秒
这个动画中更重要的是计算初始和结束位置:
- view3.getViewTreeObserver().addOnGlobalLayoutListener(
- new OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- // TODO Auto-generated method stub
- int h1 = centerLayout.getTop();
- int h2 = centerLayout.getBottom();
- DensityUtil densityUtil = new DensityUtil(
- PropertyAnimActivity.this);
- int w = densityUtil.getScreenWidth();
- fx1 = t3_icon2.getTop() + t3_icon2.getHeight();
- fy1 = -t3_icon2.getTop() - t3_icon2.getHeight();
- tx1 = -t3_icon2.getWidth() - t3_icon2.getLeft();
- ty1 = t3_icon2.getTop() + t3_icon2.getLeft()
- + t3_icon2.getWidth();
- fx2 = t3_icon3.getTop() + t3_icon3.getHeight();
- fy2 = -t3_icon3.getTop() - t3_icon3.getHeight();
- tx2 = -t3_icon3.getWidth() - t3_icon3.getLeft();
- ty2 = t3_icon3.getTop() + t3_icon3.getLeft()
- + t3_icon3.getWidth();
- fx3 = w - t3_icon4.getLeft();
- fy3 = -(w - t3_icon4.getLeft());
- tx3 = -(h2 - h1 - t3_icon4.getTop());
- ty3 = h2 - h1 - t3_icon4.getTop();
- fx4 = w - t3_icon5.getLeft();
- fy4 = -(w - t3_icon5.getLeft());
- tx4 = -(h2 - h1 - t3_icon5.getTop());
- ty4 = h2 - h1 - t3_icon5.getTop();
- }
- });
5、循环插值器
第四页动画中重要的使用了CycleInterpolator(循环插值器)
- ObjectAnimator objAnim=ObjectAnimator.ofFloat(t4_icon1, "rotation", 0f, 10f);
- CycleInterpolator interpolator = new CycleInterpolator(3.0f);
- objAnim.setStartDelay(500);
- objAnim.setDuration(3000);
- objAnim.setRepeatCount(Animation.INFINITE);// Animation.INFINITE
- objAnim.setInterpolator(interpolator);
- t4_icon1.setPivotX(t4_icon1.getWidth()*0.47f);
- t4_icon1.setPivotY(t4_icon1.getHeight()*0.05f);
- objAnim.start();