滚动后,RecyclerView中的无限动画停止 [英] Infinite animation in RecyclerView stops after scrolling

查看:120
本文介绍了滚动后,RecyclerView中的无限动画停止的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对RecyclerView进行了多类型化,并在项目内部添加了动画视图(闪烁的白色圆圈).在recyclerView滚动期间,动画可以随机停止工作.

I have multityped RecyclerView with animated views(blinking white circles) inside items. During recyclerView scrolling animations can randomly stop working.

我认为此问题与onCreateViewHolderonBindViewHolder有关,但是即使没有调用任何方法,该问题仍然存在.

I thought this problem is connected with onCreateViewHolder or onBindViewHolder, but this issue reproducing even if none of this methods were called.

动画重复计数设置为无限,clearAnimation()仅在onBindViewHolder中调用.

Animation repeat count set to infinite, clearAnimation() only called in onBindViewHolder.

我的适配器代码:

import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.TextView;

import com.annimon.stream.Stream;
import com.squareup.picasso.Picasso;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.TimeZone;

import butterknife.Bind;
import butterknife.ButterKnife;

public class ChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements View.OnClickListener {

    private final int avatarSize;
    private List<IncomingTextMessage> chatMessages = new ArrayList<>();
    private User appOwner;
    private User wallOwner;
    private int MESSAGE_TYPE_MY = 0;
    private int MESSAGE_TYPE_INTERLOCUTOR = 1;
    private SimpleDateFormat timeFormat;
    private SimpleDateFormat dateFormat;
    private static final String TAG = "ChatAdapter";

    private int bindViewHolderCallCounter = 0;


