Colouring a listview custom item element basing on value - android

I have a simple (?) problem that I can't seem able to fix.
I have to populate a listview with two columns - two string arrays.
I managed to do so, after searching a lot (see here).
Now, what I need to do is to colour the background of the second item red, purple or blue depending on its value.
Is it possible?
I know that many things can be done with custom listviews, even assigning different images based on a particular value.
Thank you in advance.

In your listadapter (for example see http://www.vogella.com/articles/AndroidListView/article.html#adapterown_example) override getView() and when setting the value of the second textview set its background color. e.g.:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.rowlayout, parent, false);
TextView textView = (TextView) rowView.findViewById(R.id.label);
textView.setText(values[position]);
String s = values[position];
if (s.startsWith("red")) {
//BACKGROUND COLOR CHANGE
textView.setBackgroundColor(getResources().getColor(R.color.your_red));**
}
return rowView;
}

Related

Change Listview item background

As Adapter for ListView, I am using custom adapter. On Adapter's getView method, I am trying to change listitem's background image using setBackgroundDrawable.
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
CurrencyModel currency = new CurrencyModel();
currency = currencyList.get(position);
if (convertView == null) {
vi = inflater.inflate(R.layout.listitem_currency, null);
}
TextView tvSymbol = (TextView) vi.findViewById(R.id.tvSymbol);
TextView tvSize = (TextView) vi.findViewById(R.id.tvSize);
TextView tvName = (TextView) vi.findViewById(R.id.tvName);
TextView tvRate = (TextView) vi.findViewById(R.id.tvRate);
tvSymbol.setText(currency.getSymbol());
tvSize.setText(currency.getSize());
tvName.setText(currency.getName());
tvRate.setText(currency.getRate());
if (currency.getSymbol().equals("AUD")) {
vi.setBackgroundDrawable(context.getResources().getDrawable(
R.drawable.bg_exch_high_cell));
}
return vi;
}
When activity starts, everything is working correctly - listitem with AUD has different background. All mystery starts when I scroll the listview - other listitems also get "special" background. The more scroll, the more listitems changed. I do not have idea why this is happening. How to solve this problem?
if (currency.getSymbol().equals("AUD")) {
vi.setBackgroundDrawable(context.getResources().getDrawable(
R.drawable.bg_exch_high_cell));
}
else {//restore default background}
This happens because cell views are reused by listview. You should restore default background for other items.
More about list view performance
TextView tvSymbol = (TextView) vi.findViewById(R.id.tvSymbol);
Before this line add the default background the you put to the item. The reason in your code why it happens is that android try using the the already created view(vi). Since if it is assigned bg_exch_high_cell, it will retain it. So reset it in the beginning.
vi.setBackgroundDrawable(context.getResources().getDrawable(
//default background drawable here ));
TextView tvSymbol = (TextView) vi.findViewById(R.id.tvSymbol);

How to save and maintain ListView items states after scroll?

After looking for some answers here, I find myself in a disturbing situation where my Listview is really getting on my nerve.
Here are the questions I looked for :
Maintain ListView Item State
How to save state of CheckBox while scrolling in ListView?
I'm using a custom adapter with a custom row as below.
My Listview is simple as it is displaying a custom row made of three elements :
1) an ImageView displaying contact picture cropped in a circle ;
2) a TextViewdisplaying the contact full name as plain text ;
3) and finally an ImageView that holds the purpouse of a CheckBox.
Please focus on the last element. The ImageView CheckBox-like will have its src changed upon click.
When the user click, the ImageView will switch between a check sign and an unchecked sign according to it's previous status. Possible status are : {checked | unchecked}
So far so good.
But as soon as I scroll the ListView, any aforementioned change will disappear as Android recycle unused view.
Here comes the so-called ViewHolder pattern. Unfortunately, this pattern is failling me on two issues :
First, when scrolling, my organized-in-an-alphabetical-order listview gets disorganized.
e.g. somehow, whitout any reason, the first displayed contact name gets displayed again later on the ListView as I scrolled. That can happen with any row ! So it would seem unused view are being wrongly re-used.
Second, and in accordance to the first issue, the checked status do seem to stay, but not always and if it does stay, it may very well stay on the wrong row ... and that can happen randomly, of course. Therefore ViewHoder is not a viable solution.
Before discouvering the ViewHolder pattern, I have been using a HashMap to store the item position upon click as followed :
ContactsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public final void onItemClick(final AdapterView<?> adapterView, final View view,
final int position, final long id) {
final ImageView check = (ImageView) view.findViewById(R.id.checkImage);
final TextView name = (TextView) view.findViewById(R.id.contactName);
final Boolean isChecked = Boolean.valueOf(checkedContactsList.isChecked(position));
if (isChecked != null && isChecked.booleanValue() == true) {
check.setImageDrawable(getActivity().getResources().getDrawable(R.drawable.unchecked_sign));
checkedContactsList.(position);
} else {
check.setImageDrawable(getActivity().getResources().getDrawable(R.drawable.checked_sign));
checkedContactsList.add(position, true);
}
}
});
I tried adding a different value instead of position.
I tried with ContactsListView.getPositionForView(view)
And I also tried with the View's ID, but still it doesn't work.
I wish I could use ContactsListView.getSelectedItemPosition() but it returns -1 as there is no selection event because I'm handling a touch/click event.
And this is how my Custom Adapter looks like :
public final View getView(final int position,
final View convertView, final ViewGroup parent) {
final LayoutInflater inflater = (LayoutInflater) this.context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View contactRowView = inflater.inflate(R.layout.contact_row, parent, false);
final ImageView contactPic = (ImageView) contactRowView.findViewById(R.id.contactPic);
final TextView contactName = (TextView) contactRowView.findViewById(R.id.contactName);
final ImageView checkImage = (ImageView) contactRowView.findViewById(R.id.checkImage);
// the list is the same as above and therefore contains the exact same entries
if (this.checkedContactsList.isChecked(position))
checkImage.setImageDrawable(this.context.getResources().getDrawable(R.drawable.checked_sign));
contactPic.setImageBitmap(cropePictureInCircle(this.contacts.get(position).getPicture()));
contactName.setText(this.contacts.get(position).getName());
return contactRowView;
}
Is there a good way to keep the checked row checked and the unchecked row unchecked in the given alphabetical order ?
Thanks !
For the list position change I know the solution but for the second problem I am still searching for a solution, anyway first make a viewHolder class;
public class ViewHolder{
//put all of your textviews and image views and
//all views here like this
TextView contactName;
ImageView checkImage;
ImageView contactImage;
}
Then edit your adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
final View contactRowView = convertView;
ViewHolder holder;
if (contactRowView == null) {
final LayoutInflater inflater = (LayoutInflater)
this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE
);
contactRowView =
inflater.inflate(R.layout.contact_row, parent,
false);
holder = new ViewHolder():
holder.contactPic = (ImageView)
contactRowView.findViewById(R.id.contactPic);
holder.contactName = (TextView)
contactRowView.findViewById(R.id.contactName);
holder.checkImage = (ImageView)
contactRowView.findViewById(R.id.checkImage);
contactRowView.setTag(holder);
} else {
holder = contactRowView.getTag();
// the list is the same as above and therefore contains the exact same entries
if (this.checkedContactsList.isChecked(position))
holder.checkImage.setImageDrawable(this.context.get.
Resources().getDrawable(R.drawable.checked_sign));
holder.contactPic.setImageBitmap(cropePictureInCircle(this.contacts.get(position).getPicture()));
holder.contactName.setText(this.contacts.get(position).getName());
return contactRowView;
}
}
Hope this helps and sorry because writing code from my phone is totally awkward.

