Android BaseAdapter,带动画到ImageView

Android BaseAdapter,带动画到ImageView,android,animation,imageview,baseadapter,Android,Animation,Imageview,Baseadapter,我已经创建了基本适配器,并将动画应用于图像视图,这是每3秒后自定义布局的一部分。每行都有一个图像数组,所以我尝试淡出当前图像并淡入新图像。我在活动中创建了带有runnable计时器的处理程序,该处理程序每3秒调用adapter.notifyDataSetChanged。如果不应用动画,我的适配器将如下所示: public class FerrariAdapter extends BaseAdapter { /* * Variable Declaration Part */ private

我已经创建了基本适配器,并将动画应用于图像视图,这是每3秒后自定义布局的一部分。每行都有一个图像数组,所以我尝试淡出当前图像并淡入新图像。我在活动中创建了带有runnable计时器的处理程序,该处理程序每3秒调用adapter.notifyDataSetChanged。如果不应用动画,我的适配器将如下所示:

public class FerrariAdapter extends BaseAdapter {

/*
 * Variable Declaration Part
 */

private Context mContext;
private ArrayList<String> mTitle, mOwner, mDate;
private HashMap<String, ArrayList<String>> mImages;
private HashMap<Integer, Integer> mLastImagePosition;
private ViewHolder mHolder;
private boolean is_animation = false;
private Animation mFadeIn, mFadeOut;

/* Constructor that initialize variables getting from activity */

public FerrariAdapter(Context mContext, ArrayList<String> mTitle,
        ArrayList<String> mOwner, ArrayList<String> mDate,
        HashMap<String, ArrayList<String>> mImages,
        HashMap<Integer, Integer> mLastImagePosition) {

    this.mContext = mContext;
    this.mTitle = mTitle;
    this.mOwner = mOwner;
    this.mDate = mDate;
    this.mImages = mImages;
    this.mLastImagePosition = mLastImagePosition;
    mFadeOut = AnimationUtils.loadAnimation(mContext, R.anim.anim_fadeout);
    mFadeIn = AnimationUtils.loadAnimation(mContext, R.anim.anim_fadein);

}

@Override
public int getCount() {
    // TODO Auto-generated method stub
    return mTitle.size();
}

@Override
public Object getItem(int position) {
    // TODO Auto-generated method stub
    return mTitle.get(position);
}

@Override
public long getItemId(int position) {
    // TODO Auto-generated method stub
    return 0;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub
    View mView = convertView;
    if (mView == null) {

        /*
         * Inflating custom layout and getting components IDs to set each
         * row of ListView
         */

        mView = LayoutInflater.from(mContext).inflate(R.layout.car_tile,
                null);
        mHolder = new ViewHolder();
        mHolder.mTitleHolder = (TextView) mView
                .findViewById(R.id.titleHolder);
        mHolder.mOwnerHolder = (TextView) mView
                .findViewById(R.id.OwnerHolder);
        mHolder.mDateHolder = (TextView) mView
                .findViewById(R.id.dateHolder);
        mHolder.mImageHolder = (ImageView) mView
                .findViewById(R.id.imageHolder);

        mView.setTag(mHolder);
    } else {
        mHolder = (ViewHolder) mView.getTag();
    }

    /* Set Value to each row */

    mHolder.mTitleHolder.setText(mTitle.get(position));
    mHolder.mOwnerHolder.setText(mOwner.get(position));
    mHolder.mDateHolder.setText(Utils.millisToDate(
            Long.parseLong(mDate.get(position)), "dd MMM yyyy HH:mm"));

    mHolder.mImageHolder.setImageBitmap(getImagefromHashmap(position));
    /*mFadeOut.setAnimationListener(new AnimationListener() {

        @Override
        public void onAnimationStart(Animation animation) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onAnimationRepeat(Animation animation) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onAnimationEnd(Animation animation) {
            // TODO Auto-generated method stub

        }
    });
    mHolder.mImageHolder.setAnimation(mFadeOut);*/

    return mView;
}

/*
 * This class is used to hold position of each component so it shouln't be
 * repeat again and again
 */

class ViewHolder {

    ImageView mImageHolder;
    TextView mTitleHolder, mOwnerHolder, mDateHolder;

}

private Bitmap getImagefromHashmap(int position) {

    Bitmap mBitmap = null;
    ArrayList<String> mImagesList = mImages.get(mTitle.get(position));
    int mLastImagePostion = mLastImagePosition.get(position);

    if (mImagesList.size() - 1 > mLastImagePostion) {

        mLastImagePostion++;
        mLastImagePosition.put(position, mLastImagePostion);

    } else {

        mLastImagePostion = 0;
        mLastImagePosition.put(position, mLastImagePostion);

    }

    String mImageName = mImagesList.get(mLastImagePostion);
    // Get the AssetManager
    AssetManager manager = mContext.getAssets();

    // Read a Bitmap from Assets
    try {
        InputStream mOpen = manager.open(mImageName);
        mBitmap = BitmapFactory.decodeStream(mOpen);

    } catch (Exception e) {

    }

    return Utils.resize(mBitmap,
            (int) (Utils.getDeviceWidth(mContext) / 2.5),
            Utils.getDeviceHeight(mContext) / 5);

}
}
通过将每行的图像更改为imageview,它运行良好。现在,当我要在getview上应用动画时,只有最后一行受到影响。因此,我认为在完成每一行的动画之前会调用getView。应用动画时:

public class FerrariAdapter extends BaseAdapter {

/*
 * Variable Declaration Part
 */

private Context mContext;
private ArrayList<String> mTitle, mOwner, mDate;
private HashMap<String, ArrayList<String>> mImages;
private HashMap<Integer, Integer> mLastImagePosition;
private ViewHolder mHolder;
private boolean is_animation = false;
private Animation mFadeIn, mFadeOut;

/* Constructor that initialize variables getting from activity */

public FerrariAdapter(Context mContext, ArrayList<String> mTitle,
        ArrayList<String> mOwner, ArrayList<String> mDate,
        HashMap<String, ArrayList<String>> mImages,
        HashMap<Integer, Integer> mLastImagePosition) {

    this.mContext = mContext;
    this.mTitle = mTitle;
    this.mOwner = mOwner;
    this.mDate = mDate;
    this.mImages = mImages;
    this.mLastImagePosition = mLastImagePosition;
    mFadeOut = AnimationUtils.loadAnimation(mContext, R.anim.anim_fadeout);
    mFadeIn = AnimationUtils.loadAnimation(mContext, R.anim.anim_fadein);

}

@Override
public int getCount() {
    // TODO Auto-generated method stub
    return mTitle.size();
}

@Override
public Object getItem(int position) {
    // TODO Auto-generated method stub
    return mTitle.get(position);
}

@Override
public long getItemId(int position) {
    // TODO Auto-generated method stub
    return 0;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub
    View mView = convertView;
    if (mView == null) {

        /*
         * Inflating custom layout and getting components IDs to set each
         * row of ListView
         */

        mView = LayoutInflater.from(mContext).inflate(R.layout.car_tile,
                null);
        mHolder = new ViewHolder();
        mHolder.mTitleHolder = (TextView) mView
                .findViewById(R.id.titleHolder);
        mHolder.mOwnerHolder = (TextView) mView
                .findViewById(R.id.OwnerHolder);
        mHolder.mDateHolder = (TextView) mView
                .findViewById(R.id.dateHolder);
        mHolder.mImageHolder = (ImageView) mView
                .findViewById(R.id.imageHolder);

        mView.setTag(mHolder);
    } else {
        mHolder = (ViewHolder) mView.getTag();
    }

    /* Set Value to each row */

    mHolder.mTitleHolder.setText(mTitle.get(position));
    mHolder.mOwnerHolder.setText(mOwner.get(position));
    mHolder.mDateHolder.setText(Utils.millisToDate(
            Long.parseLong(mDate.get(position)), "dd MMM yyyy HH:mm"));


    mFadeOut.setAnimationListener(new AnimationListener() {

        @Override
        public void onAnimationStart(Animation animation) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onAnimationRepeat(Animation animation) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onAnimationEnd(Animation animation) {
            // TODO Auto-generated method stub

            mHolder.mImageHolder.setImageBitmap(getImagefromHashmap(position));
        }
    });
    mHolder.mImageHolder.setAnimation(mFadeOut);

    return mView;
}

/*
 * This class is used to hold position of each component so it shouln't be
 * repeat again and again
 */

class ViewHolder {

    ImageView mImageHolder;
    TextView mTitleHolder, mOwnerHolder, mDateHolder;

}

private Bitmap getImagefromHashmap(int position) {

    Bitmap mBitmap = null;
    ArrayList<String> mImagesList = mImages.get(mTitle.get(position));
    int mLastImagePostion = mLastImagePosition.get(position);

    if (mImagesList.size() - 1 > mLastImagePostion) {

        mLastImagePostion++;
        mLastImagePosition.put(position, mLastImagePostion);

    } else {

        mLastImagePostion = 0;
        mLastImagePosition.put(position, mLastImagePostion);

    }

    String mImageName = mImagesList.get(mLastImagePostion);
    // Get the AssetManager
    AssetManager manager = mContext.getAssets();

    // Read a Bitmap from Assets
    try {
        InputStream mOpen = manager.open(mImageName);
        mBitmap = BitmapFactory.decodeStream(mOpen);

    } catch (Exception e) {

    }

    return Utils.resize(mBitmap,
            (int) (Utils.getDeviceWidth(mContext) / 2.5),
            Utils.getDeviceHeight(mContext) / 5);

}
}
那么,如何处理这种情况,或者如何在每行动画完成后强制调用getView呢


谢谢,

只有一个动画对象mFadeOut无法执行此操作。 调用mFadeOut.setAnimationListener…,将导致从getView返回的最后一个视图接收AnimationEnd上的回调。 您应该首先将mFadeOut对象转换为ArrayList或类似的东西,这样您就可以支持多个动画回调,或者使mFadeOut对象成为getView方法的本地对象。

这样如何:

在适配器中创建一个处理程序,其任务是运行可运行程序。 每个可运行实例将负责列表中当前可见的一行,每3秒淡入淡出一次图像。 在每次调用getView时,为该行构造一个新的Runnable,并调用myHandler.postDelayedrunnable,3000以启动淡入计时器。 在ViewHolder中保持可运行状态,当调用getView回收行时,调用myHandler.RemoveCallBackRunnable停止正在回收的视图上的3秒计时器。 在Runnable的代码中,运行动画以淡出旧图像,淡入新图像。动画启动后,以相同的3秒延迟将Runnable post本身发送到处理程序。您可能需要一个可运行的子类,以便它能够跟踪下一个要显示的图像。 这有意义吗?你需要我再解释一下吗?您需要查看代码吗

编辑:

下面是我想到的一些代码。毫无疑问,我遗漏了一些片段,但我希望你能理解。主要的目的是为每一行设置单独的计时器,为图像的输入和输出设置动画。我同意dor506的观点,即每个动画都需要不止一个。在这个解决方案中,您每次都会加载动画的新实例,这样您就可以监听它们的完成情况

    // construct the handler inside your adapter's constructor so you know it is on the UI thread
    Handler myHandler = new Handler(); 

class FadeRunnable implements Runnable {
    ImageView iv;
    int position;

    public FadeRunnable(ImageView iv, int position) {
        this.iv = iv;
        this.position = position;
    }

    @Override
    public void run() {
        Animation fadeOut = AnimationUtils.loadAnimation(mContext, R.anim.anim_fadeout);
        fadeOut.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                iv.setImageBitmap(getImagefromHashmap(position));
                Animation fadeIn = AnimationUtils.loadAnimation(mContext, R.anim.anim_fadein);
                iv.startAnimation(fadeIn);
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
            }
        });
        iv.startAnimation(fadeOut);
    }
}

