Android Animation leaves lines during movement
I have 12 ImageButtons setup in a 3x4 grid using an AbsoluteLayout. When the user clicks on an image button it grows to fill the screen, holds, and then shrinks down to its original location.
The animation works except that when the button is shrinking it sometimes leaves lines behind. (I've attached images below).
Is there a better way to achieve this animation? What can I do to prevent the drawing errors that I'm getting?
EDIT: Also the lines disappear as soon as the shrink animation finishes, they are only present during the animation.
Here is my UDATED animation code
private void animateCard(final CardButton c){
this.isAnimating = true;
CardPickerActivity.this.soundManager.playSound(c.name);
Util.logD("Card:" + c.name + " clicked!");
final int growDuration = 750;
final int holdDuration = 500;
final int shrinkDuration = 500;
c.bringToFront();
AnimationSet asGrow = new AnimationSet(true);
float newScale = 2.0f;
float newX = (CardPickerActivity.this.wDesk/2.0f - CardPickerActivity.this.cardSize/2.0f*newScale - c.getLeft())/newScale;
float newY = (CardPickerActivity.this.hDesk/2.0f - CardPickerActivity.this.cardSize/2.0f*newScale - c.getTop() )/newScale;
TranslateAnimation taG = new TranslateAnimation(0.0f, newX , 0.0f, newY);
ScaleAnimation saG = new ScaleAnimation( 1.0f, newScale, 1.0f, newScale);
taG.setRepeatCount(1);
saG.setRepeatCount(1);
taG.setRepeatMode(Animation.REVERSE);
saG.setRepeatMode(Animation.REVERSE);
asGrow.addAnimation(taG);
asGrow.addAnimation(saG);
asGrow.setDuration(growDuration);
c.startAnimation(asGrow);
}
Here is the XML Layout for the activity, ignore the layout_x and layout_y I set them later based upon the screen of the device:
<?xml version="1.0" encoding="utf-8"?>
<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/cardLayout" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.myProject.CardButton
android:id="@+id/btn1" android:text="1" android:layout_x="0px"
android:layout_y="0px" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.myProject.CardButton
android:id="@+id/btn2" android:text="2" android:layout_x="10px"
android:layout_y="10px" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.myProject.CardButton
android:id="@+id/btn3" android:text="3" android:layout_x="20px"
android:layout_y="20px" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.myProject.CardButton
android:id="@+id/btn4" android:text="4" android:layout_x="30px"
android:layout_y="30px" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.myProject.CardButton
android:id="@+id/btn5" android:text="5" android:layout_x="40px"
android:layout_y="40px" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.myProject.CardButton
android:id="@+id/btn6" android:text="6" android:layout_x="40px"
android:layout_y="40px" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.myProject.CardButton
android:id="@+id/btn7" android:text="7" android:layout_x="40px"
android:layout_y="40px" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.myProject.CardButton
android:id="@+id/btn8" android:text="8" android:layout_x="40px"
android:layout_y="40px" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.myProject.CardButton
android:id="@+id/btn9" android:text="9" android:layout_x="40px"
android:layout_y="40px" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.myProject.CardButton
android:id="@+id/btn10" android:text="10" android:layout_x="40px"
android:layout_y="40px" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.myProject.CardButton
android:id="@+id/btn11" android:text="11" android:layout_x="40px"
android:layout_y="40px" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.myProject.CardButton
android:id="@+id/btn12" android:text="12" android:layout_x="40px"
android:layout_y="40px" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</AbsoluteLayout>
Here is the CardButton class, its essentially an ImageButton with a few more m开发者_Go百科ember variables
public class CardButton extends ImageButton {
public CardButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CardButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CardButton(Context context) {
super(context);
}
public String name;
public Bitmap image;
public int soundRes;
public int imageRes;
public String customImagePath;
public String customSoundPath;
}
So I solved the problem but not in a way that I'm happy with.
First at a place in my code I wasn't showing I called:
cardButton.setBackgroundColor(Color.WHITE);
If I commented out this line the problem went away. This however produced CardButtons that looked like stock android buttons. This isn't how I wanted them to look, so I tried setting the white button "style" a number of other ways. All of which produced the bug.
In an attempt to better understand what was going on and to hunt down a possible bug in either Android or my code I created a test project that only included one activity with the 3x4 grid and nothing else. This test project contained a single activity and a single XML file. Starting with a basic grid I was un able to reproduce the bug, then I started adding more and more features to the test app and eventually had recreated the original activity but without the bug.
I thought maybe something about my new implementation was better than the original so I incorporated the new test activity into my original project. However, when I ran the test activity from original project the bug showed up again.
I now have two activities that use identical code in different Android Projects. One is the only activity in the project while the other is part of a larger project with many activities. The version in the larger project exhibits the bug while the version in the stand alone project does not. I'm not sure how to interpret this and I'd greatly appreciate any feedback/comments on this.
So until I can figure out why I get the drawing error in the context of my bigger application I'm going to use the stock android button background.
Update: On a whim I made a 9Patch background that was white. This fixed the problem.
This might be causing the issue. Sometime the animations onAnimationEnd fires a bit before the actual animation is done.
You can create a custom view or layout and overide its 'animationEnd' method and add a interface so you can set up a listener.
Here's an example
CustomLayout class
public class CustomLayout extends LinearLayout {
private LayoutAnimationListener mListner;
public CustomLayout(Context context) {
super(context);
}
public CustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onAnimationEnd() {
super.onAnimationEnd();
if(mListner != null){
mListner.onAnimationEnd(CustomLayout.this);
}
}
@Override
protected void onAnimationStart() {
super.onAnimationStart();
if(mListner != null){
mListner.onAnimationStart(CustomLayout.this);
}
}
public static interface LayoutAnimationListener {
//Notifies the start of the animation.
void onAnimationStart(CustomLayout cLayout);
//Notifies the end of the animation.
void onAnimationEnd(CustomLayout cLayout);
}
public void setLayoutAnimationListener(LayoutAnimationListener listener){
mListner = listener;
}
}
So in your activity you can use it as a normal linearlayout and instead of adding a animation listener to the animation, you can add it to the layout like
com.blessan.CustomLayout layout =
(com.blessan.CustomLayout)findViewById(R.id.counts_layout);
LayoutAnimationListener layoutAnimListener = new LayoutAnimationListener() {
@Override
public void onAnimationStart(CustomLayout cLayout) {
}
@Override
public void onAnimationEnd(CustomLayout cLayout) {
}
};
layout.setLayoutAnimationListener(layoutAnimListener);
This might work for you. Give it a try.
Improvement/could-be Solution:
I have a improvement on your code, hope it fixes your refresh problem too. Also feel this is the right way to do what you are trying.
growShrink.addAnimation(ta);
growShrink.addAnimation(sa);
holdAnim.setStartOffset(growDuration); // hold will start when grow stops.
growShrink.addAnimation(holdAnim);
growShrink.setRepeatCount(1);
growShrink.setRepeatMode(Animation.REVERSE);
growShrink.setInterpolator(new LinearInterpolator());
This will play the growing animation in reverse. No need of animation end listener to start the hold and shrink animations.
Alternate solution:
Add all your growing, holding and shrinking animations to one AnimtaionSet. Set the start offsets of hold and shrink animations appropriately.
// growAnim will start at 0.
holdAnim.setStartOffset(growDuration);
shrinkAnim.setStartOffset(growDuration+holdDuration);
精彩评论