0

Scroll down for my answer. The question doesn't really matter and the code is just confusing.

Is there a function that will allow me to fetch the id labels so I can loop a button listener easily? Currently I have in my main "container" xml that houses fragments this line of code:

public static final Map<String, Integer> RMAP = createMapR();
// Map of widget id's in R

private static Map<String, Integer> createMapR() {
    Map<String, Integer> result = new HashMap<String, Integer>(); 
    for (Field f : R.id.class.getDeclaredFields()) {
        String key = f.getName();
        Integer value = 0;
        try {
             value = f.getInt(f);
        }
        catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
        catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        result.put(key, value);
    }
    return Collections.unmodifiableMap(result);
}

and then one of my fragments will pick up the RMAP, and cross that with the labels I have specified. I'm doing this because I have a few buttons and specifying a huge list of listeners seemed inefficient, then I got sidetracked on this code.

public class BottomFragment extends Fragment {  
private final String[] LABELS = {"button_do_1", "button_woah_2", "button_foo_1", 
                                 "button_hi_2"};

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
         Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.bottom_fragment, container, false);
    for (String item : LABELS) {
            if (Container.RMAP.containsKey(item)) {
            ((Button) v.findViewById(Container.RMAP.get(item)))
                .setOnClickListener(this);
        }
    }
    return v;
}

However if there was a way to iterate through the list of android:id items specifically to BottomFragment() I wouldn't have to even need the first block of code and it would eliminate the manual list of ID's I've typed in.

Steven
  • 177
  • 13
  • The code above works. However if I were able to get the list of ID's for that specific fragment, I could add the button onClick listeners all at once in a nice loop instead of 15+ lines of setOnCLickListener(this). Right now I'm using two lists. One is populated automatically, which contains every R.id() variable. In my case it's mostly buttons and a few other widgets. – Steven Jul 21 '13 at 17:42
  • If that type of function doesn't exist, or a combination of functions that can be used to get the widget id's for that view, then that's fine, the above code works, it's just not automatic as I have LABELS where I type the ID's in manually. – Steven Jul 21 '13 at 17:43
  • 1
    You should be using a SparseArray for this kind of thing: https://developer.android.com/reference/android/util/SparseArray.html – hwrdprkns Jul 21 '13 at 17:53
  • Good to know hwrdprkns. I'm still breaking in my skills and little tidbits like this are appreciated. – Steven Jul 21 '13 at 17:58
  • 1
    Check this out: http://stackoverflow.com/questions/3920833/android-imageview-getid-returning-integer – samus Jul 21 '13 at 18:47

2 Answers2

0

Here's a rough logic sketch (in C#)... It basically does a single, top down pass over the layout, building an id-to-view map that can be looped through afterwards. There is know general way to do this, and so will have to be maintained along with the layout file (both need to be modified together).

Say you want to do this in OnCreate of the Activity that is hosting your fragment(s) (it could possibly be done in the Fragments OnMeasure or OnLayout overrides too)

Assuming your fragment's layout file has the following structure


LinearLayout

   TextView 
   TextView 

   RelativeLayout

      EditText
      EditText

   TextView

public override OnCreate()
{
   Map<int, view> idLabels = new Map<int, view>();

   View v = fragment.View;

   LinearLayout ll = (LinearLayout) v;
   idLabels.Add(ll.Id, ll)

   TextView tv1 = (TextView) ll.GetChildAt(0);
   idLabels.Add(tv1.Id, tv1)

   TextView tv2 = (TextView) ll.GetChildAt(1);
   idLabels.Add(tv2.Id, tv2)

   RelativeLayout rl = (RelativeLayout) ll.GetChildAt(2);
   idLabels.Add(rl.Id, rl) 

   // notice the numbers being passed to GetChildAt, its a traversal of Views and Viewgroups !

   EditText et1 = (EditText) rl.GetChildAt(0);
   idLabels.Add(et1.Id, et1)

   EditText et2 = (EditText) rl.GetChildAt(1);
   idLabels.Add(et2.Id, et2)

   // now, go back "up" to top-most, linear layout viewgroup and get remaining views, if any

   TextView tv3 = (TextView) ll.GetChildAt(3);
   idLabels.Add(tv3.Id, tv3)

   ...  

   foreach(int id in idLabels)
   {
       if(id == R.id.myViewIdLabel) // your R file will have all your id's in the literal form.
       {
           View v = idLabels.Map(id);
           v.SetOnClickListener(this);
       }  
   }

}

This may not be the best way, but it should work.

samus
  • 6,102
  • 6
  • 31
  • 69
0

I figured it out. The solution lies within the children of a ViewGroup. This code adds listeners for every button in that particular view. In this case the view is a fragment of only buttons. This code is handy for whenever you have lots of buttons and you want to add a listener to each one.

public static void addButtonListeners(View v, OnClickListener clickListener)
{
    ViewGroup widgets = (ViewGroup) v;
    for(int i = 0; i < widgets.getChildCount(); ++i)
    {
        View child = widgets.getChildAt(i);
        if (child instanceof Button)
        {
            Button nextButton = (Button) child;
            nextButton.setOnClickListener(clickListener);
        }
    }
}

You need to pass the view and listener to this function. The listener can by passed by just passing "this", i.e:

addButtonListeners(v, this);
Steven
  • 177
  • 13