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

@@ -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) {