Demo of layout add/remove transitions

Change-Id: Ib5f31bb0b6d16fa18cf10a426a25c7a8138f620a
This commit is contained in:
Chet Haase
2010-08-16 17:42:33 -07:00
parent d92b7c07d4
commit 43828a8383
9 changed files with 519 additions and 7 deletions

View File

@@ -839,6 +839,14 @@
</intent-filter>
</activity>
<activity android:name=".animation.AnimationCloning"
android:label="Animation/Cloning">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".animation.AnimationSeeking" android:label="Animation/Seeking">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -891,6 +899,14 @@
</intent-filter>
</activity>
<activity android:name=".animation.LayoutAnimations"
android:label="Animation/Layout Animations">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<!-- ************************************* -->
<!-- ANIMATION PACKAGE SAMPLES -->
<!-- ************************************* -->

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 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"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/container"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Run"
android:id="@+id/startButton"
/>
</LinearLayout>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 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"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/parent"
>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add Button"
android:id="@+id/addNewButton"
/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Custom Animations"
android:id="@+id/customAnimCB"
/>
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,152 @@
/*
* Copyright (C) 2010 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.apis.animation;
// Need the following import to get access to the app resources, since this
// class is in a sub-package.
import android.widget.Button;
import com.example.android.apis.R;
import android.animation.*;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.Shader;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.graphics.drawable.shapes.RectShape;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.LinearLayout;
import java.util.ArrayList;
public class AnimationCloning extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.animation_cloning);
LinearLayout container = (LinearLayout) findViewById(R.id.container);
final MyAnimationView animView = new MyAnimationView(this);
container.addView(animView);
Button starter = (Button) findViewById(R.id.startButton);
starter.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
animView.startAnimation();
}
});
}
public class MyAnimationView extends View implements Animator.AnimatorUpdateListener {
public final ArrayList<ShapeHolder> balls = new ArrayList<ShapeHolder>();
Sequencer animation = null;
private float mDensity;
public MyAnimationView(Context context) {
super(context);
mDensity = getContext().getResources().getDisplayMetrics().density;
ShapeHolder ball0 = addBall(50f, 25f);
ShapeHolder ball1 = addBall(150f, 25f);
ShapeHolder ball2 = addBall(250f, 25f);
ShapeHolder ball3 = addBall(350f, 25f);
}
private void createAnimation() {
if (animation == null) {
PropertyAnimator anim1 = new PropertyAnimator(500, balls.get(0), "y",
0f, getHeight() - balls.get(0).getHeight());
PropertyAnimator anim2 = anim1.clone();
anim2.setTarget(balls.get(1));
anim1.addUpdateListener(this);
ShapeHolder ball2 = balls.get(2);
PropertyAnimator animDown = new PropertyAnimator(500, ball2, "y",
0f, getHeight() - ball2.getHeight());
animDown.setInterpolator(new AccelerateInterpolator());
PropertyAnimator animUp = new PropertyAnimator(500, ball2, "y",
getHeight() - ball2.getHeight(), 0f);
animDown.setInterpolator(new DecelerateInterpolator());
Sequencer s1 = new Sequencer();
s1.playSequentially(animDown, animUp);
animDown.addUpdateListener(this);
animUp.addUpdateListener(this);
Sequencer s2 = (Sequencer) s1.clone();
s2.setTarget(balls.get(3));
animation = new Sequencer();
animation.playTogether(anim1, anim2, s1);
animation.playSequentially(s1, s2);
}
}
private ShapeHolder addBall(float x, float y) {
OvalShape circle = new OvalShape();
circle.resize(50f * mDensity, 50f * mDensity);
ShapeDrawable drawable = new ShapeDrawable(circle);
ShapeHolder shapeHolder = new ShapeHolder(drawable);
shapeHolder.setX(x - 25f);
shapeHolder.setY(y - 25f);
int red = (int)(100 + Math.random() * 155);
int green = (int)(100 + Math.random() * 155);
int blue = (int)(100 + Math.random() * 155);
int color = 0xff000000 | red << 16 | green << 8 | blue;
Paint paint = drawable.getPaint(); //new Paint(Paint.ANTI_ALIAS_FLAG);
int darkColor = 0xff000000 | red/4 << 16 | green/4 << 8 | blue/4;
RadialGradient gradient = new RadialGradient(37.5f, 12.5f,
50f, color, darkColor, Shader.TileMode.CLAMP);
paint.setShader(gradient);
shapeHolder.setPaint(paint);
balls.add(shapeHolder);
return shapeHolder;
}
@Override
protected void onDraw(Canvas canvas) {
for (int i = 0; i < balls.size(); ++i) {
ShapeHolder shapeHolder = balls.get(i);
canvas.save();
canvas.translate(shapeHolder.getX(), shapeHolder.getY());
shapeHolder.getShape().draw(canvas);
canvas.restore();
}
}
public void startAnimation() {
createAnimation();
animation.start();
}
public void onAnimationUpdate(Animator animation) {
invalidate();
}
}
}

View File

@@ -122,20 +122,26 @@ public class AnimatorEvents extends Activity {
if (animation == null) {
PropertyAnimator yAnim = new PropertyAnimator(1500, ball, "y",
ball.getY(), getHeight() - 50f);
yAnim.setRepeatCount(1);
yAnim.setRepeatCount(0);
yAnim.setRepeatMode(Animator.REVERSE);
yAnim.setInterpolator(new AccelerateInterpolator(2f));
yAnim.addUpdateListener(this);
yAnim.addListener(this);
PropertyAnimator xAnim = new PropertyAnimator(1500, ball, "x",
PropertyAnimator xAnim = new PropertyAnimator(1000, ball, "x",
ball.getX(), ball.getX() + 300);
xAnim.setRepeatCount(1);
xAnim.setStartDelay(0);
xAnim.setRepeatCount(0);
xAnim.setRepeatMode(Animator.REVERSE);
xAnim.setInterpolator(new AccelerateInterpolator(2f));
PropertyAnimator alphaAnim = new PropertyAnimator(1000, ball, "alpha", 1f, .5f);
Sequencer alphaSeq = new Sequencer();
alphaSeq.play(alphaAnim);
animation = new Sequencer();
((Sequencer) animation).playTogether(yAnim, xAnim);
//((Sequencer) animation).play(alphaSeq).after(500);
animation.addListener(this);
}
}

View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2009 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.apis.animation;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
/**
* A layout that arranges its children in a grid. The size of the
* cells is set by the {@link #setCellSize} method and the
* android:cell_width and android:cell_height attributes in XML.
* The number of rows and columns is determined at runtime. Each
* cell contains exactly one view, and they flow in the natural
* child order (the order in which they were added, or the index
* in {@link #addViewAt}. Views can not span multiple cells.
*
* <p>This class was copied from the FixedGridLayout Api demo; see that demo for
* more information on using the layout.</p>
*/
public class FixedGridLayout extends ViewGroup {
int mCellWidth;
int mCellHeight;
public FixedGridLayout(Context context) {
super(context);
}
public void setCellWidth(int px) {
mCellWidth = px;
requestLayout();
}
public void setCellHeight(int px) {
mCellHeight = px;
requestLayout();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int cellWidthSpec = MeasureSpec.makeMeasureSpec(mCellWidth,
MeasureSpec.AT_MOST);
int cellHeightSpec = MeasureSpec.makeMeasureSpec(mCellHeight,
MeasureSpec.AT_MOST);
int count = getChildCount();
for (int index=0; index<count; index++) {
final View child = getChildAt(index);
child.measure(cellWidthSpec, cellHeightSpec);
}
// Use the size our parents gave us
setMeasuredDimension(resolveSize(mCellWidth*count, widthMeasureSpec),
resolveSize(mCellHeight*count, heightMeasureSpec));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int cellWidth = mCellWidth;
int cellHeight = mCellHeight;
int columns = (r - l) / cellWidth;
if (columns < 0) {
columns = 1;
}
int x = 0;
int y = 0;
int i = 0;
int count = getChildCount();
for (int index=0; index<count; index++) {
final View child = getChildAt(index);
int w = child.getMeasuredWidth();
int h = child.getMeasuredHeight();
int left = x + ((cellWidth-w)/2);
int top = y + ((cellHeight-h)/2);
child.layout(left, top, left+w, top+h);
if (i >= (columns-1)) {
// advance to next row
i = 0;
x = 0;
y += cellHeight;
} else {
i++;
x += cellWidth;
}
}
}
}

