259
votes

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.

11

11 Answers

549
votes

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.

86
votes

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();
46
votes

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>
19
votes

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

16
votes

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);
7
votes

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" 
5
votes

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.

1
votes

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
votes

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"/>
0
votes

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.

0
votes

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.