Saturday, May 26, 2018

Finding an element within the same TableRow

Leave a Comment

I'm trying to create a function that pulls together information that is currently scattered around different parts of my project.

As part of this task, I have a layout file with something like the following content... basically a set of rows, with each row having a label (TextView) and a UI element (e.g. CheckBox, Spinner or EditText) to collect information from the user:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     style="@style/MyLinearLayout.Section"     android:id="@+id/section_pressure" >      <TableLayout style="@style/MyTableLayout"         android:id="@+id/table_pressure" >          <TableRow style="@style/MyTableRow" >              <TextView                 style="@style/MyTextView.Label.WithHelp"                 android:tag="label_show"                 android:text="@string/label_show" />              <CheckBox                 style="@style/MyCheckBox"                 android:id="@+id/pressure" />          </TableRow>          <TableRow style="@style/MyTableRow" >              <TextView                 style="@style/MyTextView.Label.WithHelp"                 android:tag="label_unit"                 android:text="@string/label_unit" />              <Spinner                 style="@style/MySpinnerStyle"                 android:id="@+id/pressureUnit" />          </TableRow>      </TableLayout>  </LinearLayout> 

I already have an array of all the android:id values for the UI elements, and from that I want to generate another array of the corresponding android:text labels.

e.g. from R.id.pressureUnit I want to find the associated R.string.label_unit from that TableRow, so that I have a central record of what label is used for each UI element... currently that information is scattered across lots of different layout files.

Is this possible programmatically?

3 Answers

Answers 1

From what I understand you want to find @string resource ID of a sibling view of a given view.

Assuming you have the xml file already inflated, you can do the following:

private int getSiblingStringId(@IdRes int viewId) {     View uiElement = findViewById(viewId);     ViewGroup parent = (ViewGroup) uiElement.getParent();      // iterate through the siblings     for (int i = 0; i < parent.getChildCount(); i++) {         View view = parent.getChildAt(i);         if (view instanceof TextView) {             String value = ((TextView) view).getText().toString();              // found             return getStringIdFromValue(value);         }     }      throw new IllegalArgumentException("no TextView sibling for " + viewId); }  private int getStringIdFromValue(String value) {     // get all fields using reflection     Field[] fields = R.string.class.getDeclaredFields();      for (Field field : fields) {         int stringResId = getResources().getIdentifier(field.getName(), "string", getPackageName());         String s = getString(stringResId);         if (s.equals(value)) return stringResId;     }      throw new IllegalArgumentException("no matching string for " + value); } 

The above code will work inside an activity. You might need to modify it a bit for other classes. (You will need to call findViewById, getResources and getString)

Answers 2

Well, I would set an ID to each table row. Then, programmatically get every child view under each row by iterating over the row's children. From there, you can easily manipulate every view by simply determining which one are you at by using instanceof. But, let's assume you cannot change this, you can still be doing it but it might not be efficient.

Since I don't really know the structure of your array of ids, I just assume its an array of integers called uiIds. Then, you would have to do something like

TableLayout layout = findViewById(R.id.table_pressure); TableRow tr = null; View rowChild = null; TextView tv = null; View secondaryView = null;  int tableChildCount = layout.getChildCount(); int rowChildCount = 0;  // Since I don't really know the structure of your array of ids, // I just assume its an array of integers called uiIds  //This will contain the corresponding text strings of every textview List<String> textLabels = Arrays.asList(new String[uiIds.length]);  // Go over all the rows on your table for (int i = 0; i < tableChildCount; i++) {     // I'm assuming that you only have rows as the children of your table     tr = (TableRow) layout.getChildAt(i); //This is the row      rowChildCount = tr.getChildCount();     tv = null;     secondaryView = null;      // Now go over all the children of the current row i     for (int j = 0; j < rowChildCount; j++) {         // Here I'm also assuming you only have two children on every row         rowChild = getChildAt(j);         // At this point, the view v could be any type of the ones you have         // used. Since we are interested in TextView simply do an instanceof         if ( rowChild  instanceof TextView ) {             tv = (TextView) v;         } else {             // This is the other view in the row. The ones from which you alreade have its ids             // e.g. the spinner with id pressureUnit             secondaryView = rowChild; //We do not need to cast         }     }      // Now we construct the array             if (tv != null && secondaryView != null) {         // The id we just obtained is one from the ones you have already saved         // in an array called uiIds         int secondaryViewId = secondaryView.getId();          //Now, we need to find the index of this id in uiIds         for (int idx = 0; idx < uiIds.length; idx++) {             if ( uiIds[idx] == secondaryViewId ) {                 //We have found a match. Then just add the text of the  textview in the corresponding index of our new array                 textLabels.set(idx,tv.getText().toString());             }         }      }  }  // At this point, textLabels should contain the text of the text view on every row // such that the ith element in the array you already have corresponds to  // ith element of the array we just created.  // In other words, if uiIds[0] is equals to R.id.pressureUnit, then, // textLabels.get(0) is equals to R.string.label_unit 

I have edited the answer directly on the text editor so it might have some sintax erros. Hopefully this solves your problem or at least gives you an idea.

Answers 3

To get overview of your label mappings, I suggest to code more systematically, in this case to name the label just like the id.

  • @+id/pressure => @string/label_pressure
  • @+id/pressureUnit => @string/label_pressureUnit

I know this is not a direct answer to your question. However I think, if you work in this way, you don't need a central table of your mappings at all and your layouts become more readable. Android Studio makes it really easy to do this kind of changes.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment