Load the first item after the first item in recyclerview - android

I need to implement the recyclerview with functionality as to display the first item after last like circle

Suggest you to try following changes in your adapter class. Set getItemCount to return a very large value like Integer.MAX_VALUE
#Override
public int getItemCount() {
return Integer.MAX_VALUE;
}
Then to get the actual item position need a modulus operation
#Override
public void onBindViewHolder(ActionItemViewHolder holder, int position) {
position = position % SIZE_OF_LIST;
};

Related

android reflash position after remove arrayList item

i have recyclerview with adapter.
#Override
public void onBindViewHolder(#NonNull CustomViewHolder holder, int position) {
int positions = position;
Bitmap bitmap = BitmapFactory.decodeByteArray(arrayList.get(position).getImg(), 0, arrayList.get(position).getImg().length);
holder.button.setImageBitmap(bitmap);
holder.seekBar.setProgress(arrayList.get(position).getSeek());
holder.btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int index = arrayList.indexOf(arrayList.get(positions));
arrayList.remove(arrayList.get(positions);
adapter.notifyItemRemoved(index);
}
});
}
if i have 2 item in arrayList
first, i remove item position 0.
and second, if i remove item position 0 again, i have error
android IndexOutOfBoundsException: Index: 1, Size: 1
i don't know why..
deleted one item of the two items.
And the position of one remaining item should be 0.
but why show error?
After deleting one item, I checked that the size of the arrayList was 1.
what i have to do?

How to update the view of a particular position of a recycler view which is not currently in focus on the screen?

I am actually making some visibility changes to items that are clicked of the recycler view. But when the user clicks on one object and then clicks on the other object then the previous object should come to its initial state.
The manager.findViewByPosition(position) is working fine if the view is in focus of the screen but I am not able to get the view if the element is not in current focus.
For example:- the user clicks on 1st(position) item then clicks on the last position then the findViewByPosition returns a null.
Please help and let me know if there is some other way of doing it.
The expected result should be the view of the last item to be refreshed but it's not happening for the views that are not in the current focus of the screen.
Below is my code snippet. Updated with what you suggested.
public class BodyPartWithMmtRecyclerView extends
RecyclerView.Adapter<BodyPartWithMmtRecyclerView.ViewHolder>
{
//variables defined.
int selectedPosition = -1;
static class ViewHolder extends RecyclerView.ViewHolder {
//All the view items declared here.
ViewHolder(View view) {
super(view);
//All the views are defined here.
}
}
public BodyPartWithMmtRecyclerView(List<BodyPartWithMmtSelectionModel> bodyPartsList, Context context){
//array list initialization and shared preference variables initialization
}
public BodyPartWithMmtRecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
//Creating a new view.
}
public void onBindViewHolder(#NonNull final BodyPartWithMmtRecyclerView.ViewHolder holder, #SuppressLint("RecyclerView") final int position) {
BodyPartWithMmtSelectionModel bodyPartWithMmtSelectionModel = bodyPartsList.get(position);
holder.iv_bodypart.setImageResource(bodyPartWithMmtSelectionModel.getIv_body_part());
holder.tv_body_part_name.setText(bodyPartWithMmtSelectionModel.getExercise_name());
if(selectedPosition!=position && selectedPosition!=-1){
//updated the elements view to default view. Like made the visibility and other changes here.
}
//some click listeners on the sub-elements of the items. Like textviews, spinner, etc
holder.iv_bodypart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((BodyPartSelection)context).setFabVisible();
if(selectedPosition!=-1){
((BodyPartSelection)context).visibilityChanged(selectedPosition,position);
/*here what I was doing is whenever the user clicks on an item I check weather a previous item is clicked or not then if yes then I send the position to a function that makes it to default but the issue was that if the item is not in the focus of the screen the findViewByPosition returns null.*/
}
selectedPosition = position;
bodypartSelected = holder.tv_body_part_name.getText().toString();
holder.iv_bodypart.setVisibility(View.INVISIBLE);
holder.rl_left_right.setVisibility(View.VISIBLE);
}
});
//and other listeners below
}
#Override
public int getItemCount() {
return bodyPartsList==null?0:bodyPartsList.size();
}
#Override
public int getItemViewType(int position) {
return position;
}
}
VisibilityChanged function
public void visibilityChanged(int position, int clicked){
View view = manager.findViewByPosition(position);
if(view!=null) {
Log.i("inside","visibility change");
ImageView imageView = view.findViewById(R.id.bodypartImage);
//other elements and changing the visibility of elemets to default.
}
}
I have updated my code based on the snippet you updated. Please don't change the visibility condition if-else I have added with any different logic which I saw in your code snippet. As you did, it will not update both selected and default view as RecyclerView reuse the view layout. So if the condition is not proper, you may see multiple items as selected or some other types of unwated behaviour.
public void onBindViewHolder(#NonNull final BodyPartWithMmtRecyclerView.ViewHolder holder, #SuppressLint("RecyclerView") final int position) {
BodyPartWithMmtSelectionModel bodyPartWithMmtSelectionModel = bodyPartsList.get(position);
holder.iv_bodypart.setImageResource(bodyPartWithMmtSelectionModel.getIv_body_part());
holder.tv_body_part_name.setText(bodyPartWithMmtSelectionModel.getExercise_name());
if(selectedPosition == position){
//updated the elements view to SELECTED VIEW. Like made the visibility and other changes here.
} else {
//updated the elements view to default view. Like made the visibility and other changes here.
}
//some click listeners on the sub-elements of the items. Like textviews, spinner, etc
holder.iv_bodypart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((BodyPartSelection)context).setFabVisible();
/Comment by Hari: Don't try to change the visibility of default as it will be done automatically after calling notifyDataSetChanged(). */
if(selectedPosition!=-1){
((BodyPartSelection)context).visibilityChanged(selectedPosition,position);
/*here what I was doing is whenever the user clicks on an item I check weather a previous item is clicked or not then if yes then I send the position to a function that makes it to default but the issue was that if the item is not in the focus of the screen the findViewByPosition returns null.*/
/*Comment by Hari: This snippet is valuable which is missing as you are getting null issue here.
However Don't try to change the visibility of default as it will be done automatically after calling notifyDataSetChanged(). */
}
selectedPosition = position;
bodypartSelected = holder.tv_body_part_name.getText().toString();
holder.iv_bodypart.setVisibility(View.INVISIBLE);
holder.rl_left_right.setVisibility(View.VISIBLE);
//Keep this as last statement in onClick
notifyDataSetChanged();
}
});
//and other listeners below
}
Let me know your further response.
Based on #Hari N Jha's Answer.
Call notifyDataSetChanged() when you update anything. E.g
int selectedPosition = -1;
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
//....
if(position == selectedPosition) {
//Add background color change of your layout or as you want for selected item.
} else {
//Add background color change of your layout or as you want for default item.
}
notifyDataSetChanged(); //Call notifyDataSetChanged() here after done all the stufs
//...
}