    public ChatAdapter(User appOwner, User wallOwner, Context context) {
        this.appOwner = appOwner;
        this.wallOwner = wallOwner;
        avatarSize = context.getResources().getDimensionPixelSize(R.dimen.post_avatar_size);
        timeFormat = new SimpleDateFormat(context.getString(R.string.time_format));
        dateFormat = new SimpleDateFormat(context.getString(R.string.server_date_parsing_format));
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Random rnd = new Random();
        int color = Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));

        View v;
        if (viewType == MESSAGE_TYPE_MY) {
            v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_my_chat_message, parent, false);
            v.setBackgroundColor(color);
            return new MyMessageViewHolder(v);
        } else  {  //viewType == MESSAGE_TYPE_INTERLOCUTOR
            v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_interlocutor_chat_message, parent, false);
            v.setBackgroundColor(color);
            return new InterlocutorMessageViewHolder(v);
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        bindViewHolderCallCounter++;



        Log.d(TAG, "onBindViewHolder:" + chatMessages.get(position).getText() + "   " + (getItemViewType(position) == MESSAGE_TYPE_MY));
        if (getItemViewType(position) == MESSAGE_TYPE_MY) {
            MyMessageViewHolder myMessageViewHolder = (MyMessageViewHolder) holder;
            setUserAvatar(appOwner, myMessageViewHolder.ivUserAvatar);
            myMessageViewHolder.ivUserAvatar.setTag(appOwner);
            myMessageViewHolder.ivUserAvatar.setOnClickListener(this);
            myMessageViewHolder.tvText.setText(chatMessages.get(position).getText() +" bindViewHolderCallCounter " + bindViewHolderCallCounter);
            myMessageViewHolder.tvTime.setText(formatTime(chatMessages.get(position).getDateTime()));

            setupMessageState(myMessageViewHolder, chatMessages.get(position));

        } else /*if (getItemViewType(position) == MESSAGE_TYPE_INTERLOCUTOR)*/ {
            InterlocutorMessageViewHolder interlocutorMessageViewHolder = (InterlocutorMessageViewHolder) holder;
            setUserAvatar(wallOwner, interlocutorMessageViewHolder.ivUserAvatar);
            interlocutorMessageViewHolder.ivUserAvatar.setTag(wallOwner);
            interlocutorMessageViewHolder.ivUserAvatar.setOnClickListener(this);
            interlocutorMessageViewHolder.tvText.setText(chatMessages.get(position).getText());
            interlocutorMessageViewHolder.tvTime.setText(formatTime(chatMessages.get(position).getDateTime()));

        }
    }

    private void setupMessageState(MyMessageViewHolder myMessageViewHolder, IncomingTextMessage message) {
        Log.d(TAG, "setupMessageState");

        Animation animation = AnimationUtils.loadAnimation(myMessageViewHolder.ivUserAvatar.getContext(), R.anim.fade_out_in_chat_circle);

        myMessageViewHolder.vMessageStatusAwaitingSending.clearAnimation();
        myMessageViewHolder.vMessageStatusAwaitingReading.clearAnimation();
        myMessageViewHolder.vMessageStatusAwaitingSending.clearAnimation();

        switch (message.getState()) {
            case MessageNotification.SENT: {
                Log.d(TAG, "MessageNotification.SENT" + message.getText());
                myMessageViewHolder.vMessageStatusAwaitingSending.setVisibility(View.VISIBLE);
                myMessageViewHolder.vMessageStatusAwaitingReading.setVisibility(View.INVISIBLE);
                myMessageViewHolder.vMessageStatusAwaitingSending.setVisibility(View.INVISIBLE);

                myMessageViewHolder.vMessageStatusAwaitingSending.setAnimation(animation);
                break;
            }
            case MessageNotification.RECEIVED:
            {
                Log.d(TAG, "MessageNotification.RECEIVED" + message.getText());

                myMessageViewHolder.vMessageStatusAwaitingSending.setVisibility(View.VISIBLE);
                myMessageViewHolder.vMessageStatusAwaitingReading.setVisibility(View.VISIBLE);
                myMessageViewHolder.vMessageStatusAwaitingSending.setVisibility(View.INVISIBLE);

                myMessageViewHolder.vMessageStatusAwaitingReading.setAnimation(animation);
                break;
            }
            case MessageNotification.DELIEVERED:
            {
                Log.d(TAG, "MessageNotification.DELIEVERED" + message.getText());

                myMessageViewHolder.vMessageStatusAwaitingSending.setVisibility(View.VISIBLE);
                myMessageViewHolder.vMessageStatusAwaitingReading.setVisibility(View.VISIBLE);
                myMessageViewHolder.vMessageStatusAwaitingSending.setVisibility(View.VISIBLE);

                myMessageViewHolder.vMessageStatusAwaitingReading.setAnimation(animation);
                break;
            }
            case MessageNotification.READ:
            {
                Log.d(TAG, "MessageNotification.READ" + message.getText());

                myMessageViewHolder.vMessageStatusAwaitingSending.setVisibility(View.VISIBLE);
                myMessageViewHolder.vMessageStatusAwaitingReading.setVisibility(View.VISIBLE);
                myMessageViewHolder.vMessageStatusAwaitingSending.setVisibility(View.VISIBLE);
                break;
            }
        }
    }

    private String formatTime(String severDate) {
        try {
            dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));

            return timeFormat.format(dateFormat.parse(severDate));
        } catch (ParseException e) {
            e.printStackTrace();
            Log.e(TAG, "Time string parsing error :" + severDate);
            return "";
        }

    }

    @Override
    public int getItemViewType(int position) {
        if (chatMessages.get(position).getAuthorId().equals(String.valueOf(appOwner.getId())))
            return MESSAGE_TYPE_MY;
        else return MESSAGE_TYPE_INTERLOCUTOR;
    }

    private void setUserAvatar(BaseUser user, ImageView imageView) {
        if (user != null && user.getPrimaryImageUrl() != null && !user.getPrimaryImageUrl().isEmpty()) {
            Picasso.with(imageView.getContext())
                    .load(user.getPrimaryImageUrl())
                    .error(R.drawable.ic_user_avatar_128)
                    .centerCrop()
                    .resize(avatarSize, avatarSize)
                    .transform(new RoundedTransformation())
                    .into(imageView);
        } else {
            imageView.setImageResource(R.drawable.ic_user_avatar_128);
        }
    }



 /*   public void addNewUsers(List<BaseUser> newUsers) {
        this.chatMessages = newUsers;
        this.notifyDataSetChanged();
    }*/

    public void addMessage(IncomingTextMessage incomingTextMessage) {
        this.chatMessages.add(incomingTextMessage);
        notifyDataSetChanged();
    }
    public void changeMessageState(MessageNotification notification) {
        Stream.of(chatMessages)
                .filter(message -> message.getId().equals(notification.getMessageId()))
                .forEach(message ->
                {
                    message.setState(notification.getState());
                    notifyItemChanged(chatMessages.indexOf(message));
                });
    }

    @Override
    public int getItemCount() {
        return chatMessages.size();
    }

    @Override
    public long getItemId(int position) {
        return chatMessages.get(position).getId().hashCode();
    }

    @Override
    public void onClick(View view) {
        if (view.getTag() instanceof User) {
            User user = (User) view.getTag();
            Intent intent = new Intent(view.getContext(), MainActivity.class);
            intent.putExtra(Config.USER_STRING_EXTRA, user.getId());
            view.getContext().startActivity(intent);
        }
    }

    public void addMessages(ArrayList<IncomingTextMessage> incomingTextMessages) {
        chatMessages.addAll(incomingTextMessages);
        this.notifyDataSetChanged();
    }

    class MyMessageViewHolder extends RecyclerView.ViewHolder {
        @Bind(R.id.vMessageStatusAwaitingSending)
        View vMessageStatusAwaitingSending;

        @Bind(R.id.vMessageStatusAwaitingDelivering)
        View vMessageStatusAwaitingDelivering;

        @Bind(R.id.vMessageStatusAwaitingReading)
        View vMessageStatusAwaitingReading;

        @Bind(R.id.ivUserAvatar)
        ImageView ivUserAvatar;

        @Bind(R.id.tvText)
        TextView tvText;

        @Bind(R.id.tvTime)
        TextView tvTime;

        public MyMessageViewHolder(View view) {
            super(view);
            ButterKnife.bind(this, view);
        }
    }

    class InterlocutorMessageViewHolder extends RecyclerView.ViewHolder {
        @Bind(R.id.ivUserAvatar)
        ImageView ivUserAvatar;

        @Bind(R.id.tvText)
        TextView tvText;

        @Bind(R.id.tvTime)
        TextView tvTime;

        public InterlocutorMessageViewHolder(View view) {
            super(view);
            ButterKnife.bind(this, view);
        }
    }
}