/*
 * This class is used to hold position of each component so it shouln't be
 * repeat again and again
 */
class ViewHolder {

    ImageView mImageHolder;
    TextView mTitleHolder, mOwnerHolder, mDateHolder;
    FadeRunnable mRunnable;

}

@SuppressWarnings("deprecation")
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    View mView = convertView;
    if (mView == null) {
        mView = LayoutInflater.from(mContext).inflate(R.layout.car_tile,
                null);
        mHolder = new ViewHolder();
        mHolder.mTitleHolder = (TextView) mView
                .findViewById(R.id.titleHolder);
        mHolder.mOwnerHolder = (TextView) mView
                .findViewById(R.id.OwnerHolder);
        mHolder.mDateHolder = (TextView) mView
                .findViewById(R.id.dateHolder);
        mHolder.mImageHolder = (ImageView) mView
                .findViewById(R.id.imageHolder);

        mHolder.mRunnable = new FadeRunnable(mHolder.mImageHolder, position);

        mView.setTag(mHolder);
    } else {
        mHolder = (ViewHolder) mView.getTag();
        myHandler.removeCallbacks(mHolder.mRunnable);
    }

/* Set Value to each row */
    mHolder.mTitleHolder.setText(mTitle.get(position));
    mHolder.mOwnerHolder.setText(mOwner.get(position));
    mHolder.mDateHolder.setText(Utils.millisToDate(
            Long.parseLong(mDate.get(position)), "dd MMM yyyy HH:mm"));
    mHolder.mImageHolder.setImageBitmap(getImagefromHashmap(position));

    myHandler.postDelayed(mHolder.mRunnable, 3000);

    return mView;
}
有两件事我没有做:

1我没有在Runnable中编写将自己放回下一个图像处理程序的部分。你可以在第一个监听器中编写另一个监听器,或者让FadeRunnable实现AnimationListener本身,跟踪它是否在我们的out中消失,并做正确的事情


2此解决方案可能需要一件事,但我现在不想尝试对其进行编码,即您可能需要取消一行上的一个runnable操作,如果该行被回收,而另一个runnable希望开始淡入另一个动画。如果3秒钟的计时器还没有关闭,它就可以正常工作,但是如果它关闭了,而现在旧的runnable正在制作动画,那么这可能是一个问题。

我认为主要的问题是mFadeOut始终在视图的同一引用上运行,因此,基本上每次都要重新启动动画,当然,它只在最后一项中可见。

好主意。但是你确定这能正常工作吗?因为在3秒内getview会很快调用Yes,这可能会有所帮助。但如果你能为你的步骤编写代码,那对我来说还是有帮助的,因为在做了太多的事情之后,我陷入了困境:。谢谢