Erratic behaviour of listview (Android)

In my listview I have a custom Adapter, which I build using a TreeMap, I defined the getView method which is as follows. I am trying to strike out the text in a certian textview of the listview on click, only those textviews will be striken off which contain a certain pattern of characters (y#y). However on clicking one row in the listview I am getting strike out effect on some other row.
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = inflater.inflate(R.layout.chklistlayout, parent, false);
}
TextView textView = ((TextView) convertView.findViewById(R.id.textView1));
TextView imageview = ((TextView) convertView.findViewById(R.id.textView2));
textView.setText(values[position]);
imageview.setText(mValues[position]);
String s = mValues[position];
if (s.contains("y#y")) {
System.out.println("In if of getview");
System.out.println(s);
imageview.setPaintFlags(imageview.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
} else {
}
return convertView;
}
}
I tried using a holder pattern too, using a static holder class, but the problem seems to persist. Any pointers?
this answer is half mine and half from Muhammad Babar that we both commented on the question making together a quite nice answer:
use else block to handle this, imageview.setPaintFlags() not to strike
that happens
Because of the convertView. When you scroll the list the same view
that was used before is give back to getView method. So the same
imageView that you painted with StrikeThrough before is still painted
with it. So you have to revert that action.
more over, because of this recycling, usually dealing with Adapters you must ALWAYS undo/revert/repaint/change text/change image to all the elements to make sure it will be on screen the way you want.
ps.: now you should apply a Holder pattern to get better performance.

