0

I have a list which is populated by my database. Each list row has a text view and two buttons. I want to cycle through all list rows and check the text of each text view that is inside the list and change one of the buttons backgrounds depending on the text read in.

Here is my code:

Button fav, trash;
ListView lv;
TextView tv;
Cursor data;
CursorAdapter dataSource;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.hs);


        tv = (TextView) this.findViewById(R.id.first);
        trash = (Button) this.findViewById(R.id.trashButton);
        fav = (Button) this.findViewById(R.id.favButton);



        data.moveToNext();

        dataSource = new SimpleCursorAdapter(this, R.layout.phrasebook, data,
                fields, new int[] { R.id.first}, 0);

        lv = (ListView) findViewById(R.id.list_view);

        lv.setAdapter(dataSource);

You can see that the list is populated by the data source and the text view "first" is filled with strings. I want to loop through each list row read the text view and then change the button background depending on what the text is. My problem is how do you get the id's of the text views and buttons?

I read up and discovered get child and parent but not sure if this is along the right track. I thought if I could access the list rows by id then access its children then I could do it this way but I don't know if this is possible. Any advice is appreciated.

I have experimented with creating a custom adapter, I have it working and also found a way to access positions, I am hoping to exploit this to maybe access the text views.

public class AdapterEx extends SimpleCursorAdapter {

private Context mContext;
private Context appContext;
private int layout;
private Cursor cr;
private final LayoutInflater inflater;
TextView tv;

public AdapterEx(Context context,int layout, Cursor c,String[] from,int[] to) {
    super(context,layout,c,from,to);
    this.layout=layout;
    this.mContext = context;
    this.inflater=LayoutInflater.from(context);
    this.cr=c;
}

@Override
public View newView (Context context, Cursor cursor, ViewGroup parent) {
        return inflater.inflate(layout, null);
}

@Override
public void bindView(View view, Context context, Cursor cursor) {
    super.bindView(view, context, cursor);
     tv=(TextView)view.findViewById(R.id.first);
     if(cursor.getPosition()%2==1) {
         view.setBackgroundColor(Color.rgb(206, 43, 55));
          }
          else {
              view.setBackgroundColor(Color.rgb(0, 146, 70));
          }

}

}
deucalion0
  • 2,422
  • 9
  • 55
  • 99
  • I think it's easier to create a custom adapter and while inserting the information at the custom adapter you checks the text and change the background button. – Jonas452 Jul 30 '14 at 15:13
  • Thank you for your response. I am new to adapters etc, could you show me a simple example of how I can convert my code to your suggested way? – deucalion0 Jul 30 '14 at 15:15
  • 1
    move all the getView logic into bindView and get rid of the getView method – Ifrit Jul 30 '14 at 17:22
  • I moved it and it still works :) Any thoughts on how I can achieve my goal? Cheers! – deucalion0 Jul 30 '14 at 17:31

2 Answers2

2

Here is an example:

public class AdapterEx extends ArrayAdapter<String>
{

//You are going to pass a array of String, that you'll use at the textview.

Context context;
int resourceId;
ArrayList<String> tempStrings;

public AdapterEx ( Context context, int resourceId, ArrayList<String> tempStrings) 
{

    super( context, resourceId, tempStrings);

    this.context = context;
    this.resourceId = resourceId;
    this.tempStrings= tempStrings;

}

//In this class you'll declare everything that you'll use from your xml file, like        textview, buttons and etc.
private class ViewHolder
{

    TextView textViewsHere;

    Button buttonsHere;

}

@Override
public View getDropDownView(int position, View convertView,ViewGroup parent) 
{

    return getCustomView(position, convertView, parent);

}

@Override
public View getView( int position, View convertView, ViewGroup parent )
{

    return getCustomView(position, convertView, parent);

}

private View getCustomView( int position, View convertView, ViewGroup parent )
{

    View row = convertView;

    ViewHolder holder = null;

    if( row == null )
    {

        LayoutInflater mInflater = ( ( Activity ) context ).getLayoutInflater();
        row = mInflater.inflate( resourceId, parent, false );

        holder = new ViewHolder();

        //Now you are going to link from layout using your holder. Example:
        holder.textViewsHere = (TextView) row.findViewById( R.id.textViewsHere );

        row.setTag( holder );

    }else
    {

        holder = ( ViewHolder ) row.getTag();

    }

    //After doing the link between java code and xml.
    //You are going to set the value at the textView, buttons and whatever you want.
    //You pass to this class a arrayList<String> with the values that you want at the textview.

    String valueForTheTextView = tempStrings.get(position);

    holder.textViewsHere.setText( valueForTheTextView  );

    if( valueForTheTextView .equals("whatYouWantHere"))
    {

         button.changeTheButtonBackground(); //Example

    }

    return row;

}

}

To use that you do the same with other adapater something like that AdapterEx temp = new AdapterEx( activity.this, R.layout.YOUHAVETOCREATEYOURLAYOUT, theDataHere );

