Android SelectAll functionality for Recycleview {unable to acomplish} - android

I have ReçycleView with multiple photos in grid view, and i want to accomplish Select All functionality,
when there are less items in grid that can be view on the screen without scroll, i can do the select all functionality without any problem as this all views are bind to the recycle view.
But the problem occurs when the items are more and are in scrollview and the items that are off screen i.e they are still not bind to the RecycleView and this time when the user press the select all, only the images that are viewed and Bind to Viewholder are getting selected.
I have gone through many trial and error but failed to do the same.
Request you to come-up with some solution.
Below is the RecycleView ImageItem Model and the data i need for the selection.
ImageItem imageItem = new ImageItem(path, imageView, layoutImage,
albumImage, selectionImage, uploadProgress, false, file, dbAlbumPhotos);
case SELECT_ALL:
if (imageHashMap != null && imageHashMap.size() > 0) {
for (ImageItem imageItem : imageHashMap.values()) {
if (!imageItem.isSelected()) {
imageItem.setSelected(true);
imageItem.getSelectionImage().setVisibility(View.VISIBLE);
selectedImageUrls.put(imageItem.getDbAlbumPhoto().getPhotoId(), imageItem.getDbAlbumPhoto().getUrlPhotoLarge());
}
}
}

Problem with your code is that you are updating only those items view which are currently visible.
Whenever the user chooses for functinolaity Select All, just iterate and update all the ImageItem or java bean or model values to true.
Call YourRecyclerView.notifyDataSetChanged() that the dataset has changed. Now if user unselect or select any single item then update only that bean object and call YourRecyclerView.notifyItemChanged(int pos) that item at position has changed.
Update 1: Don't put layoutImage in ImageItem bean. You need not put any ViewHolder in ImageItem. Now holder.layout image value can be set based upon if(imageItem.isSelected()) holder.layout image.setVisibilit(View.Visible) else //View.Invisible. holder.layout image will be always available in onBindViewHolder.

Related

View not hiding when dynamically done in recycler view item

I am using RecyclerView to list Items and In each single list displaying an image which will be Visible/Gone dynamically. I am using View.GONE to hide the view.
In a condition where the image should hide is not working always. It is still showing in screen,and also in debug mode i have checked that and when getting the
image.getVisiblity() it is giving me int value "8" which means the view is Gone,But still i can see that image in that list.
It happens only sometimes.
And i tried to use View.INVISIBLE and it is working all the time but it is taking the space in layout which is as expected
I am using sparseArray to store all the holders classes.I have written a method in Adapter and calling this from activity.I am trying to hide the replayIcon view
public void handleReplayButton(int pos,Boolean isDisplay) {
Holder holder = holderSparseArray.get(pos);
if(holder != null) {
if (isDisplay != null && isDisplay == true) {
holder.playIcon.setVisibility(View.GONE);
holder.pauseIcon.setVisibility(View.GONE);
holder.replayIcon.setVisibility(View.VISIBLE);
} else if(isDisplay != null && isDisplay == false) {
holder.playIcon.setVisibility(View.VISIBLE);
holder.pauseIcon.setVisibility(View.GONE);
holder.replayIcon.setVisibility(View.GONE);
} else {
holder.playIcon.setVisibility(View.GONE);
holder.pauseIcon.setVisibility(View.VISIBLE);
holder.replayIcon.setVisibility(View.GONE);
}
}
}
Here it is going to the last else statement what i want and it is setting the view to GONE.and when i call holder.replayIcon.getVisibility() it is giving me int 8 but,still i can see the icon
Try calling invisible at the end of one statement which makes it visible and vice versa.
Or
You can also try to put notifydatasetchanged().
You will have to call notifyDataSetChanged() to refresh the list in the recycler view.
But since you have to remove an item, you can also use notifyItemRemoved
Also, if you are using setVisibility() method to HIDE the view, then make sure you also set the view as VISIBLE for valid items, because the items are reused in a recycler view.
For more : https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter
If you will call notifyDataSetChanged() - it will update all the items in the list.
Don't do that if you need to update special items by index because it will take a lot of memory to redraw the all views.
Instead like the guys wrote before you should use notifyItemChanged(), notifyItemInserted() or notifyItemRemoved().
If you want to update couple views use can use notifyItemRangeChanged(), notifyItemRangeRemoved() or notifyItemRangeInserted().
You can read more about it here
Also there is one way to it. You can use DiffUtils callbacks.
Pretty good approach that work with animation already.
DiffUtils Calbacks

