How to pause/stop recyclerview animation after notifyItemRemoved()? - android

I have applied animation for my recyclerview as follows
SlideInRightAnimator animator = new SlideInRightAnimator();//using custom Animation to remove the recyclerview Item
animator.setRemoveDuration(200);//specify the duration to run the animation
mRecyclerView.setItemAnimator(animator);
I have applied this animation on recyclerview since I do not know the
However I would like to cancel stop animation in my Adapter once once I do notifyItemRemoved().
I understand the onBindViewHolder is called immediately after but not sure how can I pass my animator into my Recyclerview adapter or call the stop animation in general.
I have eventbus handler in the Fragment and I am calling the removeItem method on Adapter as below.
public void onEventMainThread(MyEvent event) {
switch (event.getEventType()) {
......
case DELETE:
mAdapter.removeItem(event.getItem());
break;
default: break;
}
}
Update: I also tried to do following after I call notify Item removed:
mRecyclerView.setItemAnimator(null);
But this eventually cancels the animation all together
Appreciate your kind response

Well, I came up with an option that works. I am sure there are better options, but here's what I did.
In my Adapter class, I copied the reference of the view holder within onBindViewHolder method. And then in theonRemoveItem method I used the viewHolder's itemview to animate using ObjectAnimator and Animation set. After the animation , I made the viewholder copy to be null.
This way I was able to achieve animation on individual view.

Related

Why Does RecyclerView Update Without notifyDataSetChanged()?

It is common knowledge to call notifyDataSetChanged() or notifyItemChanged() when you mutate an array that is being handled by a RecyclerView adapter in order to update the view and reflect the changes made. But I spun up a sample application in which neither are called when I add items to an array immediately after calling .setAdapter() in the same block, and the view updates! This behavior doesn't happen when I try to add items via a button's onClickListener or from a background thread (both require notifyDataSetChanged for the view to update).
What's going on here? Shouldn't adding items to the list immediately after calling .setAdapter() in the same block require something like notifyDataSetChanged()?
i.e.
#Override
protected void onCreate(Bundle savedInstanceState) {
...
myList.add("a");
myList.add("b");
recyclerView.setAdapter(adapter);
myList.add("c"); // the recyclerView is updating and shows "c" here! why???
findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
myList.add("e"); // the recyclerView will NOT update here unless you call `notifyDataSetChanged`
}
});
...
If you're passing an ArrayList to your Adapter, and you're adding elements in onCreate, that would be before the app has drawn your first frame.
There is a moment where you're able to add elements, because the adapter hasn't laid out the items.
And within your onClick, that would be after onCreate has finished, which means the adapter is already laid out.
You could try moving add("c"); to onPostCreate or onResume and you may see similar result as your onClick.

How to swap items from two recyclerview items that are in two fragments in one activity?

I have two fragments (a and b) inside an Activity according to the picture below.
I am able to delete from first one but how to add that item to favorites fragment RecyclerView?
Deleting actress name and adding to favorites
My Viewholder code for RecyclerView Fragment one class:
addToFavoriteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mArrayList.remove(getAdapterPosition());
notifyDataSetChanged();
}
});
How to add this deleted item inside adapter of Favorites Recyclerview?
What I would do is maintain a list of actresses (either locally or on the server) with each one containing an isFavorite boolean attribute.
Then, while you have one global list, each recyclerview is only showing a subset:
On the left, you show all actresses where isFavorite is set to false.
On the right, you show all actresses where isFavorite is set to true.
How you update it could be done a few different ways, but here is what I recommend at a high level:
Have an onClick listener for each one that bubbles up to the activity, so the activity is aware any time an actresses's favorite state changes. Every time the state changes for an actress, tell your adapters in each fragment to update.
If you don't want to refresh the entire list every time, you could integrate a remove and add method like Mauker's Answer.
You can create a method inside your adapter that removes an item from the RecyclerView, and returns the given item.
Then, you can use this item reference to add it to the second RecyclerView.
Pseudocode example
public myItem removeAndGetItem(int position) {
myItem item = mArrayList.get(position);
mArrayList.remove(position);
notifyDataSetChanged();
return item;
}
Then you could call something like (also, pseudocode):
myItem item = adapter1.removeAndGetItem(position);
adapter2.add(item);
Adjust the examples to your code, and it should do the trick.
Edit
I misread the part about the RecyclerViews being on different Fragments.
So, you can still do what I said on the example above, you'll just have to pass that item to the second Fragment, using Fragment callbacks, or Broadcasting the item, or even through an EventBus.
Instead of using notifyDataSetChanged() which can be very costly, try to use notifyItemRemoved(int position) instead. As you can see on the docs:
If you are writing an adapter it will always be more efficient to use the more specific change events if you can. Rely on notifyDataSetChanged() as a last resort.

