Weird behavior in ListView GetView() method position - android

I've a custom adapter for my ListView where I send to it a List, and if the position is in the list then the imageview (that is in the custom row) change its src to another.. Here is the GetView method:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.start_row, null); // line
// 47
holder = new ViewHolder();
holder.tv_SuraName = (TextView) convertView.findViewById(R.id.Start_Name);
holder.tv_SuraName.setTypeface(Font);
holder.tv_PageNumber = (TextView) convertView.findViewById(R.id.Start_Numbering);
holder.im_Audio = (ImageView) convertView.findViewById(R.id.Start_ImageView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tv_SuraName.setText(SuraList_SuraNamesCode[position]);
holder.tv_PageNumber.setText(Integer.toString(PageNumber[position]));
holder.im_Audio.setOnClickListener(new imageViewClickListener(position));
if (TilawaAvailable.contains(position))
holder.im_Audio.setImageResource(R.drawable.quran_list_audioavailable);
return convertView;
}
I send a List with 1 position.If I scroll the ListView slowly, this works good and only 1 imageview gets changed as it should be. But if I scroll fast, other imagesviews that are close to the correct position also gets changed!
Can anyone tell me why?

You don't ever set the imageResource to something else if position isn't contained in your list. When the view with the custom image leaves the screen it is probably getting placed at a lower position in the list and getting reused.
Try changing this:
if (TilawaAvailable.contains(position))
holder.im_Audio.setImageResource(R.drawable.quran_list_audioavailable);
To this:
if (TilawaAvailable.contains(position))
holder.im_Audio.setImageResource(R.drawable.quran_list_audioavailable);
else
holder.im_audio.setImageResource(r.drawable.SOME_THING_ELSE);

Related

Android ListView actions repeat in different items

I have a custom layout for a Listview, each row item contains a button that when clicked it shows a small imageview in the item, however the actions i perform in one item, repeats for another item down the list, for example, if i click the button in item 1, the imageview will show up in item 1 and item 10, if i click the button in item 2, the Imageview will show up on item 2 and item 11 and while i scroll it will keep repeating in different items, heres the code for my custom adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
mparent = parent;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.places_item, parent, false);
holder = new ViewHolder();
holder.placeimage = (CircularImageView) convertView.findViewById(R.id.locationimage_pilayout);
holder.addbtn = (TextView) convertView.findViewById(R.id.addbtn_pilayout);
holder.delbtn = (TextView) convertView.findViewById(R.id.delbtn_pilayout);
holder.oribtn = (TextView) convertView.findViewById(R.id.oribtn_pilayout);
holder.placename = (TextView) convertView.findViewById(R.id.locationname_pilayout);
holder.selected = (ImageView) convertView.findViewById(R.id.selected_pilayout);
holder.origin = (ImageView) convertView.findViewById(R.id.origin_pilayout);
holder.swipeLayout = (SwipeRevealLayout) convertView.findViewById(R.id.swipe_pilayout);
holder.mainLayout = (LinearLayout) convertView.findViewById(R.id.main_pilayout);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
final Place item = getItem(position);
/*
my code assigning the button click listener and assigning the views
*/
return convertView;
}
Am i missing something? im sure this could be a simple fix, but i havent found it yet. any help would be kindly appreciated.
In ListView the individual views for rows, get reused. For example, let's say the window can show up to 10 rows inside the ListView. Now when you scroll down, the 1st view gets out of the window from the top, and a new 11th view comes into the window from the bottom. In order to save memory and CPU power, Android uses the same 1st view for the 11th view. That's the purpose of convertView and the if (convertView == null) {} else {} code.
So the reason why the image is being shown in the 1st item and also in the 11th item, is that they are exactly one view object. To tackle this issue, in the getView() method, you need to reset every attribute of every view and don't rely on the defaults.
So adding a line like the one below, will get rid of the mentioned problem:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// all your code ...
holder.placeImage.setImageResource(0); //<-- This clears any previously set image.
return convertView;
}

Custom ArrayAdapter Not Just First Element Different