Adding to favorite doesn't persist state

I have a tour list in android and I am trying to implementing add to favorites.
Favorite works for the list that is added in myTours but doesn't work for tours from search list.
This is the code:
private List<Tour> tourList;
holder.imgFavourite.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(tourList.get(position).getFav().equalsIgnoreCase("0")) {
tourList.get(position).setFav("1");
// listener.onFavourited(tourList.get(position), true);
holder.imgFavourite.setImageResource(R.drawable.faved);
} else {
tourList.get(position).setFav("0");
// listener.onFavourited(tourList.get(position), false);
holder.imgFavourite.setImageResource(R.drawable.not_faved);
}
}
});
Here when I click on Fav icon gets changed to faved. But if I search for different category and again come back to that category state doesn't persist.
Any help would be appreciated.
Listview/RecyclerView reuses views. If your list has 20 items and 4 are visible at one time, as you scroll, the views are reused to show the new visible views to save memory. So if you alter the view at position 5 and scroll down and scroll back up to position 5, the view that you changed in position 5 is not the same view that you are seeing after you scroll back up. Hence the view changes
To fix this, maintain a global variable in the adapter which stores the favorite position and in the onBindViewHolder, add a condition like
if(position = favPosition)
<Change to fav view>
else
<Change to Normal View>
The else condition is really important or else multiple views will have the Fav view
For recycler view always consider both cases only one case cause your list to change behaviour(like set same image for other list item because it reuses the cell for your view).the below mistake you are doing.
In bindviewholder you are getting data from model class and based on that you set resources for imageview.which is good.
But the problem is there no case for failing of the condition so you are losing the state and if you scroll down and again come to this item you lost your state or face behaviour that goes against your requirement.
So simply provide case for not matching your condition.

Dynamic views in listview

I'm creating kind of music player which has a listview with songs (having progress bar near currently playing song)
What is important is that I have an Item with views which can be changed from outside (in some handler)
public View getView(int i, View convertView, ViewGroup viewGroup) {
RelativeLayout result;
if (convertView == null) {
result = (RelativeLayout) inflater.inflate(R.layout.list_item, viewGroup, false);
} else {
result = (RelativeLayout) convertView;
}
...
ProgressBar progressBar = result.findViewById(R.id.progressBar)
...
if (i == currentSong) {
// saving to instance variable
this.currentlyPlayingProgressBar = progressBar;
} else {
progressBar.setVisibility(View.GONE);
}
...
return result;
}
(Code was changed to focus on my problem)
Btw currentSong can be changed from outside, adapter.notifyDataSetChanged() is being called in this case.
It seems like I'm using listView incorrectly, but I don't know the better way.
The main problem is that I need to have links to views to change them.
And the only way where I can get them is in getView method which reuses those view in a way only google developers can explain=(
First problem
This is all happening in Fragment which is just a part of a viewPager. when user scrolls of this fragment and then scrolls back then getView method is being called with some strange objects inside.. And I override currentlyPlayingProgressBar with this invalid value. Which causes the freeze of my statusbar. (it starts updating wrong view)
And I have no idea which view is it..
Second problem
I am reusing list items and this means that when user scrolls list view down - then sometimes he gets actually the same list item with the same progressBar.
This progressBar must be invisible but it's not (I think it's all because of my usage of currentlyPlayingProgressBar from outside)
Thanks in advance.
You can do this in two ways:
1) notifyDataSetChanged, which just resets entire ListView and assigns all visible list items again to views. notifyDataSetChanged is very expensive, since it makes entire list and view hierarchy to be recreated, layouts are measured, etc, which is slow. For frequent update of single list item, such as progress bar change, this is overkill.
2) Find view of particular listview item, and update only that one. We'll focus on this approach.
First you need to somehow identify which list view contains which list item. Common approach is to use View.setTag in your Adapter.getView, where setTag parameter is Object of your choice, may be same item as you return for Adapter.getItem.
So later you know which ListView child view has which item assigned.
Assuming you want to update particular item displayed in ListView, you have to iterate through ListView child views to find which view displays your item:
Object myItem = ...;
for(int i = list.getChildCount(); --i>=0; ){
View v = list.getChildAt(i);
Object tag = v.getTag();
if(tag==myItem) {
// found, rebind this item
bindItemToView(myItem, v);
break;
}
}
You must expect that ListView currently may not display your list item (is scrolled away).
From code above you see that it calls bindItemToView, which is your function to bind item to list view. You'd probably call same function to setup the item view in Adapter.getView.
You may also optimize it further, assuming you want to update only ProgressBar, then don't call bindItemToView, but update only ProgressBar in your listitem view (findViewById, setup values).
Hint: you can make it even more optimal by using ViewHolder approach. Then setTag would not contain your item object, but your ViewHolder object.
#Pointer null has also given very usefull aproach, but in your case I think u are updating the list which is not visible, in this case you have to set the tag from the adapter just like the list index and curresponding check if the list item exist between the last visible item or first visible item then update it else donot update..

