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.
0 comments:
Post a Comment