4

I'm trying hard to find a way of aligning an EditText and an ImageView properly on Android. I keep getting this result:

enter image description here

The XML part is quite simple:

<LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >

    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:gravity="center"
        android:scaleType="centerInside"
        android:src="@drawable/android"
        android:visibility="gone" />

    <EditText
        android:id="@+id/edittext"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:singleLine="true" />

</LinearLayout>

I've also tried many of the suggestions below, including PravinCG's (RelativeLayout with alignTop/alignBottom):

<RelativeLayout
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:orientation="horizontal" >

    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/edittext"
        android:layout_alignTop="@+id/edittext"
        android:scaleType="centerInside"
        android:src="@drawable/android"
        android:visibility="visible" />

    <EditText
        android:id="@+id/edittext"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/image"
        android:hint="@string/username"
        android:singleLine="true" />

</RelativeLayout>

But the result is exactly the same.

I've tried playing with the EditText's background padding, intrinsic height, but to no avail.

The EditText's background drawable is different among Android versions/ROMs, and I want to support them all.

How can I make this alignment pixel perfect on any android version (and style)?

goncalossilva
  • 1,830
  • 15
  • 25
  • You should assign layout weight of edit text and image as per your screen resolution,by assigning layout weight it will look perfect in any landscape or portrait mode..just try it it may work. – Aamirkhan Feb 21 '12 at 04:36
  • Playing with padding can lead to unpredictable results in differenr resolutions. – Mike D Feb 21 '12 at 04:49

7 Answers7

8

Finally found a suitable solution that scales across different Android versions/ROMs/styles.

The main problem is that the EditText's background drawable itself has transparent padding: enter image description here

Also, I've noticed this transparent padding varies a lot between different Android versions/ROMs/styles (stock ICS, for instance, has no transparent padding at all).

In a mid-way conclusion, my original code properly alignes my ImageView with my EditText. However, what I really want is to align my ImageView with the visible part of the EditText's background.

To achieve this, I scan a Bitmap I create from my EditText's background drawable. I scan it top-bottom and bottom-up to find the amount of fully transparent lines and use those values as top/bottom padding for my ImageView. All this consistently takes less than 5ms on my N1. Here's the code:

if(editor.getBackground() != null) {
    int width = editor.getWidth();
    int height = editor.getHeight();
    Drawable backgroundDrawable = editor.getBackground().getCurrent();

    // Paint the editor's background in our bitmap
    Bitmap tempBitmap =  Bitmap.createBitmap(width, height, Config.ARGB_4444);
    backgroundDrawable.draw(new Canvas(tempBitmap));

    // Get the amount of transparent lines at the top and bottom of the bitmap to use as padding
    int topPadding = countTransparentHorizontalLines(0, height, tempBitmap);
    int bottomPadding = countTransparentHorizontalLines(height-1, -1, tempBitmap);

    // Discard the calculated padding if it means hiding the image
    if(topPadding + bottomPadding > height) {
        topPadding = 0;
        bottomPadding = 0;
    }

    tempBitmap.recycle();

    // Apply the padding
    image.setPadding(0, topPadding, 0, bottomPadding);
}

private int countTransparentHorizontalLines(int fromHeight, int toHeight, Bitmap bitmap) {
    int transparentHorizontalLines = 0;
    int width = bitmap.getWidth();
    int currentPixels[] = new int[width];
    boolean fullyTransparentLine = true;

    boolean heightRising = (fromHeight < toHeight);
    int inc =  heightRising ? 1 : -1;

    for(int height = fromHeight; heightRising ? (height < toHeight) : (toHeight < height); height+=inc) {
        bitmap.getPixels(currentPixels, 0, width, 0, height, width, 1);

        for(int currentPixel : currentPixels) {
            if(currentPixel != Color.TRANSPARENT && Color.alpha(currentPixel) != 255) {
                fullyTransparentLine = false;
                break;
            }
        }

        if(fullyTransparentLine)
            transparentHorizontalLines++;
        else
            break;
    }

    return transparentHorizontalLines;
}

And it works like a charm!

it works!