Jonas452
  • 420
  • 6
  • 19
  • Thank you I will try this, although I am not so sure what it is exactly. So in my class I will use this adapter instead of the SimpleCursorAdapter which I currently use? I am not sure what yourobjecthere is, I created a new class copying your code and this is giving me errors. Thank you! – deucalion0 Jul 30 '14 at 15:27
  • 1
    Yes, You should use that instead of SimpleCursorAdapter. And to do so, you have to create your on XML file, that'll have textView and 2 buttons. The YourObjectHere could be a MODEL of what you are passing to the adapater, if you are passing only String, just use String there. Here is a good tutorial: http://www.vogella.com/tutorials/AndroidListView/article.html – Jonas452 Jul 30 '14 at 15:30
  • Thank you Jonas I think I will finally learn about custom adapters! I have a couple of questions. I am creating this from your code above, but in the constructor the third parameter in super "animaisArrayList" is giving me an error, should this be temp instead? Also at the bottom you have YourObjectHere.get(position).getText() what is YourObjectHere? I think I understand a lot more now than I did before. Thank you! – deucalion0 Jul 30 '14 at 16:15
  • 1
    @deucalin0 Sorry, "animaisArrayList" is a veriable from my code, you have to forget about yourobjecthere, this is the String that you'll pass, What you'll do: Pass a ArrayList to that class, instead of the yourobjecthere, and use it to fill the textview. – Jonas452 Jul 30 '14 at 16:39
  • I am also getting problems because I use a SimpleCursorAdaptor and I don't think your example is this type, or is it? – deucalion0 Jul 30 '14 at 16:40
  • Do it: AdapterEx adapter = new AdapterEx( YOURACTIVITY.THIS, R.layour.YOURXML, YOURARRAYLISTWITHTHESTRINGS ); And pass this adapter to the listView.setAdapter( adapter ); Change everything that is uppercase. – Jonas452 Jul 30 '14 at 16:41
  • 1
    Give me a minute, i'll improve my example. – Jonas452 Jul 30 '14 at 16:41
  • Thank you for your updated code! One thing that I am not sure about as I use Simple Cursor Adapter, if you look at the third last line in my code you will see that the constructor should take a few more things, should I just add these to the constructor and it will work? Thanks! – deucalion0 Jul 30 '14 at 16:51
  • I couldn't understand your code, do you know what is MVC? I think you should learn and use it. I do things in a diferent way that you are doing and works for me, you have to add this code that I gave to what you need. – Jonas452 Jul 30 '14 at 16:56
  • Dude, his code is fine. The problem is that you are asking him to convert each db row returned from a cursor into a class object that can then be loaded into an ArrayList...all in the name of using an ArrayAdapter. While possible, it's a slow to do, inconvenient, and bad design. – Ifrit Jul 30 '14 at 17:01
  • @JaySoyer Isn't that the intention of MVC? When you transform the data returned from the db into a model and use this to fill something in the view. – Jonas452 Jul 30 '14 at 17:04
  • Sorta. Adapters are the controllers, right. They determine how the data is mapped to the views. How the data is stored can be different. It doesn't have to be an ArrayList. In this case it's a Cursor. Anything in the cursor has already been read off of a disk. It's the model of the data in memory. Just like an ArrayList can be a model of some form of data. That's why CursorAdapters came about. To map Cursor data models to view. – Ifrit Jul 30 '14 at 17:08
  • I'll search more about it. I do things as I shown in this code, and it's working really fine to me. – Jonas452 Jul 30 '14 at 17:13
  • I am seriously lost now :) How is it so complicated, all I want to do is change the background of a button in the list item depending on the text in a text view :( I also experimented with the code in the post you suggested Jay, I basically have a custom simple cursor adapter now which works, all I need to do is implement the additional functionality that Jonas has suggested, but I am not sure if it ties in with this adaptor? I will post my custom adapter code. Thanks! – deucalion0 Jul 30 '14 at 17:15
  • Haha. Yeah we are branching off into design philosophy and making it sound more complicated then what's it worth. However deucalion0, you're spot on. Jonas452, if you always convert your cursors into ArrayLists more power to you. Sometimes that's required, and I don't think that case applies here...especially so the OP was using the CursorAdapter just fine. – Ifrit Jul 30 '14 at 17:21
1

I disagree with Jonas452. If your data is coming from a DB, it does not make sense to force convert your data to an ArrayList simply to use an ArrayAdapter. That defeats the purpose of why CursorAdapter's exist.

Jonas452 is correct that you need to implement a custom view (which is totally possible with CursorAdapters)...however they work slightly different. Here's a great simple example showing and explaining how to do what Jonas452 talked about but with using a SimpleCursorAdapter:

Custom CursorAdapter

Once you have your bindView() method implemented, you will use this method to actually assign the data from the cursor into the TextView. Because you have the data on hand, you can choose how to render the buttons right there. The Cursor will always be at the correct row position to pull the data for. That's because bindView will be called for every item displayed in your list. The cursor passed in there will always represent the data for that given item. So whichever column the string is stored in the cursor, is the string value to use to determine what to do with your buttons.

@Override
public void bindView(View view, Context context, Cursor cursor) {
   tv=(TextView)view.findViewById(R.id.first);
   //...find your other views

   String text = cursor.getString(cursor.getColumnIndex("Your Column Name"));
   tv.setText(text);
   if (text.equals("test here")) {
       //...change button stuff
   } else {
       //...change button stuff
   }

   //....do whatever else you may need
}

Addendum, once you feel comfortable with this, I suggest learning about the ViewHolder paradigm. It's a highly recommended approach with any custom adapter. Here's another link demonstrating on using it with CursorAdapters.

Community
  • 1
  • 1
Ifrit
  • 6,791
  • 8
  • 50
  • 79
  • Thanks Jay I am looking at this example now – deucalion0 Jul 30 '14 at 16:42
  • Code was typed up on the spot...but is the basic gist of what you need to do – Ifrit Jul 30 '14 at 17:53
  • I could kiss you. After a week of trying to do this I finally got this working!! Thank you very much for your help!!! Man I am so happy to get this piece of coding behind me!!!! :)))))))))))))))))) – deucalion0 Jul 30 '14 at 17:55
  • 1
    My pleasure. I added once last addendum for further learning when customizing adapters. – Ifrit Jul 30 '14 at 17:56