ChatGPT解决这个技术问题 Extra ChatGPT

Add floating point value to android resources/values

I'm trying to add a little space between lines to my TextViews using android:lineSpacingMultiplier from the documentation:

Extra spacing between lines of text, as a multiplier. Must be a floating point value, such as "1.2".

As I'm using this in a few different TextViews I would like to add a global dimension/value to my resources, but I don't know which tag to use, if it even exists. I have tried all resource types that make sense to me, but none of them works.

What I would like to have would be something like this:

<resources>
    <dimen name="text_line_spacing">1.4</dimen>
</resources>

Edit: I'm aware of android:lineSpacingExtra (which needs a dimension with an appended unit), but I'd like to use android:lineSpacingMultiplier if possible.


T
Tomo

There is a solution:

<resources>
    <item name="text_line_spacing" format="float" type="dimen">1.0</item>
</resources>

In this way, your float number will be under @dimen. Notice that you can use other "format" and/or "type" modifiers, where format stands for:

Format = enclosing data type:

float

boolean

fraction

integer

...

and type stands for:

Type = resource type (referenced with R.XXXXX.name):

color

dimen

string

style

etc...

To fetch resource from code, you should use this snippet:

TypedValue outValue = new TypedValue();
getResources().getValue(R.dimen.text_line_spacing, outValue, true);
float value = outValue.getFloat();  

