2016-03-25 4 views
2

Ich habe mehrere Bilder RecyclerView mit animierten Ansichten (blinkende weiße Kreise) in Elemente. Während recyclerView Scroll-Animationen können nach dem Zufallsprinzip aufhören zu arbeiten.Unendliche Animation in RecyclerView stoppt nach dem Scrollen

Ich dachte dieses Problem ist mit onCreateViewHolder oder onBindViewHolder verbunden, aber dieses Problem reproduziert, auch wenn keine dieser Methoden aufgerufen wurde.

Animation Wiederholungszahl auf unendlich eingestellt, clearAnimation() nur in onBindViewHolder aufgerufen.

Mein Adaptercode:

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

Blinzeln Animation 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" /> 

enter image description here

Antwort

10

Ich stieß auf das gleiche Problem und stellte fest, dass die Animation aufhört, wenn die Ansicht aus dem Fenster entfernt wird. Wenn es wieder angebracht wird, erhalten Sie den onBindViewHolder Anruf nicht, so dass die Animation nicht gestartet wird.

Die Lösung besteht darin, onViewAttachedToWindow in Ihrem RecyclerView.Adapter<> zu überschreiben und von dort aus setAnimation aufzurufen. Sie müssen auch einen Verweis auf die IncomingTextMessage in der ViewHolder pflegen, weil onViewAttachedToWindow nicht in der Position übergeben.

Beispiel:

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

hat für mich gearbeitet! –

+0

Das hat auch für mich funktioniert. Kann jedoch jemand erklären, warum onBindViewHolder nicht aufgerufen wird, wenn es wieder angefügt wird? –

0

Versuch Animation zu null in Ihrem MessageNotification.READ Fall einzustellen:

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; 
       } 
+0

Ich habe versucht es gerade ohne success.Anyway, danke für deine Antwort. –

+0

hm .. versuchen Sie auch zu ersetzen 'myMessageViewHolder.vMessageStatusAwaitingSending.clearAnimation();' mit 'myMessageViewHolder.vMessageStatusAwaitingReading.setAnimation (null);' –

+0

Eigentlich habe ich das auch, ich habe nur darüber nicht erwähnt. Beachten Sie auch, dass 'onBindViewHolder 'Methode ruft nicht einmal an (das habe ich doppelt überprüft). Diese Tatsache macht die Sache zu kompliziert. –