Android动画在移动过程中留下了线条

4
我有12个ImageButton使用AbsoluteLayout设置在3x4的网格中。当用户点击图像按钮时,它会扩大到填充屏幕,保持一段时间,然后缩小回原来的位置。
动画效果是实现了的,但是在按钮缩小时有时会留下线条(如下面所示)。
是否有更好的方法实现这种动画效果?我该怎么做才能避免出现绘制错误?
编辑: 同时,这些线条会在缩小动画完成后消失,只在动画期间存在。
以下是我的更新后的动画代码:
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);

}

这是活动的XML布局,忽略我稍后根据设备屏幕设置的layout_x和layout_y:

<?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>

这里是CardButton类,它本质上是一个带有几个成员变量的ImageButton。
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;
}

Here is what the grid looks like before touch

Here is what the grid looks like when a button has finished growing

Here is what the grid looks like when the button has finished skrinking. Notice the white vertical lines


请问您的截图是从模拟器还是实际设备中获取的? - dustmachine
2
当动画完成时,尝试使外部布局失效。 - blessanm86
@Michele,我没有使用ListAdapter。 - slayton
1
为什么不看看这个项目?它可能不会非常高效,但可能会给你一些想法。在这里,我也做了类似的事情,扩展了一个视图以填充其余区域。 https://github.com/blessenm/GridDemo - blessanm86
1
请用您最新的代码片段替换代码。同时添加一些关于cardbutton的代码,至少包括初始化卡片对象背景图像的代码。 - Ron
显示剩余7条评论
3个回答

2
我解决了问题,但解决方式并不令我满意。
首先,在我的代码中一个不显示的位置,我调用了以下代码:
cardButton.setBackgroundColor(Color.WHITE);

如果我注释掉这一行,问题就解决了。然而,这样会产生看起来像是原生安卓按钮的CardButton。这不是我想要的外观,所以我尝试以多种方式设置白色按钮的“样式”。所有这些方法都产生了错误。
为了更好地理解发生了什么,并找出可能存在于Android或我的代码中的错误,我创建了一个测试项目,其中只包括一个带有3x4网格的活动,没有其他内容。这个测试项目包含一个单独的活动和一个单独的XML文件。从基本网格开始,我无法重现错误,然后我开始向测试应用程序添加越来越多的功能,最终重新创建了原始活动,但没有错误。
我认为也许我的新实现方式比原来的更好,所以我将新的测试活动合并到了原始项目中。然而,当我从原始项目运行测试活动时,错误再次出现。
现在我有两个使用相同代码的活动,分别位于不同的Android项目中。一个是项目中唯一的活动,另一个是众多活动的大型项目的一部分。较大项目中的版本出现了错误,而独立项目中的版本则没有。我不确定如何解释这一点,非常感谢任何关于此事的反馈/评论。
因此,在我能够弄清楚为什么在我的大型应用程序上下文中出现绘图错误之前,我将使用原生安卓按钮背景。
更新:心血来潮,我制作了一个白色的9Patch背景。这解决了问题。

1
你应该尝试比较文件,看看它们之间有什么不同。如果没有差异,那么你的应用程序可能会对CPU和内存造成大量负担,这会影响动画效果。建议在动画播放时避免播放音效。 - Ron
这两个文件是相同的。我认为你说得对,问题可能与 CPU 负载有关。接下来几天我会尝试进一步优化我的代码。如果我能够解决问题,我会回来发布结果的。 - slayton
1
我觉得你正在加载过多的音频文件或者后台正在播放太多的流。请先尝试移除这些音频,并测试程序。 - Ron
我已经删除了声音,但问题仍未解决。我也只播放一个声音,而且在动画完成之前就结束了。 - slayton
在查看了您的更新后,我感觉问题出在设置图标的可绘制边界上。 - Ron
显示剩余2条评论

1

这可能是导致问题的原因。有时候,动画的onAnimationEnd事件会在实际动画完成之前稍微提前触发。

您可以创建一个自定义视图或布局,并覆盖其“animationEnd”方法并添加一个接口,以便您可以设置监听器。

以下是一个示例

CustomLayout类

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;
    }
}

因此,在您的活动中,您可以将其用作普通的线性布局,而不是将动画侦听器添加到动画中,您可以将其添加到布局中,如下所示:

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);

这可能适合你。试试看。


1

改进/可能的解决方案:

我对你的代码有一个改进,希望它也能解决你的刷新问题。同时,我认为这是你所尝试做的正确方式。

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());

这将以相反的方式播放增长动画。无需动画结束侦听器即可启动保持和缩小动画。


备选方案:

将所有的生长、保持和缩小动画添加到一个AnimationSet中。适当设置保持和缩小动画的起始偏移量。

// growAnim will start at 0.
holdAnim.setStartOffset(growDuration); 
shrinkAnim.setStartOffset(growDuration+holdDuration);

这两个方法都没有解决绘图错误,但它们确实使代码简单了许多,谢谢! - slayton
我给你授予了奖励,因为你首先帮助我解决了动画问题,然后又与我一起追踪了绘图问题的原因。谢谢! - slayton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接