我有一个让我发疯的问题。

我有4个函数,它们可以通过UI,使用密度(1.5)和通过视图,位图,屏幕等报告的宽度/高度值正确调整图像的大小。

这在SG II上表现出色。但是在HTC Wildfire上,它报告的密度为0.75 ...有些图像在屏幕上的视觉效果太小了25%...但是当我决定将密度改写为1.0时,这些图像突然变得合适了,而其他图像变得清晰起来,但不再像正确...这让我发疯...

我只能在一些地方比较苹果和梨(像素和DIP),但是我无法让我的测试与我所读的内容相符,因此请努力确保100%确定某些内容:

...

我会在下面得到像素吗?或DIP? :

int bitmapWidth = bitmap.getWidth();


假设下面是一个包含位图的imageview。像素还是DIP?

int widthParent = view.getWidth();


实际上是DIP,对不对?

getContext().getResources().getDisplayMetrics().widthPixels;


...

这是我的代码不起作用(此代码提供的位图在视觉上可能占用2 / 3s宽度,而在此位置应该占100%的宽度)如果您检查注释,则像素值显然是正确的,但最终结果是不正确的:

vto.addOnGlobalLayoutListener(
  new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
      mainLogo.getViewTreeObserver().removeGlobalOnLayoutListener(this);
      mainLogo.setScaleType(ImageView.ScaleType.CENTER_INSIDE); // mainLogo = ImageView
      SharedCode.sharedUtilScaleImage_Width(mainLogo, false);
    }
  }
);

// ...

public static void sharedUtilScaleImage_Width(ImageView view, boolean tryBackground)
  {
    Drawable drawing = null;
    boolean useBackground = false;
    if (drawing == null) {
      drawing = view.getDrawable();
    }
    if (drawing == null) {
      if (tryBackground) {
        drawing = view.getBackground();
        useBackground = true;
      }
    }
    if (drawing == null) {
      return;
    }
    if (!(drawing instanceof BitmapDrawable)) {
      return;
    }
    Bitmap bitmap = ((BitmapDrawable)drawing).getBitmap();
    if (bitmap == null) {
      return;
    }
    //--
    int bitmapWidth = bitmap.getWidth(); // returns 770 (which is correct checking on disk)
    int bitmapHeight = bitmap.getHeight();
    // float density = 1;
    // density = MicApp.getContext().getResources().getDisplayMetrics().density; // 1.5
    float widthScreen = MicApp.getContext().getResources().getDisplayMetrics().widthPixels; // returns 480
    int widthParent = view.getWidth(); // returns 480, should be same as screen
    //--
    float xScale = ( (float) widthParent / (float) bitmapWidth);
    Matrix matrix = new Matrix();
    matrix.postScale(xScale, xScale);
    //--
    Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmapWidth, bitmapHeight, matrix, true);
    int bitmapWidth2 = scaledBitmap.getWidth(); // 480
    int bitmapHeight2 = scaledBitmap.getHeight();
    //--
    BitmapDrawable result = new BitmapDrawable(scaledBitmap);
    //--
    if (useBackground) {
      LayoutParams layoutparams = new LayoutParams(bitmapWidth, bitmapHeight);
      view.setLayoutParams(layoutparams);
      view.setBackgroundDrawable(result);
    }
    else {
      view.setImageDrawable(result);
    }
  }

最佳答案

在解码图像和显示图像之间有几个步骤。这些步骤通常用于以正确的比例显示来自资源的图像。如果仅将图像放置在/res/drawable-mdpi/中,而不是放置在其他文件夹中,则仍可以在具有其他密度的设备上以正确的尺寸显示图像。

如果要在mdpi(320dpi)设备上加载用于x-hdpi(160dpi)的图像并希望以相同的尺寸显示,则实际上需要将其像素大小加倍。例如。一个100x100像素的图像需要以200x200像素显示。

扩展涉及的地方是


解码图像(例如,参见BitmapFactory.Options#inDensity)。 BitmapFactory可以将100x100 png图像解码为200x200图像。
Bitmap的自身密度。这是每个位图的一个属性,用于存储图像的密度。如果BitmapFactory已经将100x100 mdpi图像解码为200x200,则该密度实际上会说“我是x-hdpi”。您还可以在解码时禁用缩放功能,并获得具有mdpi密度的100x100图像。显示该图像将需要绘制缩放为2倍的图像。
BitmapDrawable的目标密度,通常是设备的密度。如果BitmapDrawable必须在密度不匹配的地方绘制Bitmap,则会绘制缩放版本。


BitmapDrawablemTargetDensity中的代码应为设备密度。

private void computeBitmapSize() {
    mBitmapWidth = mBitmap.getScaledWidth(mTargetDensity);
    mBitmapHeight = mBitmap.getScaledHeight(mTargetDensity);
}


而来自BitmapmDensity的相关片段是位图的密度

public int getScaledWidth(int targetDensity) {
    return scaleFromDensity(getWidth(), mDensity, targetDensity);
}

static public int scaleFromDensity(int size, int sdensity, int tdensity) {
    if (sdensity == DENSITY_NONE || sdensity == tdensity) {
        return size;
    }

    // Scale by tdensity / sdensity, rounding up.
    return ((size * tdensity) + (sdensity >> 1)) / sdensity;
}



缩放选项,例如ImageView。如果要显示ImageDrawable表示图像(由于缩放或实际上)在屏幕上实际上是400x300像素的ImageView中200x200像素,则需要再次缩放图像。


使用ImageView.ScaleType.CENTER_INSIDE将以200x200像素绘制图像,因为CENTER_INSIDE仅在图像大于视图时缩放图像。 FIT_CENTER会将其缩放为300x300。仅CENTER根本无法缩放。它只是居中。

CENTER_INSIDE +上面的100x100 mdpi图像仍将其绘制为200x200px,因为所有缩放因子都存储在BitmapDrawable / Bitmap中。

BitmapFactory> Bitmap> BitmapDrawable> ImageView链中还有其他几个地方,例如BitmapDrawable(Bitmap bitmap)构造函数说


  API级别4中不推荐使用此构造方法。使用BitmapDrawable(Resources,Bitmap)确保可绘制对象已正确设置其目标密度。


这可能会以不希望的方式影响图像缩放。

->防止所有缩放


无需缩放即可解码
确保位图的密度是当前设备的密度,或者只是Bitmap#setDensity(Bitmap.DENSITY_NONE)
通过ImageView.ScaleType.CENTER绘制时不要应用缩放比例。

10-07 20:06