I have several layout elements which I want to process as an array, for example:
for (int j=0; j< N; j++)
((TextView)findViewById(R.id.groupStart+j)).setText(getRowText(j));
The problem is that Android doesn't understand ID definition like
android:id="#+id/groupStart+1"
Perhaps I can't find right syntax. I can assure certain IDs for element if I add them in a layout grammatically, but I want to define them in resource. I can't also edit R.java because it is automatically generated. Any recommendations?
Use this :
for(int i=0; i<5; i++){
int resID = getResources().getIdentifier("groupStart"+i, "id", getPackageName());
view = findViewById(resID);
}
Where ids are:
android:id="#+id/groupStart1"
android:id="#+id/groupStart2"
.
.
.
Related
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?
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)
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.
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.
I am new in android. I have an array of images:
private int[] textureArrayWin = {
R.drawable.basketball,
R.drawable.soccer
};
Try to dynamically add them to my view:
for(int i=0; i < textureArrayWin.length; i++){
Log.v("asd", "index=" + i);
ImageView tv = new ImageView(this);
tv.setScaleType(ScaleType.CENTER_CROP);
tv.setImageResource(textureArrayWin[i]);
tv.setAdjustViewBounds(true);
tv.setMaxHeight(20);
tv.setMaxWidth(20);
myLayout.addView(tv);
}
But don't know how:
Fit them by "setMaxHeight", they are still big
How to know index of clicked image in array or to receive some id of image which allow to know the unique id of image in my layout. In javascript, for example, I can do it by adding attr to element and in handler receive attribute by "this.getAttribute(someAttr)"
You can use the Id attribute to identify the views.
Assign a Id to each view by:
myView.setId(<some Integer value here>);
You can later refer to same view by:
View v = findViewById(<same Integer value here>);
I am trying to change the values of several TextView elements but iterating through an array list and adding these values. However I can't seem to find a way to change the R.id value that is used each time. For example:
for (int i=0; i<arrayList.size(); i++)
{
TextView t = (TextView) dialog.findViewById(R.id.value+(i));
t.setText(arrayList.get(i));
}
Where the values are in the format animals_eng1,animals_eng2 etc..
Any help appreciated.
Your best bet is to create an array containing the resource IDs of each text view and looping through them..
ex.
int[] textViewIds = new int[] { R.id.animals_eng1, R.id.animals_eng2, R.id.animals_eng3 };
Then in your activity you can loop through them and set the values like you desire
for (int i=0; i<arrayList.size(); i++)
{
((TextView)findViewById(textViewIds[i])).setText(arrayList.get(i));
}
You'll have to make sure your arrayList size is the same as the number of textview resource IDs you set or you'll end up with an out of bounds exception when looping
I don't know of a way to do exactly what you're asking, but here are two alternatives:
1.Create an array of Integers, and assign each element of the array to a different view id value
int[] ids = new int[arrayList.size()];
ids[0] = R.id.view0;
ids[1] = R.id.view1;
ids[2] = R.id.view2;
//...ids[n] = R.id.viewN; where n goes up to arrayList.size()
for (int i : ids){
((TextView)dialog.findViewById(ids[i])).setText(arrayList.get(i));
}
Note that the above method sorta defeats the point because you have to have a line for every TextView, if you want something more dynamic:
2.Tag your TextViews in your layout xml by adding android:tag="prefix0", for example, to each of your TextViews. Before the loop find the parent View of your layout, and then use the findViewWithTag method of that view within the for loop. From your code I'm guessing you're using a Dialog with a custom layout xml, so you'd first find the parent of that:
ViewGroup parent = dialog.findViewById(R.id.parent); //or whatever the name of your parent LinearLayout/RelativeLayout/whatever is
String commonPrefix = "prefix"; //or whatever you've tagged your views with
for (int i=0; i<arrayList.size(); i++){
TextView t = (TextView) parent.findViewWithTag(commonPrefix+i);
t.setText(arrayList.get(i));
}
One way to solve this would be putting your resource ids in an int array and getting the resource at index i.
TextView t = (TextView) dialog.findViewById(R.id.value+(i))
becomes
TextView t = (TextView) dialog.findViewById(resourceArray[i])
if all of your views are on the same container (and only them) , simply iterate over its children .
if not , you can add an array of ids (in res) and iterate over it .
I have a layout the contains 4 TextViews with ids: "Name1", "Name2", "Name3", "Name4"
I would like to iterate on them with a for loop,
is there any way to do this?
something like
for(int i = 1; i <= 4; i++)
{
findViewById(R.id."Name" + i)
}
I know that this code is far from being real, but any help?
Thank you!
Ron
No, you cannot do it like that because R.id.xyz is referencing a static int of a static class. It's not a string that can be concatenated like that. Also, your code ignores the return value of findViewById so it does nothing (though I realize you mentioned the code is far being real, but still an actual use case might help clarify what you're trying to do). R.id."Name" means nothing and will give you a compiler error.
To loop through you can do something like this:
int[] ids = {R.id.foo, R.id.bar};
then
for(int i = 0; i<ids.length; i++) {
View v = findViewById(ids[i]);
}
Sure you can do that sort of. You cannot access an member of R.id using a string literal you must type out the variable name.
R.id."Test" is no good but R.id.Test is fine.
If you examine the type of R.id.XYZ you will find that it is simply an integer. There is no reason why you cannot perform basic arithmetic on id values.
However it doesn't really make sense to do so. When you build your APK the compiler automatically creates a static class called R that contains references to the various resources and assets contained in your APK, such as layouts, drawables, sounds, etc..
Just because you know that the integer value for R.id.button1 is X there is no guarantee that the integer value for R.id.button2 will be X+1, in fact it could be anything.
If you want to create a list of TextViews to iterate over consider adding them to a List and then iterating over the list. Like so:
ArrayList<TextView> list = new ArrayList<TextView>();
list.add( (TextView) findViewById(R.id.textView1) );
list.add( (TextView) findViewById(R.id.textView2) );
list.add( (TextView) findViewById(R.id.textView3) );
list.add( (TextView) findViewById(R.id.textView4) );
int size = list.getSize();
for (int i=0; i< size; i++)
{
TextView tv = list.get(i);
// Do something with tv like set its label to i
tv.setText(Integer.toString(i));
}
I have many buttons in my activity (only a subset of which are visible at a time). I currently have something ugly like this:
buttonID[0] = R.id.buttonr1b1;
buttonID[1] = R.id.buttonr1b2;
buttonID[2] = R.id.buttonr1b3;
buttonID[3] = R.id.buttonr1b4;
...
buttonID[35] = R.id.buttonr1b36;
for (int i = 0; i < 36; i++) {
button[i] = (Button) findViewById(buttonID[i]);
}
Is there a more elegant way to reference all of R.id.buttonXXX ? It just looks so wrong and ugly.
Thank you.
Your instincts are correct. It's ugly and in general if you find yourself wanting to do this you should rethink your design.
If your buttons are uniform to the point where you want to loop over them to do something like this, they're probably uniform enough to generate programmatically in the first place (and you can store references as you create them) or use some form of AdapterView. What data needs to be associated with each button? Can you associate it directly using setTag/getTag? Do you need to use IDs here at all?
I'm not sure if this is more elegant or less elegant, because you will lose compile-time checking of your IDs. However, you can construct the IDs by name:
final static String PREFIX = "buttonr1b";
...
Resources res = getResources();
for (int i = 0; i < 36; i++) {
int resID = res.getIdentifier(PREFIX + i , "id", getPackageName());
button[i] = (Button) findViewById(resID);
}
Note: make sure "getPackageName()" would return the appropriate package for your R class, otherwise specify it explicitly.