Android BaseAdapter,带动画到ImageView
我已经创建了基本适配器,并将动画应用于图像视图,这是每3秒后自定义布局的一部分。每行都有一个图像数组,所以我尝试淡出当前图像并淡入新图像。我在活动中创建了带有runnable计时器的处理程序,该处理程序每3秒调用adapter.notifyDataSetChanged。如果不应用动画,我的适配器将如下所示: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
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,这可能会有所帮助。但如果你能为你的步骤编写代码,那对我来说还是有帮助的,因为在做了太多的事情之后,我陷入了困境:。谢谢