Easier way to get view's Id (string) by its Id (int) - android

I have 24 buttons in my layout, all these buttons do something similar so I want to create a generic function. But first I need to know the name (xml id) of he button.
This the XML code of the button:
<Button
android:id="#+id/add_04"
android:layout_width="42dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="15dp"
android:background="#xml/zbuttonshape"
android:onClick="onClick"
android:text="#string/mas" />
I set android:onClick="onClick" for all the buttons.
In my activity I've create a new function onClick:
This the code I've tried:
public void onClick(View v) {
String name = v.getContext().getString(v.getId());
String name2 = context.getString(v.getId());
String name3 = getString(v.getId());
String name4 = getResources().getString(v.getId());
}
But when I try to get the name (in this case "add_04") I always get "false".
Finally I've found a solution with the following code:
import java.lang.reflect.Field;
String name5 = null;
Field[] campos = R.id.class.getFields();
for(Field f:campos){
try{
if(v.getId()==f.getInt(null)){
name5 = f.getName();
break;
}
}
catch(Exception e){
e.printStackTrace();
}
}
Is there an easier way to get this ID?

like this:
/**
* #return "[package]:id/[xml-id]"
* where [package] is your package and [xml-id] is id of view
* or "no-id" if there is no id
*/
public static String getId(View view) {
if (view.getId() == View.NO_ID) return "no-id";
else return view.getResources().getResourceName(view.getId());
}
I use this in view constructors to make more meaningful TAGs

The approach is misguided to begin with. If you want to associate a piece of arbitrary data (e. g. a string) with a view, that's what tag is for. The ID is numeric and it better stay that way. A word of caution though, tags are not unique in Android, watch for accidental tag collisions within the same view tree.
EDIT much later: the OP's issue was a case of an XY problem. That said, the question title alone is a legitimate question in its own right.

Edit:
You have to use
getResources().getResourceEntryName(int resid);
If you want to retrieve the entry name associated to a resId
or
You can use getIdentifier() to retriece a resource identifier for the given resource name.
For instance:
int id = this.getResources().getIdentifier("yourtext", "string", this.getPackageName());

You can check id of each button such way:
public void onClick(View v) {
switch (v.getId()) {
case R.id.add_04:
Toast.makeText(MainActivity.this, "1", Toast.LENGTH_LONG).show();
break;
case R.id.add_05:
Toast.makeText(MainActivity.this, "2", Toast.LENGTH_LONG).show();
break;
}
}

Use this Approach to get View Id by Programming .
<TextView
android:id="#+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
/>
String id=getResources().getResourceEntryName(textView.getId());
Toast.makeText(this,id,Toast.LENGTH_LONG).show();
You will get Result ; tv

You can put this toString() inside an Android View, it will return the String resource Id.
#Override
public String toString() {
Context context;
Resources r = null;
context = getContext();
if (context != null) {
r = context.getResources();
}
String entryName = null;
if (r != null)
entryName = r.getResourceEntryName(getId());
return entryName;
}

