AnimationsDemo sample code for Animations training class.
Change-Id: I0fbf3c2f66ee4321adcc0c0bf3fe7f4b4e67584e
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.animationsdemo;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v4.app.NavUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* Demonstrates a "card-flip" animation using custom fragment transactions ({@link
|
||||
* android.app.FragmentTransaction#setCustomAnimations(int, int)}).
|
||||
*
|
||||
* <p>This sample shows an "info" action bar button that shows the back of a "card", rotating the
|
||||
* front of the card out and the back of the card in. The reverse animation is played when the user
|
||||
* presses the system Back button or the "photo" action bar button.</p>
|
||||
*/
|
||||
public class CardFlipActivity extends Activity
|
||||
implements FragmentManager.OnBackStackChangedListener {
|
||||
/**
|
||||
* A handler object, used for deferring UI operations.
|
||||
*/
|
||||
private Handler mHandler = new Handler();
|
||||
|
||||
/**
|
||||
* Whether or not we're showing the back of the card (otherwise showing the front).
|
||||
*/
|
||||
private boolean mShowingBack = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_card_flip);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
// If there is no saved instance state, add a fragment representing the
|
||||
// front of the card to this activity. If there is saved instance state,
|
||||
// this fragment will have already been added to the activity.
|
||||
getFragmentManager()
|
||||
.beginTransaction()
|
||||
.add(R.id.container, new CardFrontFragment())
|
||||
.commit();
|
||||
} else {
|
||||
mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0);
|
||||
}
|
||||
|
||||
// Monitor back stack changes to ensure the action bar shows the appropriate
|
||||
// button (either "photo" or "info").
|
||||
getFragmentManager().addOnBackStackChangedListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
|
||||
// Add either a "photo" or "finish" button to the action bar, depending on which page
|
||||
// is currently selected.
|
||||
MenuItem item = menu.add(Menu.NONE, R.id.action_flip, Menu.NONE,
|
||||
mShowingBack
|
||||
? R.string.action_photo
|
||||
: R.string.action_info);
|
||||
item.setIcon(mShowingBack
|
||||
? R.drawable.ic_action_photo
|
||||
: R.drawable.ic_action_info);
|
||||
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
// Navigate "up" the demo structure to the launchpad activity.
|
||||
// See http://developer.android.com/design/patterns/navigation.html for more.
|
||||
NavUtils.navigateUpTo(this, new Intent(this, MainActivity.class));
|
||||
return true;
|
||||
|
||||
case R.id.action_flip:
|
||||
flipCard();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// Defer an invalidation of the options menu (on modern devices, the action bar). This
|
||||
// can't be done immediately because the transaction may not yet be committed. Commits
|
||||
// are asynchronous in that they are posted to the main thread's message loop.
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackStackChanged() {
|
||||
mShowingBack = (getFragmentManager().getBackStackEntryCount() > 0);
|
||||
|
||||
// When the back stack changes, invalidate the options menu (action bar).
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* A fragment representing the front of the card.
|
||||
*/
|
||||
public static class CardFrontFragment extends Fragment {
|
||||
public CardFrontFragment() {
|
||||
}
|
||||
|
||||
@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 static class CardBackFragment extends Fragment {
|
||||
public CardBackFragment() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_card_back, container, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.animationsdemo;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.NavUtils;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* This sample demonstrates cross-fading between two overlapping views.
|
||||
*
|
||||
* <p>In this sample, the two overlapping views are a loading indicator and some text content. The
|
||||
* active view is toggled by touching the toggle button in the action bar. In real-world
|
||||
* applications, this toggle would occur as soon as content was available. Note that if content is
|
||||
* immediately available, a loading spinner shouldn't be presented and there should be no
|
||||
* animation.</p>
|
||||
*/
|
||||
public class CrossfadeActivity extends Activity {
|
||||
/**
|
||||
* The flag indicating whether content is loaded (text is shown) or not (loading spinner is
|
||||
* shown).
|
||||
*/
|
||||
private boolean mContentLoaded;
|
||||
|
||||
/**
|
||||
* The view (or view group) containing the content. This is one of two overlapping views.
|
||||
*/
|
||||
private View mContentView;
|
||||
|
||||
/**
|
||||
* The view containing the loading indicator. This is the other of two overlapping views.
|
||||
*/
|
||||
private View mLoadingView;
|
||||
|
||||
/**
|
||||
* 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_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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
getMenuInflater().inflate(R.menu.activity_crossfade, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
// Navigate "up" the demo structure to the launchpad activity.
|
||||
// See http://developer.android.com/design/patterns/navigation.html for more.
|
||||
NavUtils.navigateUpTo(this, new Intent(this, MainActivity.class));
|
||||
return true;
|
||||
|
||||
case R.id.action_toggle:
|
||||
// Toggle whether content is loaded.
|
||||
mContentLoaded = !mContentLoaded;
|
||||
showContentOrLoadingIndicator(mContentLoaded);
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cross-fades between {@link #mContentView} and {@link #mLoadingView}.
|
||||
*/
|
||||
private void showContentOrLoadingIndicator(boolean contentLoaded) {
|
||||
// Decide which view to hide and which to show.
|
||||
final View showView = contentLoaded ? mContentView : mLoadingView;
|
||||
final View hideView = contentLoaded ? mLoadingView : mContentView;
|
||||
|
||||
// Set the "show" view to 0% opacity but visible, so that it is visible
|
||||
// (but fully transparent) during the animation.
|
||||
showView.setAlpha(0f);
|
||||
showView.setVisibility(View.VISIBLE);
|
||||
|
||||
// Animate the "show" view to 100% opacity, and clear any animation listener set on
|
||||
// the view. Remember that listeners are not limited to the specific animation
|
||||
// describes in the chained method calls. Listeners are set on the
|
||||
// ViewPropertyAnimator object for the view, which persists across several
|
||||
// animations.
|
||||
showView.animate()
|
||||
.alpha(1f)
|
||||
.setDuration(mShortAnimationDuration)
|
||||
.setListener(null);
|
||||
|
||||
// Animate the "hide" 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.)
|
||||
hideView.animate()
|
||||
.alpha(0f)
|
||||
.setDuration(mShortAnimationDuration)
|
||||
.setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
hideView.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.animationsdemo;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.NavUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* This sample demonstrates how to use system-provided, automatic layout transitions. Layout
|
||||
* transitions are animations that occur when views are added to, removed from, or changed within
|
||||
* a {@link ViewGroup}.
|
||||
*
|
||||
* <p>In this sample, the user can add rows to and remove rows from a vertical
|
||||
* {@link android.widget.LinearLayout}.</p>
|
||||
*/
|
||||
public class LayoutChangesActivity extends Activity {
|
||||
/**
|
||||
* The container view which has layout change animations turned on. In this sample, this view
|
||||
* is a {@link android.widget.LinearLayout}.
|
||||
*/
|
||||
private ViewGroup mContainerView;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_layout_changes);
|
||||
|
||||
mContainerView = (ViewGroup) findViewById(R.id.container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
getMenuInflater().inflate(R.menu.activity_layout_changes, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
// Navigate "up" the demo structure to the launchpad activity.
|
||||
// See http://developer.android.com/design/patterns/navigation.html for more.
|
||||
NavUtils.navigateUpTo(this, new Intent(this, MainActivity.class));
|
||||
return true;
|
||||
|
||||
case R.id.action_add_item:
|
||||
// Hide the "empty" view since there is now at least one item in the list.
|
||||
findViewById(android.R.id.empty).setVisibility(View.GONE);
|
||||
addItem();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void addItem() {
|
||||
// Instantiate a new "row" view.
|
||||
final ViewGroup newView = (ViewGroup) LayoutInflater.from(this).inflate(
|
||||
R.layout.list_item_example, mContainerView, false);
|
||||
|
||||
// Set the text in the new row to a random country.
|
||||
((TextView) newView.findViewById(android.R.id.text1)).setText(
|
||||
COUNTRIES[(int) (Math.random() * COUNTRIES.length)]);
|
||||
|
||||
// Set a click listener for the "X" button in the row that will remove the row.
|
||||
newView.findViewById(R.id.delete_button).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
// Remove the row from its parent (the container view).
|
||||
// Because mContainerView has android:animateLayoutChanges set to true,
|
||||
// this removal is automatically animated.
|
||||
mContainerView.removeView(newView);
|
||||
|
||||
// If there are no rows remaining, show the empty view.
|
||||
if (mContainerView.getChildCount() == 0) {
|
||||
findViewById(android.R.id.empty).setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Because mContainerView has android:animateLayoutChanges set to true,
|
||||
// adding this view is automatically animated.
|
||||
mContainerView.addView(newView, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* A static list of country names.
|
||||
*/
|
||||
private static final String[] COUNTRIES = new String[]{
|
||||
"Belgium", "France", "Italy", "Germany", "Spain",
|
||||
"Austria", "Russia", "Poland", "Croatia", "Greece",
|
||||
"Ukraine",
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.animationsdemo;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ListActivity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
|
||||
/**
|
||||
* The launchpad activity for this sample project. This activity launches other activities that
|
||||
* demonstrate implementations of common animations.
|
||||
*/
|
||||
public class MainActivity extends ListActivity {
|
||||
/**
|
||||
* This class describes an individual sample (the sample title, and the activity class that
|
||||
* demonstrates this sample).
|
||||
*/
|
||||
private class Sample {
|
||||
private CharSequence title;
|
||||
private Class<? extends Activity> activityClass;
|
||||
|
||||
public Sample(int titleResId, Class<? extends Activity> activityClass) {
|
||||
this.activityClass = activityClass;
|
||||
this.title = getResources().getString(titleResId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return title.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The collection of all samples in the app. This gets instantiated in {@link
|
||||
* #onCreate(android.os.Bundle)} because the {@link Sample} constructor needs access to {@link
|
||||
* android.content.res.Resources}.
|
||||
*/
|
||||
private static Sample[] mSamples;
|
||||
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
// Instantiate the list of samples.
|
||||
mSamples = new Sample[]{
|
||||
new Sample(R.string.title_crossfade, CrossfadeActivity.class),
|
||||
new Sample(R.string.title_card_flip, CardFlipActivity.class),
|
||||
new Sample(R.string.title_screen_slide, ScreenSlideActivity.class),
|
||||
new Sample(R.string.title_zoom, ZoomActivity.class),
|
||||
new Sample(R.string.title_layout_changes, LayoutChangesActivity.class),
|
||||
};
|
||||
|
||||
setListAdapter(new ArrayAdapter<Sample>(this,
|
||||
android.R.layout.simple_list_item_1,
|
||||
android.R.id.text1,
|
||||
mSamples));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onListItemClick(ListView listView, View view, int position, long id) {
|
||||
// Launch the sample associated with this list position.
|
||||
startActivity(new Intent(MainActivity.this, mSamples[position].activityClass));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.animationsdemo;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v13.app.FragmentStatePagerAdapter;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.NavUtils;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
/**
|
||||
* Demonstrates a "screen-slide" animation using a {@link ViewPager}. Because {@link ViewPager}
|
||||
* automatically plays such an animation when calling {@link ViewPager#setCurrentItem(int)}, there
|
||||
* isn't any animation-specific code in this sample.
|
||||
*
|
||||
* <p>This sample shows a "next" button that advances the user to the next step in a wizard,
|
||||
* animating the current screen out (to the left) and the next screen in (from the right). The
|
||||
* reverse animation is played when the user presses the "previous" button.</p>
|
||||
*
|
||||
* @see ScreenSlidePageFragment
|
||||
*/
|
||||
public class ScreenSlideActivity 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);
|
||||
|
||||
// Instantiate a ViewPager and a PagerAdapter.
|
||||
mPager = (ViewPager) findViewById(R.id.pager);
|
||||
mPagerAdapter = new ScreenSlidePagerAdapter(getFragmentManager());
|
||||
mPager.setAdapter(mPagerAdapter);
|
||||
mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
// When changing pages, reset the action bar actions since they are dependent
|
||||
// on which page is currently active. An alternative approach is to have each
|
||||
// fragment expose actions itself (rather than the activity exposing actions),
|
||||
// but for simplicity, the activity provides the actions in this sample.
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
getMenuInflater().inflate(R.menu.activity_screen_slide, menu);
|
||||
|
||||
menu.findItem(R.id.action_previous).setEnabled(mPager.getCurrentItem() > 0);
|
||||
|
||||
// Add either a "next" or "finish" button to the action bar, depending on which page
|
||||
// is currently selected.
|
||||
MenuItem item = menu.add(Menu.NONE, R.id.action_next, Menu.NONE,
|
||||
(mPager.getCurrentItem() == mPagerAdapter.getCount() - 1)
|
||||
? R.string.action_finish
|
||||
: R.string.action_next);
|
||||
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
// Navigate "up" the demo structure to the launchpad activity.
|
||||
// See http://developer.android.com/design/patterns/navigation.html for more.
|
||||
NavUtils.navigateUpTo(this, new Intent(this, MainActivity.class));
|
||||
return true;
|
||||
|
||||
case R.id.action_previous:
|
||||
// Go to the previous step in the wizard. If there is no previous step,
|
||||
// setCurrentItem will do nothing.
|
||||
mPager.setCurrentItem(mPager.getCurrentItem() - 1);
|
||||
return true;
|
||||
|
||||
case R.id.action_next:
|
||||
// Advance to the next step in the wizard. If there is no next step, setCurrentItem
|
||||
// will do nothing.
|
||||
mPager.setCurrentItem(mPager.getCurrentItem() + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple pager adapter that represents 5 {@link ScreenSlidePageFragment} objects, in
|
||||
* sequence.
|
||||
*/
|
||||
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
|
||||
public ScreenSlidePagerAdapter(FragmentManager fm) {
|
||||
super(fm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
return ScreenSlidePageFragment.create(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return NUM_PAGES;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.animationsdemo;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* A fragment representing a single step in a wizard. The fragment shows a dummy title indicating
|
||||
* the page number, along with some dummy text.
|
||||
*
|
||||
* <p>This class is used by the {@link CardFlipActivity} and {@link
|
||||
* ScreenSlideActivity} samples.</p>
|
||||
*/
|
||||
public class ScreenSlidePageFragment extends Fragment {
|
||||
/**
|
||||
* The argument key for the page number this fragment represents.
|
||||
*/
|
||||
public static final String ARG_PAGE = "page";
|
||||
|
||||
/**
|
||||
* The fragment's page number, which is set to the argument value for {@link #ARG_PAGE}.
|
||||
*/
|
||||
private int mPageNumber;
|
||||
|
||||
/**
|
||||
* Factory method for this fragment class. Constructs a new fragment for the given page number.
|
||||
*/
|
||||
public static ScreenSlidePageFragment create(int pageNumber) {
|
||||
ScreenSlidePageFragment fragment = new ScreenSlidePageFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(ARG_PAGE, pageNumber);
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
public ScreenSlidePageFragment() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mPageNumber = getArguments().getInt(ARG_PAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
// Inflate the layout containing a title and body text.
|
||||
ViewGroup rootView = (ViewGroup) inflater
|
||||
.inflate(R.layout.fragment_screen_slide_page, container, false);
|
||||
|
||||
// Set the title view to show the page number.
|
||||
((TextView) rootView.findViewById(android.R.id.text1)).setText(
|
||||
getString(R.string.title_template_step, mPageNumber + 1));
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the page number represented by this fragment object.
|
||||
*/
|
||||
public int getPageNumber() {
|
||||
return mPageNumber;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.animationsdemo;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ImageButton;
|
||||
|
||||
/**
|
||||
* An image button that uses a blue highlight (@link android.R.attr.selectableItemBackground} to
|
||||
* indicate pressed and focused states.
|
||||
*/
|
||||
public class TouchHighlightImageButton extends ImageButton {
|
||||
/**
|
||||
* The highlight drawable. This generally a {@link android.graphics.drawable.StateListDrawable}
|
||||
* that's transparent in the default state, and contains a semi-transparent overlay
|
||||
* for the focused and pressed states.
|
||||
*/
|
||||
private Drawable mForegroundDrawable;
|
||||
|
||||
/**
|
||||
* The cached bounds of the view.
|
||||
*/
|
||||
private Rect mCachedBounds = new Rect();
|
||||
|
||||
public TouchHighlightImageButton(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public TouchHighlightImageButton(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public TouchHighlightImageButton(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* General view initialization used common to all constructors of the view.
|
||||
*/
|
||||
private void init() {
|
||||
// Reset default ImageButton background and padding.
|
||||
setBackgroundColor(0);
|
||||
setPadding(0, 0, 0, 0);
|
||||
|
||||
// Retrieve the drawable resource assigned to the android.R.attr.selectableItemBackground
|
||||
// theme attribute from the current theme.
|
||||
TypedArray a = getContext()
|
||||
.obtainStyledAttributes(new int[]{android.R.attr.selectableItemBackground});
|
||||
mForegroundDrawable = a.getDrawable(0);
|
||||
mForegroundDrawable.setCallback(this);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawableStateChanged() {
|
||||
super.drawableStateChanged();
|
||||
|
||||
// Update the state of the highlight drawable to match
|
||||
// the state of the button.
|
||||
if (mForegroundDrawable.isStateful()) {
|
||||
mForegroundDrawable.setState(getDrawableState());
|
||||
}
|
||||
|
||||
// Trigger a redraw.
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
// First draw the image.
|
||||
super.onDraw(canvas);
|
||||
|
||||
// Then draw the highlight on top of it. If the button is neither focused
|
||||
// nor pressed, the drawable will be transparent, so just the image
|
||||
// will be drawn.
|
||||
mForegroundDrawable.setBounds(mCachedBounds);
|
||||
mForegroundDrawable.draw(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
|
||||
// Cache the view bounds.
|
||||
mCachedBounds.set(0, 0, w, h);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.android.animationsdemo;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.NavUtils;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.ImageView;
|
||||
|
||||
/**
|
||||
* A sample showing how to zoom an image thumbnail to full-screen, by animating the bounds of the
|
||||
* zoomed image from the thumbnail bounds to the screen bounds.
|
||||
*
|
||||
* <p>In this sample, the user can touch one of two images. Touching an image zooms it in, covering
|
||||
* the entire activity content area. Touching the zoomed-in image hides it.</p>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
final View thumb2View = findViewById(R.id.thumb_button_2);
|
||||
thumb2View.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
zoomImageFromThumb(thumb2View, R.drawable.image2);
|
||||
}
|
||||
});
|
||||
|
||||
// Retrieve and cache the system's default "short" animation time.
|
||||
mShortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
// Navigate "up" the demo structure to the launchpad activity.
|
||||
// See http://developer.android.com/design/patterns/navigation.html for more.
|
||||
NavUtils.navigateUpTo(this, new Intent(this, MainActivity.class));
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* "Zooms" in a thumbnail view by assigning the high resolution image to a hidden "zoomed-in"
|
||||
* image view and animating its bounds to fit the entire activity content area. More
|
||||
* specifically:
|
||||
*
|
||||
* <ol>
|
||||
* <li>Assign the high-res image to the hidden "zoomed-in" (expanded) image view.</li>
|
||||
* <li>Calculate the starting and ending bounds for the expanded view.</li>
|
||||
* <li>Animate each of four positioning/sizing properties (X, Y, SCALE_X, SCALE_Y)
|
||||
* simultaneously, from the starting bounds to the ending bounds.</li>
|
||||
* <li>Zoom back out by running the reverse animation on click.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param thumbView The thumbnail view to zoom in.
|
||||
* @param imageResId The high-resolution version of the image represented by the thumbnail.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user