显示带有动画效果的图像视图问题

5
我希望能在GridView中使用动画展示ImageViews,我已经成功地展示并正确应用了动画。
但问题在于,如果我在ImageView1上应用动画,然后在ImageView1的动画结束之前对ImageView2应用动画,则ImageView1的动画会被打断,并且ImageView1会直接设置为最终状态。
请注意,我使用2个线程的ThreadPoolExecutor下载图像。每当一张图片完成下载时,我都会调用下面ImageAdapteraddImage(image)方法,这会将图像添加到GridView中并刷新GridView以显示最新的图像集。在这里,在渲染时,新图像会显示动画,而这个动画(我猜)会打断当前正在进行的图像的动画。 ImageAdapter:
public class ImageAdapter extends BaseAdapter {
    private Context mContext;
    private List<Bitmap> images;
    private ArrayList<Integer> colors;
    private boolean[] alreadyLoadedIndexes;
    Animation animation;
    AnimatorSet animator;

    public void addImage(Bitmap img) {
        images.add(img);
        notifyDataSetChanged();
    }

    public void setAnimation(Animation animation) {
        this.animator = null;
        this.animation = animation;
    }

    public void setAnimator(AnimatorSet animation) {
        this.animation = null;
        this.animator = animation;
    }

    public void resetImages() {
        images.clear();
        notifyDataSetChanged();
        alreadyLoadedIndexes = null;
        alreadyLoadedIndexes = new boolean[20];
    }

    // Constructor
    public ImageAdapter(Context c) {
        mContext = c;
        images = new ArrayList<Bitmap>();
        colors = new ArrayList<Integer>();
        colors.add(Color.CYAN);
        colors.add(Color.BLUE);
        colors.add(Color.GRAY);
        colors.add(Color.YELLOW);
        colors.add(Color.MAGENTA);
        alreadyLoadedIndexes = new boolean[20];
    }

    @Override
    public int getCount() {
        return 20;
    }

    @Override
    public Object getItem(int position) {
        return 20;
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ImageView imageView = new ImageView(mContext);

        imageView
                .setBackgroundColor(colors.get((int) ((Math.sqrt(position) + 2 * position) % 5)));

        // If image at index 'position' is available
        if (images.size() > position) {

            // If loading this image first time then only apply animation
            if (!alreadyLoadedIndexes[position]) {

                // If animation is specified
                if (this.animation != null) {
                    imageView.setImageBitmap(images.get(position));
                    imageView.startAnimation(animation);

                }
                // If animator set is specified
                else if (this.animator != null) {
                    imageView.setImageBitmap(null);
                    imageView.setBackgroundColor(colors.get((int) ((Math
                            .sqrt(position) + 2 * position) % 5)));
                    animator.setTarget(imageView);
                    animator.start();
                    Log.e("", "setting image after " + animator.getDuration()
                            / 2);
                    new Handler().postDelayed(
                            new runnable(imageView, images.get(position)), 500);

                } else {
                    // Use default animation if nothing is specified.
                    imageView.setImageBitmap(images.get(position));
                    animation = AnimationUtils.loadAnimation(mContext,
                            R.anim.fade_in);
                    imageView.startAnimation(animation);
                }

            } else {
                imageView.setImageBitmap(images.get(position));
            }

            alreadyLoadedIndexes[position] = true;

        }

        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imageView.setLayoutParams(new GridView.LayoutParams(150, 150));
        return imageView;
    }

    class runnable implements Runnable {

        ImageView image;
        Bitmap bitmap;

        public runnable(ImageView img, Bitmap bitmap) {
            this.image = img;
            this.bitmap = bitmap;
        }

        @Override
        public void run() {
            Log.e("", "setting image.");
            image.setImageBitmap(bitmap);
        }

    }

}
5个回答

1
尝试使用GridView的布局动画控制器,它将根据时间间隔逐个动画显示视图项。请查看此链接

请提供一个小的示例代码。我使用的是 GridView 而不是 GridLayoutGridLayoutAnimationController 是为 GridLayout 设计的。 - Geek
布局动画控制器正在应用任何布局组,GridView已成为一个布局组,请查看此示例,它将对您有所帮助。http://www.edumobile.org/android/android-development/wave-layout-animationexample/ - balaji koduri
在您的适配器中删除所有动画功能并放置在活动中,使用AnimationSet而不是AnimatorSet,布局动画控制器仅采用Animation对象。 - balaji koduri

0

你试过在adapter的getView方法之外应用动画吗?

mGridView.getChildAt(childIndexNeededToAnimate).startAnimation(animation);

这些子视图是独立的,因为它们已经被绘制出来,所以不再被回收利用。


0

你有一些备选方案。

首先,如果你不想改变你的代码,你可以在你的 adapter 类中使用 动画。关于这点,请查看此链接

在你的 adapter 类中,在 getView 内部调用动画,像这样:

 Animation animation = null;
 animation = AnimationUtils.loadAnimation(context, R.anim.push_left_in);
 animation.setDuration(500);
 convertView.startAnimation(animation);
 return convertView;

第二,你应该使用 GridLayoutAnimationController ,其中使用布局动画控制器来为网格布局的子项添加动画效果。


0

只是猜测。我不确定它是否有帮助,也不确定我是否正确地阅读了您的代码。我想问题比我猜测的更难。 然而,您正在为每个项目使用相同的动画对象。也许您应该为每个项目创建一个新的动画。这可能是您的动画在启动新动画时停止的原因,因为新调用只是重新使用和重新启动它。

祝好运。


-1
你的问题在于 notifyDataSetChanged(); 这个方法会打断动画。尝试在动画结束后再调用它。

但是,当我有50张图片要显示时,如果在调用notifyDataSetChanged()之前等待每个图片的动画完成,那么加载所有图片需要大约15-20秒。 - Geek
@Akash,请解释一下你希望它如何运作? - Ilya Gazman
我希望所有的图片都能完成动画,但同时也希望尽可能地减少图片加载时间。我寻求的是并发图片动画,而不是一个接一个的动画。 - Geek
@Akash 当一张图片正在播放动画时,另一张图片刚刚被下载,它应该等待第一张图片完成动画还是怎么处理? - Ilya Gazman

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