在 ListView 中对列表项进行动画处理

发布于 2024-11-29 09:00:31 字数 2253 浏览 3 评论 0原文

我尝试在 ListView 中为新项目添加动画。我有稳定的 id-s,所以我确切地知道要为哪个元素设置动画。问题出在ListView的回收机制上。当我知道我最近插入了一个元素时,我会在视图上调用 startAnimation 。但随后,视图被回收,填充了不同的数据。 这会导致 UI 动画错误的行。在某些时候,视图持有正确的数据,但随后被回收。我通过 logcat 确认了这一点。 有什么办法可以解决这个问题吗?

编辑:

public ExpensCursorAdapter(Context context, Cursor c, boolean autoRequery,
        CopyOnWriteArraySet<String> fadeAnimateTags) {
    super(context, c, autoRequery);
    this.mFadeAnimTags = fadeAnimateTags;
}

@Override
public boolean hasStableIds() {
    return true;
}

@Override
public void bindView(View view, Context context, Cursor cursor) {
    setup(view, context, cursor);
}

private void setup(View view, Context context, Cursor cursor) {
    final String id = cursor.getString(4);
    if (LOCAL_LOGV) Log.v(TAG, String.format("Create item for %s. Received view: %s", id, view.toString()));
    view.setTag(id);
    final TextView dateText = (TextView) view.findViewById(R.id.date);
    final TextView timeText = (TextView) view.findViewById(R.id.time);
    final TextView title = (TextView) view.findViewById(R.id.title);
    final TextView amount = (TextView) view.findViewById(R.id.amount);
    final Date date = new Date(cursor.getLong(0));
    title.setText(cursor.getString(1));
    dateText.setText(dFormat.format(date));
    timeText.setText(tFormat.format(date));
    amount.setText(String.format("%d Ft", cursor.getInt(2)));
    if (cursor.getInt(3) == 1) {
        timeText.setTextColor(Color.LTGRAY);
        title.setTextColor(Color.LTGRAY);
        dateText.setTextColor(Color.LTGRAY);
        amount.setTextColor(Color.LTGRAY);
    } else {
        timeText.setTextColor(Color.BLACK);
        title.setTextColor(Color.BLACK);
        dateText.setTextColor(Color.BLACK);
        amount.setTextColor(Color.BLACK);
    }
    if (mFadeAnimTags.contains(id)) {
     view.setAnimation(AnimationUtils.loadAnimation(context, R.anim.fade));
     mFadeAnimTags.remove(id);
    }

}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
    final LayoutInflater inflater = LayoutInflater.from(context);
    View view = inflater.inflate(R.layout.expense_list_item, parent, false);
    setup(view, context, cursor);
    return view;
}

I try to animate new items in my ListView. I have stable id-s, so I know exactly which element to animate. The problem comes from the recycle mechanism of ListView. I call startAnimation on the View when I know I got a recently inserted element. But then, the view got recycled, filled with different data.
It results on the UI animating the wrong row. At some point the view was holding the right data, but then got recycled. I confirmed this via logcat.
Is there any way to solve this?

EDIT:

public ExpensCursorAdapter(Context context, Cursor c, boolean autoRequery,
        CopyOnWriteArraySet<String> fadeAnimateTags) {
    super(context, c, autoRequery);
    this.mFadeAnimTags = fadeAnimateTags;
}

@Override
public boolean hasStableIds() {
    return true;
}

@Override
public void bindView(View view, Context context, Cursor cursor) {
    setup(view, context, cursor);
}

private void setup(View view, Context context, Cursor cursor) {
    final String id = cursor.getString(4);
    if (LOCAL_LOGV) Log.v(TAG, String.format("Create item for %s. Received view: %s", id, view.toString()));
    view.setTag(id);
    final TextView dateText = (TextView) view.findViewById(R.id.date);
    final TextView timeText = (TextView) view.findViewById(R.id.time);
    final TextView title = (TextView) view.findViewById(R.id.title);
    final TextView amount = (TextView) view.findViewById(R.id.amount);
    final Date date = new Date(cursor.getLong(0));
    title.setText(cursor.getString(1));
    dateText.setText(dFormat.format(date));
    timeText.setText(tFormat.format(date));
    amount.setText(String.format("%d Ft", cursor.getInt(2)));
    if (cursor.getInt(3) == 1) {
        timeText.setTextColor(Color.LTGRAY);
        title.setTextColor(Color.LTGRAY);
        dateText.setTextColor(Color.LTGRAY);
        amount.setTextColor(Color.LTGRAY);
    } else {
        timeText.setTextColor(Color.BLACK);
        title.setTextColor(Color.BLACK);
        dateText.setTextColor(Color.BLACK);
        amount.setTextColor(Color.BLACK);
    }
    if (mFadeAnimTags.contains(id)) {
     view.setAnimation(AnimationUtils.loadAnimation(context, R.anim.fade));
     mFadeAnimTags.remove(id);
    }

}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
    final LayoutInflater inflater = LayoutInflater.from(context);
    View view = inflater.inflate(R.layout.expense_list_item, parent, false);
    setup(view, context, cursor);
    return view;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

