274

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.

mskfisher
  • 3,291
  • 4
  • 35
  • 48
slup
  • 5,484
  • 4
  • 19
  • 14

12 Answers12

575

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.

Tomo
  • 6,847
  • 1
  • 22
  • 32
  • 2
    I tried using this but get NotFoundException, "type #0x04 is not valid", when retrieving the value from code. – Moises Jimenez Aug 30 '12 at 09:21
  • can you be more specific about problem? you've probably used wrong data type for format... – Tomo Aug 30 '12 at 18:33
  • 19
    @rodkarom to retrieve floats from xml, use this XML: `0.5` and this code to retrieve it: `float my_float = Float.parseFloat (getResources ().getString (R.string.my_float));` – gregn3 Sep 29 '12 at 11:35
  • Got the same error as @rodkarom when using type="dimen", changed to type="string" and used gregn3 suggestion to retrieve it. Thanks! – TouchBoarder Nov 09 '12 at 09:48
  • 1
    @gregn3 Couldn't that be done simply with the `` tag? – pablisco Feb 04 '14 at 11:07
  • how would I use this in XML? `@float/text_line_spacing` isn't working – Ky - Jul 14 '14 at 16:53
  • +Supuhstar, replace @float/... with @dimen, for example @dimen/text_line_spacing – Tomo Jul 14 '14 at 23:39
  • 4
    I think you should remove the hackish part, the sollution is just perfect as it is. – Mathijs Segers Feb 04 '15 at 10:36
  • Interestingly, the "really hack" approach is exactly what Dianne Hackborn recommends in [this thread](https://groups.google.com/d/msg/android-developers/LcADl0tveAY/ovQAzP-fYoQJ). – Ted Hopp Nov 02 '16 at 17:10
  • You can also retrieve value in kotlin: `val value = TypedValue().also { context.resources.getValue(R.dimen.text_line_spacing, it, true) }.float` – neske Jun 04 '20 at 00:24
94

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();
yajnesh
  • 2,089
  • 1
  • 23
  • 36
51

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>
waqaslam
  • 67,549
  • 16
  • 165
  • 178
28

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);
Alex Baker
  • 1,537
  • 2
  • 13
  • 28
20

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

Raymond Chenon
  • 11,482
  • 15
  • 77
  • 110
Cristian
  • 198,401
  • 62
  • 356
  • 264
  • 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. – peter.bartos Sep 07 '11 at 19:50
  • 4
    Exactly. It only works when you use the dimen from Java code. – Cristian Sep 08 '11 at 13:35
  • 2
    This is the best way I could find to access floats from code. – Alex Lockwood Jul 25 '13 at 16:25
  • 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! – Chris Sprague Jun 03 '14 at 23:02
  • just a note, you should use `type="fraction"` to avoid errors in Java code – adek111 Dec 19 '18 at 15:03
8

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" 
Photon Point
  • 798
  • 2
  • 13
  • 23
  • 1
    exactly what I need, I use this for different percent values for tablets and different for mobile without creating two layout files – abdu Jul 09 '18 at 11:50
5

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.

SMBiggs
  • 11,034
  • 6
  • 68
  • 83
2

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>
Trake Vital
  • 1,019
  • 10
  • 18
1

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.

0

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"/>
JJD
  • 50,076
  • 60
  • 203
  • 339
slup
  • 5,484
  • 4
  • 19
  • 14
  • 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.) – Tomo Jun 02 '12 at 16:50
  • This was my initial answer which is really outdated now, that's why I accepted your answer. :) – slup Jun 03 '12 at 22:32
0

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.

androidguy
  • 3,005
  • 2
  • 27
  • 38
0

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.