goncalossilva
  • 1,830
  • 15
  • 25
  • its good to see this that u have sol but its not good that everytime to create it at the runtime when u have many images with editText, have you find any other sol in xml or something? – PiyushMishra Apr 15 '12 at 12:09
  • Unfortunately, there isn't one. Read my answer carefully and I believe you'll understand why this isn't possible using plain XML. – goncalossilva Apr 15 '12 at 18:31
  • 1
    see we can easily do this when u have a edit text box image, the default image of textbox s creating a prob, and yah i see ur quest and ur ans as well... u did a great job i must say. But its not good when u have plenty of data for that i will recomend to use ur own image as background for textbox, editing a bitmap can take lot of memory at runtime. – PiyushMishra Apr 16 '12 at 12:41
  • Yes, in that case using your own background image without dumb borders would be a much better solution! In this case it's just one and we want to support all kinds of native EditText's... so we must resort to this. – goncalossilva Apr 16 '12 at 16:44
1

To get rid of the padding in the EditText, just use a custom image as background... rectangle with some shadow is enough... or whatever you like... and assign the background to the EditText using

android:background="@drawable/myBackground"
User
  • 31,811
  • 40
  • 131
  • 232
1

You need to use RelativeLayout with android:align_bottom and android:align_Top attribute. I am not writing the code though.

Dharmendra
  • 33,296
  • 22
  • 86
  • 129
PravinCG
  • 7,688
  • 3
  • 30
  • 55
  • You don't need to :) Anyway, it doesn't work. I've wrapped them inside a RelativeLayout and added `android:layout_alignTop` and `android:layout_alignBottom` to the ImageView. Same result as the screenshot above. – goncalossilva Feb 21 '12 at 04:56
  • Can you paste, how have you implemented it? – PravinCG Feb 21 '12 at 05:17
  • Can you also add `android:layout_alignParentTop="true"` and `android:layout_alignParentBottom="true"` in both ImageView and TextView. – PravinCG Feb 21 '12 at 16:03
  • Unfortunately, same thing. The real issue is that the EditText's background contains a few pixels of transparency (bottom mainly, but top as well): https://github.com/android/platform_frameworks_base/raw/master/core/res/res/drawable-hdpi/textfield_default.9.png – goncalossilva Feb 21 '12 at 16:12
  • 1
    What you can do is add a transparent background to editText in that case. However let me just try something. – PravinCG Feb 21 '12 at 16:14
  • If I add a transparent background to the EditText, won't it lose the system's default background for EditText? I want to keep the original style. I've been playing with the EditText' background transparent region (`getTransparentRegion()`) but I can't seem to get anything useful out of it. Thanks for the engagement in my issue :) – goncalossilva Feb 21 '12 at 16:18
  • 1
    I just tested it, you are correct there is inherent margin which is causing this issue. The only way to remove it is to use `android:background="#FFFF0000"` in your editext. You can choose any color but yes it wont be the default style. – PravinCG Feb 21 '12 at 16:25
  • Finally found a proper solution. See my answer if you're curious about how to achieve this. Thanks for all the tips! – goncalossilva Feb 21 '12 at 20:06
1

Have you tried the setCompoundDrawables() methods for the EditText.

You can try setting the intrinsic bounds using the setBounds() method on the Drawable or by using the setCompoundDrawablesWithInstrinsicBounds() method.

This should work on all devices.

Saad Farooq
  • 13,172
  • 10
  • 68
  • 94
  • I'll try that and report the results. Thanks! – goncalossilva Feb 21 '12 at 04:59
  • I've tried it and it achieves a nice effect. However, this is not really what I'm trying to achieve... using `setCompoundDrawables()` puts the image *inside* the EditText, and not right next to it. Thanks anyway, +1 for the alternative approach! – goncalossilva Feb 21 '12 at 15:47
  • Oh... OK. Well if you don't find a suitable solution you could just try to set a background to the `EditText` with either the image included and the `EditText` padded to avoid it or the `Drawable` as a compoundDrawable and a separate background drawable that discounts the drawable area – Saad Farooq Feb 21 '12 at 17:45
  • I found a suitable solution! Check my answer to see how I've done it. Thanks for the help and for making me learn how to work with `setCompoundDrawables()` ;) – goncalossilva Feb 21 '12 at 20:07
0

I used a quick workaround by simply moving the EditText down 2dp by simply adding the following to the EditText:

android:layout_marginBottom="-2dp"
android:layout_marginTop="2dp"
Brian Crider
  • 314
  • 3
  • 13
  • This workaround just will work if you have a low number of target devices. 2dp are much more in a Note 3 than a Ace 2. – ArturoNaredo Dec 11 '13 at 14:10
0

use android:layout_centerInParent = true for edit text and see weather it works?

0

remove editText's and ImageView's properties android:gravity="center" and set gravity property of linearlayout to center_vertically.

jeet
  • 29,001
  • 6
  • 52
  • 53