How do I apply mathematical operations to Android dimensions?

AndroidXmlAndroid Layout

Android Problem Overview


How do I avoid this hardcoded math...

<resources>
 <dimen name="uno">10dip</dimen>
 <dimen name="dos">6dip</dimen>
 <dimen name="uno_plus_dos">16dip</dimen>
</resources>

<Button 
 android:layout_marginTop="@dimen/uno_plus_dos" />

...and covert it to something like this?

<Button
 android:layout_marginTop="@dimin/uno + @dimen/dos" />

Android Solutions


Solution 1 - Android

You don't, sorry. Layout XML files do not support expressions. You either:

  • Leave it as @dimen/uno_plus_dos, or
  • Set your margins in Java code, where you can replace a single resource with a bunch of extra lines of code, or
  • Write your own layout preprocessor that handles expressions like this

UPDATE The data binding library supports some operations in its expressions. I am uncertain if it can handle this specific scenario.

Solution 2 - Android

One trick for simple addition is to use margin + padding.

Solution 3 - Android

Using databinding:

android:layout_marginTop="@{@dimen/uno + @dimen/dos}"

IFAIK margins adapters are not provided by the sdk. You will need to define it yourself:

@BindingAdapter("android:layout_marginTop")
public static void setBottomMargin(View view, int bottomMargin) {
    ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
    layoutParams.setMargins(layoutParams.leftMargin, layoutParams.topMargin,
            layoutParams.rightMargin, bottomMargin);
    view.setLayoutParams(layoutParams);
}

Make sure databinding is enabled for your project :

dataBinding {
    enabled = true
}

in your build.gradle.

The databinding doc is worth reading.

Solution 4 - Android

There's a few tricks around this, but it wouldn't be as nice as your proposed solution, which is something I want as well. For example, you can use layout paddings on not just the View (Button in this case), but you can also do it on the view's parent (the layout like LinearLayout/RelativeLayout). You can also put in invisibile Views (a straight View object works often) with fixed dimensions. It would be like

<View
   android:layout_width="1px"
   andoird:layout_height="@dimen/dos" />

Note that 1px is fine if want to guarantee only 1 pixel will be drawn for a dimension, which is usually what you want if you want use empty views for padding. Some say FrameLayout is better to use for empty padding, but that's descended from View

Sometimes you can combine padding and the layout padding, but that can get messy and have your view cropped. Also you can have something like a FrameLayout or a LinearLayout contain just that view, and use that to have the added padding

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJoJoView Question on Stackoverflow
Solution 1 - AndroidCommonsWareView Answer on Stackoverflow
Solution 2 - AndroidmiguelView Answer on Stackoverflow
Solution 3 - AndroidQuentin GaultierView Answer on Stackoverflow
Solution 4 - AndroidJoe PlanteView Answer on Stackoverflow