Android 在带有ViewHolder图案的适配器中使用动画
在适配器中使用动画时出现问题Android 在带有ViewHolder图案的适配器中使用动画,android,Android,在适配器中使用动画时出现问题 @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { LayoutInflater inflater = LayoutInflater.from(context); convertView = inflater.inflate(re
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(context);
convertView = inflater.inflate(resource, parent, false);
holder = new ViewHolder();
holder.newRoomView = (TextView) convertView.findViewById(R.id.newRoom);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Room item = items.get(position);
// animate new rooms
if (item.isNewRoom()) {
AlphaAnimation alphaAnim = new AlphaAnimation(1.0f, 0.0f);
alphaAnim.setDuration(1500);
alphaAnim.setAnimationListener(new AnimationListener() {
public void onAnimationEnd(Animation animation) {
holder.newRoomView.setVisibility(View.INVISIBLE);
}
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationRepeat(Animation animation) {}
});
holder.newRoomView.startAnimation(alphaAnim);
}
// ...
return convertView;
}
在适配器外部添加新房间并调用notifyDataSetChanged
时,新房间将正确设置动画,但调用onAnimationEnd
时,另一个房间(不是新房间)将隐藏
有没有办法隐藏正确的文件室?这可能是由于ListView的循环机制。尝试标记动画视图,并使用
findViewByTag
在动画端检索它。例如
public View getView(final int position, final View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(context);
convertView = inflater.inflate(resource, parent, false);
holder = new ViewHolder();
holder.newRoomView = (TextView) convertView.findViewById(R.id.newRoom);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Room item = items.get(position);
// animate new rooms
if (item.isNewRoom()) {
AlphaAnimation alphaAnim = new AlphaAnimation(1.0f, 0.0f);
alphaAnim.setDuration(1500);
alphaAnim.setAnimationListener(new AnimationListener() {
public void onAnimationEnd(Animation animation) {
View view = convertView.findViewWithTag(position);
if (view != null) {
view.setVisibility(View.INVISIBLE);
}
}
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationRepeat(Animation animation) {}
});
holder.newRoomView.startAnimation(alphaAnim);
holder.newRoomView.setTag(position);
}
// ...
return convertView;
}
如果您愿意迁移到新的,您将能够使用这个伟大的动画库,请查看它:由于您没有在
getView()
方法中声明holder
变量,我只能假设您已经在类中将其声明为实例变量。这是你的问题。当动画完成时,变量holder
正在保存对完全不同项目的引用
您需要在getView()
方法中使用声明为final
的局部变量。我不知道您是否需要getView()
方法之外的holder
变量,但如果需要,您可以这样做:
// animate new rooms
if (item.isNewRoom()) {
final ViewHolder holderCopy = holder; // make a copy
AlphaAnimation alphaAnim = new AlphaAnimation(1.0f, 0.0f);
alphaAnim.setDuration(1500);
alphaAnim.setAnimationListener(new AnimationListener() {
public void onAnimationEnd(Animation animation) {
holderCopy.newRoomView.setVisibility(View.INVISIBLE);
}
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationRepeat(Animation animation) {}
});
holder.newRoomView.startAnimation(alphaAnim);
}
当然,如果动画花费的时间太长,以致于在此期间视图已被循环使用,则此操作将不起作用。请记住,对于此类内容,您需要始终使用else语句。 否则,使用同一视图保持架的任何其他内容也将不可见
if (item.isNewRoom()) {
AlphaAnimation alphaAnim = new AlphaAnimation(1.0f, 0.0f);
alphaAnim.setDuration(1500);
alphaAnim.setAnimationListener(new AnimationListener() {
public void onAnimationEnd(Animation animation) {
holder.newRoomView.setVisibility(View.INVISIBLE);
}
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationRepeat(Animation animation) {}
});
holder.newRoomView.startAnimation(alphaAnim);
}else{
holder.newRoomView.setVisibility(View.VISIBLE);
}
嗯。我以前遇到过这个问题,这可能是Android的一个bug: 您正在使用内部对象设置动画侦听器:
alphaAnim.setAnimationListener(new AnimationListener(){/*bla bla bla*/});
将上述代码更改为类似以下内容:
AnimationListener myListener = new AnimationListener(){/*bla bla bla*/};
alphaAnim.setAnimationListener(myListener);
我知道这是一个非常疯狂的解决方案,但它在几次类似的情况下救了我的命。为什么不使用
RecyclerView
?发布你的物品布局,请注意这个答案没有用。您建议的代码与要替换的代码完全相同。您仍在创建一个匿名类,与以前一样。编译器将把两个代码段编译成完全相同的东西。@David Wasser:这在过去对我很有效。你100%确定Android上的代码完全相同吗?是的。完全一样。我不敢相信这解决了你过去可能遇到的任何问题。我的问题与OP完全相同。但由于你是一个经验丰富得多的程序员,我一到我的电脑就会删除我的答案。
AnimationListener myListener = new AnimationListener(){/*bla bla bla*/};
alphaAnim.setAnimationListener(myListener);