Spinner Displayed Value (Selection) Changing After Adapter Update (notifyDataSetChanged)

I have a Spinner. After an item is selected, and the adapter is updated by notifyDataSetChanged, the selected item displayed in the Spinner (Textview) changes. This functionality is by design. Because the selected position stayed the same but the value of the selected position changed due to the new content from updating the adapter.
I want to continue to display the originally selected item after the adapter updates.
I was hoping this solution would work, but the event/lister never fires. Maybe because I am using a Spinner and the list is not dispalyed?
https://stackoverflow.com/a/29173680/2330272
mListView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
mListView.removeOnLayoutChangeListener(this);
Log.e(TAG, "updated");
}
});
mAdapter.notifyDataSetChanged();
Update
Help with at least two questions:
How to determine when the Spinner has finished updating the view after the notifyDataSetChanged has been called for the adpater?
How to find the position (index) of a value (label) in the adapter? As the adapter be querued or elements loop thru?
If you want to maintain the current selected item, as opposed to the current selected position, then you will have to implement the adapter's getItemId(int position) callback such that:
Each item in the spinner has a unique id
The same item always has the same id
Common implementations of getItemId() just return zero, or maybe the item's position. Neither of these will work in this situation. Ideally you'll have an actual logical ID that you can return, but if the only thing you have is a String then you could use the string's hashCode() method:
#Override
public String getItem(int position) {
return list.get(position);
}
#Override
public long getItemId(int position) {
return list.get(position).hashCode();
}
Two different strings are unlikely to have the same hash code, but it's not impossible.

RecyclerView using DiffUtil, prevent to scroll bottom on change