闪烁动画xml

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="650"
    android:fromAlpha="1.0"
    android:repeatMode="reverse"
    android:repeatCount="infinite"
    android:toAlpha="0.1" />

推荐答案

我遇到了同样的问题,发现当视图与窗口分离时,动画停止了.重新连接后,您将不会收到onBindViewHolder调用,因此动画将不会开始.

I ran into the same issue and found that the animation stops when the view gets detached from the window. When it is reattached, you won't get the onBindViewHolder call so the animation won't start.

解决方案是覆盖RecyclerView.Adapter<>中的onViewAttachedToWindow并从那里调用setAnimation.您还需要在ViewHolder中维护对IncomingTextMessage的引用,因为onViewAttachedToWindow不会通过该位置.

The solution is to override onViewAttachedToWindow in your RecyclerView.Adapter<> and call setAnimation from there. You'll also need to maintain a reference to the IncomingTextMessage in the ViewHolder because onViewAttachedToWindow doesn't pass in the position.

示例:

@Override
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
  if (holder instanceof MyMessageViewHolder) {
    MyMessageViewHolder messageHolder = (MyMessageViewHolder)holder;
    setupMessageState(messageHolder, messageHolder.message); // messageHolder.message being the IncomingTextMessage kept in MyMessageViewHolder
  }
}

这篇关于滚动后,RecyclerView中的无限动画停止的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