将ImageView与EditText水平对齐

4
我正在努力寻找一种在Android上正确对齐EditTextImageView的方法。我一直得到这个结果:

enter image description here

XML部分非常简单:
<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>

我也尝试了下面许多建议,包括PravinCG的(使用alignTop / alignBottom的RelativeLayout):

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

但结果完全相同。

我尝试过调整EditText的背景填充、内在高度,但无济于事。

EditText的背景图在不同的Android版本/ROM中是不同的,我想支持它们所有。

如何使这个对齐在任何Android版本(和样式)上都是像素完美的?


您应根据屏幕分辨率分配编辑文本和图像的布局权重,通过分配布局权重,它会在任何横向或纵向模式下都看起来完美。尝试一下,可能有效。 - Aamirkhan
在不同的分辨率下,玩弄填充可能会导致不可预测的结果。 - Mike D
7个回答

8

终于找到了一种适合不同Android版本/ROMs/styles的可扩展解决方案。

主要问题是EditText的背景drawable本身具有透明填充:

enter image description here

此外,我注意到这种透明填充在不同的Android版本/ROMs/styles之间变化很大(例如,原始ICS根本没有透明填充)。

中间结论是,我的原始代码正确地将我的ImageView与我的EditText对齐。然而,我真正想要的是将我的ImageView与EditText背景的可见部分对齐。

为了实现这一点,我扫描了一个我从EditText的背景drawable创建的位图。我从上到下和从下到上扫描它,以找到完全透明行的数量,并将这些值用作我的ImageView的顶部/底部填充。所有这些都在我的N1上始终少于5ms。以下是代码:

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;
}

它像魔法一样工作!

it works!


很高兴看到您已经有了解决方案,但每次在运行时创建它并不是一个好方法,特别是当您有许多带有editText的图像时。您是否在xml或其他地方找到了其他解决方案? - PiyushMishra
很遗憾,这是不可能的。请仔细阅读我的回答,相信您会明白为什么使用纯XML不可能实现此功能。 - goncalossilva
1
看到您的问题,我想说当你有一个编辑文本框图像时,这很容易解决。文本框的默认图像创建了一个问题,但是我也看到了您的问题和答案,您做得非常好。但是当您有大量数据时,最好使用自己的图像作为文本框的背景,因为在运行时编辑位图可能会占用大量内存。 - PiyushMishra
是的,在这种情况下,使用自己的背景图像而不是愚蠢的边框将是一个更好的解决方案!在这种情况下,我们只有一个EditText,并且希望支持所有类型的本地EditText...所以我们必须采取这种方法。 - goncalossilva

1
为了去除EditText中的填充,只需使用自定义图像作为背景...一个带有一些阴影的矩形就足够了...或者您喜欢的任何其他样式...然后将该背景分配给EditText即可。
android:background="@drawable/myBackground"

1
你需要使用 RelativeLayout 并添加 android:align_bottomandroid:align_Top 属性。我不会写代码。

你不需要这样做 :) 无论如何,它都不起作用。我已经将它们包装在RelativeLayout中,并添加了android:layout_alignTopandroid:layout_alignBottom到ImageView。与上面的截图结果相同。 - goncalossilva
你能否在ImageView和TextView中都添加android:layout_alignParentTop="true"android:layout_alignParentBottom="true" - PravinCG
很不幸,同样的问题。真正的问题在于EditText的背景包含一些透明像素(主要是底部,但顶部也有):https://github.com/android/platform_frameworks_base/raw/master/core/res/res/drawable-hdpi/textfield_default.9.png - goncalossilva
1
你可以在这种情况下为editText添加一个透明的背景。不过让我试一下。 - PravinCG
1
我刚测试了一下,你是正确的,这是由于固有的边距引起的问题。唯一的解决办法是在你的editext中使用android:background ="#FFFF0000"来移除它。你可以选择任何颜色,但它不会是默认样式。 - PravinCG
显示剩余3条评论

1
你尝试过使用setCompoundDrawables()方法来处理EditText吗?
你可以通过在Drawable上使用setBounds()方法或使用setCompoundDrawablesWithInstrinsicBounds()方法来设置内在边界。
这应该适用于所有设备。

我会尝试并报告结果。谢谢! - goncalossilva
我已经尝试过它并且效果不错。然而,这并不是我真正想要实现的...使用setCompoundDrawables()将图像放置在EditText内部,而不是紧挨着它。无论如何感谢您提供的替代方法!加一赞! - goncalossilva
哦...好的。如果您找不到合适的解决方案,您可以尝试将背景设置为EditText,其中包括图像和填充EditText以避免它,或者将Drawable作为compoundDrawable和单独的背景drawable,折扣可绘制区域。 - Saad Farooq
我找到了一个合适的解决方案!请查看我的答案,看看我是如何做到的。感谢您的帮助,并让我学会了如何使用 setCompoundDrawables() ;) - goncalossilva

0

我使用了一个快速解决方法,只需将EditText向下移动2dp,只需在EditText中添加以下内容:

android:layout_marginBottom="-2dp"
android:layout_marginTop="2dp"

这种解决方法只适用于目标设备数量较少的情况。在Note 3中,2dp比Ace 2多得多。 - ArturoNaredo

0

使用 android:layout_centerInParent = true 属性来对编辑框进行布局,看看是否有效?


1
很遗憾,android:layout_centerInParent 对于 LinearLayout 没有任何效果。 - goncalossilva
它是LinearLayout,所以android:layout_centerInParent不起作用。 - Dharmendra
这在不同的分辨率、操作系统版本和ROM上无法良好适配。 - goncalossilva

0
移除editText和ImageView的属性android:gravity="center",将线性布局(linearlayout)的重心属性设置为center_vertically。

尝试过了,但是得到了相同的结果。谢谢! - goncalossilva

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接