Hacks动画篇-Hack5 附加Ken Burns特效的幻灯片
作者:李旺成
时间:2016年5月12日
在该 Hack 中将介绍如何实现 Ken Burns 特效来展示图片。
Ken Burns 特效
先来理解一下概念,什么是 Ken Burns 特效?
Ken Burns 特效,是视频产品中使用的一种平移和缩放的静态图片的特效。想了解更多,Wiki 上有比较详细的介绍:Ken Burns effect。
这不是我们的重点,重点是这到底是一种什么样的效果?Wiki 上给出下面的示意图:
Ken Burns 特效还是没概念?是的,最直观的方式是看真实的效果,可以去看看这段视频:Wiki Ken Burns effect 视频
简而言之
Ken Burns 特效是一种图片在切换之前,会缓慢在页面移动或者放大缩小,然后再慢慢切换过去。这样的效果使得每一张静止图片都有动态的效果感觉。类似的效果在电子相册,或者在电影视频对静态图片的处理中经常可见。(参考自:KenBurnsView:实现Ken Burns effect图片展示效果的效果android控件)
模拟 Ken Burns 特效
先看效果:
Ken Burns特效要实现上面的效果,需要用到 JakeWharton 大牛的 NineOldAndroids 库。该库的作用是可以让老版本的 Android (3.0 以下的版本)使用属性动画。当然,如果你不考虑兼容 Android 3.0 以下版本就用不到这个库了。
思路分析
先分析一下 Ken Burns 特效:使用缩放动画,可能同时伴随平移动画来展示当前图片,当该图片的动画展示显示完毕之后,就开始显示下一张图片并展示动画。
那么有个简单的思路:使用 ImageView 展示图片,为该 ImageView 设置一些动画,当该图片的动画结束后,切换下一张图片。
创建 Ken Burns 特效
1、创建布局
主布局使用 FrameLayout,直接把 ImageView 添加到布局中填充整个父控件。这里采用代码的方式创建,看代码:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContainer = new FrameLayout(this);
mContainer.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
mView = createNewView();
mContainer.addView(mView);
setContentView(mContainer);
}
private ImageView createNewView() {
ImageView ret = new ImageView(this);
ret.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
ret.setScaleType(ImageView.ScaleType.FIT_XY);
ret.setImageResource(PHOTOS[mIndex]);
mIndex = (mIndex + 1 < PHOTOS.length) ? mIndex + 1 : 0;
return ret;
}
代码比较简单
首先,创建一个 FrameLayout 布局容器
然后,创建 ImageView,从保存图片资源 ID 的数组中根据索引取出图片,将其设置给 ImageView
最后,将 ImageView 添加到 FrameLayout 中,将该 FrameLayout 设置为 Activity 的 ContentView。
2、开始播放动画
在 Activity onResume 的时候开始播放动画:
@Override
protected void onResume() {
super.onResume();
nextAnimation();
}
看看负责播放动画的代码:
private void nextAnimation() {
AnimatorSet anim = new AnimatorSet();
// 生成随机数,实现随机播放动画
final int index = mRandom.nextInt(ANIM_COUNT);
switch (index) {
case 0:
// 缩放动画
anim.playTogether(
ObjectAnimator.ofFloat(mView, "scaleX", 1.5f, 1f),
ObjectAnimator.ofFloat(mView, "scaleY", 1.5f, 1f));
break;
case 1:
// 缩放动画
anim.playTogether(
ObjectAnimator.ofFloat(mView, "scaleX", 1, 1.5f),
ObjectAnimator.ofFloat(mView, "scaleY", 1, 1.5f));
break;
case 2:
AnimatorProxy.wrap(mView).setScaleX(1.5f);
AnimatorProxy.wrap(mView).setScaleY(1.5f);
// 位移动画
anim.playTogether(ObjectAnimator.ofFloat(mView,
"translationY", 80f, 0f));
break;
case 3:
default:
AnimatorProxy.wrap(mView).setScaleX(1.5f);
AnimatorProxy.wrap(mView).setScaleY(1.5f);
// 位移动画
anim.playTogether(ObjectAnimator.ofFloat(mView,
"translationX", 0f, 40f));
break;
}
// 设置动画持续时间
anim.setDuration(3000);
// 设置动画监听器
anim.addListener(this);
// 播放动画
anim.start();
}
上面的代码就是设置一些属性动画,对这方面不是很了解的,后面我会专门写几篇关于动画方面学习的总结(AndroidStudyDemo 系列)。
补充说明:
AnimatorProxy 类,是 NineOldAndroids 库中的一个工具类,用于修改 View 对象的属性。该动画框架的基础是:视图的属性随时间的推移而改变(所谓的属性动画,就是随着时间的推移改变对象的属性,而产生动画效果)。之所以使用AnimatorProxy类,是因为在 Android 3.0 以下版本,有些属性没有 setters 或 getters 方法。(参考自:《50 Android Hacks》)
3、切换图片播放下一张图片
这里是这样处理的,监听动画播放,当动画结束时,删除当前的 ImageView,添加新的 ImageView,然后播放动画。代码如下:
// 实现动画监听接口
public class KenBurnsActivity extends AppCompatActivity implements Animator.AnimatorListener
...
// 实现接口中的方法
@Override
public void onAnimationCancel(Animator arg0) {
}
@Override
public void onAnimationEnd(Animator animator) {
mContainer.removeView(mView);
mView = createNewView();
mContainer.addView(mView);
nextAnimation();
}
@Override
public void onAnimationRepeat(Animator arg0) {
}
@Override
public void onAnimationStart(Animator arg0) {
}
小结
这里用到了两个技术:
- 属性动画,Android 3.0 开始提供,以前的版本可以使用 NineOldAndroids 兼容库
- 动画事件监听,监听动画的一些事件,可以针对这些事件做相应处理
项目地址
项目示例代码:
KenBurnsActivity.java
参考
Ken Burns effect
KenBurnsView:实现Ken Burns effect图片展示效果的效果android控件