Animate views before activity finished

I use view animations in a predrawlistener to animate the activity start.
Exist a similar listener to animate my views before my activity is finished?
I know the overridependingtransition method for animations in xml but i want to use ViewPropertyAnimations in a programmatically way for specific views.
I suggest you to override finish() method, then add your animation there:
#Override
public void finish (){
// do your animation
super.finish();
}
You can call YourActivity.finsih(); when you want to finish your activity from code.

RecyclerView: How to determine when scrollToPosition() has finished binding the ViewHolders

tl;dr How to wait until the true scrolling is done after calling scrollToPosition()? What I mean by true scrolling is that (1) the RecyclerView has finished the scrolling and (2) it has bound all the ViewHolders for the set position of scroll.
Description:
I am trying to fix some transition animation for recycler view and I'm having a hard time achieving it.
The app is consistent of a RecyclerView in one of the activities and a ViewPager that acts as a "detail view" when users click on an item in the RecyclerView.
The forward navigation from RecyclerView to ViewPager works perfectly fine but the problem is, the backward navigation doesn't work. Please note that the user may navigate using the ViewPager in the detail view and when they re-enter the activity with RecyclerView, the position of the item may be different from the original case, meaning the RecyclerView needs to scoll first to the item and then resume the transition animation.
The reason I can't make it to work is because I resume the animation before the RecyclerView has properly scolled and bound the underlying ViewHolders but I don't know how to wait for the scrolling to truly finish and then resume the shared element transitions.
What I do in my code (on the Reenter code) is this:
if (isReentering) {
// postpone the animation here
ActivityCompat.postponeEnterTransition(getActivity());
scollIndex = ... // determine the correct item position
layoutManager.scrollToPosition(scrollIndex);
final RecyclerView recyclerView = getRecyclerView();
new Handler().post(new Runnable() {
#Override
public void run() {
recyclerView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
recyclerView.getViewTreeObserver().removeOnPreDrawListener(this);
recyclerView.requestLayout();
ActivityCompat.startPostponedEnterTransition(getActivity());
return true;
}
});
}
});
}
I also set the transition name in my Adapter as such:
#Override
public void onBindViewHolder(TViewHolder holder, int position) {
....
holder.setTransitionName(_data.get(position).getContentId().toString());
}
The transition name is the UUID of the item, set in the underlying View. Both the ViewPager and the RecyclerView set this correctly.
The scrollIndex is correct and the RecyclerView does scroll to it but here's the catch: The scrolling and binding only takes effect after I've already started the postponed enter transition in my code (by calling ActivityCompat.startPostponedEnterTransition(getActivity());) which causes weird transition animations.
What I would like to happen is to somehow wait until the scrolling and the ViewHolder binding is finished before calling startPostponedEnterTransition so my question is, how can I find out when the scrolling has finished and all the ViewHolders are bound so that I can call this?
Many thanks in advance,
You can check, if the ViewHolders have been bound, by using the code in this answer.

ViewPager OnLongClick listener not firing

I have a fragment which contains a ViewPager. When I inflate the layout, I assign an OnLongClick listener to it as follows:
mPager.setOnLongClickListener(mOnPagerLongClickListener);
However, when I perform a long click on the ViewPager, nothing happens. What can I do to make this work? Or do I need to assign the listener to every view in the ViewPager instead? Assigning the listener to the GridViews which the ViewPager contains doesn't seem to work either.
Excuse for putting on a query, but I am able to solve the issue. It won't be helpful to you but may come in handy for any other viewer.
The simple solution is to assign listener directly to ImageView's object rather assigning it to ViewPager's object, i.e, assigning viewPager.setOnLongClickListener will not fire anything.
So, we have to initialize ImageView with onLongClickListeners in the class extending PageAdapter in instantiateItem() by:
imageView.setOnLongClickListener(new OnLongClickListener()){
#Override
public boolean onLongClick(View v) {
// Do your stuff
return false;
}
});

Categories

Resources