Kotlin version (from #gadget) as view extension:
val View.stringId: String
get() {
return if (this.id == -0x1)
"no-id"
else
this.resources.getResourceName(this.id)
}

It's a late answer but may useful someone looking out for a way to get the resource id (int) for any view / drawable / String programmatic.
image from res/drawable
int resID = getResources().getIdentifier("my_image",
"drawable", getPackageName());
view based on resource name
int resID = getResources().getIdentifier("my_resource",
"id", getPackageName());
string
int resID = getResources().getIdentifier("my_string",
"string", getPackageName());

The answer by #King of Masses is great. Here is my in Kotlin:
image from res/drawable
val viewId = context.resources.getIdentifier("my_image", "drawable", context.packageName)
view based on resource name
val viewId = context.resources.getIdentifier("my_textview_id", "id", context.packageName)
string
val viewId = context.resources.getIdentifier("my_string", "string", context.packageName)
Layout
val viewId = context.resources.getIdentifier("my_custom_layout", "layout", context.packageName)

Related

Android: Enable certain button with id as index

I have 50 styled buttons with identificators like "level_i", I need to enable button with certain i in id.
I have code to work with indexed aarays in string xml, but I have no proper ideas how to change it for my usage
Class<R.id.array> res;
Field field;
try {
res = R.array.class;
field = res.getField("words_" + fname);
//set myString to the string resource myArray[fname,y]
myString = getResources().obtainTypedArray(field.getInt(null)).getString(y);
}
catch (Exception e) {
e.printStackTrace();
}
I believe you are saying that you have an ID resource named "words_" + fname for example R.id.words_100. If that is correct, then you can first get the ID using the name of the resource with getIdentifier. Then you can get the actual ID, then you can find the view with that ID:
String resName = "words_" + fname";
Resources res = getResources();
int resId = res.getIdentifier(resName, "id", getPackageName());
View button = findViewById(resId);
EDIT:
Modified original answer to fetch resources from R.id rather than R.string-array.

Android: How check if a image exists in a IF clause?

I need to know how check if an image exists in R.drawable, It has to be dynamic so I have to use a string that gives me the name of the image.
I've tried with '!=null' or exist but it hasn't worked.... Help please!!!!!!!!!
titulo=bundle.getString("titulo");
textView = (TextView) findViewById( R.id.textView1);
textView.setText(titulo);
foto="f"+bundle.getString("numero")+"a";
System.out.println(foto);
flipper =(ViewFlipper) findViewById(R.id.vfFlipper);
this gives me the name of the image a need...
image = new ImageView(this);
image= new ImageView(this);
image.setImageResource(R.drawable.f00a1);
image.setScaleType(ScaleType.FIT_CENTER);
flipper.addView(image);
Whith this I can use the image but i need to use the variable "foto" so it can be dynamic
Thanks!
Everything in the R class is an integer - you can't create a string to represent a resource id. The closest you can get is to use getResources() then call...
getIdentifier(String name, String defType, String defPackage)
...this will allow you to find the integer which represents your resource based on the resource name.
you could use getResources to get an instance of Resources class. In Resources class, you have getDrawable If the resource is not found, you would get ResourceNotFoundException which also means the image is not found.
so the code will be something like this
Resource r = getResources();
Bool fileFound = true;
Drawable d = null;
try{
d = r.getDrawable(your_image_id);
}
catch(ResourceNotFoundException e){
fileFound = false;
}
if(findFound){
// Your operations
// set drawable to your imageview.
}
Thank you all! i mix the two answers and .. it work!
Resource r = getResources();
Bool fileFound = true;
Drawable d = null;
try{
d = r.getDrawable(getIdentifier(foto1, "drawable", getPackageName());
}
catch(ResourceNotFoundException e){
fileFound = false;
}
if(findFound){
// Your operations
// set drawable to your imageview.
}
getResources().getIdentifier("icon", "drawable", "your.package.namespace");
check for non zero value for above statement.
if(0)
//does not exists
else
//exists
private boolean isDrawableImageExists(String imgName) {
int id = getResources().getIdentifier(imgName, "drawable", getPackageName());
return id != 0;
}

How to do a findViewById (R.id.>> StringVarHere << )?

Searched and working on this a long while - no luck. ( It must be simple ? Thanks for the assist. )
Trying to get / set a screen full of EditTexts' text, but not with the usual, more hard-coded way:
... findViewById (R.id.SomeTextWidgetId) ;
Instead, I'm trying to figure out a reusable way via a variable holding the (String) name_of_widget.
In psuedo code:
findViewById (R.id.>> StringVarHere << ); // how to do that ?
I tried also this findViewById method, but it didn't work (!?)
//// given:
static final String FIELD_TV_FEE = "TextViewFee" ;
static final String FIELD_TV_FOO = "TextViewFoo" ;
static final String FIELD_TV_FUM = "TextViewFum" ;
//// and some arbitrary number more of similar fields
static final String [] ALL_FIELDS = {
FIELD_TV_FEE ,
FIELD_TV_FOO ,
FIELD_TV_FUM // ...
} ;
//// ...
//// this part works
int ResourceID;
String stringVarHere = FIELD_TV_FEE;
//// outputs a correct id, say '0x7f05000f' as in R.id.xxx below
ResourceID = context
.getResources()
.getIdentifier ( stringVarHere,
"id",
context
.getApplicationInfo()
.packageName
) ;
Log.d ("MyClass" , "RESID = " + Integer.toHexString(ResourceID) ) ;
/*
* that's where I'm stuck ^^^ ... how do I do:
*/
String field_name ;
for ( field_name : ALL_FIELDS ) {
(EditText) SomethingLike_a_findViewById(field_name).setText ("Hello Wurld") ;
}
I've tried .setId ...
//// details
<!-- excerpt from working xml layout -->
<EditText
android:id="#+id/TextViewFee"
android:inputType="text"
android:layout ... etc ...
/>
<EditText
android:id="#+id/TextViewFoo"
android:inputType="text"
android:layout ... etc ...
/>
<EditText
android:id="#+id/TextViewFum"
android:inputType="text"
android:layout ... etc ...
/>
As expected, the gen'ed R file has something like this:
// ...
public static final class id {
public static final int TextViewFee=0x7f05000f;
public static final int TextViewFum=0x7f05001c;
public static final int TextViewFoo=0x7f05001d;
// ... etc
Yes, thanks - it makes sense to do it in the activity. I was trying to keep it from getting too code bulky. Here's what I'm doing now, based on your and A-C's helpful suggestions. The intention is to get all the text of fields of a form back in one String[]. (I know I could brute force all the fields too.)
What do you all think about this below - seems very similar to your suggestion, madlymad ? I am wondering if this is a poor design approach ?
public class FoodBar {
private Activity activity;
private Context ctx;
public FoodBar ( Activity _activity ) {
this.activity = _activity;
this.ctx = this.activity.getApplicationContext() ;
}
public String[] getTextFromAllEditTexts () { // the UI views
int res_id = 0;
int i = 0;
String [] retValues = new String [MyClassName.ALL_FIELDS_LENGTH] ;
for (String field : MyClassName.ALL_FIELDS_ALL_VEHICLES) {
res_id = this.ctx.getResources()
.getIdentifier ( field, "id", this.ctx.getPackageName() );
((EditText) this.activity
.findViewById (res_id))
.setText( "Meat and Potatoes" ) ;
// redundant - get it right back to make sure it really went in !
retVal[i++] = ((EditText) this.activity
.findViewById (res_id))
.getText().toString() ;
}
return retVal;
} // end func
} // end class
Then from the Activity class, it's just:
String [] theFields = null;
FoodBar = new FoodBar (this);
try {
theFields = FoodBar.getTextFromAllEditTexts ();
} catch (Exception e) {
Log.d ("OOPS", "There's a big mess in the Foodbar: " + e.toString() );
}
The way you could do it is (as I understand the way you are trying):
This can be in non-Activity (YourClassname.java):
public static int getMyId(Context context, String field) {
return context.getResources().getIdentifier (field, "id", context.getPackageName());
}
in Activity-class:
for ( String field_name : YourClassname.ALL_FIELDS ) {
int resid = YourClassname.getMyId(context, field_name);
if(resid != 0) { // 0 = not found
EditText et = (EditText) findViewById(resid);
if (et != null) {
et .setText ("Hello Wurld") ;
}
}
}
But I think it's better to code in the activity class like:
String packageName = getPackageName();
Resources res = getResources();
for ( String field_name : YourClassname.ALL_FIELDS ) {
int resid = res.getIdentifier (field_name, "id", packageName);
if(resid != 0) {// 0 = not found
EditText et = (EditText) findViewById(resid);
if (et != null) {
et .setText ("Hello Wurld") ;
}
}
}
A-C suggested something along the lines of:
res_id = getResources().getIdentifier (field, "id", getPackageName());
((EditText)findViewById (res_id)).setText("NoLongerFubar");
this DOES work - when I tried it standalone in a test rig. Thanks ! Still not sure what was blowing up, but I suspect it was Context or Resource items not being accessible.
Note that variable names (such as R.id.some_id) are only available at compile time and cannot be accessed from a String value at run time. Since these ids are declared as ints, you might consider using an int[] or List<Integer> to store the ids. Depending on how dynamic your layout is and what you are doing with the Views in it, you might even want to simply create the Views at run time and store an array or List of them without using any ids at all.

Param in button to change activity

My button sends a parameter to the function.
<Button
android:id="#+id/tela1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Chinese Day"
android:onClick="loadPage"
android:tag="page1"
/>
My function should use this parameter to load the page1 activity.
public void loadPage(View view) {
String page = (String) view.getTag();
setContentView(R.layout.page);
}
How to make this work?
Tks
You want to specify in the button's tag the name of the layout, right?
Try the following:
String page = (String) view.getTag();
int layoutId= getResources().getIdentifier(page, "layout", getPackageName());
setContentView(layoutId);
Hope this helps.
You could use Java reflection API.
Each activity is an integer in R.layout. You only need to search for the attribute inside R.layout and then get its integer value to shove into setContentView.
try {
String tag = (String) btn.getTag(); // Button in variable "btn"
Class<R.layout> cls = R.layout.class;
Field field = cls.getDeclaredField(tag);
Integer obj = (Integer) field.get(null); // You could do these two in one line
int value = obj.intValue();
Log.i("Test", "Actvity id code = " + obj.toString()); // Testing code
setContentView(value);
}
catch (Exception e) {
e.printStackTrace();
return;
}

Accessing contents of R.string using a variable to represent the resource name

I have a few strings which I need to translate and display. Those strings are in variables. I have the translation in the strings.xml file.
I want to display the "translated version" of the string. For example, inside an Activity:
String name = "Water";
TextView nameDisplay = new TextView(this).
nameDisplay.setText(name);
In the strings file I have the definition
<string name="Water">French word for Water</string>
If I used something like this:
nameDisplay.setText(R.string.KnownName);
it would work. But in my case, the name is stored in a variable so I do not know what to do in order for the setText method to function properly.
My current workaround is
String translation = ""
if(name == "Water") {
translation = getString(R.string.Water);
}
else {
...
}
nameDisplay.setText(translation);
... but this does not scale very well.
Any suggestions?
Should I store the translated version in the variable?
You can use the method to convert string into int identifier:
public static int getStringIdentifier(Context context, String name) {
return context.getResources().getIdentifier(name, "string", context.getPackageName());
}
Pass in an activity as context parameter (or any other Context instance). Then you can use the identifier as usual with getString() method.
Note that conversion from string to identifier uses reflection and thus can be not that fast, so use carefully.
private String getStringResourceByName(String aString)
{
String packageName = context.getPackageName();
int resId = getResources().getIdentifier(aString, "string", packageName);
return getString(resId);
}
Another thing you can do is map the string to the resource. That way you can have the string in a variable (or build it programmatically) and then use the map to look up the resource id.
Example
strings.xml
<string name="water_english">water</string>
<string name="water_spanish">agua</string>
<string name="water_chinese">水</string>
<string name="water_mongolian">ᠤᠰᠥ</string>
Code
public class MainActivity extends AppCompatActivity {
private Map<String, Integer> stringForResourceIdMap = createMap();
private Map<String, Integer> createMap() {
Map<String, Integer> result = new HashMap<>();
result.put("water_english", R.string.water_english);
result.put("water_spanish", R.string.water_spanish);
result.put("water_chinese", R.string.water_chinese);
result.put("water_mongolian", R.string.water_mongolian);
return result;
}
private String getMyStringResource(String lookupString) {
int resourceId = stringForResourceIdMap.get(lookupString); // R.string.xxx
return getString(resourceId);
}
// ...
}
Note
If you are localizing your app with different translations, then you should be using different resource folders.
As a Kotlin extension, ArK's answer could be written the following way. It also catches an exception when you give it an unknown key.
fun Context.getStringWithResKey(nameResKey: String): String {
val resId = resources.getIdentifier(nameResKey, "string", packageName)
return try {
getString(resId)
} catch (e: Exception) {
Log.e(this.javaClass.simpleName, "Couldn't find string value for key '$nameResKey'", e)
""
}
}

Categories

Resources