diff options
Diffstat (limited to 'docs/html/training/animation')
21 files changed, 1241 insertions, 0 deletions
diff --git a/docs/html/training/animation/anim_card_flip.mp4 b/docs/html/training/animation/anim_card_flip.mp4 Binary files differnew file mode 100755 index 0000000..e885f98 --- /dev/null +++ b/docs/html/training/animation/anim_card_flip.mp4 diff --git a/docs/html/training/animation/anim_card_flip.ogv b/docs/html/training/animation/anim_card_flip.ogv Binary files differnew file mode 100755 index 0000000..33cd86c --- /dev/null +++ b/docs/html/training/animation/anim_card_flip.ogv diff --git a/docs/html/training/animation/anim_card_flip.webm b/docs/html/training/animation/anim_card_flip.webm Binary files differnew file mode 100755 index 0000000..a670d78 --- /dev/null +++ b/docs/html/training/animation/anim_card_flip.webm diff --git a/docs/html/training/animation/anim_crossfade.mp4 b/docs/html/training/animation/anim_crossfade.mp4 Binary files differnew file mode 100644 index 0000000..ced7cc9 --- /dev/null +++ b/docs/html/training/animation/anim_crossfade.mp4 diff --git a/docs/html/training/animation/anim_crossfade.ogv b/docs/html/training/animation/anim_crossfade.ogv Binary files differnew file mode 100644 index 0000000..7ec417a --- /dev/null +++ b/docs/html/training/animation/anim_crossfade.ogv diff --git a/docs/html/training/animation/anim_crossfade.webm b/docs/html/training/animation/anim_crossfade.webm Binary files differnew file mode 100644 index 0000000..21e7228 --- /dev/null +++ b/docs/html/training/animation/anim_crossfade.webm diff --git a/docs/html/training/animation/anim_layout_changes.mp4 b/docs/html/training/animation/anim_layout_changes.mp4 Binary files differnew file mode 100644 index 0000000..0709601 --- /dev/null +++ b/docs/html/training/animation/anim_layout_changes.mp4 diff --git a/docs/html/training/animation/anim_layout_changes.ogv b/docs/html/training/animation/anim_layout_changes.ogv Binary files differnew file mode 100644 index 0000000..75f5250 --- /dev/null +++ b/docs/html/training/animation/anim_layout_changes.ogv diff --git a/docs/html/training/animation/anim_layout_changes.webm b/docs/html/training/animation/anim_layout_changes.webm Binary files differnew file mode 100644 index 0000000..a99a566 --- /dev/null +++ b/docs/html/training/animation/anim_layout_changes.webm diff --git a/docs/html/training/animation/anim_screenslide.mp4 b/docs/html/training/animation/anim_screenslide.mp4 Binary files differnew file mode 100755 index 0000000..3e65026 --- /dev/null +++ b/docs/html/training/animation/anim_screenslide.mp4 diff --git a/docs/html/training/animation/anim_screenslide.ogv b/docs/html/training/animation/anim_screenslide.ogv Binary files differnew file mode 100755 index 0000000..c45ebd4 --- /dev/null +++ b/docs/html/training/animation/anim_screenslide.ogv diff --git a/docs/html/training/animation/anim_screenslide.webm b/docs/html/training/animation/anim_screenslide.webm Binary files differnew file mode 100755 index 0000000..c72adbc --- /dev/null +++ b/docs/html/training/animation/anim_screenslide.webm diff --git a/docs/html/training/animation/anim_zoom.mp4 b/docs/html/training/animation/anim_zoom.mp4 Binary files differnew file mode 100644 index 0000000..4326c35 --- /dev/null +++ b/docs/html/training/animation/anim_zoom.mp4 diff --git a/docs/html/training/animation/anim_zoom.ogv b/docs/html/training/animation/anim_zoom.ogv Binary files differnew file mode 100644 index 0000000..e5793f3 --- /dev/null +++ b/docs/html/training/animation/anim_zoom.ogv diff --git a/docs/html/training/animation/anim_zoom.webm b/docs/html/training/animation/anim_zoom.webm Binary files differnew file mode 100644 index 0000000..b3b7566 --- /dev/null +++ b/docs/html/training/animation/anim_zoom.webm diff --git a/docs/html/training/animation/cardflip.jd b/docs/html/training/animation/cardflip.jd new file mode 100644 index 0000000..ab3eb3a --- /dev/null +++ b/docs/html/training/animation/cardflip.jd @@ -0,0 +1,365 @@ +page.title=Displaying Card Flip Animations +trainingnavtop=true + +@jd:body + <div id="tb-wrapper"> + <div id="tb"> + <h2> + This lesson teaches you to + </h2> + <ol> + <li> + <a href="#animators">Create the Animators</a> + </li> + <li> + <a href="#views">Create the Views</a> + </li> + <li> + <a href="#fragment">Create the Fragment</a> + </li> + <li> + <a href="#animate">Animate the Card Flip</a> + </li> + </ol> + </div> + </div> + <p> 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. + </p> + <p>Here's what a card flip looks like: + </p> + + <div class="framed-galaxynexus-land-span-8"> + <video class="play-on-hover" autoplay> + <source src="anim_card_flip.mp4" type="video/mp4"> + <source src="anim_card_flip.webm" type="video/webm"> + <source src="anim_card_flip.ogv" type="video/ogg"> + </video> + </div> + <div class="figure-caption"> + Card flip animation + <div class="video-instructions"> </div> + </div> + + <p> + If you want to jump ahead and see a full working example, + <a href="{@docRoot}shareables/training/Animations.zip">download</a> and + run the sample app and select the Card Flip example. See the following + files for the code implementation: + </p> + <ul> + <li> + <code>src/CardFlipActivity.java</code> + </li> + <li> + <code>animator/card_flip_right_in.xml</code> + </li> + <li> + <code>animator/card_flip_right_out.xml</code> + </li> + <li> + <code>animator/card_flip_right_in.xml</code> + </li> + <li> + <code>animator/card_flip_left_out.xml</code> + </li> + <li> + <code>layout/fragment_card_back.xml</code> + </li> + <li> + <code>layout/fragment_card_front.xml</code> + </li> + </ul> + + <h2 id="animate"> + Create the Animators + </h2> + <p> + Create the animations for the card flips. You'll need two animators for when the front + of the card animates out and to the left and in and from the left. You'll also need two animators + for when the back of the card animates in and from the right and out and to the right. + </p> + <h4> + card_flip_left_in.xml + </h4> +<pre> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- Before rotating, immediately set the alpha to 0. --> + <objectAnimator + android:valueFrom="1.0" + android:valueTo="0.0" + android:propertyName="alpha" + android:duration="0" /> + + <!-- Rotate. --> + <objectAnimator + android:valueFrom="-180" + android:valueTo="0" + android:propertyName="rotationY" + android:interpolator="@android:interpolator/accelerate_decelerate" + android:duration="@integer/card_flip_time_full" /> + + <!-- Half-way through the rotation (see startOffset), set the alpha to 1. --> + <objectAnimator + android:valueFrom="0.0" + android:valueTo="1.0" + android:propertyName="alpha" + android:startOffset="@integer/card_flip_time_half" + android:duration="1" /> +</set> +</pre> + <h4> + card_flip_left_out.xml + </h4> + <pre> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- Rotate. --> + <objectAnimator + android:valueFrom="0" + android:valueTo="180" + android:propertyName="rotationY" + android:interpolator="@android:interpolator/accelerate_decelerate" + android:duration="@integer/card_flip_time_full" /> + + <!-- Half-way through the rotation (see startOffset), set the alpha to 0. --> + <objectAnimator + android:valueFrom="1.0" + android:valueTo="0.0" + android:propertyName="alpha" + android:startOffset="@integer/card_flip_time_half" + android:duration="1" /> +</set> + </pre> + <h4> + card_flip_right_in.xml + </h4> + <pre> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- Before rotating, immediately set the alpha to 0. --> + <objectAnimator + android:valueFrom="1.0" + android:valueTo="0.0" + android:propertyName="alpha" + android:duration="0" /> + + <!-- Rotate. --> + <objectAnimator + android:valueFrom="180" + android:valueTo="0" + android:propertyName="rotationY" + android:interpolator="@android:interpolator/accelerate_decelerate" + android:duration="@integer/card_flip_time_full" /> + + <!-- Half-way through the rotation (see startOffset), set the alpha to 1. --> + <objectAnimator + android:valueFrom="0.0" + android:valueTo="1.0" + android:propertyName="alpha" + android:startOffset="@integer/card_flip_time_half" + android:duration="1" /> +</set> + +</pre> + <h4> + card_flip_right_out.xml + </h4> + <pre> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- Rotate. --> + <objectAnimator + android:valueFrom="0" + android:valueTo="-180" + android:propertyName="rotationY" + android:interpolator="@android:interpolator/accelerate_decelerate" + android:duration="@integer/card_flip_time_full" /> + + <!-- Half-way through the rotation (see startOffset), set the alpha to 0. --> + <objectAnimator + android:valueFrom="1.0" + android:valueTo="0.0" + android:propertyName="alpha" + android:startOffset="@integer/card_flip_time_half" + android:duration="1" /> +</set> +</pre> + <h2 id="views"> + Create the Views + </h2> + <p> + Each side of the "card" is a separate layout that can contain any content you want, + such as two screens of text, two images, or any combination of views to flip between. You'll then + use the two layouts in the fragments that you'll later animate. The following layouts + create one side of a card that shows text: + </p> + + <pre> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:background="#a6c" + android:padding="16dp" + android:gravity="bottom"> + + <TextView android:id="@android:id/text1" + style="?android:textAppearanceLarge" + android:textStyle="bold" + android:textColor="#fff" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/card_back_title" /> + + <TextView style="?android:textAppearanceSmall" + android:textAllCaps="true" + android:textColor="#80ffffff" + android:textStyle="bold" + android:lineSpacingMultiplier="1.2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/card_back_description" /> + +</LinearLayout> +</pre> +<p> +and the other side of the card that displays an {@link android.widget.ImageView}: +</p> +<pre> +<ImageView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:src="@drawable/image1" + android:scaleType="centerCrop" + android:contentDescription="@string/description_image_1" /> +</pre> + <h2 id="fragment"> + Create the Fragment + </h2> + <p> + Create fragment classes for the front and back of the card. These classes return the layouts + that you created previously in the {@link android.app.Fragment#onCreateView onCreateView()} method + of each fragment. You can then create instances of this fragment in the parent activity + where you want to show the card. The following example shows nested fragment classes inside + of the parent activity that uses them: + </p> + <pre> +public class CardFlipActivity extends Activity { + ... + /** + * A fragment representing the front of the card. + */ + public class CardFrontFragment extends Fragment { + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_card_front, container, false); + } + } + + /** + * A fragment representing the back of the card. + */ + public class CardBackFragment extends Fragment { + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_card_back, container, false); + } + } +} +</pre> + <h2 id="animate"> + Animate the Card Flip + </h2> + + <p> Now, you'll need to display the fragments inside of a parent activity. + To do this, first create the layout for your activity. The following example creates a + {@link android.widget.FrameLayout} that you + can add fragments to at runtime:</p> + + <pre> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/container" + android:layout_width="match_parent" + android:layout_height="match_parent" /> +</pre> + + <p>In the activity code, set the content view to be the layout that you just created. It's also + good idea to show a default fragment when the activity is created, so the following example + activity shows you how to display the front of the card by default: + </p> + + + +<pre> +public class CardFlipActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_activity_card_flip); + + if (savedInstanceState == null) { + getFragmentManager() + .beginTransaction() + .add(R.id.container, new CardFrontFragment()) + .commit(); + } + } + ... +} +</pre> + <p> + Now that you have the front of the card showing, you can show the back of the card + with the flip animation at an appropriate time. Create a method to show the other + side of the card that does the following things: + </p> + <ul> + <li>Sets the custom animations that you created earlier for the fragment transitions. + </li> + <li>Replaces the currently displayed fragment with a new fragment and animates this event + with the custom animations that you created. + </li> + <li>Adds the previously displayed fragment to the fragment back stack + so when the user presses the <em>Back</em> button, the card flips back over. + </li> + </ul> + <pre> +private void flipCard() { + if (mShowingBack) { + getFragmentManager().popBackStack(); + return; + } + + // Flip to the back. + + mShowingBack = true; + + // Create and commit a new fragment transaction that adds the fragment for the back of + // the card, uses custom animations, and is part of the fragment manager's back stack. + + getFragmentManager() + .beginTransaction() + + // Replace the default fragment animations with animator resources representing + // rotations when switching to the back of the card, as well as animator + // resources representing rotations when flipping back to the front (e.g. when + // the system Back button is pressed). + .setCustomAnimations( + R.animator.card_flip_right_in, R.animator.card_flip_right_out, + R.animator.card_flip_left_in, R.animator.card_flip_left_out) + + // Replace any fragments currently in the container view with a fragment + // representing the next page (indicated by the just-incremented currentPage + // variable). + .replace(R.id.container, new CardBackFragment()) + + // Add this transaction to the back stack, allowing users to press Back + // to get to the front of the card. + .addToBackStack(null) + + // Commit the transaction. + .commit(); +} +</pre>
\ No newline at end of file diff --git a/docs/html/training/animation/crossfade.jd b/docs/html/training/animation/crossfade.jd new file mode 100644 index 0000000..99e879b --- /dev/null +++ b/docs/html/training/animation/crossfade.jd @@ -0,0 +1,208 @@ +page.title=Crossfading Two Views +trainingnavtop=true + + +@jd:body + + <div id="tb-wrapper"> + <div id="tb"> + <h2> + This lesson teaches you to: + </h2> + <ol> + <li> + <a href="#views">Create the Views</a> + </li> + <li> + <a href="#setup">Set up the Animation</a> + </li> + <li> + <a href="#animate">Crossfade the Views</a> + </li> + </ol> + </div> + </div> + + <p> + Crossfade animations (also know as dissolve) gradually fade out one UI component while simultaneously fading in + another. This animation is useful for situations where you want to switch content or views + in your app. Crossfades are very subtle and short but offer a fluid transition from one screen to the + next. When you don't use them, however, transitions often feel abrupt or hurried. + </p> + <p>Here's an example of a crossfade from a progress indicator to some text content. + </p> + +<div class="framed-galaxynexus-land-span-8"> + <video class="play-on-hover" autoplay> + <source src="anim_crossfade.mp4" type="video/mp4"> + <source src="anim_crossfade.webm" type="video/webm"> + <source src="anim_crossfade.ogv" type="video/ogg"> + </video> +</div> +<div class="figure-caption"> +Crossfade animation + <div class="video-instructions"> </div> +</div> + + <p> + If you want to jump ahead and see a full working example, + <a href="{@docRoot}shareables/training/Animations.zip">download</a> + and run the sample app and select the Crossfade example. + See the following files for the code implementation: + </p> + <ul> + <li> + <code>src/CrossfadeActivity.java</code> + </li> + <li> + <code>layout/activity_crossfade.xml</code> + </li> + <li> + <code>menu/activity_crossfade.xml</code> + </li> + </ul> + <h2 id="views"> + Create the Views + </h2> + <p> + Create the two views that you want to crossfade. The following example creates a progress + indicator and a scrollable text view: + </p> + <pre> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/content" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <TextView style="?android:textAppearanceMedium" + android:lineSpacingMultiplier="1.2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/lorem_ipsum" + android:padding="16dp" /> + + </ScrollView> + + <ProgressBar android:id="@+id/loading_spinner" + style="?android:progressBarStyleLarge" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" /> + +</FrameLayout> +</pre> + <h2 id="setup"> + Set up the Animation + </h2> + <p> + To set up the animation: + </p> + <ol> + <li>Create member variables for the views that you want to crossfade. You need + these references later when modifying the views during the animation. + </li> + <li>For the view that is being faded in, set its visibility to {@link + android.view.View#GONE}. This prevents the view from taking up layout space and omits it + from layout calculations, speeding up processing. + </li> + <li>Cache the <code>{@link android.R.integer#config_shortAnimTime}</code> + system property in a member variable. This property defines a standard + "short" duration for the animation. This duration is ideal for subtle animations or + animations that occur very frequently. {@link android.R.integer#config_longAnimTime} and + {@link android.R.integer#config_mediumAnimTime} are also available if you wish to use them. + </li> + </ol> + <p> + Here's an example using the layout from the previous code snippet as the activity content + view: + </p> + <pre> +public class CrossfadeActivity extends Activity { + + private View mContentView; + private View mLoadingView; + private int mShortAnimationDuration; + + ... + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_crossfade); + + mContentView = findViewById(R.id.content); + mLoadingView = findViewById(R.id.loading_spinner); + + // Initially hide the content view. + mContentView.setVisibility(View.GONE); + + // Retrieve and cache the system's default "short" animation time. + mShortAnimationDuration = getResources().getInteger( + android.R.integer.config_shortAnimTime); + } + +</pre> + <h2 id="animate"> + Crossfade the Views + </h2> + <p> + Now that the views are properly set up, crossfade them by doing the following: + </p> + <ol> + <li>For the view that is fading in, set the alpha value to <code>0</code> and the visibility + to {@link android.view.View#VISIBLE}. (Remember that it was initially set to {@link + android.view.View#GONE}.) This makes the view visible but completely transparent. + </li> + <li>For the view that is fading in, animate its alpha value from <code>0</code> to + <code>1</code>. At the same time, for the view that is fading out, animate the alpha value + from <code>1</code> to <code>0</code>. + </li> + <li>Using {@link android.animation.Animator.AnimatorListener#onAnimationEnd onAnimationEnd()} + in an {@link android.animation.Animator.AnimatorListener}, set the visibility of the view + that was fading out to {@link android.view.View#GONE}. Even though the alpha value is <code>0</code>, + setting the view's visibility to {@link android.view.View#GONE} prevents the view from taking + up layout space and omits it from layout calculations, speeding up processing. + </li> + </ol> + <p> + The following method shows an example of how to do this: + </p> + <pre> +private View mContentView; +private View mLoadingView; +private int mShortAnimationDuration; + +... + +private void crossfade() { + + // Set the content view to 0% opacity but visible, so that it is visible + // (but fully transparent) during the animation. + mContentView.setAlpha(0f); + mContentView.setVisibility(View.VISIBLE); + + // Animate the content view to 100% opacity, and clear any animation + // listener set on the view. + mContentView.animate() + .alpha(1f) + .setDuration(mShortAnimationDuration) + .setListener(null); + + // Animate the loading view to 0% opacity. After the animation ends, + // set its visibility to GONE as an optimization step (it won't + // participate in layout passes, etc.) + mHideView.animate() + .alpha(0f) + .setDuration(mShortAnimationDuration) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mHideView.setVisibility(View.GONE); + } + }); +} +</pre>
\ No newline at end of file diff --git a/docs/html/training/animation/index.jd b/docs/html/training/animation/index.jd new file mode 100644 index 0000000..9cc7e6c --- /dev/null +++ b/docs/html/training/animation/index.jd @@ -0,0 +1,86 @@ +page.title=Adding Animations +trainingnavtop=true +startpage=true + +@jd:body + <div id="tb-wrapper"> + <div id="tb"> + <h2> + Dependencies and prerequisites + </h2> + <ul> + <li>Android 4.0 or later + </li> + <li>Experience building an Android <a href="{@docRoot}guide/topics/ui/index.html">User + Interface</a> + </li> + </ul> + <h2> + You should also read + </h2> + <ul> + <li> + <a href="{@docRoot}guide/topics/graphics/prop-animation.html">Property Animation</a> + </li> + </ul> + <h2> + Try it out + </h2> + <div class="download-box"> + <a href="{@docRoot}shareables/training/Animations.zip" class= + "button">Download the sample app</a> + <p class="filename"> + Animations.zip + </p> + </div> + </div> + </div> + <p> + Animations can add subtle visual cues that notify users about what's going on in your app and + improve their mental model of your app's interface. Animations are especially useful when the + screen changes state, such as when content loads or new actions become available. Animations + can also add a polished look to your app, which gives your app a higher quality feel. + </p> + <p> + Keep in mind though, that overusing animations or using them at the wrong time can be + detrimental, such as when they cause delays. This training class shows you how to + implement some common types of animations that can increase usability and add flair without + annoying your users. + </p> + + <h2> + Lessons + </h2> + <dl> + <dt> + <b><a href="crossfade.html">Crossfading Two Views</a></b> + </dt> + <dd> + Learn how to crossfade between two overlapping views. This lesson shows you how to crossfade a progress + indicator to a view that contains text content. + </dd> + <dt> + <b><a href="screen-slide.html">Using ViewPager for Screen Slides</a></b> + </dt> + <dd> + Learn how to animate between horizontally adjacent screens with a sliding transition. + </dd> + <dt> + <b><a href="cardflip.html">Displaying Card Flip Animations</a></b> + </dt> + <dd> + Learn how to animate between two views with a flipping motion. + </dd> + <dt> + <b><a href="zoom.html">Zooming a View</a></b> + </dt> + <dd> + Learn how to enlarge views with a touch-to-zoom animation. + </dd> + <dt> + <b><a href="layout.html">Animating Layout Changes</a></b> + </dt> + <dd> + Learn how to enable built-in animations when adding, removing, or updating child views in a layout. + </dd> + </dl>
\ No newline at end of file diff --git a/docs/html/training/animation/layout.jd b/docs/html/training/animation/layout.jd new file mode 100644 index 0000000..b8e0077 --- /dev/null +++ b/docs/html/training/animation/layout.jd @@ -0,0 +1,77 @@ +page.title=Animating Layout Changes +trainingnavtop=true + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>This lesson teaches you to:</h2> + <ol> + <li><a href="#views">Create the Layout</a></li> + <li><a href="#add">Add, Update, or Remove Items from the Layout</a></li> + </ol> + +</div> +</div> + + <p>A layout animation is a pre-loaded animation that the system runs each time you make a change + to the layout configuration. All you need to do is set an attribute in the layout to tell the + Android system to animate these layout changes, and system-default animations are carried out for you. + </p> +<p class="note"><strong>Tip</strong>: If you want to supply custom layout animations, +create a {@link android.animation.LayoutTransition} object and supply it to +the layout with the {@link android.view.ViewGroup#setLayoutTransition setLayoutTransition()} +method. +</p> + Here's what a default layout animation looks like when adding items to a list: +</p> + + <div class="framed-galaxynexus-land-span-8"> + <video class="play-on-hover" autoplay> + <source src="anim_layout_changes.mp4" type="video/mp4"> + <source src="anim_layout_changes.webm" type="video/webm"> + <source src="anim_layout_changes.ogv" type="video/ogg"> + </video> + </div> + <div class="figure-caption"> + Layout animation + <div class="video-instructions"> </div> + </div> + +<p>If you want to jump ahead and see a full working example, +<a href="{@docRoot}shareables/training/Animations.zip">download</a> and +run the sample app and select the Crossfade example. See the following files for the +code implementation:</p> +<ol> + <li><code>src/LayoutChangesActivity.java</code></li> + <li><code>layout/activity_layout_changes.xml</code></li> + <li><code>menu/activity_layout_changes.xml</code></li> +</ol> + +<h2 id="views">Create the Layout</h2> +<p>In your activity's layout XML file, set the <code>android:animateLayoutChanges</code> + attribute to <code>true</code> for the layout that you want to enable animations for. + For instance:</p> + +<pre> +<LinearLayout android:id="@+id/container" + android:animateLayoutChanges="true" + ... +/> +</pre> + +<h2 id="activity">Add, Update, or Remove Items from the Layout</h2> +<p> +Now, all you need to do is add, remove, or update items in the layout +and the items are animated automatically: +</p> +<pre> +private ViewGroup mContainerView; +... +private void addItem() { + View newView; + ... + mContainerView.addView(newView, 0); +} +</pre> diff --git a/docs/html/training/animation/screen-slide.jd b/docs/html/training/animation/screen-slide.jd new file mode 100755 index 0000000..8a7af67 --- /dev/null +++ b/docs/html/training/animation/screen-slide.jd @@ -0,0 +1,185 @@ +page.title=Using ViewPager for Screen Slides +trainingnavtop=true + +@jd:body + + <div id="tb-wrapper"> + <div id="tb"> + <h2>This lesson teaches you to</h2> + <ol> + <li><a href="#views">Create the Views</a></li> + <li><a href="#fragment">Create the Fragment</a></li> + <li><a href="#viewpager">Animate the Screen Slide</a></li> + </ol> + </div> + </div> + <p> + Screen slides are transitions between one entire screen to another and are common with UIs + like setup wizards or slideshows. This lesson shows you how to do screen slides with + a {@link android.support.v4.view.ViewPager} provided by the <a href= + "{@docRoot}/tools/extras/support-library.html">support library</a>. + {@link android.support.v4.view.ViewPager}s can animate screen slides + automatically. Here's what a screen slide looks like that transitions from + one screen of content to the next: + </p> + + <div class="framed-galaxynexus-land-span-8"> + <video class="play-on-hover" autoplay> + <source src="anim_screenslide.mp4" type="video/mp4"> + <source src="anim_screenslide.webm" type="video/webm"> + <source src="anim_screenslide.ogv" type="video/ogg"> + </video> + </div> + + <div class="figure-caption"> + Screen slide animation + <div class="video-instructions"> </div> + </div> + +<p>If you want to jump ahead and see a full working example, +<a href="{@docRoot}shareables/training/Animations.zip">download</a> +and run the sample app and select the Screen Slide example. See the +following files for the code implementation:</p> +<ul> + <li><code>src/ScreenSlidePageFragment.java</code></li> + <li><code>src/ScreenSlideActivity.java</code></li> + <li><code>layout/activity_screen_slide.xml</code></li> + <li><code>layout/fragment_screen_slide_page.xml</code></li> +</ul> + +<h2 id="views">Create the Views</h2> + <p>Create a layout file that you'll later use for the content of a fragment. The following example + contains a text view to display some text: + +<pre> +<com.example.android.animationsdemo.ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/content" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <TextView style="?android:textAppearanceMedium" + android:padding="16dp" + android:lineSpacingMultiplier="1.2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/lorem_ipsum" /> + +</com.example.android.animationsdemo.ScrollView> +</pre> + +<h2 id="fragment">Create the Fragment</h2> +<p>Create a {@link android.support.v4.app.Fragment} class that returns the layout +that you just created in the {@link android.app.Fragment#onCreateView onCreateView()} + method. You can then create instances of this fragment in the parent activity whenever you need a new page to + display to the user:</p> + + +<pre> +public class ScreenSlidePageFragment extends Fragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + ViewGroup rootView = (ViewGroup) inflater.inflate( + R.layout.fragment_screen_slide_page, container, false); + + return rootView; + } +} +</pre> + +<h2 id="viewpager">Screen Slides with ViewPager</h2> + +<p>{@link android.support.v4.view.ViewPager}s have built-in swipe gestures to transition + through pages, and they display screen slide animations by default, so you don't need to create any. {@link android.support.v4.view.ViewPager}s use +{@link android.support.v4.view.PagerAdapter}s as a supply for new pages to display, so the {@link android.support.v4.view.PagerAdapter} will use the +fragment class that you created earlier. + </p> + +<p>To begin, create a layout that contains a {@link android.support.v4.view.ViewPager}:</p> + +<pre> +<android.support.v4.view.ViewPager + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/pager" + android:layout_width="match_parent" + android:layout_height="match_parent" /> +</pre> + +<p>Create an activity that does the following things: +</p> + +<ul> + <li>Sets the content view to be the layout with the {@link android.support.v4.view.ViewPager}.</li> + <li>Create a class that extends the {@link android.support.v13.app.FragmentStatePagerAdapter} abstract class. Implement + the {@link android.support.v4.app.FragmentStatePagerAdapter#getItem getItem()} method to supply + instances of <code>ScreenSlidePageFragment</code> as new pages. The pager adapter also requires that you implement the + {@link android.support.v4.view.PagerAdapter#getCount getCount()} method, which returns the amount of pages the adapter will create (five in the example). + <li>Hooks up the {@link android.support.v4.view.PagerAdapter} to the {@link android.support.v4.view.ViewPager}</code>.</li> + <li>Handle's the device's back button by moving backwards in the virtual stack of fragments. + If the user is already on the first page, go back on the activity back stack.</li> +</ul> + +<pre> +public class ScreenSlidePagerActivity extends FragmentActivity { + /** + * The number of pages (wizard steps) to show in this demo. + */ + private static final int NUM_PAGES = 5; + + /** + * The pager widget, which handles animation and allows swiping horizontally to access previous + * and next wizard steps. + */ + private ViewPager mPager; + + /** + * The pager adapter, which provides the pages to the view pager widget. + */ + private PagerAdapter mPagerAdapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_screen_slide_pager); + + // Instantiate a ViewPager and a PagerAdapter. + mPager = (ViewPager) findViewById(R.id.pager); + mPagerAdapter = new ScreenSlidePagerAdapter(getFragmentManager()); + mPager.setAdapter(mPagerAdapter); + } + + @Override + public void onBackPressed() { + if (mPager.getCurrentItem() == 0) { + // If the user is currently looking at the first step, allow the system to handle the + // Back button. This calls finish() on this activity and pops the back stack. + super.onBackPressed(); + } else { + // Otherwise, select the previous step. + mPager.setCurrentItem(mPager.getCurrentItem() - 1); + } + } + + /** + * A simple pager adapter that represents 5 ScreenSlidePageFragment objects, in + * sequence. + */ + private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter { + public ScreenSlidePagerAdapter(FragmentManager fm) { + super(fm); + } + + @Override + public Fragment getItem(int position) { + return new ScreenSlidePageFragment(); + } + + @Override + public int getCount() { + return NUM_PAGES; + } + } +} +</pre>
\ No newline at end of file diff --git a/docs/html/training/animation/zoom.jd b/docs/html/training/animation/zoom.jd new file mode 100644 index 0000000..5dc2b6c --- /dev/null +++ b/docs/html/training/animation/zoom.jd @@ -0,0 +1,320 @@ +page.title=Zooming a View +trainingnavtop=true + +@jd:body + + <div id="tb-wrapper"> + <div id="tb"> + <h2> + This lesson teaches you to: + </h2> + <ol> + <li> + <a href="#views">Create the Views</a> + </li> + <li> + <a href="#setup">Set up the Zoom Animation</a> + </li> + <li> + <a href="#animate">Zoom the View</a> + </li> + </ol> + </div> + </div> + <p> + This lesson demonstrates how to do a touch-to-zoom animation, which is useful for apps such as photo + galleries to animate a view from a thumbnail to a full-size image that fills the screen. + </p> + <p>Here's what a touch-to-zoom animation looks like that + expands an image thumbnail to fill the screen: + </p> + + <div class="framed-galaxynexus-land-span-8"> + <video class="play-on-hover" autoplay> + <source src="anim_zoom.mp4" type="video/mp4"> + <source src="anim_zoom.webm" type="video/webm"> + <source src="anim_zoom.ogv" type="video/ogg"> + </video> + </div> + <div class="figure-caption"> + Zoom animation + <div class="video-instructions"> </div> + </div> + + <p> + If you want to jump ahead and see a full working example, + <a href="{@docRoot}shareables/training/Animations.zip">download</a> and + run the sample app and select the + Zoom example. See the following files for the code implementation: + </p> + <ul> + <li> + <code>src/TouchHighlightImageButton.java</code> (a simple helper class that shows a blue + touch highlight when the image button is pressed) + </li> + <li> + <code>src/ZoomActivity.java</code> + </li> + <li> + <code>layout/activity_zoom.xml</code> + </li> + </ul> + <h2 id="views"> + Create the Views + </h2> + <p> + Create a layout file that contains the small and large version of the content that you want + to zoom. The following example creates an {@link android.widget.ImageButton} for clickable image thumbnail + and an {@link android.widget.ImageView} that displays the enlarged view of the image: + </p> + <pre> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/container" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:padding="16dp"> + + <ImageButton + android:id="@+id/thumb_button_1" + android:layout_width="100dp" + android:layout_height="75dp" + android:layout_marginRight="1dp" + android:src="@drawable/thumb1" + android:scaleType="centerCrop" + android:contentDescription="@string/description_image_1" /> + + </LinearLayout> + + <!-- This initially-hidden ImageView will hold the expanded/zoomed version of + the images above. Without transformations applied, it takes up the entire + screen. To achieve the "zoom" animation, this view's bounds are animated + from the bounds of the thumbnail button above, to its final laid-out + bounds. + --> + + <ImageView + android:id="@+id/expanded_image" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:visibility="invisible" + android:contentDescription="@string/description_zoom_touch_close" /> + +</FrameLayout> +</pre> + <h2 id="setup"> + Set up the Zoom Animation + </h2> + <p> + Once you apply your layout, set up the event handlers that trigger the zoom animation. + The following example adds a {@link android.view.View.OnClickListener} to the {@link + android.widget.ImageButton} to execute the zoom animation when the user + clicks the image button: + </p> + <pre> +public class ZoomActivity extends FragmentActivity { + // Hold a reference to the current animator, + // so that it can be canceled mid-way. + private Animator mCurrentAnimator; + + // The system "short" animation time duration, in milliseconds. This + // duration is ideal for subtle animations or animations that occur + // very frequently. + private int mShortAnimationDuration; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_zoom); + + // Hook up clicks on the thumbnail views. + + final View thumb1View = findViewById(R.id.thumb_button_1); + thumb1View.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + zoomImageFromThumb(thumb1View, R.drawable.image1); + } + }); + + // Retrieve and cache the system's default "short" animation time. + mShortAnimationDuration = getResources().getInteger( + android.R.integer.config_shortAnimTime); + } + ... +} +</pre> + <h2 id="animate"> + Zoom the View + </h2> + <p> + You'll now need to animate from the normal sized view to the zoomed view + when appropriate. In general, you need to animate from the bounds of the normal-sized view to the + bounds of the larger-sized view. The following method shows you how to implement a zoom animation that + zooms from an image thumbnail to an enlarged view by doing the following things: + </p> + <ol> + <li>Assign the high-res image to the hidden "zoomed-in" (enlarged) {@link + android.widget.ImageView}. The following example loads a large image resource on the UI + thread for simplicity. You will want to do this loading in a separate thread to prevent + blocking on the UI thread and then set the bitmap on the UI thread. Ideally, the bitmap + should not be larger than the screen size. + </li> + <li>Calculate the starting and ending bounds for the {@link android.widget.ImageView}. + </li> + <li>Animate each of the four positioning and sizing properties <code>{@link + android.view.View#X}</code>, <code>{@link android.view.View#Y}</code>, ({@link + android.view.View#SCALE_X}, and <code>{@link android.view.View#SCALE_Y}</code>) + simultaneously, from the starting bounds to the ending bounds. These four animations are + added to an {@link android.animation.AnimatorSet} so that they can be started at the same + time. + </li> + <li>Zoom back out by running a similar animation but in reverse when the user touches the + screen when the image is zoomed in. You can do this by adding a {@link + android.view.View.OnClickListener} to the {@link android.widget.ImageView}. When clicked, the + {@link android.widget.ImageView} minimizes back down to the size of the image thumbnail and + sets its visibility to {@link android.view.View#GONE} to hide it. + </li> + </ol> + <pre> +private void zoomImageFromThumb(final View thumbView, int imageResId) { + // If there's an animation in progress, cancel it + // immediately and proceed with this one. + if (mCurrentAnimator != null) { + mCurrentAnimator.cancel(); + } + + // Load the high-resolution "zoomed-in" image. + final ImageView expandedImageView = (ImageView) findViewById( + R.id.expanded_image); + expandedImageView.setImageResource(imageResId); + + // Calculate the starting and ending bounds for the zoomed-in image. + // This step involves lots of math. Yay, math. + final Rect startBounds = new Rect(); + final Rect finalBounds = new Rect(); + final Point globalOffset = new Point(); + + // The start bounds are the global visible rectangle of the thumbnail, + // and the final bounds are the global visible rectangle of the container + // view. Also set the container view's offset as the origin for the + // bounds, since that's the origin for the positioning animation + // properties (X, Y). + thumbView.getGlobalVisibleRect(startBounds); + findViewById(R.id.container) + .getGlobalVisibleRect(finalBounds, globalOffset); + startBounds.offset(-globalOffset.x, -globalOffset.y); + finalBounds.offset(-globalOffset.x, -globalOffset.y); + + // Adjust the start bounds to be the same aspect ratio as the final + // bounds using the "center crop" technique. This prevents undesirable + // stretching during the animation. Also calculate the start scaling + // factor (the end scaling factor is always 1.0). + float startScale; + if ((float) finalBounds.width() / finalBounds.height() + > (float) startBounds.width() / startBounds.height()) { + // Extend start bounds horizontally + startScale = (float) startBounds.height() / finalBounds.height(); + float startWidth = startScale * finalBounds.width(); + float deltaWidth = (startWidth - startBounds.width()) / 2; + startBounds.left -= deltaWidth; + startBounds.right += deltaWidth; + } else { + // Extend start bounds vertically + startScale = (float) startBounds.width() / finalBounds.width(); + float startHeight = startScale * finalBounds.height(); + float deltaHeight = (startHeight - startBounds.height()) / 2; + startBounds.top -= deltaHeight; + startBounds.bottom += deltaHeight; + } + + // Hide the thumbnail and show the zoomed-in view. When the animation + // begins, it will position the zoomed-in view in the place of the + // thumbnail. + thumbView.setAlpha(0f); + expandedImageView.setVisibility(View.VISIBLE); + + // Set the pivot point for SCALE_X and SCALE_Y transformations + // to the top-left corner of the zoomed-in view (the default + // is the center of the view). + expandedImageView.setPivotX(0f); + expandedImageView.setPivotY(0f); + + // Construct and run the parallel animation of the four translation and + // scale properties (X, Y, SCALE_X, and SCALE_Y). + 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; + + // Upon clicking the zoomed-in image, it should zoom back down + // to the original bounds and show the thumbnail instead of + // the expanded image. + final float startScaleFinal = startScale; + expandedImageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (mCurrentAnimator != null) { + mCurrentAnimator.cancel(); + } + + // Animate the four positioning/sizing properties in parallel, + // back to their original values. + 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; + } + }); +} +</pre>
\ No newline at end of file |