1

Should be a simple issue... but one I'm unable to nail! This is a simple layout that aims to show an icon illustrating a header, with the text slightly taller than the icon. The intention is for the icon to be vertically centered with the text, but for some reason the icon is a few pixels higher than it should be no matter text / icon sizes. (Icon is a vector drawable in case it does matter.)

Layout

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="8dp">

    <ImageView
        android:id="@+id/icon_readings_raw"
        android:src="@drawable/ic_equals"
        android:tint="@color/colorPrimary"
        android:layout_width="14dp"
        android:layout_height="14dp"
        android:layout_alignParentStart="true"
        android:layout_centerVertical="true"
        android:layout_marginEnd="7dp"/>

    <TextView
        android:text="Raw sensor readings"
        android:textAllCaps="true"
        android:textColor="@color/colorPrimary"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toEndOf="@id/icon_readings_raw"/>

</RelativeLayout>

Result

RelativeLayout not centering drawable

Question

How do I center the icon with the text? Not asking for hacky solutions and magic numbers, please tell me why android:layout_centerVertical="true" is not working as expected.

Edit #1

Led on a small path of discovery by @AntonMakov I am coming to the conclusion that it might be down to sub-pixel rendering optimizations and the nature of the preview window. My preview is set to Nexus 5X & API27. With ?android:attr/textAppearanceSmall TextView renders as exactly 19sp; playing with icon height I noticed that when it is set to {19,13,9,7,3}sp the icon is rendered vertically centered. When subtracting these numbers from 19sp we get {0,6,10,12,16}sp... always an even number. And it makes sense as only then can you get an equal amount of screen top and bottom.

What I do not understand yet is why not all even deltas yield a correct result (eg. TextView set to 19sp and ImageView set to 15sp for a delta of 4). Furthermore, the "right" combinations depend on the device selected (Nexus 6 behaves slightly differently), and also look a little bit different when displayed in an emulator.

What now? Should we trust that Android OS does The Right Thing on actual devices? Is it just the preview that is to blame — a far-from-precise approximation of the real thing whose calculations need not be taken too seriously?

Onik
  • 19,396
  • 14
  • 68
  • 91
