How to change item position of a recycle view from within its adapter? - android

Is it possible to change the item from within the adapter itself?
What am I trying to a achieve?
I have created a simple recycler view and it has a simple list item, but when the user clicks on the item a bottom sheet dialog gets displayed (that bottom sheet is being created in the adapter itself so it's different for every item) that bottom sheet dialog have a back and next button which can allow the user to move back and forth through the item view
When the user clicks on item -> bottom sheet dialog gets displayed -> if he presses next I have to show next following item with its bottom sheet opened.
How can I move from I item to another within the adapter?

you can pass position and list item as ArrayList to bottom sheet and update UI on next and previous buttons.
for example, you can create a method in your bottom sheet to update bottom sheet UI:
var listItem = ArrayList<Objects>()
var position = 0
private fun updateUi() {
val item = listItem[position]
///update ui with item
}
on next button click:
position += 1
if (position == listItem.size)
{
// end of list
} else
{
updateUi()
}
and on pervious button click:
position -= 1
if (position == -1)
{
// end of list
} else
{
updateUi()
}

RecyclerView has a couple of convenience methods, scrollToPosition and smoothScrollToPosition (the latter needs a little setup, check the link). You can use these to change the current item being displayed.
That requires having a reference to the RecyclerView though, which your Adapter doesn't have (or at least, it doesn't expose it). There's a callback when on starts observing the adapter though. So you could store that reference when you get it (but don't hold onto it when the equivalent onDetached callback happens)
Personally I'd want to separate all these things out, have them coordinated by the containing fragment, or some other component. So instead of one component (the adapter) managing what other components are doing and showing, it just calls a function saying "hey this item got clicked" and what happens as a result is none of its concern.
There's lots of ways to coordinate that, but it keeps things neater if you can separate that functionality. When one thing that has a specific job (displaying items and handling clicks) starts doing other stuff (messing with other UI components, handling stuff they do) it can start getting complex. Up to you but it's worth thinking about!

Thanks to everyone who shared their ideas.
Here is what I finally did
created an interface within the adapter
implemented that interface in the fragment which was starting the adapter
when the user press the next or previous button, I dismiss the current bottom sheet and then I call the function in the interface and also pass it the position of either next to or previous item
When the implemented function gets called in the fragment, first I move the list to that position second i get the item on that positon and third call perform on click on that item and it displayed the bottom sheet of that item
here is the fun which get called in fragment
override fun onAddIconClick(position: Int) {
surveyBinding.surveyRecV.scrollToPosition(position)
val v: View? = surveyBinding.surveyRecV.layoutManager?.findViewByPosition(position)
if(v != null) {
v.findViewById<ImageView>(R.id.viewAddIcon).performClick()
val temp = v.findViewById<TextView>(R.id.viewMainTitle)
Log.i("here22" , temp.text.toString())
}
}

Related

View not updating in OnClickListener

i am trying to make an E-Leaning app.
I have a submit button, that when pressed, sends the user's answer to a server to be evaluated.
During that evaluation, I want to display a loading indicator (I am simply using Android Studio's progress bar).
During the onViewCreated of my fragment, I set the onClickListener as follows:
submit_button.setOnClickListener {
submit_button.isClickable = false
loadingIndicator.visibility = View.VISIBLE
inputFragment.passDataToActivityAndEvaluate()
}
On press, a coroutine is launched that makes an html request. After that, I want to hide the loading spinner before navigating the child fragment
loadingIndicator.visibility = View.INVISIBLE
submit_button.isClickable = true
The idea sounded simple enough, however, I discovered that when trying to make any form of UI change in the OnClickListener, it only gets applied when the evaulation is already done and the app has navigated to the next fragment.

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.

Is there any way to update the appearance of one RecyclerView element without a full reload?

I'm making an app that has a main RecyclerView "feed" comprised of post elements.
You can click on a post which takes you to a detailed view.
I opted to put the detailed view in a "transparent" activity so that when the detailed view is clicked on, the current activity is paused and the new one starts. This means that the feed activity does not lose its state and the recyclerview maintains its position so that when the user clicks back the activity/fragment does not need to reload.
On both the feed's posts and the detailed view, I have thumb buttons that can be clicked. When the user enters the detailed view, I pass in the thumb button's state and it's initialized in onCreate(). When the user exits the detailed view, I need to update the state of the thumb button in the main feed (to keep them in sync) without refreshing the entire recyclerview. This requires me refreshing the dataset (and subsequently updating the appearance) in one item of the recyclerview without refreshing/reloading the entire recyclerview. Is this possible?
I tried doing this by updating the data set used by my adapter and calling notifyItemChanged(position) but this did not work. I was told this method calls onBindViewHolder (which would then call my bind method and update the view).
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// Here, I'm updating my mRecipes data set after returning from the detailed view
if (requestCode == 0) {
int adaptpos = Integer.parseInt(data.getStringExtra("adaptpos"));
String likes = data.getStringExtra("likes");
String favorites = data.getStringExtra("favorites");
mRecipes[adaptpos].setLikes(likes);
mRecipes[adaptpos].setFavorites(favorites);
mAdapter.notifyDataSetChanged();
mAdapter.notifyItemChanged(adaptpos);
}
}
Any help going about this would be greatly appreciated. If all else fails, I may have to just reload the entire fragment to reflect the change in state.
You can use DiffUtil to handle this scenario , its an easy way to handle updates to recycler view items and was recently added to the support library.
This medium post explains the implementation

How can I change a Preference when WearableListView snaps to new list item?

I've implemented a WearableListView in order to allow the user to choose a preference in my app. Currently, whenever the user clicks on an item, I save that item's tag in a preference. This code lives in the onClick method of the class implementing WearableListView.onClick
I've also noticed that when I change the item selected in the list (the item in center screen)
that persists upon leaving and coming back to this list. So I'm wondering how can I access that offset value? Or what method is called in order to make your current item persist once you leave and come back to a list? I would like the user to not need to click on the list item, but simply scroll away and that item tag save.
I cannot test it right now, but please take a look at WearableListView.OnScrollListener class.
There is a promising-looking method called onCentralPositionChanged(int centralPosition). Just add it via addOnScrollListener(WearableListView.OnScrollListener listener) method and update your preferences in onCentralPositionChanged callback:
public void onCentralPositionChanged(int centralPosition) {
// update your preferences according to centralPosition
}

Update View on Resume (Return to view after selecting an item from list view)

I have a view that displays some data for a selected city using a web service, it works fine if I have already selected a city. View is populated with data using onCreateView as its inherits from Fragment.
But, user can select a new city, by going to next view. As the user selects the city and press back button, now how can I update the view ?
Edit:
View1: Displays data if a city is already selected.
User goes from view1 to view 2
View2:Select a city from list view (On list item click, city is saved and onBackPressed is called to move back to View1)
Now when View1 is is presented again, how to update view ?
First way - Create fragment transaction and replace fragment
Second way - Implement setCity method in your fragment and update view in this method.
One way is to use onResume when returning to a view, and if the view needs to be updated.
#Override
public void onResume(){
// TODO: code here
}

Categories

Resources