We can change image by name using string interpolation in Swift. Is there a way to achieve this in Kotlin? Can we change selected image programatically in Kotlin?
let image = UIIMage(named : "\(imageName)_selected")
You can:
val resourceId = resources.getIdentifier("${imagename}_selected", "drawable", packageName)
Personally, I'd go for a solution like this:
val resourceId = when (imageName) {
"image1" -> R.drawable.image1_selected
"image2" -> R.drawable.image2_selected
}
Although this is a little bit longer, it gives compile time warnings and errors, assuring you the drawable is there.
Perhaps the question is: why are you getting the string imageName? Can it be solved better?
Related
Sadly, I failed to find any answer to this question on SO or elsewhere.
I am studying Kotlin and Android development and I wonder how I can insert a value of a variable in a name of another variable. Or if there is another, better solution to this problem I have.
Suppose, my code looks like this:
...
private fun rollDice() {
// Create new Dice object with 6 sides and roll the dice
val dice = Dice(6)
val diceRoll = dice.roll()
// Find the ImageView in the layout
val diceImage: ImageView = findViewById(R.id.imageView)
// Determine which drawable resource ID to use based on the dice roll
val drawableResource = when (diceRoll) {
1 -> R.drawable.dice_1
2 -> R.drawable.dice_2
3 -> R.drawable.dice_3
4 -> R.drawable.dice_4
5 -> R.drawable.dice_5
else -> R.drawable.dice_6
}
// Update the ImageView with the correct drawable resource ID
diceImage.setImageResource(drawableResource)
// Update the content description
diceImage.contentDescription = diceRoll.toString()
}
...
I wonder if in the
"Determine which drawable resource ID to use based on the dice roll"
block I could actually use something like this (also, sorry, I don't know the correct syntax yet):
val drawableResource = R.drawable.{"dice_"+ diceRoll.toString()}
This way I could have saved much space and make the code easily extensible, if, for example, I had a 20-sided dice, I still would have needed this single line of code.
Or else I would have needed to add
when(diceRoll){
...
20 lines of code here
...
}
How can I solve this problem?
Thank you.
Thanks to Shlomi Katriel for linking the correct solution to this in comment on the original post.
A way to formulate my question in this context would be exactly as in linked post — "How to get a resource id with a known resource name?"
My solution code for this exact case (changed 2 blocks):
// Determine which drawable resource ID to use based on the dice roll
val drawableResourceId : Int = this.resources.getIdentifier("dice_$diceRoll", "drawable",this.packageName)
// Update the ImageView with the correct drawable resource ID
diceImage.setImageResource(drawableResourceId)
Is it possible to do something like
var myThemeVariable = "redTheme" //could be either redTheme, greenTheme, or blueTheme for example
context.setTheme(R.style.myThemeVariable) //sets theme to R.style.redTheme
instead of what i usually do
var myThemeVariable = "redTheme" //could be either redTheme, greenTheme, or blueTheme
when (myThemeVariable)
{
"redTheme" -> context.setTheme(R.style.redTheme)
"greenTheme" -> context.setTheme(R.style.greenTheme)
"blueTheme" -> context.setTheme(R.style.blueTheme)
}
In this example it's not super cluttered, but in my actual code there's a lot more. My current solution is not only hard to understand, add to, or remove from; it's also (I imagine) unnecessarily computationally expensive. Is something akin to the first approach possible? If it's not, does any language have something like it? Thanks!
Thanks y'all, in the end I searched about #blackapps' and #Haseeb Hassan Asif's recommendations and found this post so I ended up doing this :)
val themeResID = context.resources.getIdentifier((sharedPreferences.getString("theme", "default_standard")), "style", context.packageName) //get theme from shared preferences
context.setTheme(themeResID)
getIdentifier uses reflection under the hood, so it has poor performance. If you're using it sparingly, like to set the theme once whenever a button is pressed, that performance difference will not be noticeable. But the code is overly complicated either way.
Just use your IDs directly like this. No Strings or when statements are necessary.
var myThemeVariable = R.style.redTheme // redTheme, greenTheme, or blueTheme
context.setTheme(myThemeVariable)
I use the composable function image. I need to use the specific image depending on the variable it gets.
it looks like the code underneath when hardcoded and this works for the specific image.
Image(
painterResource(id = R.drawable.carrot),
contentDescription = "carrot",
)
The problem is i want it to work like the picture below where recipe.image changes depending on what it gets from the database.
Image(
painterResource(id = recipe.image),
contentDescription = "recipe.name",
)
Somehow it needs the exact path to the drawable that is saved localy.
What i have tried:
I've tried to upload R.drawable.carrot directly to the database as an Integer, it saves it as something like 2400440340, when this integer gets into the painterResource it crashes.
I've tried to save the "R.drawable.carrot" directly as a string into the database but that don't work either because the painter needs an integer.
The only suggestions i can find to this problem on this site is this answer from 11 years ago:
int drawableId = getResources().getIdentifier(drawablename, "drawable", getPackageName());
imageview.setImageResource(drawableId);
I can't seem to find the functions getResources or the getIdentifier.
What i have tried: I've tried to upload R.drawable.carrot directly to the database as an Integer, it saves it as something like 2400440340, when this integer gets into the painterResource it crashes.
It crashes because this Int value in Resources is just a runtime reference, which means if you restart the app, the Resource, for example R.drawable.carrot, gets new referenced.
If you want another image in your painterResource, you have to change the value of recipe.name somewhere or you save your image binaries in the database (which is not very performant, I recommend not to do that).
You can load them over assets:
If you dont't have an assets folder, creat one in this location:
app/src/main/assets/
And then you can access it with a function like this:
fun getImageFromAssets(imageName: String): Bitmap {
val imageStream = assets.open(imageName)
val bitmap = BitmapFactory.decodeStream(imageStream)
imageStream.close()
return bitmap
}
Android Studio will suggest you to "Inline" the variable but don't do that. If you Inline the BitmapFactory at the return point, you close the Stream before you decode it.
You can now simply call the name from the database like:
val image: Bitmap = getImageFromAssets("imageName.jpg")
I have a json animation that I'm using with LottieAnimation, but my feature needs that I change a text and an image inside the animation in runtime.
The animation is a ranking like a podium. Then animated winner text and image are loaded from the backend. So I need to set these values.
Right now I know that TextDelegate can handle the Text problem, but it only works with View, as the old way to do it. It needs the View in constructor. I don't find a way to do this with Compose. And about the image, I have no glues.
Can someone help me?
Depending on your json file structure, you have two ways of settings an image
Place used images inside src/main/assets/lottieImages. Names should be the same as mentioned in your json file, in my case it's img_0.png.
val composition by rememberLottieComposition(
LottieCompositionSpec.RawRes(R.raw.we_accept),
imageAssetsFolder = "lottieImages"
)
Set a bitmap to key path, like I'm taking it from the resources, using dynamic properties
val bitmap = remember {
BitmapFactory.decodeResource(context.resources, R.drawable.my_image)
}
val dynamicProperties = rememberLottieDynamicProperties(
rememberLottieDynamicProperty(LottieProperty.IMAGE, bitmap, "weaccept.jpg"),
)
LottieAnimation(
composition,
dynamicProperties = dynamicProperties
)
I'm using this json as a sample animation.
As for the text, Lottie TextDelegate does not seem to be ported to compose, I suggest you create a feature request on github.
I would like to understand, why I can't dynamically change the drawable resource from my imageView.
I have different use cases, and in function of these use cases I have to change my imageView. In my code I tried these solutions below, but I can't get my imageView refresh. It keeps the default drawable resource defined first. Here what I tried:
int imgRes = activity.getResources().getIdentifier("packageName:drawable/"+"my_drawable_name", null, null);
OR
int imgRes = activity.getResources().getIdentifier("drawable/"+"my_drawable_name", "drawable", activity.getPackageName());
imageIcon.setImageResource(imgRes);
imageIcon.invalidate();
And also:
imageIcon.setImageDrawable(null);
imageIcon.setImageDrawable(activity.getResources().getDrawable(R.drawable.my_drawable_name));
imageIcon.invalidate();
I'm in one adapter and I passed this ImageView from my activity to my adapter. And I'm doing this operation from this adapter which go the instance of my imageView.
So I tried to change this resource my_drawable_name but in both cases above, my imageView is never updated/refresh, and its image resource doesn't change. I have no error it just doesn't work. Am I doing something wrong ? What's the best practice to dynamically change a resource from an imageview by code?
No need to append drawable directory. It is the default behavior of android to get best suited drawable according to device.
Try using following code:
int imgRes = activity.getResources().getIdentifier("my_drawable_name", "drawable", activity.getPackageName());
try imageIcon.setImageResource(R.drawable.my_drawable_name);