RecyclerView中的无限动画在滚动后停止

时间:2016-03-25 11:58:03

标签: android android-animation android-recyclerview

我在项目中有多个Project动画视图(闪烁的白色圆圈)。在RecyclerView滚动期间,动画会随机停止工作。

我认为此问题与recyclerViewonCreateViewHolder有关,但即使没有调用此方法,此问题也会重现。

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

我的适配器代码:

onBindViewHolder

闪烁动画xml

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);
        }
    }
}

enter image description here

2 个答案:

答案 0 :(得分:13)

我遇到了同样的问题,发现当视图从窗口中分离时动画停止了。重新连接后,您将无法进行onBindViewHolder调用,因此动画将无法启动。

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

示例:

@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
  }
}

答案 1 :(得分:0)

尝试在MessageNotification.READ案例中将动画设置为null:

    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);

                    myMessageViewHolder.vMessageStatusAwaitingReading.setAnimation(null);

                    break;
                }