View File

@@ -0,0 +1,167 @@
/*
* Copyright (C) 2010 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.apis.animation;
// Need the following import to get access to the app resources, since this
// class is in a sub-package.
import com.example.android.apis.R;
import android.animation.Animatable;
import android.animation.AnimatableListenerAdapter;
import android.animation.Keyframe;
import android.animation.LayoutTransition;
import android.animation.PropertyAnimator;
import android.animation.PropertyValuesHolder;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
/**
* This application demonstrates the seeking capability of Animator. The SeekBar in the
* UI allows you to set the position of the animation. Pressing the Run button will play from
* the current position of the animation.
*/
public class LayoutAnimations extends Activity {
private int numButtons = 1;
ViewGroup container = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_animations);
container = new FixedGridLayout(this.getApplicationContext());
((FixedGridLayout)container).setCellHeight(50);
((FixedGridLayout)container).setCellWidth(100);
final LayoutTransition transitioner = new LayoutTransition();
container.setLayoutTransition(transitioner);
ViewGroup parent = (ViewGroup) findViewById(R.id.parent);
parent.addView(container);
Button addButton = (Button) findViewById(R.id.addNewButton);
addButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Button newButton = new Button(getApplicationContext());
newButton.setText("Click To Remove " + (numButtons++));
newButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
container.removeView(v);
}
});
container.addView(newButton, Math.min(1, container.getChildCount()));
}
});
CheckBox customAnimCB = (CheckBox) findViewById(R.id.customAnimCB);
customAnimCB.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
long duration;
if (isChecked) {
transitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
transitioner.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 30);
setupAnimations(transitioner);
duration = 500;
} else {
transitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 0);
transitioner.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 0);
transitioner.setAnimatable(LayoutTransition.APPEARING, null);
transitioner.setAnimatable(LayoutTransition.DISAPPEARING, null);
transitioner.setAnimatable(LayoutTransition.CHANGE_APPEARING, null);
transitioner.setAnimatable(LayoutTransition.CHANGE_DISAPPEARING, null);
duration = 300;
}
transitioner.setDuration(duration);
}
});
}
private void setupAnimations(LayoutTransition transition) {
// Changing while Adding
PropertyValuesHolder<Integer> pvhLeft =
new PropertyValuesHolder<Integer>("left", 0, 1);
PropertyValuesHolder<Integer> pvhTop =
new PropertyValuesHolder<Integer>("top", 0, 1);
PropertyValuesHolder<Integer> pvhRight =
new PropertyValuesHolder<Integer>("right", 0, 1);
PropertyValuesHolder<Integer> pvhBottom =
new PropertyValuesHolder<Integer>("bottom", 0, 1);
PropertyValuesHolder<Float> pvhScaleX =
new PropertyValuesHolder<Float>("scaleX", 1f, 0f, 1f);
PropertyValuesHolder<Float> pvhScaleY =
new PropertyValuesHolder<Float>("scaleY", 1f, 0f, 1f);
final PropertyAnimator changeIn =
new PropertyAnimator(transition.getDuration(LayoutTransition.CHANGE_APPEARING),
this, pvhLeft, pvhTop, pvhRight, pvhBottom, pvhScaleX, pvhScaleY);
transition.setAnimatable(LayoutTransition.CHANGE_APPEARING, changeIn);
changeIn.addListener(new AnimatableListenerAdapter() {
public void onAnimationEnd(Animatable anim) {
View view = (View) ((PropertyAnimator) anim).getTarget();
view.setScaleX(1f);
view.setScaleY(1f);
}
});
// Changing while Removing
Keyframe kf0 = new Keyframe(0f, 0f);
Keyframe kf1 = new Keyframe(.9999f, 360f);
Keyframe kf2 = new Keyframe(1f, 0f);
PropertyValuesHolder<Keyframe> pvhRotation =
new PropertyValuesHolder<Keyframe>("rotation", kf0, kf1, kf2);
final PropertyAnimator changeOut =
new PropertyAnimator(transition.getDuration(LayoutTransition.CHANGE_DISAPPEARING),
this, pvhLeft, pvhTop, pvhRight, pvhBottom, pvhRotation);
transition.setAnimatable(LayoutTransition.CHANGE_DISAPPEARING, changeOut);
changeOut.addListener(new AnimatableListenerAdapter() {
public void onAnimationEnd(Animatable anim) {
View view = (View) ((PropertyAnimator) anim).getTarget();
view.setRotation(0f);
}
});
// Adding
PropertyAnimator<Float> animIn =
new PropertyAnimator<Float>(transition.getDuration(LayoutTransition.APPEARING),
null, "rotationY", 90f, 0f);
transition.setAnimatable(LayoutTransition.APPEARING, animIn);
animIn.addListener(new AnimatableListenerAdapter() {
public void onAnimationEnd(Animatable anim) {
View view = (View) ((PropertyAnimator) anim).getTarget();
view.setRotationY(0f);
}
});
// Removing
PropertyAnimator<Float> animOut =
new PropertyAnimator<Float>(transition.getDuration(LayoutTransition.DISAPPEARING),
null, "rotationX", 0f, 90f);
transition.setAnimatable(LayoutTransition.DISAPPEARING, animOut);
animIn.addListener(new AnimatableListenerAdapter() {
public void onAnimationEnd(Animatable anim) {
View view = (View) ((PropertyAnimator) anim).getTarget();
view.setRotationX(0f);
}
});
}
}

View File

@@ -52,7 +52,7 @@ public class MultiPropertyAnimation extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.animation_seeking);
setContentView(R.layout.animation_multi_property);
LinearLayout container = (LinearLayout) findViewById(R.id.container);
final MyAnimationView animView = new MyAnimationView(this);
container.addView(animView);

View File

@@ -78,11 +78,9 @@ public class ShapeHolder {
}
public float getWidth() {
//return shape.getIntrinsicWidth();
return shape.getShape().getWidth();
}
public void setWidth(float width) {
//shape.setIntrinsicWidth(width);
Shape s = shape.getShape();
s.resize(width, s.getHeight());
}
@@ -93,7 +91,6 @@ public class ShapeHolder {
public void setHeight(float height) {
Shape s = shape.getShape();
s.resize(s.getWidth(), height);
//shape.setIntrinsicHeight(height);
}
public ShapeHolder(ShapeDrawable s) {