动画分类
Android动画有3类:帧动画、视图动画、属性动画。帧动画和视图动画又统称为补间动画。Android 3.0(API LEVEL 11)开始支持属性动画。
帧动画
帧动画是针对Drawable资源的动画。其本质是一系列Drawable资源的连续变化,其本质是AnimationDrawable对象。其使用方法如下:
定义AnimationDrawable
资源中用到了表示天气的三张图片
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@mipmap/ic_sunny" android:duration="200" />
<item android:drawable="@mipmap/ic_slight_drizzle" android:duration="200" />
<item android:drawable="@mipmap/ic_haze" android:duration="200" />
</animation-list>
代码
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews() {
ImageView sampleIv= (ImageView)findViewById(R.id.iv_sample);
sampleIv.setBackgroundResource(R.drawable.wether_list);
final AnimationDrawable animationDrawable = (AnimationDrawable)sampleIv.getBackground();
sampleIv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animationDrawable.start();
}
});
}
效果图
点击图片之后就会连续变换不同的图片出来
视图动画
视图动画是对视图控件(View)应用动画,其本质是连续修改View的属性来展现变化。主要有Scale,Rotate,Translate,Alpha。使用方法如下:
定义动画资源
旋转动画
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
/>
透明度动画
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="0"
android:toAlpha="1">
</alpha>
位移动画
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="-100%"
android:toXDelta="0"
android:fromYDelta="-20%"
android:toYDelta="0">
</translate>
组合动画
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:fromAlpha="0.2"
android:toAlpha="1">
</alpha>
<scale
android:fromXScale="0%"
android:fromYScale="0%"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="100%"
android:toYScale="100%"/>
<rotate
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360"
/>
</set>
代码
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews() {
final ImageView sampleIv= (ImageView)findViewById(R.id.iv_sample);
final Animation animation = AnimationUtils.loadAnimation(this,R.anim.roate360);
animation.setDuration(1500);
animation.setInterpolator(this,android.R.anim.linear_interpolator);
animation.setRepeatCount(Animation.INFINITE);
sampleIv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sampleIv.startAnimation(animation);
}
});
}
效果图
属性动画
接下来重点讲属性动画。
属性动画不仅仅针对视图(View),它几乎可以应用到任何对象。你可以定义属性动画来改变任意对象的属性,不管这个对象是否会在屏幕上呈现出来。属性动画的本质是在一定时间段内连续地改变对象的属性。
属性动画和视图动画的区别
- 视图动画只能针对视图对象应用动画,而且视图动画只能针对视图的部分应用动画,例如可以缩放,旋转,但是不能对视图背景色应用动画等等。
- 视图动画只会改变视图绘制的位置,而不会改变视图本身所在的位置。所以如果一个视图通过视图动画移动到了另一位置,你点击它的新位置并不会正确的响应点击事件,而必须在原来的初始位置点击才会有效果。
- 属性动画则完全没有上边的限制,可以使用属性动画作用在任何对象的任何属性,不管它是视图控件还是非视图控件。并且,属性动画会真正的改变对象本身,事件都会在动画后的位置上生效。
- 当然,使用视图动画的开销比属性动画要低,我们可用用很少的步骤和很少的代码去实现是视图动画效果。所以,如果视图动画可以达到目标,也没必要一定要用属性动画。
简单的例子
淡入淡出动画
showView.setAlpha(0f);
showView.setVisibility(View.VISIBLE);
showView.animate()
.alpha(1f)
.setDuration(300/*ms*/)
.setListener(null);
hideView.animate()
.alpha(0f)
.setDuration(mShortAnimationDuration)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
hideView.setVisibility(View.GONE);
}
});
效果图
翻转动画
下面展示如何在切换Fragmeng时应用翻转动画
java代码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_card_flip);
if (savedInstanceState == null) {
// 如果没有实例,则将CardFrontFragment添加到Activity
//否则表明之前已经添加Fragment了
getFragmentManager()
.beginTransaction()
.add(R.id.container, new CardFrontFragment())
.commit();
} else {
mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0);
}
// 监控返回栈的变化,以便正确地显示操作图标
getFragmentManager().addOnBackStackChangedListener(this);
}
@Override
public void onBackStackChanged() {
mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0);
// 当返回栈发生变化,更新菜单显示
invalidateOptionsMenu();
}
private void flipCard() {
//如果返回栈中有实例,直接返回当前一个Fragment
if (mShowingBack) {
getFragmentManager().popBackStack();
return;
}
//指示可以返回上一个Fragment
mShowingBack = true;
//添加CarBackFragment
getFragmentManager()
.beginTransaction()
// 自定义Frameng切换时的动画
//包括切换当当前Fragment和返回到上一个Fragment的动画
//这样当按返回按钮时也会有动画效果
.setCustomAnimations(
R.animator.card_flip_right_in/*enter*/, R.animator.card_flip_right_out/*exit*/,
R.animator.card_flip_left_in/*popEnter*/, R.animator.card_flip_left_out/*popExit*/)
// 替换Fragment
.replace(R.id.container, new CardBackFragment())
// 将该事务添加到返回栈,这样才能响应返回按钮操作
.addToBackStack(null)
// 提交事务
.commit();
// 延迟更新菜单
mHandler.post(new Runnable() {
@Override
public void run() {
invalidateOptionsMenu();
}
});
}
动画资源
car_flip_right_in.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 在旋转动画之前,立刻将apha 设为0,注意duration=0 -->
<objectAnimator
android:valueFrom="1.0"
android:valueTo="0.0"
android:propertyName="alpha"
android:duration="0" />
<!-- 旋转动画 -->
<objectAnimator
android:valueFrom="180"
android:valueTo="0"
android:propertyName="rotationY"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:duration="300" />
<!-- 在旋转动画执行到二分之一的时候,立刻将alpha设为1,使之可见,注意 startOffset = 150. -->
<objectAnimator
android:valueFrom="0.0"
android:valueTo="1.0"
android:propertyName="alpha"
android:startOffset="150"
android:duration="1" />
</set>
card_flip_right_out.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 旋转 -->
<objectAnimator
android:valueFrom="0"
android:valueTo="-180"
android:propertyName="rotationY"
android:interpolator="@android:interpolator/accelerate_decelerate"
android:duration="@integer/card_flip_time_full" />
<!-- 旋转一半的时候设置透明度为1,使之可见. -->
<objectAnimator
android:valueFrom="1.0"
android:valueTo="0.0"
android:propertyName="alpha"
android:startOffset="@integer/card_flip_time_half"
android:duration="1" />
</set>
card_flip_left_in.xml 和car_flip_right_in.xml差不多,只是rotationY动画的起止角度 valueFrom=”-180”,valueTo=”0”.
card_flip_left_out.xml 和car_flip_right_out.xml差不多,只是rotationY动画的起止角度 valueFrom=”0”,valueTo=”180”.
效果图
滑屏动画
下面展示有何在ViewPager切换Page的时候应用动画
java代码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen_slide);
//实例化ViewPager和PagerAdapter对象
mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new ScreenSlidePagerAdapter(getFragmentManager());
mPager.setAdapter(mPagerAdapter);
mPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
invalidateOptionsMenu();
}
});
}
菜单操作
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
//...
case R.id.action_zoom:
//设置缩放动画,在切换page的时候会看到效果
mPager.setPageTransformer(false,new ZoomPageTransformer());
return true;
case R.id.action_depth:
mPager.setPageTransformer(false,new DepthPageTransformer());
return true;
case R.id.action_default:
//恢复默认动画
mPager.setPageTransformer(false,null);
return true;
}
return super.onOptionsItemSelected(item);
}
DepthPageTransformer.java
public class DepthPageTransformer implements ViewPager.PageTransformer {
@Override
public void transformPage(View page, float position) {
int pageWidth = page.getWidth();
if(position <= -1){
//当不在屏幕显示范围时,恢复所有属性
page.setAlpha(1);
page.setTranslationX(0);
page.setScaleX(1);
page.setScaleY(1);
}else if(position < 0){
//屏幕左侧page
page.setTranslationX(-position*pageWidth);
page.setScaleX(position*0.3f+1f);
page.setScaleY(position*0.3f+1f);
page.setAlpha(1+position*0.8f);
}else if(position < 1) {
//屏幕右侧page
page.setTranslationX(0);
page.setScaleX(1);
page.setScaleY(1);
page.setAlpha(1);
}else{
//当不在屏幕显示范围时,恢复所有属性
page.setAlpha(1);
page.setTranslationX(0);
page.setScaleX(1);
page.setScaleY(1);
}
}
}
ZoomPageTransformer.java
public class ZoomPageTransformer implements ViewPager.PageTransformer {
@Override
public void transformPage(View page, float position) {
if(position <= -1){
//当不在屏幕显示范围时,恢复所有属性
page.setScaleX(1);
page.setScaleY(1);
page.setTranslationX(0);
page.setAlpha(1);
}else if(position < 1){
//在屏幕上显示的page
float pageWidth = page.getWidth();
float pageHeight = page.getHeight();
float scaleFactor = Math.max(0.85f,1 -Math.abs(position));
page.setScaleX(scaleFactor);
page.setScaleY(scaleFactor);
page.setAlpha(scaleFactor);
float verticalMargin = pageHeight*(1-scaleFactor)/2;
float horizonMargin = pageWidth*(1-scaleFactor)/2;
if(position < 0){
page.setTranslationX(horizonMargin-verticalMargin/2);
}else {
page.setTranslationX(-horizonMargin+verticalMargin/2);
}
}else{
//当不在屏幕显示范围时,恢复所有属性
page.setScaleX(1);
page.setScaleY(1);
page.setTranslationX(0);
page.setAlpha(1);
}
}
}
效果图
缩放动画
java代码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_zoom);
mImageRcv = (RecyclerView)findViewById(R.id.rcv_images);
mAdapter = new ImageAdapter(this);
mAdapter.setOnItemClickListener(new ImageAdapter.OnItemClickListener() {
@Override
public void onItemClicked(View view, int pos) {
zoomImageFromThumb(view,mAdapter.getItemData(pos));
}
});
mImageRcv.setAdapter(mAdapter);
mImageRcv.setLayoutManager(new GridLayoutManager(this,3,
LinearLayoutManager.VERTICAL,false));
mShortAnimationDuration = getResources()
.getInteger(android.R.integer.config_shortAnimTime);
}
/**
* 动画执行关键代码
**/
private void zoomImageFromThumb(final View thumbView, int imageResId) {
// 取消上一个动画
if (mCurrentAnimator != null) {
mCurrentAnimator.cancel();
}
// 加载高清图片
final ImageView expandedImageView = (ImageView) findViewById(R.id.expanded_image);
expandedImageView.setImageResource(imageResId);
// 计算尺寸,以便精准动画
final Rect startBounds = new Rect();
final Rect finalBounds = new Rect();
final Point globalOffset = new Point();
// 获取屏幕绝对坐标
thumbView.getGlobalVisibleRect(startBounds);
findViewById(R.id.container).getGlobalVisibleRect(finalBounds, globalOffset);
startBounds.offset(-globalOffset.x, -globalOffset.y);
finalBounds.offset(-globalOffset.x, -globalOffset.y);
//
float startScale;
if ((float) finalBounds.width() / finalBounds.height()
> (float) startBounds.width() / startBounds.height()) {
startScale = (float) startBounds.height() / finalBounds.height();
} else {
startScale = (float) startBounds.width() / finalBounds.width();
}
//隐藏缩略图并开始动画显示高清图
thumbView.setAlpha(0f);
expandedImageView.setVisibility(View.VISIBLE);
// 设置动画的中心为坐标原点
expandedImageView.setPivotX(0f);
expandedImageView.setPivotY(0f);
// 构造动画
AnimatorSet set = new AnimatorSet();
set
.play(ObjectAnimator.ofFloat(expandedImageView, View.X, startBounds.left,
finalBounds.left))
.with(ObjectAnimator.ofFloat(expandedImageView, View.Y, startBounds.top,
finalBounds.top))
.with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_X, startScale, 1f))
.with(ObjectAnimator.ofFloat(expandedImageView, View.SCALE_Y, startScale, 1f));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mCurrentAnimator = null;
}
@Override
public void onAnimationCancel(Animator animation) {
mCurrentAnimator = null;
}
});
set.start();
mCurrentAnimator = set;
//再次点击还原,逆过程
final float startScaleFinal = startScale;
expandedImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mCurrentAnimator != null) {
mCurrentAnimator.cancel();
}
AnimatorSet set = new AnimatorSet();
set
.play(ObjectAnimator.ofFloat(expandedImageView, View.X, startBounds.left))
.with(ObjectAnimator.ofFloat(expandedImageView, View.Y, startBounds.top))
.with(ObjectAnimator
.ofFloat(expandedImageView, View.SCALE_X, startScaleFinal))
.with(ObjectAnimator
.ofFloat(expandedImageView, View.SCALE_Y, startScaleFinal));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
thumbView.setAlpha(1f);
expandedImageView.setVisibility(View.GONE);
mCurrentAnimator = null;
}
@Override
public void onAnimationCancel(Animator animation) {
thumbView.setAlpha(1f);
expandedImageView.setVisibility(View.GONE);
mCurrentAnimator = null;
}
});
set.start();
mCurrentAnimator = set;
}
});
}
效果图
以上就是动画相关的知识。
时间: 2024-10-12 20:04:39