Iterating ListView items in Android

I want to iterate a list of items into a ListView. This code below is not enough to iterate all the items into the list because of the weird behaviour of getChildCount() function which only returns the visible item count.
for (int i = 0; i < list.getChildCount(); i++) {
item = (View)list.getChildAt(i);
product = (Product)item.getTag();
// make some visual changes if product.id == someProductId
}
My screen displays 7 results and when there are more than 7 items into the list, it's not possible to access to the 8th item or so.. Only visible items..
Should I use ListIterator instead?
Thanks.
You need to customize your list adapter's getView() method, and put your check inside it to check if the current item's id matches:
Product product = items.get(position);
if(product.id == someProductId) {
//make visual changes
} else {
//reset visual changes to default to account for recycled views
}
Since typically only the visible items only exist at a specific time, getView is called whenever more need to be seen. They're created at that time, typically recycling views from the now-invisible items in the list (hence why you want to reset the changes if the criteria does NOT match).
So #kcoppock solved your first problem it seems you got another problem. How to update the view item? The android SMS application shows one way:
create your own list view item like this:
public class MyListItem extends RelativeLayout {
...
}
in your list view item layout file:
< MyListItem android:layout_width=.....>
...
</ MyListItem >
and in your code, when your view item can be seen, register MyListItem as a data changed listener(the data is up to you). I mean, when your data changed, then you can update the item directly.
Check out the SMS application source code to read more.
The number of views in the ListView(7) is different from the number of items in the adapter(which is more than 7) .Try to use a BaseAdapter.

How to Identify a ListViewItem to Update a Single Row

I have a ListView displays information about an object. When I click a ListView Item, I open an Activity that let's me manipulate parameters of the object held in the adapter. These parameters are updated and stored remotely.
When I return to the ListView (via the back button), I want to update the ListView Item that I clicked originally by requesting the parameter values from the remote server.
I am currently doing this up updating the entire ListView by clearing it and rebuilding it.
How do I reference the ListView Item so that I can update the data for that item only?
Thanks,
Jason
Just set the data for your adapter and call notifyDatasetChanged. Android only draws the rows that are visible anyway, so it's pretty efficient.
Knowing the position of the view, this can be done.
View singleItemView = myListView.getChildAt(position);
ImageView icn = (ImageView) singleItemView.findViewById(R.id.icn_icon);
ProgressBar prg = (ProgressBar) singleItemView.findViewById(R.id.prg_icon);
icn.setVisibility(View.GONE);
prg.setVisibility(View.VISIBLE);
(EDIT)
This doesn't work because the "position" of the View could be changed upon returning from another Activity. After the onResume() fires, getView() is called and the position of the visible ListView Items are numbered starting with 0. So, the ListView items (id and position) become renumbered based on visiblity. As a result, I end up accessing the wrong object.

Categories

Resources