I'm working on making a custom ArrayAdapter so that my list has the first element in a different color.
The thing is, when I execute this code in the get view method:
#Override
public View getView(int position, View convertView, ViewGroup parent){
Club club = (Club)getItem(position);
if(convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent, false);
}
TextView textView = (TextView)convertView.findViewById(R.id.txtListItem);
if(position == 0 && club.getName().contains("All")){
textView.setTextColor(ContextCompat.getColor(getContext(), R.color.orange));
}
textView.setText(club.getName());
return convertView;
}
The first item is orange, yes, but the 10th one (below the screen) is also when I scroll down :( in another list with more elements than what the screen can hold, I have several that are orange.. I don't understand why, please help!
This is happening because views are recycling/reused. You are setting orange color for the first item but not setting default color for the rest. Just add an else clause to your if statement above, something like this
if(position == 0 && club.getName().contains("All")){
Log.d(ClubAdapter.class.getName(), club.getName());
textView.setTextColor(ContextCompat.getColor(getContext(), R.color.orange));
}else{
textView.setTextColor(ContextCompat.getColor(getContext(), R.color.your_default_color));
}
Most likely this happens because Android is recycling the view which was originally used for the first row. You need an else clause to set the color back to normal.
This happens because the adapter tries to reuse as many views as possible for performance improvement. That's why you should not create a view in getView, but reuse them (only create if it is null):
if(convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.list_item, parent, false);
}
Even though you shouldn't create a new view, you have to make sure that you set the parameters that you want for each getView call (also called "binding"), so:
if(position == 0){
//set your first view color and whatever
}else{
//set your common view colors..
}
Because listview recycle views Google suggests to use the ViewHolder pattern. You should also set a default color if the cell is different. It would look something like this.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if(convertView == null){
convertView = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
viewHolder = new ViewHolder();
viewHolder.textView = (TextView) convertView.findViewById(R.id.txtListItem);
convertView.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) convertView.getTag();
}
if(position == 0 && club.getName().contains("All")){
viewHolder.textView.setTextColor(ContextCompat.getColor(getContext(), R.color.orange));
}else{
//Set default color
}
viewHolder.textView.setText(club.getName());
return convertView;
}
static class ViewHolder {
protected TextView textView;
}

Weird changes when trying to change color of textview in a list adapter, dynamically

I have a listfragment which I am populating with a adapter extending Base adapter.
I want a textview in one particular to be of a different color.
This is my target: (Forgive me for the "Title" spelling, I was in a hurry)
However when I scroll the list up and down, textviews from different rows also change color randomly,like this:
I have tried with and without viewholders, with the same result. I can't seem to find out what the problem is.
This is my getView method
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolderItem viewHolder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.shedrow, null);
viewHolder = new ViewHolderItem();
viewHolder.txt=(TextView) convertView.findViewById(R.id.textview1);
viewHolder.txt2=(TextView) convertView.findViewById(R.id.textview2);
convertView.setTag(viewHolder);
}
else
{
viewHolder = (ViewHolderItem) convertView.getTag();
}
viewHolder.txt.setTypeface(tf);
viewHolder.txt2.setTypeface(tf);
viewHolder.txt.setText(schedStorage.getProgramTitle(position));
if (position==0)
{
viewHolder.txt2.setTextColor(color);
viewHolder.txt2.setTypeface(tf, Typeface.BOLD);
}
viewHolder.txt2.setText(sTimes.get(position));
return convertView;
}
convertView is a reused View (Row). When you scroll up and down and the first row goes off screen, Android may choose to reuse it when new rows show on-screen. If it gets reused, the color of txt2 will still be set to green. To avoid this, you should set the color and Typeface of txt2 when position != 0.
if (position==0) {
viewHolder.txt2.setTextColor(color);
viewHolder.txt2.setTypeface(tf, Typeface.BOLD);
} else {
viewHolder.txt2.setTextColor(Color.BLACK);
viewHolder.txt2.setTypeface(tf, Typeface.NORMAL);
}

Custom adapter getting wrong position on getView metod in ListView

