【Android】Animation动画(二)
Displaying Card Flip Animations
This lesson shows you how to do a card flip animation with custom fragment animations. Card flips animate between views of content by showing an animation that emulates a card flipping over.(说白了就是界面切换,只不过View是通过Fragment实现的)上代码:
1 /* 2 * Copyright 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.animationsdemo; 18 19 import android.app.Activity; 20 import android.app.Fragment; 21 import android.app.FragmentManager; 22 import android.content.Intent; 23 import android.os.Bundle; 24 import android.os.Handler; 25 import android.support.v4.app.NavUtils; 26 import android.view.LayoutInflater; 27 import android.view.Menu; 28 import android.view.MenuItem; 29 import android.view.View; 30 import android.view.ViewGroup; 31 import android.widget.TextView; 32 33 /** 34 * Demonstrates a "card-flip" animation using custom fragment transactions ({@link 35 * android.app.FragmentTransaction#setCustomAnimations(int, int)}). 36 * 37 * <p>This sample shows an "info" action bar button that shows the back of a "card", rotating the 38 * front of the card out and the back of the card in. The reverse animation is played when the user 39 * presses the system Back button or the "photo" action bar button.</p> 40 */ 41 public class CardFlipActivity extends Activity 42 implements FragmentManager.OnBackStackChangedListener { 43 /** 44 * A handler object, used for deferring UI operations. 45 */ 46 private Handler mHandler = new Handler(); 47 48 /** 49 * Whether or not we're showing the back of the card (otherwise showing the front). 50 */ 51 private boolean mShowingBack = false; 52 53 @Override 54 protected void onCreate(Bundle savedInstanceState) { 55 super.onCreate(savedInstanceState); 56 setContentView(R.layout.activity_card_flip); 57 58 if (savedInstanceState == null) { 59 // If there is no saved instance state, add a fragment representing the 60 // front of the card to this activity. If there is saved instance state, 61 // this fragment will have already been added to the activity. 62 getFragmentManager() 63 .beginTransaction() 64 .add(R.id.container, new CardFrontFragment()) 65 .commit(); 66 } else { 67 mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0); 68 } 69 70 // Monitor back stack changes to ensure the action bar shows the appropriate 71 // button (either "photo" or "info"). 72 getFragmentManager().addOnBackStackChangedListener(this); 73 } 74 75 @Override 76 public boolean onCreateOptionsMenu(Menu menu) { 77 super.onCreateOptionsMenu(menu); 78 79 // Add either a "photo" or "finish" button to the action bar, depending on which page 80 // is currently selected. 81 MenuItem item = menu.add(Menu.NONE, R.id.action_flip, Menu.NONE, 82 mShowingBack 83 ? R.string.action_photo 84 : R.string.action_info); 85 item.setIcon(mShowingBack 86 ? R.drawable.ic_action_photo 87 : R.drawable.ic_action_info); 88 item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 89 return true; 90 } 91 92 @Override 93 public boolean onOptionsItemSelected(MenuItem item) { 94 switch (item.getItemId()) { 95 case android.R.id.home: 96 // Navigate "up" the demo structure to the launchpad activity. 97 // See http://developer.android.com/design/patterns/navigation.html for more. 98 NavUtils.navigateUpTo(this, new Intent(this, MainActivity.class)); 99 return true; 100 101 case R.id.action_flip: 102 flipCard(); 103 return true; 104 } 105 106 return super.onOptionsItemSelected(item); 107 } 108 109 private void flipCard() { 110 if (mShowingBack) { 111 getFragmentManager().popBackStack(); 112 return; 113 } 114 115 // Flip to the back. 116 117 mShowingBack = true; 118 119 // Create and commit a new fragment transaction that adds the fragment for the back of 120 // the card, uses custom animations, and is part of the fragment manager's back stack. 121 122 getFragmentManager() 123 .beginTransaction() 124 125 // Replace the default fragment animations with animator resources representing 126 // rotations when switching to the back of the card, as well as animator 127 // resources representing rotations when flipping back to the front (e.g. when 128 // the system Back button is pressed). 129 .setCustomAnimations( 130 R.animator.card_flip_right_in, R.animator.card_flip_right_out, 131 R.animator.card_flip_left_in, R.animator.card_flip_left_out) 132 133 // Replace any fragments currently in the container view with a fragment 134 // representing the next page (indicated by the just-incremented currentPage 135 // variable). 136 .replace(R.id.container, new CardBackFragment()) 137 138 // Add this transaction to the back stack, allowing users to press Back 139 // to get to the front of the card. 140 .addToBackStack(null) 141 142 // Commit the transaction. 143 .commit(); 144 145 // Defer an invalidation of the options menu (on modern devices, the action bar). This 146 // can't be done immediately because the transaction may not yet be committed. Commits 147 // are asynchronous in that they are posted to the main thread's message loop. 148 mHandler.post(new Runnable() { 149 @Override 150 public void run() { 151 invalidateOptionsMenu(); 152 } 153 }); 154 } 155 156 @Override 157 public void onBackStackChanged() { 158 mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0); 159 160 // When the back stack changes, invalidate the options menu (action bar). 161 invalidateOptionsMenu(); 162 } 163 164 /** 165 * A fragment representing the front of the card. 166 */ 167 public static class CardFrontFragment extends Fragment { 168 public CardFrontFragment() { 169 } 170 171 @Override 172 public View onCreateView(LayoutInflater inflater, ViewGroup container, 173 Bundle savedInstanceState) { 174 return inflater.inflate(R.layout.fragment_card_front, container, false); 175 } 176 } 177 178 /** 179 * A fragment representing the back of the card. 180 */ 181 public static class CardBackFragment extends Fragment { 182 public CardBackFragment() { 183 } 184 185 @Override 186 public View onCreateView(LayoutInflater inflater, ViewGroup container, 187 Bundle savedInstanceState) { 188 return inflater.inflate(R.layout.fragment_card_back, container, false); 189 } 190 } 191 }
这段代码修改了Fragment从栈中保存和退出的动画,四个动画分别是:
1)card_flip_left_in.xml
1 <set xmlns:android="http://schemas.android.com/apk/res/android"> 2 <!-- Before rotating, immediately set the alpha to 0. --> 3 <objectAnimator 4 android:valueFrom="1.0" 5 android:valueTo="0.0" 6 android:propertyName="alpha" 7 android:duration="0" /> 8 9 <!-- Rotate. --> 10 <objectAnimator 11 android:valueFrom="-180" 12 android:valueTo="0" 13 android:propertyName="rotationY" 14 android:interpolator="@android:interpolator/accelerate_decelerate" 15 android:duration="@integer/card_flip_time_full" /> 16 17 <!-- Half-way through the rotation (see startOffset), set the alpha to 1. --> 18 <objectAnimator 19 android:valueFrom="0.0" 20 android:valueTo="1.0" 21 android:propertyName="alpha" 22 android:startOffset="@integer/card_flip_time_half" 23 android:duration="1" /> 24 </set>
2)card_flip_left_out.xml
1 <set xmlns:android="http://schemas.android.com/apk/res/android"> 2 <!-- Rotate. --> 3 <objectAnimator 4 android:valueFrom="0" 5 android:valueTo="180" 6 android:propertyName="rotationY" 7 android:interpolator="@android:interpolator/accelerate_decelerate" 8 android:duration="@integer/card_flip_time_full" /> 9 10 <!-- Half-way through the rotation (see startOffset), set the alpha to 0. --> 11 <objectAnimator 12 android:valueFrom="1.0" 13 android:valueTo="0.0" 14 android:propertyName="alpha" 15 android:startOffset="@integer/card_flip_time_half" 16 android:duration="1" /> 17 </set>
3)card_flip_right_in.xml
1 <set xmlns:android="http://schemas.android.com/apk/res/android"> 2 <!-- Before rotating, immediately set the alpha to 0. --> 3 <objectAnimator 4 android:valueFrom="1.0" 5 android:valueTo="0.0" 6 android:propertyName="alpha" 7 android:duration="0" /> 8 9 <!-- Rotate. --> 10 <objectAnimator 11 android:valueFrom="180" 12 android:valueTo="0" 13 android:propertyName="rotationY" 14 android:interpolator="@android:interpolator/accelerate_decelerate" 15 android:duration="@integer/card_flip_time_full" /> 16 17 <!-- Half-way through the rotation (see startOffset), set the alpha to 1. --> 18 <objectAnimator 19 android:valueFrom="0.0" 20 android:valueTo="1.0" 21 android:propertyName="alpha" 22 android:startOffset="@integer/card_flip_time_half" 23 android:duration="1" />
4)card_flip_right_out.xml
1 <set xmlns:android="http://schemas.android.com/apk/res/android"> 2 <!-- Rotate. --> 3 <objectAnimator 4 android:valueFrom="0" 5 android:valueTo="-180" 6 android:propertyName="rotationY" 7 android:interpolator="@android:interpolator/accelerate_decelerate" 8 android:duration="@integer/card_flip_time_full" /> 9 10 <!-- Half-way through the rotation (see startOffset), set the alpha to 0. --> 11 <objectAnimator 12 android:valueFrom="1.0" 13 android:valueTo="0.0" 14 android:propertyName="alpha" 15 android:startOffset="@integer/card_flip_time_half" 16 android:duration="1" /> 17 </set>
这边有个奇怪的ObjectAnimator,暂不讨论。
关键代码都在这里了,再加上两个View即可。其实很简单,就是修改了Fragment默认的切换动画,然后通过压栈和退栈实现了效果,不过可以仔细研究一下它的动画xml,比如通过设置duration=0来让某种属性(类似alpha)瞬间改变。
(详见:http://developer.android.com/training/animation/cardflip.html#views )