2

In my Android project, I need to find views in my Activity by their tags rather than their IDs. (If you ask me why I don't simply use findViewById, It's not my prefer, and is complicated to describe, but currently I can't rely on R.id. constants!) So far, to find views in my code, I have managed to use this successfully:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.index);
    mainViewGroup = (ViewGroup)getWindow().getDecorView();
    TextView indexCaption = (TextView) mainViewGroup.findViewWithTag("index_caption");
    // Now I have my TextView and can use it without problem
}

But now, the problem is my custom ArrayAdapter in the same activity:

    class IconicAdapter extends ArrayAdapter<String> {
    IconicAdapter() {
                    // How I can use Tag instead of R.layout.index_row_caption here?!!!
        super(IndexActivity.this, R.layout.index_row, R.id.index_row_caption, arrayList);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = super.getView(position, convertView, parent);
                    // Some customizations...
        return (row);
    }
}

and index_row.xml for that IconicAdapter:

android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/content_bg" >

<TextView
    android:id="@+id/index_row_caption"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:layout_toLeftOf="@+id/index_row_icon"
    android:layout_toRightOf="@+id/index_row_search"
    android:gravity="right"
    android:tag="index_row_caption"
    android:textAppearance="?android:attr/textAppearanceLarge" />

<ImageView
    android:id="@+id/index_row_icon"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:tag="index_row_icon" />

<ImageView
    android:id="@+id/index_row_search"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_centerVertical="true"
    android:src="@drawable/index_row_search"
    android:tag="index_row_search" />

How I can avoid using R.id.index_row_caption in the constructor and replace it with something related to its tag?

EDIT: At last, I have ended up to this code and it worked great: (credits and bounty goes for pawelzieba who helped me on this)

    class IconicAdapter extends ArrayAdapter<String> {
    IconicAdapter() {
        super(IndexActivity.this, R.layout.index_row, 0, arrayList);
    }

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

        View view;
        if (convertView == null) {
            LayoutInflater mInflater = IndexActivity.this.getLayoutInflater();
            view = mInflater.inflate(R.layout.index_row, parent, false);
        } else {
            view = convertView;
        }

        //find views
        TextView text = (TextView) view.findViewWithTag("index_row_caption");

        //fill views with data
        text.setText(arrayList.get(position));          

        return view;
    }
}
yrajabi
  • 637
  • 1
  • 9
  • 28
  • you have to find a way to be able to rely on R.id constants, that's how android works. Also, id is made to be unique and to index view, tag is simply a extra data. It is not indexed, and not unique. – njzk2 Sep 03 '12 at 09:37
  • @njzk2 Yes, I know R.id is very better and android works with them. But in my current project, I need to alter some layouts, and add some widgets to them AFTER my code has compiled and classes.dex has been created. Then I would recompile my resources by aapt.exe, and This, would change R.id constants. So I can't rely any R.id in my code. Yes, It's not normal, but is my case just right now! – yrajabi Sep 03 '12 at 09:47
  • if you declare the ids a priori, i'm not entirely sure it would change the ids when you would recompile – njzk2 Sep 03 '12 at 10:01

3 Answers3

2

Extend ArrayAdapter and override getView() method.

public View getView(int position, View convertView, ViewGroup parent) {
    View view;

    if (convertView == null) {
        view = mInflater.inflate(R.layout.index_row, parent, false);
    } else {
        view = convertView;
    }

    //find views
    TextView text = (TextView) view.findViewWithTag("index_row_caption");

    //fill views with data
    //example:
    T item = getItem(position);
    text.setText(item.toString());


    return view;
}

Then row resource id passed to constructor is unused.

To get better performance use View Holder Pattern to call findViewWithTag only once on create row's view: http://www.vogella.com/articles/AndroidListView/article.html#adapterperformance_hoder

pawelzieba
  • 16,082
  • 3
  • 46
  • 72
  • You mean I completely remove this line? super(IndexActivity.this, R.layout.index_row, R.id.index_row_caption, arrayList); – yrajabi Sep 08 '12 at 15:27
  • You can't override constructor. You can create your own without resource id. Or you can create general purpose adapter which uses tag instead of id, then you could pass tag to constructor. It's up to your needs. – pawelzieba Sep 08 '12 at 15:30
  • Ok, I tried to rewrite my IconicAdapter based on your answer. please take a look at my edited question (last part) and see if it is what you mean? is it the real solution? – yrajabi Sep 08 '12 at 15:44
  • Thanks so much, I managed to do it by using your answer and hints. now it works without using any IDs. I think now it's time to optimize it by using ViewHolder which you suggested. – yrajabi Sep 08 '12 at 16:18
  • I'm glad it helped. Have fun while coding. – pawelzieba Sep 08 '12 at 16:27
1

If you want to use R.id values as a constant, you can declare them in public.xml. The resource ids will remain constant across the builds. SO you dont have to use tags just because you need constant ids.

Check this post

Community
  • 1
  • 1
nandeesh
  • 24,740
  • 6
  • 69
  • 79
  • Great! Where were you till now?!! :) However I solved the "always constant" id problem in a hacky way by adding underscore sign "_" to first of resources names, but your hint is very valuable for me. I accepted pawelzieba's answer as it was exact solution to the question on this page, but you really pointed to a nice and more global solution. Thanks very much. – yrajabi Sep 08 '12 at 21:38
  • I get stuck again! please see my new question about public.xml http://stackoverflow.com/questions/12334857/how-to-add-id-to-public-xml – yrajabi Sep 08 '12 at 22:07
0

You can do this by following:

Add the android:tag="someTag" attribute to your view in xml layout file.

And to access that view, simply use:

findViewByTag(); method

In this way you can access your views via tags and not by id's.

Shrikant Ballal
  • 7,067
  • 7
  • 41
  • 61
  • If you mean findViewWithTag(), I have currently used that for normal views, but my question was actually about using tag in the constructor of my ArrayAdapter. On which view I should call findViewWithTag()?! – yrajabi Sep 03 '12 at 09:50