* commit '58cbe71cc434d787e54d3b3a1d7d86af9727857c': New DevBytes animation demos
@@ -0,0 +1,45 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.android.activityanim"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="16"
|
||||
android:targetSdkVersion="17" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme" >
|
||||
<activity
|
||||
android:name="com.example.android.activityanim.ActivityAnimations"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.example.android.activityanim.PictureDetailsActivity"
|
||||
android:label="@string/subactivity_name"
|
||||
android:theme="@style/Transparent" >
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 183 KiB |
|
After Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 222 KiB |
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,21 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:id="@+id/gridLayout" >
|
||||
|
||||
</GridLayout>
|
||||
@@ -0,0 +1,41 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/topLevelLayout">
|
||||
|
||||
<view
|
||||
class="com.example.android.activityanim.ShadowLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/shadowLayout"
|
||||
android:visibility="visible" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/imageView" />
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:scaleType="centerInside" />
|
||||
|
||||
|
||||
</view>
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,24 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_slow"
|
||||
android:orderInCategory="100"
|
||||
android:showAsAction="never"
|
||||
android:title="@string/menu_slow_animations"
|
||||
android:checkable="true"/>
|
||||
|
||||
</menu>
|
||||
@@ -0,0 +1,21 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<string name="app_name">Activity Animations</string>
|
||||
<string name="subactivity_name">PictureInfo!</string>
|
||||
<string name="menu_slow_animations">Slow</string>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,39 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!--
|
||||
Base application theme, dependent on API level. This theme is replaced
|
||||
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
|
||||
<!--
|
||||
Theme customizations available in newer API levels can go in
|
||||
res/values-vXX/styles.xml, while customizations related to
|
||||
backward-compatibility can go here.
|
||||
-->
|
||||
</style>
|
||||
|
||||
<!-- Application theme. -->
|
||||
<style name="AppTheme" parent="AppBaseTheme">
|
||||
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
|
||||
</style>
|
||||
|
||||
<style name="Transparent">
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.activityanim;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.ColorMatrix;
|
||||
import android.graphics.ColorMatrixColorFilter;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.GridLayout;
|
||||
import android.widget.ImageView;
|
||||
|
||||
/**
|
||||
* This example shows how to create a custom activity animation when you want something more
|
||||
* than window animations can provide. The idea is to disable window animations for the
|
||||
* activities and to instead launch or return from the sub-activity immediately, but use
|
||||
* property animations inside the activities to customize the transition.
|
||||
*
|
||||
* Watch the associated video for this demo on the DevBytes channel of developer.android.com
|
||||
* or on the DevBytes playlist in the androiddevelopers channel on YouTube at
|
||||
* https://www.youtube.com/playlist?list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0.
|
||||
*/
|
||||
public class ActivityAnimations extends Activity {
|
||||
|
||||
private static final String PACKAGE = "com.example.android.activityanim";
|
||||
static float sAnimatorScale = 1;
|
||||
|
||||
GridLayout mGridLayout;
|
||||
HashMap<ImageView, PictureData> mPicturesData = new HashMap<ImageView, PictureData>();
|
||||
BitmapUtils mBitmapUtils = new BitmapUtils();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_animations);
|
||||
|
||||
// Grayscale filter used on all thumbnails
|
||||
ColorMatrix grayMatrix = new ColorMatrix();
|
||||
grayMatrix.setSaturation(0);
|
||||
ColorMatrixColorFilter grayscaleFilter = new ColorMatrixColorFilter(grayMatrix);
|
||||
|
||||
mGridLayout = (GridLayout) findViewById(R.id.gridLayout);
|
||||
mGridLayout.setColumnCount(3);
|
||||
mGridLayout.setUseDefaultMargins(true);
|
||||
|
||||
// add all photo thumbnails to layout
|
||||
Resources resources = getResources();
|
||||
ArrayList<PictureData> pictures = mBitmapUtils.loadPhotos(resources);
|
||||
for (int i = 0; i < pictures.size(); ++i) {
|
||||
PictureData pictureData = pictures.get(i);
|
||||
BitmapDrawable thumbnailDrawable =
|
||||
new BitmapDrawable(resources, pictureData.thumbnail);
|
||||
thumbnailDrawable.setColorFilter(grayscaleFilter);
|
||||
ImageView imageView = new ImageView(this);
|
||||
imageView.setOnClickListener(thumbnailClickListener);
|
||||
imageView.setImageDrawable(thumbnailDrawable);
|
||||
mPicturesData.put(imageView, pictureData);
|
||||
mGridLayout.addView(imageView);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.activity_better_window_animations, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == R.id.menu_slow) {
|
||||
sAnimatorScale = item.isChecked() ? 1 : 5;
|
||||
item.setChecked(!item.isChecked());
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* When the user clicks a thumbnail, bundle up information about it and launch the
|
||||
* details activity.
|
||||
*/
|
||||
private View.OnClickListener thumbnailClickListener = new View.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// Interesting data to pass across are the thumbnail size/location, the
|
||||
// resourceId of the source bitmap, the picture description, and the
|
||||
// orientation (to avoid returning back to an obsolete configuration if
|
||||
// the device rotates again in the meantime)
|
||||
int[] screenLocation = new int[2];
|
||||
v.getLocationOnScreen(screenLocation);
|
||||
PictureData info = mPicturesData.get(v);
|
||||
Intent subActivity = new Intent(ActivityAnimations.this,
|
||||
PictureDetailsActivity.class);
|
||||
int orientation = getResources().getConfiguration().orientation;
|
||||
subActivity.
|
||||
putExtra(PACKAGE + ".orientation", orientation).
|
||||
putExtra(PACKAGE + ".resourceId", info.resourceId).
|
||||
putExtra(PACKAGE + ".left", screenLocation[0]).
|
||||
putExtra(PACKAGE + ".top", screenLocation[1]).
|
||||
putExtra(PACKAGE + ".width", v.getWidth()).
|
||||
putExtra(PACKAGE + ".height", v.getHeight()).
|
||||
putExtra(PACKAGE + ".description", info.description);
|
||||
startActivity(subActivity);
|
||||
|
||||
// Override transitions: we don't want the normal window animation in addition
|
||||
// to our custom one
|
||||
overridePendingTransition(0, 0);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.activityanim;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.widget.ImageView;
|
||||
|
||||
public class BitmapUtils {
|
||||
|
||||
int[] mPhotos = {
|
||||
R.drawable.p1,
|
||||
R.drawable.p2,
|
||||
R.drawable.p3,
|
||||
R.drawable.p4
|
||||
};
|
||||
|
||||
String[] mDescriptions = {
|
||||
"This picture was taken while sunbathing in a natural hot spring, which was " +
|
||||
"unfortunately filled with acid, which is a lasting memory from that trip, whenever I " +
|
||||
"I look at my own skin.",
|
||||
"I took this shot with a pinhole camera mounted on a tripod constructed out of " +
|
||||
"soda straws. I felt that that combination best captured the beauty of the landscape " +
|
||||
"in juxtaposition with the detritus of mankind.",
|
||||
"I don't remember where or when I took this picture. All I know is that I was really " +
|
||||
"drunk at the time, and I woke up without my left sock.",
|
||||
"Right before I took this picture, there was a busload of school children right " +
|
||||
"in my way. I knew the perfect shot was coming, so I quickly yelled 'Free candy!!!' " +
|
||||
"and they scattered.",
|
||||
};
|
||||
|
||||
static HashMap<Integer, Bitmap> sBitmapResourceMap = new HashMap<Integer, Bitmap>();
|
||||
|
||||
/**
|
||||
* Load pictures and descriptions. A real app wouldn't do it this way, but that's
|
||||
* not the point of this animation demo. Loading asynchronously is a better way to go
|
||||
* for what can be time-consuming operations.
|
||||
*/
|
||||
public ArrayList<PictureData> loadPhotos(Resources resources) {
|
||||
ArrayList<PictureData> pictures = new ArrayList<PictureData>();
|
||||
for (int i = 0; i < 30; ++i) {
|
||||
int resourceId = mPhotos[(int) (Math.random() * mPhotos.length)];
|
||||
Bitmap bitmap = getBitmap(resources, resourceId);
|
||||
Bitmap thumbnail = getThumbnail(bitmap, 200);
|
||||
String description = mDescriptions[(int) (Math.random() * mDescriptions.length)];
|
||||
pictures.add(new PictureData(resourceId, description, thumbnail));
|
||||
}
|
||||
return pictures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to get bitmap from cache or, if not there, load it
|
||||
* from its resource.
|
||||
*/
|
||||
static Bitmap getBitmap(Resources resources, int resourceId) {
|
||||
Bitmap bitmap = sBitmapResourceMap.get(resourceId);
|
||||
if (bitmap == null) {
|
||||
bitmap = BitmapFactory.decodeResource(resources, resourceId);
|
||||
sBitmapResourceMap.put(resourceId, bitmap);
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a thumbnail image given the original source bitmap and a max
|
||||
* dimension (width or height).
|
||||
*/
|
||||
private Bitmap getThumbnail(Bitmap original, int maxDimension) {
|
||||
int width = original.getWidth();
|
||||
int height = original.getHeight();
|
||||
int scaledWidth, scaledHeight;
|
||||
if (width >= height) {
|
||||
float scaleFactor = (float) maxDimension / width;
|
||||
scaledWidth = 200;
|
||||
scaledHeight = (int) (scaleFactor * height);
|
||||
} else {
|
||||
float scaleFactor = (float) maxDimension / height;
|
||||
scaledWidth = (int) (scaleFactor * width);
|
||||
scaledHeight = 200;
|
||||
}
|
||||
Bitmap thumbnail = Bitmap.createScaledBitmap(original, scaledWidth, scaledHeight, true);
|
||||
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.activityanim;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
public class PictureData {
|
||||
int resourceId;
|
||||
String description;
|
||||
Bitmap thumbnail;
|
||||
|
||||
public PictureData(int resourceId, String description, Bitmap thumbnail) {
|
||||
this.resourceId = resourceId;
|
||||
this.description = description;
|
||||
this.thumbnail = thumbnail;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.activityanim;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.app.Activity;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorMatrix;
|
||||
import android.graphics.ColorMatrixColorFilter;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* This sub-activity shows a zoomed-in view of a specific photo, along with the
|
||||
* picture's text description. Most of the logic is for the animations that will
|
||||
* be run when the activity is being launched and exited. When launching,
|
||||
* the large version of the picture will resize from the thumbnail version in the
|
||||
* main activity, colorizing it from the thumbnail's grayscale version at the
|
||||
* same time. Meanwhile, the black background of the activity will fade in and
|
||||
* the description will eventually slide into place. The exit animation runs all
|
||||
* of this in reverse.
|
||||
*
|
||||
*/
|
||||
public class PictureDetailsActivity extends Activity {
|
||||
|
||||
private static final TimeInterpolator sDecelerator = new DecelerateInterpolator();
|
||||
private static final TimeInterpolator sAccelerator = new AccelerateInterpolator();
|
||||
private static final String PACKAGE_NAME = "com.example.android.activityanim";
|
||||
private static final int ANIM_DURATION = 500;
|
||||
|
||||
private BitmapDrawable mBitmapDrawable;
|
||||
private ColorMatrix colorizerMatrix = new ColorMatrix();
|
||||
ColorDrawable mBackground;
|
||||
int mLeftDelta;
|
||||
int mTopDelta;
|
||||
float mWidthScale;
|
||||
float mHeightScale;
|
||||
private ImageView mImageView;
|
||||
private TextView mTextView;
|
||||
private FrameLayout mTopLevelLayout;
|
||||
private ShadowLayout mShadowLayout;
|
||||
private int mOriginalOrientation;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.picture_info);
|
||||
mImageView = (ImageView) findViewById(R.id.imageView);
|
||||
mTopLevelLayout = (FrameLayout) findViewById(R.id.topLevelLayout);
|
||||
mShadowLayout = (ShadowLayout) findViewById(R.id.shadowLayout);
|
||||
mTextView = (TextView) findViewById(R.id.description);
|
||||
|
||||
// Retrieve the data we need for the picture/description to display and
|
||||
// the thumbnail to animate it from
|
||||
Bundle bundle = getIntent().getExtras();
|
||||
Bitmap bitmap = BitmapUtils.getBitmap(getResources(),
|
||||
bundle.getInt(PACKAGE_NAME + ".resourceId"));
|
||||
String description = bundle.getString(PACKAGE_NAME + ".description");
|
||||
final int thumbnailTop = bundle.getInt(PACKAGE_NAME + ".top");
|
||||
final int thumbnailLeft = bundle.getInt(PACKAGE_NAME + ".left");
|
||||
final int thumbnailWidth = bundle.getInt(PACKAGE_NAME + ".width");
|
||||
final int thumbnailHeight = bundle.getInt(PACKAGE_NAME + ".height");
|
||||
mOriginalOrientation = bundle.getInt(PACKAGE_NAME + ".orientation");
|
||||
|
||||
mBitmapDrawable = new BitmapDrawable(getResources(), bitmap);
|
||||
mImageView.setImageDrawable(mBitmapDrawable);
|
||||
mTextView.setText(description);
|
||||
|
||||
mBackground = new ColorDrawable(Color.BLACK);
|
||||
mTopLevelLayout.setBackground(mBackground);
|
||||
|
||||
// Only run the animation if we're coming from the parent activity, not if
|
||||
// we're recreated automatically by the window manager (e.g., device rotation)
|
||||
if (savedInstanceState == null) {
|
||||
ViewTreeObserver observer = mImageView.getViewTreeObserver();
|
||||
observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
|
||||
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
mImageView.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
|
||||
// Figure out where the thumbnail and full size versions are, relative
|
||||
// to the screen and each other
|
||||
int[] screenLocation = new int[2];
|
||||
mImageView.getLocationOnScreen(screenLocation);
|
||||
mLeftDelta = thumbnailLeft - screenLocation[0];
|
||||
mTopDelta = thumbnailTop - screenLocation[1];
|
||||
|
||||
// Scale factors to make the large version the same size as the thumbnail
|
||||
mWidthScale = (float) thumbnailWidth / mImageView.getWidth();
|
||||
mHeightScale = (float) thumbnailHeight / mImageView.getHeight();
|
||||
|
||||
runEnterAnimation();
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The enter animation scales the picture in from its previous thumbnail
|
||||
* size/location, colorizing it in parallel. In parallel, the background of the
|
||||
* activity is fading in. When the pictue is in place, the text description
|
||||
* drops down.
|
||||
*/
|
||||
public void runEnterAnimation() {
|
||||
final long duration = (long) (ANIM_DURATION * ActivityAnimations.sAnimatorScale);
|
||||
|
||||
// Set starting values for properties we're going to animate. These
|
||||
// values scale and position the full size version down to the thumbnail
|
||||
// size/location, from which we'll animate it back up
|
||||
mImageView.setPivotX(0);
|
||||
mImageView.setPivotY(0);
|
||||
mImageView.setScaleX(mWidthScale);
|
||||
mImageView.setScaleY(mHeightScale);
|
||||
mImageView.setTranslationX(mLeftDelta);
|
||||
mImageView.setTranslationY(mTopDelta);
|
||||
|
||||
// We'll fade the text in later
|
||||
mTextView.setAlpha(0);
|
||||
|
||||
// Animate scale and translation to go from thumbnail to full size
|
||||
mImageView.animate().setDuration(duration).
|
||||
scaleX(1).scaleY(1).
|
||||
translationX(0).translationY(0).
|
||||
setInterpolator(sDecelerator).
|
||||
withEndAction(new Runnable() {
|
||||
public void run() {
|
||||
// Animate the description in after the image animation
|
||||
// is done. Slide and fade the text in from underneath
|
||||
// the picture.
|
||||
mTextView.setTranslationY(-mTextView.getHeight());
|
||||
mTextView.animate().setDuration(duration/2).
|
||||
translationY(0).alpha(1).
|
||||
setInterpolator(sDecelerator);
|
||||
}
|
||||
});
|
||||
|
||||
// Fade in the black background
|
||||
ObjectAnimator bgAnim = ObjectAnimator.ofInt(mBackground, "alpha", 0, 255);
|
||||
bgAnim.setDuration(duration);
|
||||
bgAnim.start();
|
||||
|
||||
// Animate a color filter to take the image from grayscale to full color.
|
||||
// This happens in parallel with the image scaling and moving into place.
|
||||
ObjectAnimator colorizer = ObjectAnimator.ofFloat(PictureDetailsActivity.this,
|
||||
"saturation", 0, 1);
|
||||
colorizer.setDuration(duration);
|
||||
colorizer.start();
|
||||
|
||||
// Animate a drop-shadow of the image
|
||||
ObjectAnimator shadowAnim = ObjectAnimator.ofFloat(mShadowLayout, "shadowDepth", 0, 1);
|
||||
shadowAnim.setDuration(duration);
|
||||
shadowAnim.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* The exit animation is basically a reverse of the enter animation, except that if
|
||||
* the orientation has changed we simply scale the picture back into the center of
|
||||
* the screen.
|
||||
*
|
||||
* @param endAction This action gets run after the animation completes (this is
|
||||
* when we actually switch activities)
|
||||
*/
|
||||
public void runExitAnimation(final Runnable endAction) {
|
||||
final long duration = (long) (ANIM_DURATION * ActivityAnimations.sAnimatorScale);
|
||||
|
||||
// No need to set initial values for the reverse animation; the image is at the
|
||||
// starting size/location that we want to start from. Just animate to the
|
||||
// thumbnail size/location that we retrieved earlier
|
||||
|
||||
// Caveat: configuration change invalidates thumbnail positions; just animate
|
||||
// the scale around the center. Also, fade it out since it won't match up with
|
||||
// whatever's actually in the center
|
||||
final boolean fadeOut;
|
||||
if (getResources().getConfiguration().orientation != mOriginalOrientation) {
|
||||
mImageView.setPivotX(mImageView.getWidth() / 2);
|
||||
mImageView.setPivotY(mImageView.getHeight() / 2);
|
||||
mLeftDelta = 0;
|
||||
mTopDelta = 0;
|
||||
fadeOut = true;
|
||||
} else {
|
||||
fadeOut = false;
|
||||
}
|
||||
|
||||
// First, slide/fade text out of the way
|
||||
mTextView.animate().translationY(-mTextView.getHeight()).alpha(0).
|
||||
setDuration(duration/2).setInterpolator(sAccelerator).
|
||||
withEndAction(new Runnable() {
|
||||
public void run() {
|
||||
// Animate image back to thumbnail size/location
|
||||
mImageView.animate().setDuration(duration).
|
||||
scaleX(mWidthScale).scaleY(mHeightScale).
|
||||
translationX(mLeftDelta).translationY(mTopDelta).
|
||||
withEndAction(endAction);
|
||||
if (fadeOut) {
|
||||
mImageView.animate().alpha(0);
|
||||
}
|
||||
// Fade out background
|
||||
ObjectAnimator bgAnim = ObjectAnimator.ofInt(mBackground, "alpha", 0);
|
||||
bgAnim.setDuration(duration);
|
||||
bgAnim.start();
|
||||
|
||||
// Animate the shadow of the image
|
||||
ObjectAnimator shadowAnim = ObjectAnimator.ofFloat(mShadowLayout,
|
||||
"shadowDepth", 1, 0);
|
||||
shadowAnim.setDuration(duration);
|
||||
shadowAnim.start();
|
||||
|
||||
// Animate a color filter to take the image back to grayscale,
|
||||
// in parallel with the image scaling and moving into place.
|
||||
ObjectAnimator colorizer =
|
||||
ObjectAnimator.ofFloat(PictureDetailsActivity.this,
|
||||
"saturation", 1, 0);
|
||||
colorizer.setDuration(duration);
|
||||
colorizer.start();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriding this method allows us to run our exit animation first, then exiting
|
||||
* the activity when it is complete.
|
||||
*/
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
runExitAnimation(new Runnable() {
|
||||
public void run() {
|
||||
// *Now* go ahead and exit the activity
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called by the colorizing animator. It sets a saturation factor that is then
|
||||
* passed onto a filter on the picture's drawable.
|
||||
* @param value
|
||||
*/
|
||||
public void setSaturation(float value) {
|
||||
colorizerMatrix.setSaturation(value);
|
||||
ColorMatrixColorFilter colorizerFilter = new ColorMatrixColorFilter(colorizerMatrix);
|
||||
mBitmapDrawable.setColorFilter(colorizerFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
super.finish();
|
||||
|
||||
// override transitions to skip the standard window animations
|
||||
overridePendingTransition(0, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.activityanim;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BlurMaskFilter;
|
||||
import android.graphics.BlurMaskFilter.Blur;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Paint.Style;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
/**
|
||||
* This custom layout paints a drop shadow behind all children. The size and opacity
|
||||
* of the drop shadow is determined by a "depth" factor that can be set and animated.
|
||||
*/
|
||||
public class ShadowLayout extends RelativeLayout {
|
||||
|
||||
Paint mShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
float mShadowDepth;
|
||||
Bitmap mShadowBitmap;
|
||||
static final int BLUR_RADIUS = 6;
|
||||
static final RectF sShadowRectF = new RectF(0, 0, 200, 200);
|
||||
static final Rect sShadowRect = new Rect(0, 0, 200 + 2 * BLUR_RADIUS, 200 + 2 * BLUR_RADIUS);
|
||||
static RectF tempShadowRectF = new RectF(0, 0, 0, 0);
|
||||
|
||||
public ShadowLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init();
|
||||
}
|
||||
|
||||
public ShadowLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public ShadowLayout(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the constructors - sets up the drawing parameters for the drop shadow.
|
||||
*/
|
||||
private void init() {
|
||||
mShadowPaint.setColor(Color.BLACK);
|
||||
mShadowPaint.setStyle(Style.FILL);
|
||||
setWillNotDraw(false);
|
||||
mShadowBitmap = Bitmap.createBitmap(sShadowRect.width(),
|
||||
sShadowRect.height(), Bitmap.Config.ARGB_8888);
|
||||
Canvas c = new Canvas(mShadowBitmap);
|
||||
mShadowPaint.setMaskFilter(new BlurMaskFilter(BLUR_RADIUS, Blur.NORMAL));
|
||||
c.translate(BLUR_RADIUS, BLUR_RADIUS);
|
||||
c.drawRoundRect(sShadowRectF, sShadowRectF.width() / 40,
|
||||
sShadowRectF.height() / 40, mShadowPaint);
|
||||
}
|
||||
|
||||
/**
|
||||
* The "depth" factor determines the offset distance and opacity of the shadow (shadows that
|
||||
* are further away from the source are offset greater and are more translucent).
|
||||
* @param depth
|
||||
*/
|
||||
public void setShadowDepth(float depth) {
|
||||
if (depth != mShadowDepth) {
|
||||
mShadowDepth = depth;
|
||||
mShadowPaint.setAlpha((int) (100 + 150 * (1 - mShadowDepth)));
|
||||
invalidate(); // We need to redraw when the shadow attributes change
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriding onDraw allows us to draw shadows behind every child of this container.
|
||||
* onDraw() is called to draw a layout's content before the children are drawn, so the
|
||||
* shadows will be drawn first, behind the children (which is what we want).
|
||||
*/
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
for (int i = 0; i < getChildCount(); ++i) {
|
||||
View child = getChildAt(i);
|
||||
if (child.getVisibility() != View.VISIBLE || child.getAlpha() == 0) {
|
||||
continue;
|
||||
}
|
||||
int depthFactor = (int) (80 * mShadowDepth);
|
||||
canvas.save();
|
||||
canvas.translate(child.getLeft() + depthFactor,
|
||||
child.getTop() + depthFactor);
|
||||
canvas.concat(child.getMatrix());
|
||||
tempShadowRectF.right = child.getWidth();
|
||||
tempShadowRectF.bottom = child.getHeight();
|
||||
canvas.drawBitmap(mShadowBitmap, sShadowRect, tempShadowRectF, mShadowPaint);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
41
samples/devbytes/animation/Anticipation/AndroidManifest.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.android.anticipation"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="14"
|
||||
android:targetSdkVersion="17" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme" >
|
||||
<activity
|
||||
android:name="com.example.android.anticipation.Anticipation"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 14 KiB |
28
samples/devbytes/animation/Anticipation/res/layout/main.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/container"
|
||||
android:clipChildren="false"
|
||||
tools:context=".Anticipation" >
|
||||
|
||||
<view
|
||||
class="com.example.android.anticipation.AnticiButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="AnticiButton"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,26 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme for API 14+. This theme completely replaces
|
||||
AppBaseTheme from BOTH res/values/styles.xml and
|
||||
res/values-v11/styles.xml on API 14+ devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
|
||||
<!-- API 14 theme customizations can go here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<string name="app_name">Anticipation</string>
|
||||
<string name="hello_world">Hello world!</string>
|
||||
<string name="menu_settings">Settings</string>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,34 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme, dependent on API level. This theme is replaced
|
||||
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Light">
|
||||
<!--
|
||||
Theme customizations available in newer API levels can go in
|
||||
res/values-vXX/styles.xml, while customizations related to
|
||||
backward-compatibility can go here.
|
||||
-->
|
||||
</style>
|
||||
|
||||
<!-- Application theme. -->
|
||||
<style name="AppTheme" parent="AppBaseTheme">
|
||||
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.anticipation;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.RectF;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
import android.view.animation.OvershootInterpolator;
|
||||
import android.widget.Button;
|
||||
|
||||
/**
|
||||
* Custom button which can be deformed by skewing the top left and right, to simulate
|
||||
* anticipation and follow-through animation effects. Clicking on the button runs
|
||||
* an animation which moves the button left or right, applying the skew effect to the
|
||||
* button. The logic of drawing the button with a skew transform is handled in the
|
||||
* draw() override.
|
||||
*/
|
||||
public class AnticiButton extends Button {
|
||||
|
||||
private static final LinearInterpolator sLinearInterpolator = new LinearInterpolator();
|
||||
private static final DecelerateInterpolator sDecelerator = new DecelerateInterpolator(8);
|
||||
private static final AccelerateInterpolator sAccelerator = new AccelerateInterpolator();
|
||||
private static final OvershootInterpolator sOvershooter = new OvershootInterpolator();
|
||||
private static final DecelerateInterpolator sQuickDecelerator = new DecelerateInterpolator();
|
||||
|
||||
private float mSkewX = 0;
|
||||
ObjectAnimator downAnim = null;
|
||||
boolean mOnLeft = true;
|
||||
RectF mTempRect = new RectF();
|
||||
|
||||
public AnticiButton(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public AnticiButton(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init();
|
||||
}
|
||||
|
||||
public AnticiButton(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setOnTouchListener(mTouchListener);
|
||||
setOnClickListener(new OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
runClickAnim();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The skew effect is handled by changing the transform of the Canvas
|
||||
* and then calling the usual superclass draw() method.
|
||||
*/
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
if (mSkewX != 0) {
|
||||
canvas.translate(0, getHeight());
|
||||
canvas.skew(mSkewX, 0);
|
||||
canvas.translate(0, -getHeight());
|
||||
}
|
||||
super.draw(canvas);
|
||||
}
|
||||
|
||||
/**
|
||||
* Anticipate the future animation by rearing back, away from the direction of travel
|
||||
*/
|
||||
private void runPressAnim() {
|
||||
downAnim = ObjectAnimator.ofFloat(this, "skewX", mOnLeft ? .5f : -.5f);
|
||||
downAnim.setDuration(2500);
|
||||
downAnim.setInterpolator(sDecelerator);
|
||||
downAnim.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish the "anticipation" animation (skew the button back from the direction of
|
||||
* travel), animate it to the other side of the screen, then un-skew the button
|
||||
* with an Overshoot effect.
|
||||
*/
|
||||
private void runClickAnim() {
|
||||
// Anticipation
|
||||
ObjectAnimator finishDownAnim = null;
|
||||
if (downAnim != null && downAnim.isRunning()) {
|
||||
// finish the skew animation quickly
|
||||
downAnim.cancel();
|
||||
finishDownAnim = ObjectAnimator.ofFloat(this, "skewX",
|
||||
mOnLeft ? .5f : -.5f);
|
||||
finishDownAnim.setDuration(150);
|
||||
finishDownAnim.setInterpolator(sQuickDecelerator);
|
||||
}
|
||||
|
||||
// Slide. Use LinearInterpolator in this rare situation where we want to start
|
||||
// and end fast (no acceleration or deceleration, since we're doing that part
|
||||
// during the anticipation and overshoot phases).
|
||||
ObjectAnimator moveAnim = ObjectAnimator.ofFloat(this,
|
||||
View.TRANSLATION_X, mOnLeft ? 400 : 0);
|
||||
moveAnim.setInterpolator(sLinearInterpolator);
|
||||
moveAnim.setDuration(150);
|
||||
|
||||
// Then overshoot by stopping the movement but skewing the button as if it couldn't
|
||||
// all stop at once
|
||||
ObjectAnimator skewAnim = ObjectAnimator.ofFloat(this, "skewX",
|
||||
mOnLeft ? -.5f : .5f);
|
||||
skewAnim.setInterpolator(sQuickDecelerator);
|
||||
skewAnim.setDuration(100);
|
||||
// and wobble it
|
||||
ObjectAnimator wobbleAnim = ObjectAnimator.ofFloat(this, "skewX", 0);
|
||||
wobbleAnim.setInterpolator(sOvershooter);
|
||||
wobbleAnim.setDuration(150);
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
set.playSequentially(moveAnim, skewAnim, wobbleAnim);
|
||||
if (finishDownAnim != null) {
|
||||
set.play(finishDownAnim).before(moveAnim);
|
||||
}
|
||||
set.start();
|
||||
mOnLeft = !mOnLeft;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the button to its un-pressed state
|
||||
*/
|
||||
private void runCancelAnim() {
|
||||
if (downAnim != null && downAnim.isRunning()) {
|
||||
downAnim.cancel();
|
||||
ObjectAnimator reverser = ObjectAnimator.ofFloat(this, "skewX", 0);
|
||||
reverser.setDuration(200);
|
||||
reverser.setInterpolator(sAccelerator);
|
||||
reverser.start();
|
||||
downAnim = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle touch events directly since we want to react on down/up events, not just
|
||||
* button clicks
|
||||
*/
|
||||
private View.OnTouchListener mTouchListener = new View.OnTouchListener() {
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (isPressed()) {
|
||||
performClick();
|
||||
setPressed(false);
|
||||
break;
|
||||
}
|
||||
// No click: Fall through; equivalent to cancel event
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
// Run the cancel animation in either case
|
||||
runCancelAnim();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
float x = event.getX();
|
||||
float y = event.getY();
|
||||
boolean isInside = (x > 0 && x < getWidth() &&
|
||||
y > 0 && y < getHeight());
|
||||
if (isPressed() != isInside) {
|
||||
setPressed(isInside);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
setPressed(true);
|
||||
runPressAnim();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public float getSkewX() {
|
||||
return mSkewX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the amount of left/right skew on the button, which determines how far the button
|
||||
* leans.
|
||||
*/
|
||||
public void setSkewX(float value) {
|
||||
if (value != mSkewX) {
|
||||
mSkewX = value;
|
||||
invalidate(); // force button to redraw with new skew value
|
||||
invalidateSkewedBounds(); // also invalidate appropriate area of parent
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Need to invalidate proper area of parent for skewed bounds
|
||||
*/
|
||||
private void invalidateSkewedBounds() {
|
||||
if (mSkewX != 0) {
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.setSkew(-mSkewX, 0);
|
||||
mTempRect.set(0, 0, getRight(), getBottom());
|
||||
matrix.mapRect(mTempRect);
|
||||
mTempRect.offset(getLeft() + getTranslationX(), getTop() + getTranslationY());
|
||||
((View) getParent()).invalidate((int) mTempRect.left, (int) mTempRect.top,
|
||||
(int) (mTempRect.right +.5f), (int) (mTempRect.bottom + .5f));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.anticipation;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
|
||||
/**
|
||||
* This example shows how to animate some simple deformations on a standard UI widget
|
||||
* to achieve some interactive and cartoon-ish effects.
|
||||
*
|
||||
* Watch the associated video for this demo on the DevBytes channel of developer.android.com
|
||||
* or on the DevBytes playlist in the androiddevelopers channel on YouTube at
|
||||
* https://www.youtube.com/playlist?list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0.
|
||||
*/
|
||||
public class Anticipation extends Activity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.main);
|
||||
}
|
||||
|
||||
}
|
||||
41
samples/devbytes/animation/CurvedMotion/AndroidManifest.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.android.curvedmotion"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="11"
|
||||
android:targetSdkVersion="11" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme" >
|
||||
<activity
|
||||
android:name="com.example.android.curvedmotion.CurvedMotion"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,33 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
tools:context=".CurvedMotion" >
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:id="@+id/button"
|
||||
android:text="Click Me!" />
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -0,0 +1,25 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme for API 11+. This theme completely replaces
|
||||
AppBaseTheme from res/values/styles.xml on API 11+ devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
|
||||
<!-- API 11 theme customizations can go here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,26 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme for API 14+. This theme completely replaces
|
||||
AppBaseTheme from BOTH res/values/styles.xml and
|
||||
res/values-v11/styles.xml on API 14+ devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
|
||||
<!-- API 14 theme customizations can go here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,21 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<string name="app_name">CurvedMotion</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
<string name="hello_world">Hello world!</string>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,34 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme, dependent on API level. This theme is replaced
|
||||
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Light">
|
||||
<!--
|
||||
Theme customizations available in newer API levels can go in
|
||||
res/values-vXX/styles.xml, while customizations related to
|
||||
backward-compatibility can go here.
|
||||
-->
|
||||
</style>
|
||||
|
||||
<!-- Application theme. -->
|
||||
<style name="AppTheme" parent="AppBaseTheme">
|
||||
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.curvedmotion;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A simple Path object that holds information about the points along
|
||||
* a path. The API allows you to specify a move location (which essentially
|
||||
* jumps from the previous point in the path to the new one), a line location
|
||||
* (which creates a line segment from the previous location) and a curve
|
||||
* location (which creates a B<>zier curve from the previous location).
|
||||
*/
|
||||
public class AnimatorPath {
|
||||
|
||||
// The points in the path
|
||||
ArrayList<PathPoint> mPoints = new ArrayList<PathPoint>();
|
||||
|
||||
|
||||
/**
|
||||
* Move from the current path point to the new one
|
||||
* specified by x and y. This will create a discontinuity if this point is
|
||||
* neither the first point in the path nor the same as the previous point
|
||||
* in the path.
|
||||
*/
|
||||
public void moveTo(float x, float y) {
|
||||
mPoints.add(PathPoint.moveTo(x, y));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a straight line from the current path point to the new one
|
||||
* specified by x and y.
|
||||
*/
|
||||
public void lineTo(float x, float y) {
|
||||
mPoints.add(PathPoint.lineTo(x, y));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a quadratic B<>zier curve from the current path point to the new one
|
||||
* specified by x and y. The curve uses the current path location as the first anchor
|
||||
* point, the control points (c0X, c0Y) and (c1X, c1Y), and (x, y) as the end anchor.
|
||||
*/
|
||||
public void curveTo(float c0X, float c0Y, float c1X, float c1Y, float x, float y) {
|
||||
mPoints.add(PathPoint.curveTo(c0X, c0Y, c1X, c1Y, x, y));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Collection of PathPoint objects that describe all points in the path.
|
||||
*/
|
||||
public Collection<PathPoint> getPoints() {
|
||||
return mPoints;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.curvedmotion;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.Button;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.RelativeLayout.LayoutParams;
|
||||
|
||||
/**
|
||||
* This app shows how to move a view in a curved path between two endpoints.
|
||||
* The real work is done by PathEvaluator, which interpolates along a path
|
||||
* using Bezier control and anchor points in the path.
|
||||
*
|
||||
* Watch the associated video for this demo on the DevBytes channel of developer.android.com
|
||||
* or on the DevBytes playlist in the androiddevelopers channel on YouTube at
|
||||
* https://www.youtube.com/playlist?list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0.
|
||||
*/
|
||||
public class CurvedMotion extends Activity {
|
||||
|
||||
private static final DecelerateInterpolator sDecelerateInterpolator =
|
||||
new DecelerateInterpolator();
|
||||
boolean mTopLeft = true;
|
||||
Button mButton;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_curved_motion);
|
||||
|
||||
mButton = (Button) findViewById(R.id.button);
|
||||
mButton.setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// Capture current location of button
|
||||
final int oldLeft = mButton.getLeft();
|
||||
final int oldTop = mButton.getTop();
|
||||
|
||||
// Change layout parameters of button to move it
|
||||
moveButton();
|
||||
|
||||
// Add OnPreDrawListener to catch button after layout but before drawing
|
||||
mButton.getViewTreeObserver().addOnPreDrawListener(
|
||||
new ViewTreeObserver.OnPreDrawListener() {
|
||||
public boolean onPreDraw() {
|
||||
mButton.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
|
||||
// Capture new location
|
||||
int left = mButton.getLeft();
|
||||
int top = mButton.getTop();
|
||||
int deltaX = left - oldLeft;
|
||||
int deltaY = top - oldTop;
|
||||
|
||||
// Set up path to new location using a B<>zier spline curve
|
||||
AnimatorPath path = new AnimatorPath();
|
||||
path.moveTo(-deltaX, -deltaY);
|
||||
path.curveTo(-(deltaX/2), -deltaY, 0, -deltaY/2, 0, 0);
|
||||
|
||||
// Set up the animation
|
||||
final ObjectAnimator anim = ObjectAnimator.ofObject(
|
||||
CurvedMotion.this, "buttonLoc",
|
||||
new PathEvaluator(), path.getPoints().toArray());
|
||||
anim.setInterpolator(sDecelerateInterpolator);
|
||||
anim.start();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles button location on click between top-left and bottom-right
|
||||
*/
|
||||
private void moveButton() {
|
||||
LayoutParams params = (LayoutParams) mButton.getLayoutParams();
|
||||
if (mTopLeft) {
|
||||
params.removeRule(RelativeLayout.ALIGN_PARENT_LEFT);
|
||||
params.removeRule(RelativeLayout.ALIGN_PARENT_TOP);
|
||||
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
|
||||
} else {
|
||||
params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
|
||||
params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
||||
params.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT);
|
||||
params.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
|
||||
}
|
||||
mButton.setLayoutParams(params);
|
||||
mTopLeft = !mTopLeft;
|
||||
}
|
||||
|
||||
/**
|
||||
* We need this setter to translate between the information the animator
|
||||
* produces (a new "PathPoint" describing the current animated location)
|
||||
* and the information that the button requires (an xy location). The
|
||||
* setter will be called by the ObjectAnimator given the 'buttonLoc'
|
||||
* property string.
|
||||
*/
|
||||
public void setButtonLoc(PathPoint newLoc) {
|
||||
mButton.setTranslationX(newLoc.mX);
|
||||
mButton.setTranslationY(newLoc.mY);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.curvedmotion;
|
||||
|
||||
import android.animation.TypeEvaluator;
|
||||
|
||||
/**
|
||||
* This evaluator interpolates between two PathPoint values given the value t, the
|
||||
* proportion traveled between those points. The value of the interpolation depends
|
||||
* on the operation specified by the endValue (the operation for the interval between
|
||||
* PathPoints is always specified by the end point of that interval).
|
||||
*/
|
||||
public class PathEvaluator implements TypeEvaluator<PathPoint> {
|
||||
@Override
|
||||
public PathPoint evaluate(float t, PathPoint startValue, PathPoint endValue) {
|
||||
float x, y;
|
||||
if (endValue.mOperation == PathPoint.CURVE) {
|
||||
float oneMinusT = 1 - t;
|
||||
x = oneMinusT * oneMinusT * oneMinusT * startValue.mX +
|
||||
3 * oneMinusT * oneMinusT * t * endValue.mControl0X +
|
||||
3 * oneMinusT * t * t * endValue.mControl1X +
|
||||
t * t * t * endValue.mX;
|
||||
y = oneMinusT * oneMinusT * oneMinusT * startValue.mY +
|
||||
3 * oneMinusT * oneMinusT * t * endValue.mControl0Y +
|
||||
3 * oneMinusT * t * t * endValue.mControl1Y +
|
||||
t * t * t * endValue.mY;
|
||||
} else if (endValue.mOperation == PathPoint.LINE) {
|
||||
x = startValue.mX + t * (endValue.mX - startValue.mX);
|
||||
y = startValue.mY + t * (endValue.mY - startValue.mY);
|
||||
} else {
|
||||
x = endValue.mX;
|
||||
y = endValue.mY;
|
||||
}
|
||||
return PathPoint.moveTo(x, y);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.curvedmotion;
|
||||
|
||||
/**
|
||||
* A class that holds information about a location and how the path should get to that
|
||||
* location from the previous path location (if any). Any PathPoint holds the information for
|
||||
* its location as well as the instructions on how to traverse the preceding interval from the
|
||||
* previous location.
|
||||
*/
|
||||
public class PathPoint {
|
||||
|
||||
/**
|
||||
* The possible path operations that describe how to move from a preceding PathPoint to the
|
||||
* location described by this PathPoint.
|
||||
*/
|
||||
public static final int MOVE = 0;
|
||||
public static final int LINE = 1;
|
||||
public static final int CURVE = 2;
|
||||
|
||||
/**
|
||||
* The location of this PathPoint
|
||||
*/
|
||||
float mX, mY;
|
||||
|
||||
/**
|
||||
* The first control point, if any, for a PathPoint of type CURVE
|
||||
*/
|
||||
float mControl0X, mControl0Y;
|
||||
|
||||
/**
|
||||
* The second control point, if any, for a PathPoint of type CURVE
|
||||
*/
|
||||
float mControl1X, mControl1Y;
|
||||
|
||||
/**
|
||||
* The motion described by the path to get from the previous PathPoint in an AnimatorPath
|
||||
* to the location of this PathPoint. This can be one of MOVE, LINE, or CURVE.
|
||||
*/
|
||||
int mOperation;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Line/Move constructor
|
||||
*/
|
||||
private PathPoint(int operation, float x, float y) {
|
||||
mOperation = operation;
|
||||
mX = x;
|
||||
mY = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Curve constructor
|
||||
*/
|
||||
private PathPoint(float c0X, float c0Y, float c1X, float c1Y, float x, float y) {
|
||||
mControl0X = c0X;
|
||||
mControl0Y = c0Y;
|
||||
mControl1X = c1X;
|
||||
mControl1Y = c1Y;
|
||||
mX = x;
|
||||
mY = y;
|
||||
mOperation = CURVE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns a PathPoint object that describes a line to the given xy location.
|
||||
*/
|
||||
public static PathPoint lineTo(float x, float y) {
|
||||
return new PathPoint(LINE, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns a PathPoint object that describes a curve to the given xy location
|
||||
* with the control points at c0 and c1.
|
||||
*/
|
||||
public static PathPoint curveTo(float c0X, float c0Y, float c1X, float c1Y, float x, float y) {
|
||||
return new PathPoint(c0X, c0Y, c1X, c1Y, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns a PathPoint object that describes a discontinuous move to the given
|
||||
* xy location.
|
||||
*/
|
||||
public static PathPoint moveTo(float x, float y) {
|
||||
return new PathPoint(MOVE, x, y);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.android.listviewitemanimations"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="9"
|
||||
android:targetSdkVersion="16" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme" >
|
||||
<activity
|
||||
android:theme="@style/WithoutBackground"
|
||||
android:name="com.example.android.listviewitemanimations.ListViewItemAnimations"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,37 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ListViewAnimations" >
|
||||
|
||||
<view
|
||||
class="com.example.android.listviewitemanimations.BackgroundContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/listViewBackground">
|
||||
|
||||
<ListView
|
||||
android:id="@+id/listview"
|
||||
android:divider="@null"
|
||||
android:dividerHeight="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</view>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,25 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/tv_background_with_divider"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSmall"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp"
|
||||
android:textSize="20dp"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="48dp"
|
||||
/>
|
||||
@@ -0,0 +1,37 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ListViewAnimations" >
|
||||
|
||||
<view
|
||||
class="com.example.android.listviewitemanimations.BackgroundContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/listViewBackground">
|
||||
|
||||
<ListView
|
||||
android:id="@+id/listview"
|
||||
android:divider="@null"
|
||||
android:dividerHeight="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</view>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,24 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/tv_background_with_divider"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSmall"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||
/>
|
||||
@@ -0,0 +1,25 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme for API 11+. This theme completely replaces
|
||||
AppBaseTheme from res/values/styles.xml on API 11+ devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
|
||||
<!-- API 11 theme customizations can go here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,26 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme for API 14+. This theme completely replaces
|
||||
AppBaseTheme from BOTH res/values/styles.xml and
|
||||
res/values-v11/styles.xml on API 14+ devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
|
||||
<!-- API 14 theme customizations can go here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,21 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<string name="app_name">ListViewItemAnimations</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
<string name="hello_world">Hello world!</string>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,38 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme, dependent on API level. This theme is replaced
|
||||
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Light">
|
||||
<!--
|
||||
Theme customizations available in newer API levels can go in
|
||||
res/values-vXX/styles.xml, while customizations related to
|
||||
backward-compatibility can go here.
|
||||
-->
|
||||
</style>
|
||||
|
||||
<!-- Application theme. -->
|
||||
<style name="AppTheme" parent="AppBaseTheme">
|
||||
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
|
||||
</style>
|
||||
|
||||
<style name="WithoutBackground" parent="AppTheme">
|
||||
<item name="android:windowBackground">@null</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.listviewitemanimations;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
public class BackgroundContainer extends FrameLayout {
|
||||
|
||||
boolean mShowing = false;
|
||||
Drawable mShadowedBackground;
|
||||
int mOpenAreaTop, mOpenAreaBottom, mOpenAreaHeight;
|
||||
boolean mUpdateBounds = false;
|
||||
|
||||
public BackgroundContainer(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public BackgroundContainer(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public BackgroundContainer(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mShadowedBackground = getContext().getResources().getDrawable(R.drawable.shadowed_background);
|
||||
}
|
||||
|
||||
public void showBackground(int top, int bottom) {
|
||||
setWillNotDraw(false);
|
||||
mOpenAreaTop = top;
|
||||
mOpenAreaHeight = bottom;
|
||||
mShowing = true;
|
||||
mUpdateBounds = true;
|
||||
}
|
||||
|
||||
public void hideBackground() {
|
||||
setWillNotDraw(true);
|
||||
mShowing = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (mShowing) {
|
||||
if (mUpdateBounds) {
|
||||
mShadowedBackground.setBounds(0, 0, getWidth(), mOpenAreaHeight);
|
||||
}
|
||||
canvas.save();
|
||||
canvas.translate(0, mOpenAreaTop);
|
||||
mShadowedBackground.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.listviewitemanimations;
|
||||
|
||||
public class Cheeses {
|
||||
|
||||
public static final String[] sCheeseStrings = {
|
||||
"Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
|
||||
"Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",
|
||||
"Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese",
|
||||
"Ami du Chambertin", "Anejo Enchilado", "Anneau du Vic-Bilh", "Anthoriro", "Appenzell",
|
||||
"Aragon", "Ardi Gasna", "Ardrahan", "Armenian String", "Aromes au Gene de Marc",
|
||||
"Asadero", "Asiago", "Aubisque Pyrenees", "Autun", "Avaxtskyr", "Baby Swiss",
|
||||
"Babybel", "Baguette Laonnaise", "Bakers", "Baladi", "Balaton", "Bandal", "Banon",
|
||||
"Barry's Bay Cheddar", "Basing", "Basket Cheese", "Bath Cheese", "Bavarian Bergkase",
|
||||
"Baylough", "Beaufort", "Beauvoorde", "Beenleigh Blue", "Beer Cheese", "Bel Paese",
|
||||
"Bergader", "Bergere Bleue", "Berkswell", "Beyaz Peynir", "Bierkase", "Bishop Kennedy",
|
||||
"Blarney", "Bleu d'Auvergne", "Bleu de Gex", "Bleu de Laqueuille",
|
||||
"Bleu de Septmoncel", "Bleu Des Causses", "Blue", "Blue Castello", "Blue Rathgore",
|
||||
"Blue Vein (Australian)", "Blue Vein Cheeses", "Bocconcini", "Bocconcini (Australian)",
|
||||
"Boeren Leidenkaas", "Bonchester", "Bosworth", "Bougon", "Boule Du Roves",
|
||||
"Boulette d'Avesnes", "Boursault", "Boursin", "Bouyssou", "Bra", "Braudostur",
|
||||
"Breakfast Cheese", "Brebis du Lavort", "Brebis du Lochois", "Brebis du Puyfaucon",
|
||||
"Bresse Bleu", "Brick", "Brie", "Brie de Meaux", "Brie de Melun", "Brillat-Savarin",
|
||||
"Brin", "Brin d' Amour", "Brin d'Amour", "Brinza (Burduf Brinza)",
|
||||
"Briquette de Brebis", "Briquette du Forez", "Broccio", "Broccio Demi-Affine",
|
||||
"Brousse du Rove", "Bruder Basil", "Brusselae Kaas (Fromage de Bruxelles)", "Bryndza",
|
||||
"Buchette d'Anjou", "Buffalo", "Burgos", "Butte", "Butterkase", "Button (Innes)",
|
||||
"Buxton Blue", "Cabecou", "Caboc", "Cabrales", "Cachaille", "Caciocavallo", "Caciotta",
|
||||
"Caerphilly", "Cairnsmore", "Calenzana", "Cambazola", "Camembert de Normandie",
|
||||
"Canadian Cheddar", "Canestrato", "Cantal", "Caprice des Dieux", "Capricorn Goat",
|
||||
"Capriole Banon", "Carre de l'Est", "Casciotta di Urbino", "Cashel Blue", "Castellano",
|
||||
"Castelleno", "Castelmagno", "Castelo Branco", "Castigliano", "Cathelain",
|
||||
"Celtic Promise", "Cendre d'Olivet", "Cerney", "Chabichou", "Chabichou du Poitou",
|
||||
"Chabis de Gatine", "Chaource", "Charolais", "Chaumes", "Cheddar",
|
||||
"Cheddar Clothbound", "Cheshire", "Chevres", "Chevrotin des Aravis", "Chontaleno",
|
||||
"Civray", "Coeur de Camembert au Calvados", "Coeur de Chevre", "Colby", "Cold Pack",
|
||||
"Comte", "Coolea", "Cooleney", "Coquetdale", "Corleggy", "Cornish Pepper",
|
||||
"Cotherstone", "Cotija", "Cottage Cheese", "Cottage Cheese (Australian)",
|
||||
"Cougar Gold", "Coulommiers", "Coverdale", "Crayeux de Roncq", "Cream Cheese",
|
||||
"Cream Havarti", "Crema Agria", "Crema Mexicana", "Creme Fraiche", "Crescenza",
|
||||
"Croghan", "Crottin de Chavignol", "Crottin du Chavignol", "Crowdie", "Crowley",
|
||||
"Cuajada", "Curd", "Cure Nantais", "Curworthy", "Cwmtawe Pecorino",
|
||||
"Cypress Grove Chevre", "Danablu (Danish Blue)", "Danbo", "Danish Fontina",
|
||||
"Daralagjazsky", "Dauphin", "Delice des Fiouves", "Denhany Dorset Drum", "Derby",
|
||||
"Dessertnyj Belyj", "Devon Blue", "Devon Garland", "Dolcelatte", "Doolin",
|
||||
"Doppelrhamstufel", "Dorset Blue Vinney", "Double Gloucester", "Double Worcester",
|
||||
"Dreux a la Feuille", "Dry Jack", "Duddleswell", "Dunbarra", "Dunlop", "Dunsyre Blue",
|
||||
"Duroblando", "Durrus", "Dutch Mimolette (Commissiekaas)", "Edam", "Edelpilz",
|
||||
"Emental Grand Cru", "Emlett", "Emmental", "Epoisses de Bourgogne", "Esbareich",
|
||||
"Esrom", "Etorki", "Evansdale Farmhouse Brie", "Evora De L'Alentejo", "Exmoor Blue",
|
||||
"Explorateur", "Feta", "Feta (Australian)", "Figue", "Filetta", "Fin-de-Siecle",
|
||||
"Finlandia Swiss", "Finn", "Fiore Sardo", "Fleur du Maquis", "Flor de Guia",
|
||||
"Flower Marie", "Folded", "Folded cheese with mint", "Fondant de Brebis",
|
||||
"Fontainebleau", "Fontal", "Fontina Val d'Aosta", "Formaggio di capra", "Fougerus",
|
||||
"Four Herb Gouda", "Fourme d' Ambert", "Fourme de Haute Loire", "Fourme de Montbrison",
|
||||
"Fresh Jack", "Fresh Mozzarella", "Fresh Ricotta", "Fresh Truffles", "Fribourgeois",
|
||||
"Friesekaas", "Friesian", "Friesla", "Frinault", "Fromage a Raclette", "Fromage Corse",
|
||||
"Fromage de Montagne de Savoie", "Fromage Frais", "Fruit Cream Cheese",
|
||||
"Frying Cheese", "Fynbo", "Gabriel", "Galette du Paludier", "Galette Lyonnaise",
|
||||
"Galloway Goat's Milk Gems", "Gammelost", "Gaperon a l'Ail", "Garrotxa", "Gastanberra",
|
||||
"Geitost", "Gippsland Blue", "Gjetost", "Gloucester", "Golden Cross", "Gorgonzola",
|
||||
"Gornyaltajski", "Gospel Green", "Gouda", "Goutu", "Gowrie", "Grabetto", "Graddost",
|
||||
"Grafton Village Cheddar", "Grana", "Grana Padano", "Grand Vatel",
|
||||
"Grataron d' Areches", "Gratte-Paille", "Graviera", "Greuilh", "Greve",
|
||||
"Gris de Lille", "Gruyere", "Gubbeen", "Guerbigny", "Halloumi",
|
||||
"Halloumy (Australian)", "Haloumi-Style Cheese", "Harbourne Blue", "Havarti",
|
||||
"Heidi Gruyere", "Hereford Hop", "Herrgardsost", "Herriot Farmhouse", "Herve",
|
||||
"Hipi Iti", "Hubbardston Blue Cow", "Hushallsost", "Iberico", "Idaho Goatster",
|
||||
"Idiazabal", "Il Boschetto al Tartufo", "Ile d'Yeu", "Isle of Mull", "Jarlsberg",
|
||||
"Jermi Tortes", "Jibneh Arabieh", "Jindi Brie", "Jubilee Blue", "Juustoleipa",
|
||||
"Kadchgall", "Kaseri", "Kashta", "Kefalotyri", "Kenafa", "Kernhem", "Kervella Affine",
|
||||
"Kikorangi", "King Island Cape Wickham Brie", "King River Gold", "Klosterkaese",
|
||||
"Knockalara", "Kugelkase", "L'Aveyronnais", "L'Ecir de l'Aubrac", "La Taupiniere",
|
||||
"La Vache Qui Rit", "Laguiole", "Lairobell", "Lajta", "Lanark Blue", "Lancashire",
|
||||
"Langres", "Lappi", "Laruns", "Lavistown", "Le Brin", "Le Fium Orbo", "Le Lacandou",
|
||||
"Le Roule", "Leafield", "Lebbene", "Leerdammer", "Leicester", "Leyden", "Limburger",
|
||||
"Lincolnshire Poacher", "Lingot Saint Bousquet d'Orb", "Liptauer", "Little Rydings",
|
||||
"Livarot", "Llanboidy", "Llanglofan Farmhouse", "Loch Arthur Farmhouse",
|
||||
"Loddiswell Avondale", "Longhorn", "Lou Palou", "Lou Pevre", "Lyonnais", "Maasdam",
|
||||
"Macconais", "Mahoe Aged Gouda", "Mahon", "Malvern", "Mamirolle", "Manchego",
|
||||
"Manouri", "Manur", "Marble Cheddar", "Marbled Cheeses", "Maredsous", "Margotin",
|
||||
"Maribo", "Maroilles", "Mascares", "Mascarpone", "Mascarpone (Australian)",
|
||||
"Mascarpone Torta", "Matocq", "Maytag Blue", "Meira", "Menallack Farmhouse",
|
||||
"Menonita", "Meredith Blue", "Mesost", "Metton (Cancoillotte)", "Meyer Vintage Gouda",
|
||||
"Mihalic Peynir", "Milleens", "Mimolette", "Mine-Gabhar", "Mini Baby Bells", "Mixte",
|
||||
"Molbo", "Monastery Cheeses", "Mondseer", "Mont D'or Lyonnais", "Montasio",
|
||||
"Monterey Jack", "Monterey Jack Dry", "Morbier", "Morbier Cru de Montagne",
|
||||
"Mothais a la Feuille", "Mozzarella", "Mozzarella (Australian)",
|
||||
"Mozzarella di Bufala", "Mozzarella Fresh, in water", "Mozzarella Rolls", "Munster",
|
||||
"Murol", "Mycella", "Myzithra", "Naboulsi", "Nantais", "Neufchatel",
|
||||
"Neufchatel (Australian)", "Niolo", "Nokkelost", "Northumberland", "Oaxaca",
|
||||
"Olde York", "Olivet au Foin", "Olivet Bleu", "Olivet Cendre",
|
||||
"Orkney Extra Mature Cheddar", "Orla", "Oschtjepka", "Ossau Fermier", "Ossau-Iraty",
|
||||
"Oszczypek", "Oxford Blue", "P'tit Berrichon", "Palet de Babligny", "Paneer", "Panela",
|
||||
"Pannerone", "Pant ys Gawn", "Parmesan (Parmigiano)", "Parmigiano Reggiano",
|
||||
"Pas de l'Escalette", "Passendale", "Pasteurized Processed", "Pate de Fromage",
|
||||
"Patefine Fort", "Pave d'Affinois", "Pave d'Auge", "Pave de Chirac", "Pave du Berry",
|
||||
"Pecorino", "Pecorino in Walnut Leaves", "Pecorino Romano", "Peekskill Pyramid",
|
||||
"Pelardon des Cevennes", "Pelardon des Corbieres", "Penamellera", "Penbryn",
|
||||
"Pencarreg", "Perail de Brebis", "Petit Morin", "Petit Pardou", "Petit-Suisse",
|
||||
"Picodon de Chevre", "Picos de Europa", "Piora", "Pithtviers au Foin",
|
||||
"Plateau de Herve", "Plymouth Cheese", "Podhalanski", "Poivre d'Ane", "Polkolbin",
|
||||
"Pont l'Eveque", "Port Nicholson", "Port-Salut", "Postel", "Pouligny-Saint-Pierre",
|
||||
"Pourly", "Prastost", "Pressato", "Prince-Jean", "Processed Cheddar", "Provolone",
|
||||
"Provolone (Australian)", "Pyengana Cheddar", "Pyramide", "Quark",
|
||||
"Quark (Australian)", "Quartirolo Lombardo", "Quatre-Vents", "Quercy Petit",
|
||||
"Queso Blanco", "Queso Blanco con Frutas --Pina y Mango", "Queso de Murcia",
|
||||
"Queso del Montsec", "Queso del Tietar", "Queso Fresco", "Queso Fresco (Adobera)",
|
||||
"Queso Iberico", "Queso Jalapeno", "Queso Majorero", "Queso Media Luna",
|
||||
"Queso Para Frier", "Queso Quesadilla", "Rabacal", "Raclette", "Ragusano", "Raschera",
|
||||
"Reblochon", "Red Leicester", "Regal de la Dombes", "Reggianito", "Remedou",
|
||||
"Requeson", "Richelieu", "Ricotta", "Ricotta (Australian)", "Ricotta Salata", "Ridder",
|
||||
"Rigotte", "Rocamadour", "Rollot", "Romano", "Romans Part Dieu", "Roncal", "Roquefort",
|
||||
"Roule", "Rouleau De Beaulieu", "Royalp Tilsit", "Rubens", "Rustinu", "Saaland Pfarr",
|
||||
"Saanenkaese", "Saga", "Sage Derby", "Sainte Maure", "Saint-Marcellin",
|
||||
"Saint-Nectaire", "Saint-Paulin", "Salers", "Samso", "San Simon", "Sancerre",
|
||||
"Sap Sago", "Sardo", "Sardo Egyptian", "Sbrinz", "Scamorza", "Schabzieger", "Schloss",
|
||||
"Selles sur Cher", "Selva", "Serat", "Seriously Strong Cheddar", "Serra da Estrela",
|
||||
"Sharpam", "Shelburne Cheddar", "Shropshire Blue", "Siraz", "Sirene", "Smoked Gouda",
|
||||
"Somerset Brie", "Sonoma Jack", "Sottocenare al Tartufo", "Soumaintrain",
|
||||
"Sourire Lozerien", "Spenwood", "Sraffordshire Organic", "St. Agur Blue Cheese",
|
||||
"Stilton", "Stinking Bishop", "String", "Sussex Slipcote", "Sveciaost", "Swaledale",
|
||||
"Sweet Style Swiss", "Swiss", "Syrian (Armenian String)", "Tala", "Taleggio", "Tamie",
|
||||
"Tasmania Highland Chevre Log", "Taupiniere", "Teifi", "Telemea", "Testouri",
|
||||
"Tete de Moine", "Tetilla", "Texas Goat Cheese", "Tibet", "Tillamook Cheddar",
|
||||
"Tilsit", "Timboon Brie", "Toma", "Tomme Brulee", "Tomme d'Abondance",
|
||||
"Tomme de Chevre", "Tomme de Romans", "Tomme de Savoie", "Tomme des Chouans", "Tommes",
|
||||
"Torta del Casar", "Toscanello", "Touree de L'Aubier", "Tourmalet",
|
||||
"Trappe (Veritable)", "Trois Cornes De Vendee", "Tronchon", "Trou du Cru", "Truffe",
|
||||
"Tupi", "Turunmaa", "Tymsboro", "Tyn Grug", "Tyning", "Ubriaco", "Ulloa",
|
||||
"Vacherin-Fribourgeois", "Valencay", "Vasterbottenost", "Venaco", "Vendomois",
|
||||
"Vieux Corse", "Vignotte", "Vulscombe", "Waimata Farmhouse Blue",
|
||||
"Washed Rind Cheese (Australian)", "Waterloo", "Weichkaese", "Wellington",
|
||||
"Wensleydale", "White Stilton", "Whitestone Farmhouse", "Wigmore", "Woodside Cabecou",
|
||||
"Xanadu", "Xynotyro", "Yarg Cornish", "Yarra Valley Pyramid", "Yorkshire Blue",
|
||||
"Zamorano", "Zanetti Grana Padano", "Zanetti Parmigiano Reggiano"
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.listviewitemanimations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.animation.AlphaAnimation;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.Animation.AnimationListener;
|
||||
import android.view.animation.AnimationSet;
|
||||
import android.view.animation.TranslateAnimation;
|
||||
import android.widget.ListView;
|
||||
|
||||
/**
|
||||
* This example shows how to use a swipe effect to remove items from a ListView,
|
||||
* and how to use animations to complete the swipe as well as to animate the other
|
||||
* items in the list into their final places. This code works on runtimes back to Gingerbread
|
||||
* (Android 2.3), by using the android.view.animation classes on earlier releases.
|
||||
*
|
||||
* Watch the associated video for this demo on the DevBytes channel of developer.android.com
|
||||
* or on the DevBytes playlist in the androiddevelopers channel on YouTube at
|
||||
* https://www.youtube.com/playlist?list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0.
|
||||
*/
|
||||
public class ListViewItemAnimations extends Activity {
|
||||
|
||||
final ArrayList<View> mCheckedViews = new ArrayList<View>();
|
||||
StableArrayAdapter mAdapter;
|
||||
ListView mListView;
|
||||
BackgroundContainer mBackgroundContainer;
|
||||
boolean mSwiping = false;
|
||||
boolean mItemPressed = false;
|
||||
HashMap<Long, Integer> mItemIdTopMap = new HashMap<Long, Integer>();
|
||||
boolean mAnimating = false;
|
||||
float mCurrentX = 0;
|
||||
float mCurrentAlpha = 1;
|
||||
|
||||
private static final int SWIPE_DURATION = 250;
|
||||
private static final int MOVE_DURATION = 150;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_list_view_item_animations);
|
||||
|
||||
mBackgroundContainer = (BackgroundContainer) findViewById(R.id.listViewBackground);
|
||||
mListView = (ListView) findViewById(R.id.listview);
|
||||
final ArrayList<String> cheeseList = new ArrayList<String>();
|
||||
for (int i = 0; i < Cheeses.sCheeseStrings.length; ++i) {
|
||||
cheeseList.add(Cheeses.sCheeseStrings[i]);
|
||||
}
|
||||
mAdapter = new StableArrayAdapter(this,R.layout.opaque_text_view, cheeseList,
|
||||
mTouchListener);
|
||||
mListView.setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current runtime is Honeycomb or later
|
||||
*/
|
||||
private boolean isRuntimePostGingerbread() {
|
||||
return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB;
|
||||
}
|
||||
|
||||
private View.OnTouchListener mTouchListener = new View.OnTouchListener() {
|
||||
|
||||
float mDownX;
|
||||
private int mSwipeSlop = -1;
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public boolean onTouch(final View v, MotionEvent event) {
|
||||
if (mSwipeSlop < 0) {
|
||||
mSwipeSlop = ViewConfiguration.get(ListViewItemAnimations.this).
|
||||
getScaledTouchSlop();
|
||||
}
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
if (mAnimating) {
|
||||
// Multi-item swipes not handled
|
||||
return true;
|
||||
}
|
||||
mItemPressed = true;
|
||||
mDownX = event.getX();
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
setSwipePosition(v, 0);
|
||||
mItemPressed = false;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
{
|
||||
if (mAnimating) {
|
||||
return true;
|
||||
}
|
||||
float x = event.getX();
|
||||
if (isRuntimePostGingerbread()) {
|
||||
x += v.getTranslationX();
|
||||
}
|
||||
float deltaX = x - mDownX;
|
||||
float deltaXAbs = Math.abs(deltaX);
|
||||
if (!mSwiping) {
|
||||
if (deltaXAbs > mSwipeSlop) {
|
||||
mSwiping = true;
|
||||
mListView.requestDisallowInterceptTouchEvent(true);
|
||||
mBackgroundContainer.showBackground(v.getTop(), v.getHeight());
|
||||
}
|
||||
}
|
||||
if (mSwiping) {
|
||||
setSwipePosition(v, deltaX);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
{
|
||||
if (mAnimating) {
|
||||
return true;
|
||||
}
|
||||
// User let go - figure out whether to animate the view out, or back into place
|
||||
if (mSwiping) {
|
||||
float x = event.getX();
|
||||
if (isRuntimePostGingerbread()) {
|
||||
x += v.getTranslationX();
|
||||
}
|
||||
float deltaX = x - mDownX;
|
||||
float deltaXAbs = Math.abs(deltaX);
|
||||
float fractionCovered;
|
||||
float endX;
|
||||
final boolean remove;
|
||||
if (deltaXAbs > v.getWidth() / 4) {
|
||||
// Greater than a quarter of the width - animate it out
|
||||
fractionCovered = deltaXAbs / v.getWidth();
|
||||
endX = deltaX < 0 ? -v.getWidth() : v.getWidth();
|
||||
remove = true;
|
||||
} else {
|
||||
// Not far enough - animate it back
|
||||
fractionCovered = 1 - (deltaXAbs / v.getWidth());
|
||||
endX = 0;
|
||||
remove = false;
|
||||
}
|
||||
// Animate position and alpha
|
||||
long duration = (int) ((1 - fractionCovered) * SWIPE_DURATION);
|
||||
animateSwipe(v, endX, duration, remove);
|
||||
} else {
|
||||
mItemPressed = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Animates a swipe of the item either back into place or out of the listview container.
|
||||
* NOTE: This is a simplified version of swipe behavior, for the purposes of this demo
|
||||
* about animation. A real version should use velocity (via the VelocityTracker class)
|
||||
* to send the item off or back at an appropriate speed.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
private void animateSwipe(final View view, float endX, long duration, final boolean remove) {
|
||||
mAnimating = true;
|
||||
mListView.setEnabled(false);
|
||||
if (isRuntimePostGingerbread()) {
|
||||
view.animate().setDuration(duration).
|
||||
alpha(remove ? 0 : 1).translationX(endX).
|
||||
setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
// Restore animated values
|
||||
view.setAlpha(1);
|
||||
view.setTranslationX(0);
|
||||
if (remove) {
|
||||
animateOtherViews(mListView, view);
|
||||
} else {
|
||||
mBackgroundContainer.hideBackground();
|
||||
mSwiping = false;
|
||||
mAnimating = false;
|
||||
mListView.setEnabled(true);
|
||||
}
|
||||
mItemPressed = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
TranslateAnimation swipeAnim = new TranslateAnimation(mCurrentX, endX, 0, 0);
|
||||
AlphaAnimation alphaAnim = new AlphaAnimation(mCurrentAlpha, remove ? 0 : 1);
|
||||
AnimationSet set = new AnimationSet(true);
|
||||
set.addAnimation(swipeAnim);
|
||||
set.addAnimation(alphaAnim);
|
||||
set.setDuration(duration);
|
||||
view.startAnimation(set);
|
||||
setAnimationEndAction(set, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (remove) {
|
||||
animateOtherViews(mListView, view);
|
||||
} else {
|
||||
mBackgroundContainer.hideBackground();
|
||||
mSwiping = false;
|
||||
mAnimating = false;
|
||||
mListView.setEnabled(true);
|
||||
}
|
||||
mItemPressed = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the horizontal position and translucency of the view being swiped.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
private void setSwipePosition(View view, float deltaX) {
|
||||
float fraction = Math.abs(deltaX) / view.getWidth();
|
||||
if (isRuntimePostGingerbread()) {
|
||||
view.setTranslationX(deltaX);
|
||||
view.setAlpha(1 - fraction);
|
||||
} else {
|
||||
// Hello, Gingerbread!
|
||||
TranslateAnimation swipeAnim = new TranslateAnimation(deltaX, deltaX, 0, 0);
|
||||
mCurrentX = deltaX;
|
||||
mCurrentAlpha = (1 - fraction);
|
||||
AlphaAnimation alphaAnim = new AlphaAnimation(mCurrentAlpha, mCurrentAlpha);
|
||||
AnimationSet set = new AnimationSet(true);
|
||||
set.addAnimation(swipeAnim);
|
||||
set.addAnimation(alphaAnim);
|
||||
set.setFillAfter(true);
|
||||
set.setFillEnabled(true);
|
||||
view.startAnimation(set);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method animates all other views in the ListView container (not including ignoreView)
|
||||
* into their final positions. It is called after ignoreView has been removed from the
|
||||
* adapter, but before layout has been run. The approach here is to figure out where
|
||||
* everything is now, then allow layout to run, then figure out where everything is after
|
||||
* layout, and then to run animations between all of those start/end positions.
|
||||
*/
|
||||
private void animateOtherViews(final ListView listview, View viewToRemove) {
|
||||
int firstVisiblePosition = listview.getFirstVisiblePosition();
|
||||
for (int i = 0; i < listview.getChildCount(); ++i) {
|
||||
View child = listview.getChildAt(i);
|
||||
int position = firstVisiblePosition + i;
|
||||
long itemId = mAdapter.getItemId(position);
|
||||
if (child != viewToRemove) {
|
||||
mItemIdTopMap.put(itemId, child.getTop());
|
||||
}
|
||||
}
|
||||
// Delete the item from the adapter
|
||||
int position = mListView.getPositionForView(viewToRemove);
|
||||
mAdapter.remove(mAdapter.getItem(position));
|
||||
|
||||
// After layout runs, capture position of all itemIDs, compare to pre-layout
|
||||
// positions, and animate changes
|
||||
final ViewTreeObserver observer = listview.getViewTreeObserver();
|
||||
observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
|
||||
public boolean onPreDraw() {
|
||||
observer.removeOnPreDrawListener(this);
|
||||
boolean firstAnimation = true;
|
||||
int firstVisiblePosition = listview.getFirstVisiblePosition();
|
||||
for (int i = 0; i < listview.getChildCount(); ++i) {
|
||||
final View child = listview.getChildAt(i);
|
||||
int position = firstVisiblePosition + i;
|
||||
long itemId = mAdapter.getItemId(position);
|
||||
Integer startTop = mItemIdTopMap.get(itemId);
|
||||
int top = child.getTop();
|
||||
if (startTop == null) {
|
||||
// Animate new views along with the others. The catch is that they did not
|
||||
// exist in the start state, so we must calculate their starting position
|
||||
// based on whether they're coming in from the bottom (i > 0) or top.
|
||||
int childHeight = child.getHeight() + listview.getDividerHeight();
|
||||
startTop = top + (i > 0 ? childHeight : -childHeight);
|
||||
}
|
||||
int delta = startTop - top;
|
||||
if (delta != 0) {
|
||||
Runnable endAction = firstAnimation ?
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
mBackgroundContainer.hideBackground();
|
||||
mSwiping = false;
|
||||
mAnimating = false;
|
||||
mListView.setEnabled(true);
|
||||
}
|
||||
} :
|
||||
null;
|
||||
firstAnimation = false;
|
||||
moveView(child, 0, 0, delta, 0, endAction);
|
||||
}
|
||||
}
|
||||
mItemIdTopMap.clear();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Animate a view between start and end X/Y locations, using either old (pre-3.0) or
|
||||
* new animation APIs.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
private void moveView(View view, float startX, float endX, float startY, float endY,
|
||||
Runnable endAction) {
|
||||
final Runnable finalEndAction = endAction;
|
||||
if (isRuntimePostGingerbread()) {
|
||||
view.animate().setDuration(MOVE_DURATION);
|
||||
if (startX != endX) {
|
||||
ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, startX, endX);
|
||||
anim.setDuration(MOVE_DURATION);
|
||||
anim.start();
|
||||
setAnimatorEndAction(anim, endAction);
|
||||
endAction = null;
|
||||
}
|
||||
if (startY != endY) {
|
||||
ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, startY, endY);
|
||||
anim.setDuration(MOVE_DURATION);
|
||||
anim.start();
|
||||
setAnimatorEndAction(anim, endAction);
|
||||
}
|
||||
} else {
|
||||
TranslateAnimation translator = new TranslateAnimation(startX, endX, startY, endY);
|
||||
translator.setDuration(MOVE_DURATION);
|
||||
view.startAnimation(translator);
|
||||
if (endAction != null) {
|
||||
view.getAnimation().setAnimationListener(new AnimationListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
finalEndAction.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private void setAnimatorEndAction(Animator animator, final Runnable endAction) {
|
||||
if (endAction != null) {
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
endAction.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void setAnimationEndAction(Animation animation, final Runnable endAction) {
|
||||
if (endAction != null) {
|
||||
animation.setAnimationListener(new AnimationListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
endAction.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility, to avoid having to implement every method in AnimationListener in
|
||||
* every implementation class
|
||||
*/
|
||||
static class AnimationListenerAdapter implements AnimationListener {
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animation animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animation animation) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.listviewitemanimations;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
||||
public class StableArrayAdapter extends ArrayAdapter<String> {
|
||||
|
||||
HashMap<String, Integer> mIdMap = new HashMap<String, Integer>();
|
||||
View.OnTouchListener mTouchListener;
|
||||
|
||||
public StableArrayAdapter(Context context, int textViewResourceId,
|
||||
List<String> objects, View.OnTouchListener listener) {
|
||||
super(context, textViewResourceId, objects);
|
||||
mTouchListener = listener;
|
||||
for (int i = 0; i < objects.size(); ++i) {
|
||||
mIdMap.put(objects.get(i), i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
String item = getItem(position);
|
||||
return mIdMap.get(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
View view = super.getView(position, convertView, parent);
|
||||
if (view != convertView) {
|
||||
// Add touch listener to every new view to track swipe motion
|
||||
view.setOnTouchListener(mTouchListener);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.android.listviewremovalanimation"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="16"
|
||||
android:targetSdkVersion="16" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme" >
|
||||
<activity
|
||||
android:theme="@style/WithoutBackground"
|
||||
android:name="com.example.android.listviewremovalanimation.ListViewRemovalAnimation"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 197 B |
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,37 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ListViewAnimations" >
|
||||
|
||||
<view
|
||||
class="com.example.android.listviewremovalanimation.BackgroundContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/listViewBackground">
|
||||
|
||||
<ListView
|
||||
android:id="@+id/listview"
|
||||
android:divider="@null"
|
||||
android:dividerHeight="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</view>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,24 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/tv_background_with_divider"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSmall"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||
/>
|
||||
@@ -0,0 +1,25 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme for API 11+. This theme completely replaces
|
||||
AppBaseTheme from res/values/styles.xml on API 11+ devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
|
||||
<!-- API 11 theme customizations can go here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,26 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme for API 14+. This theme completely replaces
|
||||
AppBaseTheme from BOTH res/values/styles.xml and
|
||||
res/values-v11/styles.xml on API 14+ devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
|
||||
<!-- API 14 theme customizations can go here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,21 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<string name="app_name">ListViewRemovalAnimation</string>
|
||||
<string name="use_positions">Use Positions</string>
|
||||
<string name="delete_selected">Delete Selected</string>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,37 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme, dependent on API level. This theme is replaced
|
||||
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Light">
|
||||
<!--
|
||||
Theme customizations available in newer API levels can go in
|
||||
res/values-vXX/styles.xml, while customizations related to
|
||||
backward-compatibility can go here.
|
||||
-->
|
||||
</style>
|
||||
|
||||
<!-- Application theme. -->
|
||||
<style name="AppTheme" parent="AppBaseTheme">
|
||||
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
|
||||
</style>
|
||||
|
||||
<style name="WithoutBackground" parent="AppTheme">
|
||||
<item name="android:windowBackground">@null</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.listviewremovalanimation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
public class BackgroundContainer extends FrameLayout {
|
||||
|
||||
boolean mShowing = false;
|
||||
Drawable mShadowedBackground;
|
||||
int mOpenAreaTop, mOpenAreaBottom, mOpenAreaHeight;
|
||||
boolean mUpdateBounds = false;
|
||||
|
||||
public BackgroundContainer(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public BackgroundContainer(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public BackgroundContainer(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mShadowedBackground =
|
||||
getContext().getResources().getDrawable(R.drawable.shadowed_background);
|
||||
}
|
||||
|
||||
public void showBackground(int top, int bottom) {
|
||||
setWillNotDraw(false);
|
||||
mOpenAreaTop = top;
|
||||
mOpenAreaHeight = bottom;
|
||||
mShowing = true;
|
||||
mUpdateBounds = true;
|
||||
}
|
||||
|
||||
public void hideBackground() {
|
||||
setWillNotDraw(true);
|
||||
mShowing = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (mShowing) {
|
||||
if (mUpdateBounds) {
|
||||
mShadowedBackground.setBounds(0, 0, getWidth(), mOpenAreaHeight);
|
||||
}
|
||||
canvas.save();
|
||||
canvas.translate(0, mOpenAreaTop);
|
||||
mShadowedBackground.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.listviewremovalanimation;
|
||||
|
||||
public class Cheeses {
|
||||
|
||||
public static final String[] sCheeseStrings = {
|
||||
"Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
|
||||
"Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",
|
||||
"Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese",
|
||||
"Ami du Chambertin", "Anejo Enchilado", "Anneau du Vic-Bilh", "Anthoriro", "Appenzell",
|
||||
"Aragon", "Ardi Gasna", "Ardrahan", "Armenian String", "Aromes au Gene de Marc",
|
||||
"Asadero", "Asiago", "Aubisque Pyrenees", "Autun", "Avaxtskyr", "Baby Swiss",
|
||||
"Babybel", "Baguette Laonnaise", "Bakers", "Baladi", "Balaton", "Bandal", "Banon",
|
||||
"Barry's Bay Cheddar", "Basing", "Basket Cheese", "Bath Cheese", "Bavarian Bergkase",
|
||||
"Baylough", "Beaufort", "Beauvoorde", "Beenleigh Blue", "Beer Cheese", "Bel Paese",
|
||||
"Bergader", "Bergere Bleue", "Berkswell", "Beyaz Peynir", "Bierkase", "Bishop Kennedy",
|
||||
"Blarney", "Bleu d'Auvergne", "Bleu de Gex", "Bleu de Laqueuille",
|
||||
"Bleu de Septmoncel", "Bleu Des Causses", "Blue", "Blue Castello", "Blue Rathgore",
|
||||
"Blue Vein (Australian)", "Blue Vein Cheeses", "Bocconcini", "Bocconcini (Australian)",
|
||||
"Boeren Leidenkaas", "Bonchester", "Bosworth", "Bougon", "Boule Du Roves",
|
||||
"Boulette d'Avesnes", "Boursault", "Boursin", "Bouyssou", "Bra", "Braudostur",
|
||||
"Breakfast Cheese", "Brebis du Lavort", "Brebis du Lochois", "Brebis du Puyfaucon",
|
||||
"Bresse Bleu", "Brick", "Brie", "Brie de Meaux", "Brie de Melun", "Brillat-Savarin",
|
||||
"Brin", "Brin d' Amour", "Brin d'Amour", "Brinza (Burduf Brinza)",
|
||||
"Briquette de Brebis", "Briquette du Forez", "Broccio", "Broccio Demi-Affine",
|
||||
"Brousse du Rove", "Bruder Basil", "Brusselae Kaas (Fromage de Bruxelles)", "Bryndza",
|
||||
"Buchette d'Anjou", "Buffalo", "Burgos", "Butte", "Butterkase", "Button (Innes)",
|
||||
"Buxton Blue", "Cabecou", "Caboc", "Cabrales", "Cachaille", "Caciocavallo", "Caciotta",
|
||||
"Caerphilly", "Cairnsmore", "Calenzana", "Cambazola", "Camembert de Normandie",
|
||||
"Canadian Cheddar", "Canestrato", "Cantal", "Caprice des Dieux", "Capricorn Goat",
|
||||
"Capriole Banon", "Carre de l'Est", "Casciotta di Urbino", "Cashel Blue", "Castellano",
|
||||
"Castelleno", "Castelmagno", "Castelo Branco", "Castigliano", "Cathelain",
|
||||
"Celtic Promise", "Cendre d'Olivet", "Cerney", "Chabichou", "Chabichou du Poitou",
|
||||
"Chabis de Gatine", "Chaource", "Charolais", "Chaumes", "Cheddar",
|
||||
"Cheddar Clothbound", "Cheshire", "Chevres", "Chevrotin des Aravis", "Chontaleno",
|
||||
"Civray", "Coeur de Camembert au Calvados", "Coeur de Chevre", "Colby", "Cold Pack",
|
||||
"Comte", "Coolea", "Cooleney", "Coquetdale", "Corleggy", "Cornish Pepper",
|
||||
"Cotherstone", "Cotija", "Cottage Cheese", "Cottage Cheese (Australian)",
|
||||
"Cougar Gold", "Coulommiers", "Coverdale", "Crayeux de Roncq", "Cream Cheese",
|
||||
"Cream Havarti", "Crema Agria", "Crema Mexicana", "Creme Fraiche", "Crescenza",
|
||||
"Croghan", "Crottin de Chavignol", "Crottin du Chavignol", "Crowdie", "Crowley",
|
||||
"Cuajada", "Curd", "Cure Nantais", "Curworthy", "Cwmtawe Pecorino",
|
||||
"Cypress Grove Chevre", "Danablu (Danish Blue)", "Danbo", "Danish Fontina",
|
||||
"Daralagjazsky", "Dauphin", "Delice des Fiouves", "Denhany Dorset Drum", "Derby",
|
||||
"Dessertnyj Belyj", "Devon Blue", "Devon Garland", "Dolcelatte", "Doolin",
|
||||
"Doppelrhamstufel", "Dorset Blue Vinney", "Double Gloucester", "Double Worcester",
|
||||
"Dreux a la Feuille", "Dry Jack", "Duddleswell", "Dunbarra", "Dunlop", "Dunsyre Blue",
|
||||
"Duroblando", "Durrus", "Dutch Mimolette (Commissiekaas)", "Edam", "Edelpilz",
|
||||
"Emental Grand Cru", "Emlett", "Emmental", "Epoisses de Bourgogne", "Esbareich",
|
||||
"Esrom", "Etorki", "Evansdale Farmhouse Brie", "Evora De L'Alentejo", "Exmoor Blue",
|
||||
"Explorateur", "Feta", "Feta (Australian)", "Figue", "Filetta", "Fin-de-Siecle",
|
||||
"Finlandia Swiss", "Finn", "Fiore Sardo", "Fleur du Maquis", "Flor de Guia",
|
||||
"Flower Marie", "Folded", "Folded cheese with mint", "Fondant de Brebis",
|
||||
"Fontainebleau", "Fontal", "Fontina Val d'Aosta", "Formaggio di capra", "Fougerus",
|
||||
"Four Herb Gouda", "Fourme d' Ambert", "Fourme de Haute Loire", "Fourme de Montbrison",
|
||||
"Fresh Jack", "Fresh Mozzarella", "Fresh Ricotta", "Fresh Truffles", "Fribourgeois",
|
||||
"Friesekaas", "Friesian", "Friesla", "Frinault", "Fromage a Raclette", "Fromage Corse",
|
||||
"Fromage de Montagne de Savoie", "Fromage Frais", "Fruit Cream Cheese",
|
||||
"Frying Cheese", "Fynbo", "Gabriel", "Galette du Paludier", "Galette Lyonnaise",
|
||||
"Galloway Goat's Milk Gems", "Gammelost", "Gaperon a l'Ail", "Garrotxa", "Gastanberra",
|
||||
"Geitost", "Gippsland Blue", "Gjetost", "Gloucester", "Golden Cross", "Gorgonzola",
|
||||
"Gornyaltajski", "Gospel Green", "Gouda", "Goutu", "Gowrie", "Grabetto", "Graddost",
|
||||
"Grafton Village Cheddar", "Grana", "Grana Padano", "Grand Vatel",
|
||||
"Grataron d' Areches", "Gratte-Paille", "Graviera", "Greuilh", "Greve",
|
||||
"Gris de Lille", "Gruyere", "Gubbeen", "Guerbigny", "Halloumi",
|
||||
"Halloumy (Australian)", "Haloumi-Style Cheese", "Harbourne Blue", "Havarti",
|
||||
"Heidi Gruyere", "Hereford Hop", "Herrgardsost", "Herriot Farmhouse", "Herve",
|
||||
"Hipi Iti", "Hubbardston Blue Cow", "Hushallsost", "Iberico", "Idaho Goatster",
|
||||
"Idiazabal", "Il Boschetto al Tartufo", "Ile d'Yeu", "Isle of Mull", "Jarlsberg",
|
||||
"Jermi Tortes", "Jibneh Arabieh", "Jindi Brie", "Jubilee Blue", "Juustoleipa",
|
||||
"Kadchgall", "Kaseri", "Kashta", "Kefalotyri", "Kenafa", "Kernhem", "Kervella Affine",
|
||||
"Kikorangi", "King Island Cape Wickham Brie", "King River Gold", "Klosterkaese",
|
||||
"Knockalara", "Kugelkase", "L'Aveyronnais", "L'Ecir de l'Aubrac", "La Taupiniere",
|
||||
"La Vache Qui Rit", "Laguiole", "Lairobell", "Lajta", "Lanark Blue", "Lancashire",
|
||||
"Langres", "Lappi", "Laruns", "Lavistown", "Le Brin", "Le Fium Orbo", "Le Lacandou",
|
||||
"Le Roule", "Leafield", "Lebbene", "Leerdammer", "Leicester", "Leyden", "Limburger",
|
||||
"Lincolnshire Poacher", "Lingot Saint Bousquet d'Orb", "Liptauer", "Little Rydings",
|
||||
"Livarot", "Llanboidy", "Llanglofan Farmhouse", "Loch Arthur Farmhouse",
|
||||
"Loddiswell Avondale", "Longhorn", "Lou Palou", "Lou Pevre", "Lyonnais", "Maasdam",
|
||||
"Macconais", "Mahoe Aged Gouda", "Mahon", "Malvern", "Mamirolle", "Manchego",
|
||||
"Manouri", "Manur", "Marble Cheddar", "Marbled Cheeses", "Maredsous", "Margotin",
|
||||
"Maribo", "Maroilles", "Mascares", "Mascarpone", "Mascarpone (Australian)",
|
||||
"Mascarpone Torta", "Matocq", "Maytag Blue", "Meira", "Menallack Farmhouse",
|
||||
"Menonita", "Meredith Blue", "Mesost", "Metton (Cancoillotte)", "Meyer Vintage Gouda",
|
||||
"Mihalic Peynir", "Milleens", "Mimolette", "Mine-Gabhar", "Mini Baby Bells", "Mixte",
|
||||
"Molbo", "Monastery Cheeses", "Mondseer", "Mont D'or Lyonnais", "Montasio",
|
||||
"Monterey Jack", "Monterey Jack Dry", "Morbier", "Morbier Cru de Montagne",
|
||||
"Mothais a la Feuille", "Mozzarella", "Mozzarella (Australian)",
|
||||
"Mozzarella di Bufala", "Mozzarella Fresh, in water", "Mozzarella Rolls", "Munster",
|
||||
"Murol", "Mycella", "Myzithra", "Naboulsi", "Nantais", "Neufchatel",
|
||||
"Neufchatel (Australian)", "Niolo", "Nokkelost", "Northumberland", "Oaxaca",
|
||||
"Olde York", "Olivet au Foin", "Olivet Bleu", "Olivet Cendre",
|
||||
"Orkney Extra Mature Cheddar", "Orla", "Oschtjepka", "Ossau Fermier", "Ossau-Iraty",
|
||||
"Oszczypek", "Oxford Blue", "P'tit Berrichon", "Palet de Babligny", "Paneer", "Panela",
|
||||
"Pannerone", "Pant ys Gawn", "Parmesan (Parmigiano)", "Parmigiano Reggiano",
|
||||
"Pas de l'Escalette", "Passendale", "Pasteurized Processed", "Pate de Fromage",
|
||||
"Patefine Fort", "Pave d'Affinois", "Pave d'Auge", "Pave de Chirac", "Pave du Berry",
|
||||
"Pecorino", "Pecorino in Walnut Leaves", "Pecorino Romano", "Peekskill Pyramid",
|
||||
"Pelardon des Cevennes", "Pelardon des Corbieres", "Penamellera", "Penbryn",
|
||||
"Pencarreg", "Perail de Brebis", "Petit Morin", "Petit Pardou", "Petit-Suisse",
|
||||
"Picodon de Chevre", "Picos de Europa", "Piora", "Pithtviers au Foin",
|
||||
"Plateau de Herve", "Plymouth Cheese", "Podhalanski", "Poivre d'Ane", "Polkolbin",
|
||||
"Pont l'Eveque", "Port Nicholson", "Port-Salut", "Postel", "Pouligny-Saint-Pierre",
|
||||
"Pourly", "Prastost", "Pressato", "Prince-Jean", "Processed Cheddar", "Provolone",
|
||||
"Provolone (Australian)", "Pyengana Cheddar", "Pyramide", "Quark",
|
||||
"Quark (Australian)", "Quartirolo Lombardo", "Quatre-Vents", "Quercy Petit",
|
||||
"Queso Blanco", "Queso Blanco con Frutas --Pina y Mango", "Queso de Murcia",
|
||||
"Queso del Montsec", "Queso del Tietar", "Queso Fresco", "Queso Fresco (Adobera)",
|
||||
"Queso Iberico", "Queso Jalapeno", "Queso Majorero", "Queso Media Luna",
|
||||
"Queso Para Frier", "Queso Quesadilla", "Rabacal", "Raclette", "Ragusano", "Raschera",
|
||||
"Reblochon", "Red Leicester", "Regal de la Dombes", "Reggianito", "Remedou",
|
||||
"Requeson", "Richelieu", "Ricotta", "Ricotta (Australian)", "Ricotta Salata", "Ridder",
|
||||
"Rigotte", "Rocamadour", "Rollot", "Romano", "Romans Part Dieu", "Roncal", "Roquefort",
|
||||
"Roule", "Rouleau De Beaulieu", "Royalp Tilsit", "Rubens", "Rustinu", "Saaland Pfarr",
|
||||
"Saanenkaese", "Saga", "Sage Derby", "Sainte Maure", "Saint-Marcellin",
|
||||
"Saint-Nectaire", "Saint-Paulin", "Salers", "Samso", "San Simon", "Sancerre",
|
||||
"Sap Sago", "Sardo", "Sardo Egyptian", "Sbrinz", "Scamorza", "Schabzieger", "Schloss",
|
||||
"Selles sur Cher", "Selva", "Serat", "Seriously Strong Cheddar", "Serra da Estrela",
|
||||
"Sharpam", "Shelburne Cheddar", "Shropshire Blue", "Siraz", "Sirene", "Smoked Gouda",
|
||||
"Somerset Brie", "Sonoma Jack", "Sottocenare al Tartufo", "Soumaintrain",
|
||||
"Sourire Lozerien", "Spenwood", "Sraffordshire Organic", "St. Agur Blue Cheese",
|
||||
"Stilton", "Stinking Bishop", "String", "Sussex Slipcote", "Sveciaost", "Swaledale",
|
||||
"Sweet Style Swiss", "Swiss", "Syrian (Armenian String)", "Tala", "Taleggio", "Tamie",
|
||||
"Tasmania Highland Chevre Log", "Taupiniere", "Teifi", "Telemea", "Testouri",
|
||||
"Tete de Moine", "Tetilla", "Texas Goat Cheese", "Tibet", "Tillamook Cheddar",
|
||||
"Tilsit", "Timboon Brie", "Toma", "Tomme Brulee", "Tomme d'Abondance",
|
||||
"Tomme de Chevre", "Tomme de Romans", "Tomme de Savoie", "Tomme des Chouans", "Tommes",
|
||||
"Torta del Casar", "Toscanello", "Touree de L'Aubier", "Tourmalet",
|
||||
"Trappe (Veritable)", "Trois Cornes De Vendee", "Tronchon", "Trou du Cru", "Truffe",
|
||||
"Tupi", "Turunmaa", "Tymsboro", "Tyn Grug", "Tyning", "Ubriaco", "Ulloa",
|
||||
"Vacherin-Fribourgeois", "Valencay", "Vasterbottenost", "Venaco", "Vendomois",
|
||||
"Vieux Corse", "Vignotte", "Vulscombe", "Waimata Farmhouse Blue",
|
||||
"Washed Rind Cheese (Australian)", "Waterloo", "Weichkaese", "Wellington",
|
||||
"Wensleydale", "White Stilton", "Whitestone Farmhouse", "Wigmore", "Woodside Cabecou",
|
||||
"Xanadu", "Xynotyro", "Yarg Cornish", "Yarra Valley Pyramid", "Yorkshire Blue",
|
||||
"Zamorano", "Zanetti Grana Padano", "Zanetti Parmigiano Reggiano"
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.listviewremovalanimation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.ListView;
|
||||
|
||||
/**
|
||||
* This example shows how to use a swipe effect to remove items from a ListView,
|
||||
* and how to use animations to complete the swipe as well as to animate the other
|
||||
* items in the list into their final places.
|
||||
*
|
||||
* Watch the associated video for this demo on the DevBytes channel of developer.android.com
|
||||
* or on YouTube at https://www.youtube.com/watch?v=NewCSg2JKLk.
|
||||
*/
|
||||
public class ListViewRemovalAnimation extends Activity {
|
||||
|
||||
StableArrayAdapter mAdapter;
|
||||
ListView mListView;
|
||||
BackgroundContainer mBackgroundContainer;
|
||||
boolean mSwiping = false;
|
||||
boolean mItemPressed = false;
|
||||
HashMap<Long, Integer> mItemIdTopMap = new HashMap<Long, Integer>();
|
||||
|
||||
private static final int SWIPE_DURATION = 250;
|
||||
private static final int MOVE_DURATION = 150;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_list_view_deletion);
|
||||
|
||||
mBackgroundContainer = (BackgroundContainer) findViewById(R.id.listViewBackground);
|
||||
mListView = (ListView) findViewById(R.id.listview);
|
||||
android.util.Log.d("Debug", "d=" + mListView.getDivider());
|
||||
final ArrayList<String> cheeseList = new ArrayList<String>();
|
||||
for (int i = 0; i < Cheeses.sCheeseStrings.length; ++i) {
|
||||
cheeseList.add(Cheeses.sCheeseStrings[i]);
|
||||
}
|
||||
mAdapter = new StableArrayAdapter(this,R.layout.opaque_text_view, cheeseList,
|
||||
mTouchListener);
|
||||
mListView.setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle touch events to fade/move dragged items as they are swiped out
|
||||
*/
|
||||
private View.OnTouchListener mTouchListener = new View.OnTouchListener() {
|
||||
|
||||
float mDownX;
|
||||
private int mSwipeSlop = -1;
|
||||
|
||||
@Override
|
||||
public boolean onTouch(final View v, MotionEvent event) {
|
||||
if (mSwipeSlop < 0) {
|
||||
mSwipeSlop = ViewConfiguration.get(ListViewRemovalAnimation.this).
|
||||
getScaledTouchSlop();
|
||||
}
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
if (mItemPressed) {
|
||||
// Multi-item swipes not handled
|
||||
return false;
|
||||
}
|
||||
mItemPressed = true;
|
||||
mDownX = event.getX();
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
v.setAlpha(1);
|
||||
v.setTranslationX(0);
|
||||
mItemPressed = false;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
{
|
||||
float x = event.getX() + v.getTranslationX();
|
||||
float deltaX = x - mDownX;
|
||||
float deltaXAbs = Math.abs(deltaX);
|
||||
if (!mSwiping) {
|
||||
if (deltaXAbs > mSwipeSlop) {
|
||||
mSwiping = true;
|
||||
mListView.requestDisallowInterceptTouchEvent(true);
|
||||
mBackgroundContainer.showBackground(v.getTop(), v.getHeight());
|
||||
}
|
||||
}
|
||||
if (mSwiping) {
|
||||
v.setTranslationX((x - mDownX));
|
||||
v.setAlpha(1 - deltaXAbs / v.getWidth());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
{
|
||||
// User let go - figure out whether to animate the view out, or back into place
|
||||
if (mSwiping) {
|
||||
float x = event.getX() + v.getTranslationX();
|
||||
float deltaX = x - mDownX;
|
||||
float deltaXAbs = Math.abs(deltaX);
|
||||
float fractionCovered;
|
||||
float endX;
|
||||
float endAlpha;
|
||||
final boolean remove;
|
||||
if (deltaXAbs > v.getWidth() / 4) {
|
||||
// Greater than a quarter of the width - animate it out
|
||||
fractionCovered = deltaXAbs / v.getWidth();
|
||||
endX = deltaX < 0 ? -v.getWidth() : v.getWidth();
|
||||
endAlpha = 0;
|
||||
remove = true;
|
||||
} else {
|
||||
// Not far enough - animate it back
|
||||
fractionCovered = 1 - (deltaXAbs / v.getWidth());
|
||||
endX = 0;
|
||||
endAlpha = 1;
|
||||
remove = false;
|
||||
}
|
||||
// Animate position and alpha of swiped item
|
||||
// NOTE: This is a simplified version of swipe behavior, for the
|
||||
// purposes of this demo about animation. A real version should use
|
||||
// velocity (via the VelocityTracker class) to send the item off or
|
||||
// back at an appropriate speed.
|
||||
long duration = (int) ((1 - fractionCovered) * SWIPE_DURATION);
|
||||
mListView.setEnabled(false);
|
||||
v.animate().setDuration(duration).
|
||||
alpha(endAlpha).translationX(endX).
|
||||
withEndAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Restore animated values
|
||||
v.setAlpha(1);
|
||||
v.setTranslationX(0);
|
||||
if (remove) {
|
||||
animateRemoval(mListView, v);
|
||||
} else {
|
||||
mBackgroundContainer.hideBackground();
|
||||
mSwiping = false;
|
||||
mListView.setEnabled(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
mItemPressed = false;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This method animates all other views in the ListView container (not including ignoreView)
|
||||
* into their final positions. It is called after ignoreView has been removed from the
|
||||
* adapter, but before layout has been run. The approach here is to figure out where
|
||||
* everything is now, then allow layout to run, then figure out where everything is after
|
||||
* layout, and then to run animations between all of those start/end positions.
|
||||
*/
|
||||
private void animateRemoval(final ListView listview, View viewToRemove) {
|
||||
int firstVisiblePosition = listview.getFirstVisiblePosition();
|
||||
for (int i = 0; i < listview.getChildCount(); ++i) {
|
||||
View child = listview.getChildAt(i);
|
||||
if (child != viewToRemove) {
|
||||
int position = firstVisiblePosition + i;
|
||||
long itemId = mAdapter.getItemId(position);
|
||||
mItemIdTopMap.put(itemId, child.getTop());
|
||||
}
|
||||
}
|
||||
// Delete the item from the adapter
|
||||
int position = mListView.getPositionForView(viewToRemove);
|
||||
mAdapter.remove(mAdapter.getItem(position));
|
||||
|
||||
final ViewTreeObserver observer = listview.getViewTreeObserver();
|
||||
observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
|
||||
public boolean onPreDraw() {
|
||||
observer.removeOnPreDrawListener(this);
|
||||
boolean firstAnimation = true;
|
||||
int firstVisiblePosition = listview.getFirstVisiblePosition();
|
||||
for (int i = 0; i < listview.getChildCount(); ++i) {
|
||||
final View child = listview.getChildAt(i);
|
||||
int position = firstVisiblePosition + i;
|
||||
long itemId = mAdapter.getItemId(position);
|
||||
Integer startTop = mItemIdTopMap.get(itemId);
|
||||
int top = child.getTop();
|
||||
if (startTop != null) {
|
||||
if (startTop != top) {
|
||||
int delta = startTop - top;
|
||||
child.setTranslationY(delta);
|
||||
child.animate().setDuration(MOVE_DURATION).translationY(0);
|
||||
if (firstAnimation) {
|
||||
child.animate().withEndAction(new Runnable() {
|
||||
public void run() {
|
||||
mBackgroundContainer.hideBackground();
|
||||
mSwiping = false;
|
||||
mListView.setEnabled(true);
|
||||
}
|
||||
});
|
||||
firstAnimation = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Animate new views along with the others. The catch is that they did not
|
||||
// exist in the start state, so we must calculate their starting position
|
||||
// based on neighboring views.
|
||||
int childHeight = child.getHeight() + listview.getDividerHeight();
|
||||
startTop = top + (i > 0 ? childHeight : -childHeight);
|
||||
int delta = startTop - top;
|
||||
child.setTranslationY(delta);
|
||||
child.animate().setDuration(MOVE_DURATION).translationY(0);
|
||||
if (firstAnimation) {
|
||||
child.animate().withEndAction(new Runnable() {
|
||||
public void run() {
|
||||
mBackgroundContainer.hideBackground();
|
||||
mSwiping = false;
|
||||
mListView.setEnabled(true);
|
||||
}
|
||||
});
|
||||
firstAnimation = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
mItemIdTopMap.clear();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.listviewremovalanimation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
||||
public class StableArrayAdapter extends ArrayAdapter<String> {
|
||||
|
||||
HashMap<String, Integer> mIdMap = new HashMap<String, Integer>();
|
||||
View.OnTouchListener mTouchListener;
|
||||
|
||||
public StableArrayAdapter(Context context, int textViewResourceId,
|
||||
List<String> objects, View.OnTouchListener listener) {
|
||||
super(context, textViewResourceId, objects);
|
||||
mTouchListener = listener;
|
||||
for (int i = 0; i < objects.size(); ++i) {
|
||||
mIdMap.put(objects.get(i), i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
String item = getItem(position);
|
||||
return mIdMap.get(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
View view = super.getView(position, convertView, parent);
|
||||
if (view != convertView) {
|
||||
// Add touch listener to every new view to track swipe motion
|
||||
view.setOnTouchListener(mTouchListener);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
}
|
||||
41
samples/devbytes/animation/LiveButton/AndroidManifest.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.android.livebutton"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="14"
|
||||
android:targetSdkVersion="17" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme" >
|
||||
<activity
|
||||
android:name="com.example.android.livebutton.LiveButton"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,29 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".LiveButton" >
|
||||
|
||||
<Button
|
||||
android:id="@+id/clickMe"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:text="Click me!" />
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -0,0 +1,26 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme for API 14+. This theme completely replaces
|
||||
AppBaseTheme from BOTH res/values/styles.xml and
|
||||
res/values-v11/styles.xml on API 14+ devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
|
||||
<!-- API 14 theme customizations can go here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
22
samples/devbytes/animation/LiveButton/res/values/strings.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<string name="app_name">LiveButton</string>
|
||||
<string name="hello_world">Hello world!</string>
|
||||
<string name="menu_settings">Settings</string>
|
||||
|
||||
</resources>
|
||||
34
samples/devbytes/animation/LiveButton/res/values/styles.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme, dependent on API level. This theme is replaced
|
||||
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Light">
|
||||
<!--
|
||||
Theme customizations available in newer API levels can go in
|
||||
res/values-vXX/styles.xml, while customizations related to
|
||||
backward-compatibility can go here.
|
||||
-->
|
||||
</style>
|
||||
|
||||
<!-- Application theme. -->
|
||||
<style name="AppTheme" parent="AppBaseTheme">
|
||||
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.livebutton;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.OvershootInterpolator;
|
||||
import android.widget.Button;
|
||||
|
||||
/**
|
||||
* This app shows a simple application of anticipation and follow-through techniques as
|
||||
* the button animates into its pressed state and animates back out of it, overshooting
|
||||
* end state before resolving.
|
||||
*
|
||||
* Watch the associated video for this demo on the DevBytes channel of developer.android.com
|
||||
* or on the DevBytes playlist in the androiddevelopers channel on YouTube at
|
||||
* https://www.youtube.com/playlist?list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0.
|
||||
*/
|
||||
public class LiveButton extends Activity {
|
||||
|
||||
DecelerateInterpolator sDecelerator = new DecelerateInterpolator();
|
||||
OvershootInterpolator sOvershooter = new OvershootInterpolator(10f);
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_overshoot);
|
||||
|
||||
final Button clickMeButton = (Button) findViewById(R.id.clickMe);
|
||||
clickMeButton.animate().setDuration(200);
|
||||
|
||||
clickMeButton.setOnTouchListener(new View.OnTouchListener() {
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View arg0, MotionEvent arg1) {
|
||||
if (arg1.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
clickMeButton.animate().setInterpolator(sDecelerator).
|
||||
scaleX(.7f).scaleY(.7f);
|
||||
} else if (arg1.getAction() == MotionEvent.ACTION_UP) {
|
||||
clickMeButton.animate().setInterpolator(sOvershooter).
|
||||
scaleX(1f).scaleY(1f);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.android.multipropertyanimations"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="14"
|
||||
android:targetSdkVersion="17" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme" >
|
||||
<activity
|
||||
android:name="com.example.android.multipropertyanimations.MultiPropertyAnimations"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,46 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".MultiPropertyAnimations" >
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:onClick="runValueAnimator"
|
||||
android:text="Animate Me!" />
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:onClick="runViewPropertyAnimator"
|
||||
android:text="Animate Me!" />
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:onClick="runObjectAnimators"
|
||||
android:text="Animate Me!" />
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:onClick="runObjectAnimator"
|
||||
android:text="Animate Me!" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,26 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme for API 14+. This theme completely replaces
|
||||
AppBaseTheme from BOTH res/values/styles.xml and
|
||||
res/values-v11/styles.xml on API 14+ devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
|
||||
<!-- API 14 theme customizations can go here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,21 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<string name="app_name">MultiPropertyAnimations</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
<string name="hello_world">Hello world!</string>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,34 @@
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!--
|
||||
Base application theme, dependent on API level. This theme is replaced
|
||||
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
|
||||
-->
|
||||
<style name="AppBaseTheme" parent="android:Theme.Light">
|
||||
<!--
|
||||
Theme customizations available in newer API levels can go in
|
||||
res/values-vXX/styles.xml, while customizations related to
|
||||
backward-compatibility can go here.
|
||||
-->
|
||||
</style>
|
||||
|
||||
<!-- Application theme. -->
|
||||
<style name="AppTheme" parent="AppBaseTheme">
|
||||
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.multipropertyanimations;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.animation.ValueAnimator.AnimatorUpdateListener;
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* This example shows various ways of animating multiple properties in parallel.
|
||||
*
|
||||
* Watch the associated video for this demo on the DevBytes channel of developer.android.com
|
||||
* or on the DevBytes playlist in the androiddevelopers channel on YouTube at
|
||||
* https://www.youtube.com/playlist?list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0.
|
||||
*/
|
||||
public class MultiPropertyAnimations extends Activity {
|
||||
|
||||
private static final float TX_START = 0;
|
||||
private static final float TY_START = 0;
|
||||
private static final float TX_END = 400;
|
||||
private static final float TY_END = 200;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_multi_property_animations);
|
||||
}
|
||||
|
||||
/**
|
||||
* A very manual approach to animation uses a ValueAnimator to animate a fractional
|
||||
* value and then turns that value into the final property values which are then set
|
||||
* directly on the target object.
|
||||
*/
|
||||
public void runValueAnimator(final View view) {
|
||||
ValueAnimator anim = ValueAnimator.ofFloat(0, 400);
|
||||
anim.addUpdateListener(new AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animator) {
|
||||
float fraction = animator.getAnimatedFraction();
|
||||
view.setTranslationX(TX_START + fraction * (TX_END - TX_START));
|
||||
view.setTranslationY(TY_START + fraction * (TY_END - TY_START));
|
||||
}
|
||||
});
|
||||
anim.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* ViewPropertyAnimator is the cleanest and most efficient way of animating
|
||||
* View properties, even when there are multiple properties to be animated
|
||||
* in parallel.
|
||||
*/
|
||||
public void runViewPropertyAnimator(View view) {
|
||||
view.animate().translationX(TX_END).translationY(TY_END);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiple ObjectAnimator objects can be created and run in parallel.
|
||||
*/
|
||||
public void runObjectAnimators(View view) {
|
||||
ObjectAnimator.ofFloat(view, View.TRANSLATION_X, TX_END).start();
|
||||
ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, TY_END).start();
|
||||
// Optional: use an AnimatorSet to run these in parallel
|
||||
}
|
||||
|
||||
/**
|
||||
* Using PropertyValuesHolder objects enables the use of a single ObjectAnimator
|
||||
* per target, even when there are multiple properties being animated on that target.
|
||||
*/
|
||||
public void runObjectAnimator(View view) {
|
||||
PropertyValuesHolder pvhTX = PropertyValuesHolder.ofFloat(View.TRANSLATION_X, TX_END);
|
||||
PropertyValuesHolder pvhTY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, TY_END);
|
||||
ObjectAnimator.ofPropertyValuesHolder(view, pvhTX, pvhTY).start();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2013 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.squashandstretch"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="14"
|
||||
android:targetSdkVersion="17" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme" >
|
||||
<activity
|
||||
android:name="com.example.squashandstretch.SquashAndStretch"
|
||||
android:label="@string/app_name" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 14 KiB |