I know that this is confusing (you'd expect call like getResources().getDimension(R.dimen.text_line_spacing)), but Android dimensions have special treatment and pure "float" number is not valid dimension.

Additionally, there is small "hack" to put float number into dimension, but be WARNED that this is really hack, and you are risking chance to lose float range and precision.

<resources>
    <dimen name="text_line_spacing">2.025px</dimen>
</resources>

and from code, you can get that float by

float lineSpacing = getResources().getDimension(R.dimen.text_line_spacing);

in this case, value of lineSpacing is 2.024993896484375, and not 2.025 as you would expected.


I tried using this but get NotFoundException, "type #0x04 is not valid", when retrieving the value from code.
can you be more specific about problem? you've probably used wrong data type for format...
@rodkarom to retrieve floats from xml, use this XML: <item type="string" format="float" name="my_float">0.5</item> and this code to retrieve it: float my_float = Float.parseFloat (getResources ().getString (R.string.my_float));
@gregn3 Couldn't that be done simply with the <string> tag?
I think you should remove the hackish part, the sollution is just perfect as it is.
y
yajnesh

As described in this link http://droidista.blogspot.in/2012/04/adding-float-value-to-your-resources.html

Declare in dimen.xml

<item name="my_float_value" type="dimen" format="float">9.52</item>

Referencing from xml

@dimen/my_float_value

Referencing from java

TypedValue typedValue = new TypedValue();
getResources().getValue(R.dimen.my_float_value, typedValue, true);
float myFloatValue = typedValue.getFloat();

w
waqaslam

All the solutions suggest you to use the predefined float value through code.

But in case you are wondering how to reference the predefined float value in XML (for example layouts), then following is an example of what I did and it's working perfectly:

Define resource values as type="integer" but format="float", for example:

<item name="windowWeightSum" type="integer" format="float">6.0</item>
<item name="windowNavPaneSum" type="integer" format="float">1.5</item>
<item name="windowContentPaneSum" type="integer" format="float">4.5</item>

And later use them in your layout using @integer/name_of_resource, for example:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:weightSum="@integer/windowWeightSum"                 // float 6.0
    android:orientation="horizontal">

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="@integer/windowNavPaneSum"        // float 1.5
        android:orientation="vertical">
        <!-- other views -->
    </LinearLayout>

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="@integer/windowContentPaneSum"    // float 4.5
        android:orientation="vertical">
        <!-- other views -->
    </LinearLayout>

</LinearLayout>

This is the best answer because it enables me to change dynamically dimension values upon screen rotation without having to write code.
@Vyacheslav for drawables, you should use standard dimensions
it doesnt work at all. AndroidStudio fails even with dimentions
I meant using <dimen>
What if we have to reference these values programmatically?
A
Alex Baker

Add a float to dimens.xml:

<item format="float" name="my_dimen" type="dimen">1.2</item>

To reference from XML:

<EditText 
    android:lineSpacingMultiplier="@dimen/my_dimen"
    ...

To read this value programmatically you can use ResourcesCompat.getFloat from androidx.core

Gradle dependency:

implementation("androidx.core:core:${version}")

Usage:

import androidx.core.content.res.ResourcesCompat;

...

float value = ResourcesCompat.getFloat(context.getResources(), R.dimen.my_dimen);

R
Raymond Chenon

I also found a workaround which seems to work fine with no warnings:

<resources>
    <item name="the_name" type="dimen">255%</item>
    <item name="another_name" type="dimen">15%</item>
</resources>

Then:

// theName = 2.55f
float theName = getResources().getFraction(R.dimen.the_name, 1, 1);
// anotherName = 0.15f
float anotherName = getResources().getFraction(R.dimen.another_name, 1, 1);

Warning : it only works when you use the dimen from Java code not from xml


This unfortunatelly doesn't work, if I use such value in XML definition: android:lineSpacingMultiplier="@dimen/TEXT_SPACING_MULTIPLIER". It causes NumberFormatException while inflating layout.
Exactly. It only works when you use the dimen from Java code.
This is the best way I could find to access floats from code.
In floats.xml I added 25% and then in my drawable I used this percent to set the shadow gradient's center using android:centerY="@dimen/shadow_percent". This worked perfectly to set the shadow to 25% of the total height of the layer-list. THANK YOU!
just a note, you should use type="fraction" to avoid errors in Java code
P
Photon Point

We can also use it for the guideline of the constraint layout.

Create integer.xml file and add into

 <item name="guideline_button_top" type="integer" format="float">0.60</item>

Use from a layout.xml file

 app:layout_constraintGuide_percent="@integer/guideline_button_top" 

exactly what I need, I use this for different percent values for tablets and different for mobile without creating two layout files
S
SMBiggs

I used a style to solve this issue. The official link is here.

Pretty useful stuff. You make a file to hold your styles (like "styles.xml"), and define them inside it. You then reference the styles in your layout (like "main.xml").

Here's a sample style that does what you want:

<style name="text_line_spacing">
   <item name="android:lineSpacingMultiplier">1.4</item>
</style>

Let's say you want to alter a simple TextView with this. In your layout file you'd type:

<TextView
   style="@style/summary_text"
   ...
   android:text="This sentence has 1.4 times more spacing than normal."
/>

Try it--this is essentially how all the built-in UI is done on the android. And by using styles, you have the option to modify all sorts of other aspects of your Views as well.


T
Thanasis Kapelonis

If you have simple floats that you control the range of, you can also have an integer in the resources and divide by the number of decimal places you need straight in code.

So something like this

<integer name="strokeWidth">356</integer>

is used with 2 decimal places

this.strokeWidthFromResources = resources_.getInteger(R.integer.strokeWidth);    
circleOptions.strokeWidth((float) strokeWidthFromResources/ 100);

and that makes it 3.56f

Not saying this is the most elegant solution but for simple projects, it's convenient.


J
JJD

I found a solution, which works, but does result in a Warning (WARN/Resources(268): Converting to float: TypedValue{t=0x3/d=0x4d "1.2" a=2 r=0x7f06000a}) in LogCat.

<resources>
    <string name="text_line_spacing">1.2</string>
</resources>

<android:lineSpacingMultiplier="@string/text_line_spacing"/>

see my answer above. you can use "generic" resource item, where you should specify format and type. format is for java type (float, boolean, fraction, integer, etc.), and type is for android gen resource reference ("dimen" for R.dimen, "color" for R.color, "string" for R.string, etc.)
This was my initial answer which is really outdated now, that's why I accepted your answer. :)
a
androidguy

Although I've used the accepted answer in the past, it seems with the current Build Tools it is possible to do:

   <dimen name="listAvatarWidthPercent">0.19</dimen>

I'm using Build Tools major version 29.


S
Spirit of the Void

The float or double parameter can be stored as a string:

<resources>
    <string name="x">0.01</string>
</resources>

and then obtained as:

double value = Double.parseDouble(this.getString(R.string.x));

Use java.lang.Float.parseFloat() if you want x parsed to a float.


T
Trake Vital

If somebody is interested in "tricking the system" when you are allowed to give only specific types of xml values, especially when using xml values for embedded weights in android layout formatting, you could do something like this:

    <item name="actvity_top_panel_weight" format="float" type="integer">1.5</item>

The xml value above acts like a float but is called an integer.

Then you could use it as the following without a problem:

        <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="@integer/actvity_top_panel_weight"
        android:orientation="horizontal"></LinearLayout>