* commit 'd6bbf71dc552d54ffde25e8c00ed96630a5221a6': docs: animations au class
This commit is contained in:
BIN
docs/downloads/training/Animations.zip
Normal file
BIN
docs/downloads/training/Animations.zip
Normal file
Binary file not shown.
BIN
docs/html/training/animation/anim_card_flip.mp4
Executable file
BIN
docs/html/training/animation/anim_card_flip.mp4
Executable file
Binary file not shown.
BIN
docs/html/training/animation/anim_card_flip.ogv
Executable file
BIN
docs/html/training/animation/anim_card_flip.ogv
Executable file
Binary file not shown.
BIN
docs/html/training/animation/anim_card_flip.webm
Executable file
BIN
docs/html/training/animation/anim_card_flip.webm
Executable file
Binary file not shown.
BIN
docs/html/training/animation/anim_crossfade.mp4
Normal file
BIN
docs/html/training/animation/anim_crossfade.mp4
Normal file
Binary file not shown.
BIN
docs/html/training/animation/anim_crossfade.ogv
Normal file
BIN
docs/html/training/animation/anim_crossfade.ogv
Normal file
Binary file not shown.
BIN
docs/html/training/animation/anim_crossfade.webm
Normal file
BIN
docs/html/training/animation/anim_crossfade.webm
Normal file
Binary file not shown.
BIN
docs/html/training/animation/anim_layout_changes.mp4
Normal file
BIN
docs/html/training/animation/anim_layout_changes.mp4
Normal file
Binary file not shown.
BIN
docs/html/training/animation/anim_layout_changes.ogv
Normal file
BIN
docs/html/training/animation/anim_layout_changes.ogv
Normal file
Binary file not shown.
BIN
docs/html/training/animation/anim_layout_changes.webm
Normal file
BIN
docs/html/training/animation/anim_layout_changes.webm
Normal file
Binary file not shown.
BIN
docs/html/training/animation/anim_screenslide.mp4
Executable file
BIN
docs/html/training/animation/anim_screenslide.mp4
Executable file
Binary file not shown.
BIN
docs/html/training/animation/anim_screenslide.ogv
Executable file
BIN
docs/html/training/animation/anim_screenslide.ogv
Executable file
Binary file not shown.
BIN
docs/html/training/animation/anim_screenslide.webm
Executable file
BIN
docs/html/training/animation/anim_screenslide.webm
Executable file
Binary file not shown.
BIN
docs/html/training/animation/anim_zoom.mp4
Normal file
BIN
docs/html/training/animation/anim_zoom.mp4
Normal file
Binary file not shown.
BIN
docs/html/training/animation/anim_zoom.ogv
Normal file
BIN
docs/html/training/animation/anim_zoom.ogv
Normal file
Binary file not shown.
BIN
docs/html/training/animation/anim_zoom.webm
Normal file
BIN
docs/html/training/animation/anim_zoom.webm
Normal file
Binary file not shown.
365
docs/html/training/animation/cardflip.jd
Normal file
365
docs/html/training/animation/cardflip.jd
Normal file
@@ -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>
|
||||
208
docs/html/training/animation/crossfade.jd
Normal file
208
docs/html/training/animation/crossfade.jd
Normal file
@@ -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>
|
||||
86
docs/html/training/animation/index.jd
Normal file
86
docs/html/training/animation/index.jd
Normal file
@@ -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>
|
||||
77
docs/html/training/animation/layout.jd
Normal file
77
docs/html/training/animation/layout.jd
Normal file
@@ -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>
|
||||
185
docs/html/training/animation/screen-slide.jd
Executable file
185
docs/html/training/animation/screen-slide.jd
Executable file
@@ -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>
|
||||
320
docs/html/training/animation/zoom.jd
Normal file
320
docs/html/training/animation/zoom.jd
Normal file
@@ -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>
|
||||
@@ -287,6 +287,34 @@
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="nav-section">
|
||||
<div class="nav-section-header"><a href="<?cs var:toroot ?>training/animation/index.html">
|
||||
<span class="en">Adding Animations</span>
|
||||
</a></div>
|
||||
<ul>
|
||||
<li><a href="<?cs var:toroot ?>training/animation/crossfade.html">
|
||||
<span class="en">Crossfading Two Views</span>
|
||||
</a>
|
||||
</li>
|
||||
<li><a href="<?cs var:toroot ?>training/animation/screen-slide.html">
|
||||
<span class="en">Using ViewPager for Screen Slide</span>
|
||||
</a>
|
||||
</li>
|
||||
<li><a href="<?cs var:toroot ?>training/animation/cardflip.html">
|
||||
<span class="en">Displaying Card Flip Animations</span>
|
||||
</a>
|
||||
</li>
|
||||
<li><a href="<?cs var:toroot ?>training/animation/zoom.html">
|
||||
<span class="en">Zooming a View</span>
|
||||
</a>
|
||||
</li>
|
||||
<li><a href="<?cs var:toroot ?>training/animation/layout.html">
|
||||
<span class="en">Animating Layout Changes</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="nav-section">
|
||||
<div class="nav-section-header"><a href="<?cs var:toroot ?>training/managing-audio/index.html">
|
||||
|
||||
Reference in New Issue
Block a user