Dav
  • 1,102
  • 3
  • 10
  • 22
  • try `android:centerVertical="true"` instead – Jacky Jan 31 '18 at 03:40
  • you can combine them both by using only TextView and use drawable left and set the src to imageview. You can change the distance from it by using drawable padding – Anton Makov Jan 31 '18 at 03:56
  • @AntonMakov that was my initial idea but changing the size of the icon and centering is even more problematic then, especially on API 21. – Dav Jan 31 '18 at 04:00
  • @Jacky *Unknown attribute android:centerVertical* I'm afraid. – Dav Jan 31 '18 at 04:01
  • 1
    why don't you use a `ConstraintLayout` instead of relative layout. it is more flexible than relative layout and can position an item with ease than using a recyclerview – Sony Jan 31 '18 at 04:08
  • Maybe try to align top and bottom the imageview to the text, the image should be in the center of the relative layout – Anton Makov Jan 31 '18 at 04:37
  • @AntonMakov if I do `android:layout_alignTop="@id/myTextView"` and `android:layout_alignBottom="@id/myTextView"` the *ImageView* gets vertically stretched to the height of the *TextView*. I'm trying to center it, not stretch to 100% container height. – Dav Jan 31 '18 at 10:01
  • @Sony if I fail to diagnose the issue with the *RelativeLayout* I might try that but would prefer to understand what's going on here rather than abandon ship early. The way I see it is that it's either an Android bug (unlikely?) or a problem with my code (very likely, just haven't found it yet). – Dav Jan 31 '18 at 10:03
  • I think the problem is because you fixed the size of the image, to check this instead of putting size in dp, change it to wrap content, then increase the text size for instance for 22sp and then you will see the image will be centered, not sure why it's happening such way – Anton Makov Jan 31 '18 at 15:29
  • @AntonMakov thanks for this suggestion, it seems that your hint led me down a path that gave at least *some* answers. Please check the updated question and see what you think. – Dav Jan 31 '18 at 17:38
  • have you tried to change the size of the vector asset within the file and then change the actual size of the image view to wrap content sometimes there are issues with dp conversions – Anton Makov Jan 31 '18 at 18:02
  • @AntonMakov as in "I want the image to be 16sp so resize the image to exactly 16sp"? No, I have not tried because the entire point of vector assets for me is the ability to adjust the size, so this is a compromise I am not willing to make. – Dav Feb 01 '18 at 10:42
  • No, what I meant was to adjust the size of the asset itself in the vector file, then change the image size in your layout to wrap content. By the way I think sp is for font size and not for pixel size you should use dp instead – Anton Makov Feb 01 '18 at 12:18
  • If you still have this issue, this might be useful https://stackoverflow.com/questions/34936590/why-isnt-my-vector-drawable-scaling-as-expected – Anton Makov Feb 05 '18 at 20:03
  • Thanks for your suggestion! Will test once I find the time to re-visit the issue, but I suspect it will not improve the situation much — the problem manifested itself via a bounding box and its line being out of center with my *RelativeLayout* rather than quality issues *inside* the bounding box. – Dav Feb 06 '18 at 18:54

3 Answers3

0

By looking at you icon i think there is some padding in it from all side. Hence even if you put it center vertical the padding provided to the icon disturbs the alignment with text view.

If you pad your TextView from bottom that might work but it will be a device dependent solution. so i will not suggest it.

I will advise you to Design the icon Again without any padding from all sides.

Amardeep
  • 1,414
  • 11
  • 18
  • This is a valid step on the road to eventual success. But as you can see on the image no matter what the *content* of the icon is, its *bounding box* is still not centered within the parent layout and this is what I'm chasing at the moment. – Dav Jan 31 '18 at 09:58
0

You can set the following attribute to ImageView for centering the image view vertically

<TextView
    android:id="@+id/text"
    android:text="Raw sensor readings"
    android:textAllCaps="true"
    android:textColor="@color/black"
    android:textAppearance="?android:attr/textAppearanceSmall"
    android:layout_width="wrap_content"
    android:layout_centerVertical="true"
    android:layout_height="wrap_content"
    android:layout_toEndOf="@+id/icon_readings_raw"/>

<ImageView
    android:id="@+id/icon_readings_raw"
    android:src="@drawable/ic_launcher"
    android:tint="@color/white"
    android:layout_width="14dp"
    android:layout_height="14dp"
    android:layout_alignParentStart="true"
    android:layout_centerVertical="true"
    android:layout_alignBaseline="@+id/text"
    android:layout_marginEnd="7dp"/>

  • This produces [the following result](https://imgur.com/a/RfW8r). Thanks for taking the time to respond but it seems that was a bit of a shot in the dark. – Dav Jan 31 '18 at 11:43
  • Now the *RelativeLayout* is much larger but *ImageView* is still not centered with its vertical center line. See [here](https://imgur.com/a/dJZAz). – Dav Jan 31 '18 at 12:38
0

With further testing it seems that the reason for apparent misalignment is in the preview window rather than Android itself. I noticed that the icon appears properly aligned with the RelativeLayout when the difference in their sizes is an even number (eg. text/layout have a height of 19sp and the icon is 13sp for a difference of 6sp). More importantly, even if the icon appeared misaligned with RelativeLayout's center, it would look fine on an actual device.

Moral of the story: do not trust the preview window in Android Studio! When it does show something strange up close, layout you have all right to expect to look slightly differently, double check on an actual device before wasting too much time chasing shadows! It's called a preview window (and not HiDef Pixel-Perfect Simulator) for a reason, it turns out.

Dav
  • 1,102
  • 3
  • 10
  • 22