画▽骨i 2024-12-06 09:00:31

如果您使用 http:// /kylewbanks.com/blog/Implementing-Google-Plus-Style-ListView-Animations-on-Android
(无需自定义库)

private int lastPosition = -1;

@覆盖
公共视图 getView(int 位置,视图 ConvertView,ViewGroup 父级){
    //加载你的视图,填充它,等等...
    视图视图= ...;

    动画animation = AnimationUtils.loadAnimation(getContext(), (position > lastPosition) ? R.anim.up_from_bottom : R.anim.down_from_top);
    view.startAnimation(动画);
    最后位置=位置;

    返回视图;
}

up_from_bottom.xml


<设置 xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="@android:anim/decelerate_interpolator">
    <翻译>
        android:fromXDelta="0%" android:toXDelta="0%"
        android:fromYDelta="100%" android:toYDelta="0%"
        机器人:持续时间=“400”/>

down_from_bottom.xml


<设置 xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="@android:anim/decelerate_interpolator">
    <翻译>
        android:fromXDelta="0%" android:toXDelta="0%"
        android:fromYDelta="-100%" android:toYDelta="0%"
        机器人:持续时间=“400”/>

If you use getView() simple code from http://kylewbanks.com/blog/Implementing-Google-Plus-Style-ListView-Animations-on-Android,
(No need custom library)

private int lastPosition = -1;

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    //Load your view, populate it, etc...
    View view = ...;

    Animation animation = AnimationUtils.loadAnimation(getContext(), (position > lastPosition) ? R.anim.up_from_bottom : R.anim.down_from_top);
    view.startAnimation(animation);
    lastPosition = position;

    return view;
}

up_from_bottom.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="@android:anim/decelerate_interpolator">
    <translate
        android:fromXDelta="0%" android:toXDelta="0%"
        android:fromYDelta="100%" android:toYDelta="0%"
        android:duration="400" />
</set>

down_from_bottom.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="@android:anim/decelerate_interpolator">
    <translate
        android:fromXDelta="0%" android:toXDelta="0%"
        android:fromYDelta="-100%" android:toYDelta="0%"
        android:duration="400" />
</set>
海之角 2024-12-06 09:00:31

查看 ListViewAnimations 库来为 ListView 项目设置动画。

基本上,您只需要再添加两行即可使项目动画化:

之前:

MyListAdapter mAdapter = new MyListAdapter(this, getItems());
getListView().setAdapter(mAdapter);

之后:

MyListAdapter mAdapter = new MyListAdapter(this, getItems());
AlphaInAnimationAdapter alphaInAnimationAdapter = new AlphaInAnimationAdapter(mAdapter);
alphaInAnimationAdapter.setAbsListView(getListView());
getListView().setAdapter(alphaInAnimationAdapter);

Have a look at the ListViewAnimations library to animate your ListView items.

Basically, you would only have to add two more lines to have your items animated:

Before:

MyListAdapter mAdapter = new MyListAdapter(this, getItems());
getListView().setAdapter(mAdapter);

After:

MyListAdapter mAdapter = new MyListAdapter(this, getItems());
AlphaInAnimationAdapter alphaInAnimationAdapter = new AlphaInAnimationAdapter(mAdapter);
alphaInAnimationAdapter.setAbsListView(getListView());
getListView().setAdapter(alphaInAnimationAdapter);
太阳公公是暖光 2024-12-06 09:00:31

我有类似的问题。我不确定这是否是正确的方法,但您可以尝试在开始新视图之前清除视图上的动画,以取消回收视图中的任何剩余动画。这对我有帮助。

if(flag == false) {
    v.clearAnimation();
    Animation animation = AnimationUtils.loadAnimation(getActivity(), R.anim.slide_top_to_bottom);
    v.startAnimation(animation);
}

I had a similar problem. I'm not 100% sure if this is the right way to go, but you can try clearing the animation on the view before starting a new one to cancel any leftover animation from the recycled view. This helped me.

if(flag == false) {
    v.clearAnimation();
    Animation animation = AnimationUtils.loadAnimation(getActivity(), R.anim.slide_top_to_bottom);
    v.startAnimation(animation);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文