I have list view with custom array adapter. I want to get items click position from getView method. I am getting a few list view items position but when i add more then 7 items into my list i get wrong position from getView method. I mean when i click 9th list item it returns 1.
Here is my code
#Override
public View getView(int pos, View convertView, ViewGroup parent) {
this.position = pos;
Log.v("View position", Integer.toString(pos));
lineView = convertView;
if(lineView==null)
{
adapterLine=new AdapterLine();
layoutInflater=context.getLayoutInflater();
lineView=layoutInflater.inflate(com.inomera.sanalmarket.main.R.layout.adapter, null,true);
adapterLine.sListText = (TextView) lineView.findViewById(R.id.sListText);
adapterLine.sListCheckbox = (CheckBox) lineView.findViewById(R.id.sListCheckbox);
adapterLine.sListImageView = (ImageView) lineView.findViewById(R.id.imageView1);
adapterLine.gestureOverlayView = (GestureOverlayView) lineView.findViewById(com.inomera.sanalmarket.main.R.id.gestureOverlayView1);
adapterLine.gestureOverlayView.setGestureVisible(false);
// To remember whitch tab is selected
adapterLine.sListImageView.setTag(pos);
adapterLine.sListCheckbox.setTag(pos);
adapterLine.sListText.setTag(pos);
Log.v("adapter", "position of adapter is " + Integer.toString(pos));
Thanks for any help!
The array adapter will only create one object per visible row in your list view. After this, the adapter will recycle that already created view. This is the purpose of the:
if(lineView==null)
line in your adapter.
You will want to put in an else section that sets up the row using the recycled view. This other article may be helpful:
How can I make my ArrayAdapter follow the ViewHolder pattern?
This implementation is incomplete add else section which sets value from data. here is implementation which worked for me
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
LayoutInflater inflator = reportViewContext.getLayoutInflater();
convertView = inflator.inflate(R.layout.tabitems, null);
viewHolder.name= (TextView) convertView
.findViewById(R.id.user_reportTab_userName);
//set other values needed in viewHolder if any
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder)convertView.getTag();
}
//data is list of Data model
if(data.size()<=0) {
//if data unavailable }
else {
/***** Get each Model object from Array list ********/
System.out.println("Position:"+position);
/************ Set Model values in Holder elements ***********/
viewHolder.name.setText(data.get(position).getName());
}
return convertView;
}
I know the question is very old, answered in case anyone stumbled on similar problem

Difficulty in changing the background color of a particular row in an Android Custom ListView

I am confused in changing the background colour of a particular row in an list view, below is the code I tried. Different rows gets highlighted as i scroll the list, I could like to understand the reason behind this. The logic seems to quite simple, but the results are unpredictable. How am I supposed to achieve this.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.rows_for_layout, null);
holder = new ViewHolder();
holder.name = (TextView)convertView.findViewById(R.id.name);
holder.rated=(ImageView)convertView.findViewById(R.id.rated);
convertView.setTag(holder);
}else {
holder = (ViewHolder) convertView.getTag();
}
//selected_position is the position where the list has to be highlighted
if(position==selected_position){
holder.name.setText(elements.get(position).get("name"));
convertView.setBackgroundResource(R.drawable.highlight_this);
holder.rated.setBackgroundResource(R.drawable.star_image);
}else{
holder.name.setText(elements.get(position).get("name"));
}
return convertView;
}//getView ![alt text][1]
Your else statement does not reset the background color to its original. The getView method can recycle a view that was previously in your list but is not visible anymore. If the background was changed, then it will still be that background color from when it was originally created, which can depend on your state.
So, to "reset" that, add the following in your else:
if(position==selected_position){
holder.name.setText(elements.get(position).get("name"));
convertView.setBackgroundResource(R.drawable.highlight_this);
holder.rated.setBackgroundResource(R.drawable.star_image);
}else{
holder.name.setText(elements.get(position).get("name"));
//Add this
convertView.setBackgroundResource(R.drawable.not_highlighted);
}

Categories

Resources