Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically accessing a view that is defined in a fragment's XML in Android

I'm in the process of making an Android 3 app that has a tab-based navigation. Being quite new to Android I searched for tab tutorials and found a few different approaches, out of which an implementation based on Fragments + ActionBar seemed to be the best. I followed these tutorials

http://www.abelski.com/courses/android3ui/actionbar.pdf (the last few slides) and http://www.youtube.com/watch?v=gMu8XhxUBl8 (same lesson in video format)

...and got to the point where the tabs show up, I can switch between them OK, and simple TextViews inside them show up fine.

Now, problems arise when I want one of the tabs to have a spinner widget that is defined in the fragment's XML file and populate it with items that are defined in the strings.xml file. When I try to access the spinner with getViewById() from the onCreate() method I always get a null value as a result.

As I understand it, to fix this I need to somehow declare the XML of the fragment (similarly like main layout has been done with setContentView(R.layout.main)) so that getViewById() knows where to look for the spinner (Eclipse's autocomplete finds it already though). However, I'm at complete loss how to do this, since none of the tutorials tackled the scenario where you want to modify the XML-based Fragments' contents inside the code.

The main.xml looks like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">


<LinearLayout android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:id="@+id/fragment_placeholder"></LinearLayout>

</LinearLayout>

tab1_fragment.xml like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical" 
              android:layout_width="fill_parent" 
              android:layout_height="fill_parent">

    <Spinner android:id="@+id/spinner1" 
             android:layout_width="wrap_content" 
             android:layout_height="wrap_content"/>
</LinearLayout>

and onCreate method like this:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    ActionBar ab = getActionBar();
    ab.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    ActionBar.Tab newAuditTab = ab.newTab().setText(R.string.tabheader_new_audit);
    Fragment newAuditFrag = new FragmentTabNewAudit();
    newAuditTab.setTabListener(new TabListener(newAuditFrag));
    ab.addTab(newAuditTab);

    //and the same for other tabs

    Spinner spinner = (Spinner) findViewById(R.id.spinner1); // this returns null
    ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
            this, R.array.cell_array, android.R.layout.simple_spinner_item); //cell_array is defined in strings.xml


    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);
    spinner.setOnItemSelectedListener(new MyOnItemSelectedListener());  
}

Accessing the views that are defined in main.xml via R.id works fine, so in this case the problem isn't related to Eclipse's auto-importing of the R class, I think.

I guess I could define the spinner programmatically to get around the issue, but there is probably a more elegant solution to this, I hope. I can't see the Android big picture well enough yet to quite know where to look.

like image 340
tway Avatar asked Sep 29 '11 13:09

tway


1 Answers

As the spinner is not a child of the Activity itself, findViewById can not find it. As the spinner is a child of the fragment, you might try:

Spinner spinner = (Spinner)newAuditFrag.getView().findViewById(R.id.spinner1);

However, I'm not sure when the view for a fragment is created, so getView() might also return null that that point in your code. You could then try to move the code into onResume, which is called after onCreate.

like image 130
Thorsten Dittmar Avatar answered Sep 17 '22 18:09

Thorsten Dittmar