将ImageView的ScaleType设置为“center”不起作用,与我的期望不符。

4
我有一个关于ImageView的布局如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:descendantFocusability="blocksDescendants">
    <ImageView
        android:id="@+id/imageview_icon"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:scaleType="fitCenter" />
    (...)
</LinearLayout>

那些48dp相当于36px、48px和72px在ldpi、mdpi和hdpi中。所有将用于此ImageView的图像基本上都是图标,我已经在网上找到了我想要的应用程序(免费许可证)。但不幸的是,它不带有大于48px的图像,并且使用不同的图像是不可能的。所以我需要一个新的解决方案…
目前,我在ldpi和mdpi文件夹中分别拥有36px和48px的图像。但是我在hdpi上遇到了麻烦。我想要运行在hdpi设备上的设备使用mdpi图像(可用的更大的图像)并将其原样使用,而不进行缩放。基本上,hdpi的ImageView为72px,因此我希望48px的图像位于72px内部,在中心位置,而不进行缩放。为此,我尝试更改上面ImageView中的scaleType为center,但是图像仍然被缩放。
我的最终问题是,如何正确解决上述问题?我如何在各自的密度中使用ldpi和mdpi图像,但是让运行hdpi的设备选择可用的最大图像(即mdpi),并防止任何缩放,只需将图像放入ImageView的中心?
编辑: 我自己回答了这个问题,但是其他人可能正在寻找的答案可能是这个。但是我确实提供了一些关于正在发生的事情和潜在问题的见解。如果可以,请查看并提供解决方法/修复程序。我敢你:)

是的,尝试了大多数逻辑可能性。什么都没用 :( - rfgamaral
我可以问一下你为什么需要这个吗?通常人们希望在普通屏幕上,五个 64dp 的图标应该始终占据整个屏幕宽度(即 320dp),不论设备分辨率如何,图标始终保持相同的外观,并且图标的两侧始终接触(可选择使用与设备无关的填充)。 - Daniel Fekete
我不明白你的问题... - rfgamaral
我在我的项目工作中使用了一个库来实现可提取性(使背景变圆),但当我将其更改为ImageView时,它完美地工作了! - vrushabh chitalia
7个回答

14

这个问题实际上不是一个问题,我向任何找到它的人道歉,希望接受的答案能够满足他们的需求。

为了明确起见,scaleType=centerInside 的工作效果是符合预期的。也就是说,如果您有一张比 ImageView 更小的图像,则该图像不会被缩放到ImageView的边界范围内,而是保持在中心位置且不缩放。

但是,为了使以上内容按预期工作,Drawable必须放置在nodpi文件夹中。我知道这并不总是可行的。因此,当Drawable必须放置在密度文件夹中而不是nodpi文件夹中时,scaleType属性只能在特定情况下使用。

它将在何时起作用:

  • 您在具有Xdpi密度的设备/模拟器上运行应用程序,并且Xdpi密度文件夹中有Drawable(这里的X表示lmh或者xh)。
  • 您在设备/模拟器上运行应用程序,例如使用hdpi密度,但hdpi文件夹中没有Drawable,并且系统从nodpi文件夹中选择替代Drawable(通常不知道它会从哪个文件夹中选择)。

它将不起作用的情况:

  • 您在设备/模拟器上运行应用程序,例如使用hdpi密度,但hdpi文件夹中没有Drawable,并且系统从任何其他密度文件夹(而不是nodpi文件夹)中选择替代Drawable,那么Drawable将缩放到ImageView边界,并且scaleType属性不起作用。
总之,对于我的问题,没有“正确”的答案,它真的取决于你想要实现什么。对于我的问题,我只需要做两件事:a)将ImageViewscaleType设置为centerInside;b)将mdpi文件夹中的所有可绘制对象复制到hdpi文件夹中(如上所述,scaleType=centerInside会使其正常工作)。
当然,复制可绘制对象并不是最优解,但我找不到其他解决方案,迄今为止也没有其他人能找到...因此,在这段时间里,我会把这个方法标记为接受的。
那么,最佳答案/解决方案是什么呢?
在我看来,如果设备/模拟器正在运行hdpi,并且在hdpi文件夹中没有匹配的可绘制对象,则应从mdpi文件夹中选择可绘制对象而不进行缩放,从而允许scaleType属性发挥作用。或者强制系统进入nodpi文件夹,如果在相应密度文件夹中找不到匹配的可绘制对象,则可能是一种解决方案。
因此,如果有人能够提供这个问题的解决方法/修复方法,那将是真正正确的答案。如果发生这种情况,我会改变接受的状态。