I have a problem with my recyclerViev, specifically with the scrolling.
I have some list, which is updated in real time, some item is added, some removed, and everything is sorted by some parameter.
So the item which was initially first on the list, can have its parameter changed, which will be in different position after the sorting.
So my recyclerView is for example focusing on the initial item, and after change, when some item has "better" parameter is changing position with that initial item.
Problem is, i want to focus on the new item, with "better" parameter when I'm not scrolling, but i don't want to focusing on it when i scroll by touch(so my touch will not be interrupted by scrolling to current first item on the list).
So i don't want to force this code after every change in my recyclerView data:
recyclerView.scrollToPosition(0);
because as i said, i will be interrupted by this scroll when i am touching my recyclerView list and go down to see other items and in the same time there will be a change in my list.
Is there a way to accomplish this?
To be specific, i am using DiffCallback from the DiffUtil, to support animations when there is a change in my current recyclerView list - it compares the old list with another new list and apply all the wanted animations and notifications(item added, removed, changed position). So i never call
notifyDataSetChanged
or anything like that
Here is my DiffUtil callback:
public static class DevicesDiffCallback extends DiffUtil.Callback{
List<DeviceInfo> oldDevices;
List<DeviceInfo> newDevices;
public DevicesDiffCallback(List<NexoDeviceInfo> newDevices, List<NexoDeviceInfo> oldDevices) {
this.newDevices = newDevices;
this.oldDevices = oldDevices;
}
#Override
public int getOldListSize() {
return oldDevices != null ? oldDevices.size() : 0;
}
#Override
public int getNewListSize() {
return newDevices != null ? newDevices.size() : 0;
}
#Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return oldDevices.get(oldItemPosition).getNexoIdentifier().getSerialNumber().equals(newDevices.get(newItemPosition).getNexoIdentifier().getSerialNumber());
}
#Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return oldDevices.get(oldItemPosition).equals(newDevices.get(newItemPosition));
}
#Override
public Object getChangePayload(int oldItemPosition, int newItemPosition) {
return super.getChangePayload(oldItemPosition, newItemPosition);
}
}
And i set it like this in my adapter, when i get the list of new data to be populated and replace the old data:
public void setData(List<DeviceInfo> data) {
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DevicesDiffCallback(this.mData, data), false);
diffResult.dispatchUpdatesTo(this);
mData = data;
}
I'm not sure about this answer but, I think your code to call DiffUtil is not proper. Try using this :
public void addItems(List<Recipe> recipeList) {
List<Recipe> newRecipeList = new ArrayList<>();
newRecipeList.addAll(this.recipeList);
newRecipeList.addAll(recipeList);
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new RecipeDiffUtilCallback(this.recipeList, newRecipeList));
this.recipeList.addAll(recipeList);
diffResult.dispatchUpdatesTo(this);
}

How do I Add OnScrollListener to Image gallery demo?

I have found some image gallery demo on below link:
http://www.androidauthority.com/how-to-build-an-image-gallery-app-718976/
But it's loading all the images together. How do I add OnScrollListeners to this project?
You have to do code on your Adapter OnBindViewHolder() method
This is your Code :
#Override
public void onBindViewHolder(MyAdapter.ViewHolder viewHolder, int i) {
viewHolder.title.setText(galleryList.get(i).getImage_title());
viewHolder.img.setScaleType(ImageView.ScaleType.CENTER_CROP);
viewHolder.img.setImageResource((galleryList.get(i).getImage_ID()));
}
In the above code onBindViewHolder(MyAdapter.ViewHolder viewHolder, int i) here int i is the position of the image by getting position you can perform action within OnBindViewHolder.
#Override
public void onBindViewHolder(MyAdapter.ViewHolder viewHolder, int i) {
viewHolder.title.setText(galleryList.get(i).getImage_title());
viewHolder.img.setScaleType(ImageView.ScaleType.CENTER_CROP);
viewHolder.img.setImageResource((galleryList.get(i).getImage_ID()));
Log.e("POSITION",""+i); //This will show you position on LOG.
Toast.makeText(getApplicationContext()," "+i,Toast.LENGTH_SHORT).show();
//Example : Hiding second position image
if(i==2){
viewHolder.img.setVisibility(View.GONE);
}
}
Note : In RecyclerView OnBindViewHolder is calling in every row ,So what you have to do just code inside of the OnBindViewHolder.Its not setting images in a single time Recyclerview getting images by calling OnbindViewHolder for every row and setting the images.

Categories

Resources