Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I animate a child view in a recyclerView element after notifyItemChange() in onBindViewHolder()

I want to animate a textView inside a recyclerView to transition upwards when I call notifyItemChanged(position). This is my onBindViewholder() that is being called automatically when a change in the adapter occurs:

@Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    if (unfoldedIndexes.contains(position)) { // if already unfolded
        bindUnfoldedState(holder, holder.getLayoutPosition());
    }else{ // show the folded state}
}

public void bindUnfoldedState(ViewHolder holder, int position){


    if(lc.isBtnEnabled()){
            holder.Price.setText("text");
            holder.Price.animate().alpha(1.0f).setDuration(500);
            holder.Price.animate().translationY(-38).setDuration(500);
            holder.checkText.animate().translationY(38).setDuration(500);
        }else {
            holder.Price.animate().alpha(0.0f).setDuration(500);
            holder.Price.animate().translationY(0).setDuration(500);
            holder.checkText.animate().translationY(0).setDuration(500);
        }

}

my notifyItemChanged() is being called from a fragment onClick like so:

 ok.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
            // some changes to the data
            adapter.getLcns().get(Position).setBtnEnabled(true);
            adapter.notifyItemChanged(Position);
            }
}

isBtnEnabled() is true if setBtnEnabled(true) is called.

The problem is that the animation is not happening. With logs I can confirm that onBindViewHolder() is being called and the animation should appear but it is not happening.

I was using anormal listView before I converted to a recyclerView and the animations were working in on getView()

like image 701
bcsta Avatar asked Sep 10 '19 12:09

bcsta


1 Answers

Use Adapter.notifyItemChanged(position, payload) to deploy an update to already visible ViewHolders:

OnClick:

ok.setOnClickListener(new View.OnClickListener(){
    @Override
    public void onClick(View view) {
        // some changes to the data
        adapter.getLcns().get(Position).setBtnEnabled(true);
        adapter.notifyItemChanged(Position, true);   // "true" is the payload
    }
}

Adapter:

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position, List<Object> payloads) {
    if(payloads != null && !payloads.isEmpty()){  // update payloads, partial rebind
        Object lastPayload = payloads.get(payloads.size -1)); // in this case only last payload is meaningful
        if(lastPayload instanceof Boolean)
            bindUnfoldedState(holder, lastPayload);
    }else
        onBindViewHolder(holder, position);   // regular binding of item
}

public void bindUnfoldedState(ViewHolder holder, boolean unfold){
     if(unfold){ ... } 
     else { ... }
}

// you should also consider adding this override to prevent animation leaking when viewholder
// is recycled and reused for another position:
@Override
public void onViewRecycled(ViewHolder holder){
    holder.Price.animate().cancel();
    holder.checkText.animate().cancel();
}
like image 158
Pawel Avatar answered Nov 13 '22 03:11

Pawel