How to acces listview item during creation/start of activity?

For my application i retrieve a number from the database. When the activity starts up it has to show the number in a different color then the other numbers in the list.
After retrieving the data from the database this is my code:
int row = 5;
TextView child = (TextView)ListView.GetChildAt(row);
child.SetTextColor(Color.Red);
This code was placed in the OnCreate function. I kept getting a null value back for the child textview. I then found out that the reason for the null value is that in the OnCreate function the listview still needs to be rendered. I then moved the code to the OnStart() function but this didn't work either.
Can anyone tell me how I should retrieve the child row from the listview during the creation/start of the activity?
even if you will be able to do it this way you will experience problems with this view getting recycled .. (you will see other views getting colored with red when you scroll up and down).
You need to override your adapter and set the view's color in the position you want
under getView() -
TextView myText = (TextView) view.findViewById(R.Id ....
if (pos==5)
myText.setTextColor(Color.Red);
else
myText.setTextColor(Color.Black); //original color..
EDIT:
you don't need to have a custom xml. if you find android's xml you can find its id. I believe its android.R.id.text1 . so your adapter should look something like
myAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1) {
#Override
public View getView(int position, View v, ViewGroup parent) {
if (v == null) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(android.R.layout.simple_list_item_1, null);
}
View view = super.getView(position, v, parent);
if (position==5)
view.setTextColor(Color.Red);
else
view.setTextColor(Color.Black); //original color..
}
myList.setAdapter(myAdapter);
not sure I got it all right but something like that..
hope it helps.

How do I set a background color for each item in a list view based on content

So I've been modifying the notepad tutorial code: http://developer.android.com/resources/tutorials/notepad/notepad-ex1.html .
Basically what I want to do is to create specific layout styles (i.e. background color) for different rows within the ListView based on the content. So for example, the text for the title is "1" so the background of that row will be red. Or, if the text for the title is "2" then the background of that row (or list item) will be green.
What I'm trying to accomplish is to have a summary of the the rows in the database and color-code each row based upon what category (numerical field) the item is stored as.
They use SimpleCursorAdapter, and you need to write your own in order to change the output. In your adapter, which handles the presentation of your data, you can override the method getView(). Then populate each row with the data from the db. And depending on the data, set a different background color.
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.my_layout, null);
}
Cursor.moveToPosition(position);
ImageView img = (ImageView)v.findViewById(R.id.bg);
if (Cursor.getString(Cursor.getColumnIndex("column")).equals("black")) {
img.setImageBackground(Color.Black);
}
return v;
Hwa Rang's answer is correct. You might also want to use the getItem method to get the item at a particular position on the list to determine what type of data it is. Then change the background color of that row in getView method

Categories

Resources