2
在我的情况下,我将图像设置为 android:background。当我将其设置为 android:src 时,它可以正常工作!

1
我是这样解决的:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">
    <!-- Here is where the money is -->
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:gravity="center_horizontal|center_vertical">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    </LinearLayout>
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        ...
    </LinearLayout>
</LinearLayout>

0

试试这个:

<FrameLayout android:layout_width="48dp" android:layout_height="48dp">
<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"

    android:maxWidth="48px"
    android:maxHeight="48px"
    android:adjustViewBounds="true"
    android:src="..."
    />
</FrameLayout>

并将图像通常放置在ldpi / mdpi文件夹中。

尽管我不建议使用像素值。


然后将 ImageView 包装在 <FrameLayout android:layout_width="48dp" android:layout_height="48dp"> 中。您需要多频繁使用此操作?我认为 ImageView 不是为部分以密度无关方式 ldpi-mdpi 工作而设计的,而不是在 hdpi 中。 - Daniel Fekete
你能否编辑你的回答并提供一个完整的例子来说明你最后的建议吗? - rfgamaral
不是我想要的,你仍然强制图片不超过48px,而我不想要这样。如果它们确实是48px,我希望它们是48px,但如果它们更小,我希望它们更小,如果它们更大,我希望它们更大(但不要超过48dp,在hdpi中为72px)。也许我没有正确地解释自己,但我不确定如何更好地做到这一点。值得一提的是,我还尝试了类似于FrameLayout想法的示例,但没有使用'max'参数,图像仍然被缩放到FrameLayout的全尺寸。 - rfgamaral
那么将图像从mdpi复制到hdpi,这样它们就会相同,并且只需使用简单的ImageView即可。 - Daniel Fekete
在广泛地测试了这个问题之后,我得出了一个结论和对真正问题的洞察。如果您愿意,请查看我的答案并发表评论,如果您有什么要补充或知道真正的答案,请告诉我。谢谢。 - rfgamaral
显示剩余2条评论

0
创建自定义的ImageView:
package x;

public class MaxMDPIImageView extends ImageView {

    public MaxMDPIImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        float density = getResources().getDisplayMetrics().density;
        if (density>1) {
            canvas.translate(getWidth()/2-getWidth()/density/2, getHeight()/2-getHeight()/density/2);
            canvas.scale(1/density, 1/density);
        }
        super.onDraw(canvas);
    }

}

使用方法很简单:

<x.MaxMDPIImageView
    android:src="@drawable/icon"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
    />

如果我正确理解你的代码,我认为你仍然不明白我想做什么。那段代码(如果我理解正确)将更改每个图像大小,而我不想要那样。无论如何,这个问题已经不再相关了,请阅读我的长篇回答。 - rfgamaral

0

尝试一下

imageview.setAdjustViewBounds(false);

0

尝试将其从hdpi文件夹中移除,并放置在drawable-nodpi文件夹中。我不确定层次结构是什么(是否nodpi会覆盖ldpi和mdpi文件夹),但这将是我的第一次尝试。


我从未在“hdpi”文件夹中放置任何内容。我只在“mdpi”文件夹中有48px的图像和在“ldpi”文件夹中有36px的图像。我相信被“hdpi”设备选中的图像是“mdpi”文件夹中的图像。问题在于,这个图像正在被缩放,而它不应该被缩放,因为我明确告诉它不要缩放(scaleType=center)。 - rfgamaral
尝试使用nodpi文件夹中的48px图像。 - Kevin Coppock
如果我将mdpi文件夹中所有48px图像的副本创建到nodpi文件夹中,它仍然无法正常工作。我不知道hdpi设备使用哪个文件夹中的图像,但它仍会缩放到ImageView大小。当它们都应该工作时,scaleType=centerscaleType=centerInside都不起作用。 - rfgamaral
嗯...一个不好的解决方案是在<supports-screens>下将android:anydensity="false"添加到您的清单中。然后,您需要自己管理任何必要的缩放。如果将mdpi图像复制到hdpi文件夹中会有问题吗?图片足够大吗? - Kevin Coppock
是的,它们足够大且数量过多,以至于会产生重复项并需要手动处理扩展。这不是我想要的解决方案。一定有什么地方出了问题,这应该可以工作... - rfgamaral
显示剩余3条评论

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