简体   繁体   English

基于分辨率/密度的资源的最佳质量图像分配

[英]Best quality image allocation from resources based on resolution/density

I'm struggling with a pretty trivial task in the Android "multiple-screen sizes" domain. 我正在努力解决Android“多屏尺寸”领域的一项非常简单的任务。

What I'm trying to achieve 我想要实现的目标

A layout matching the screen width, with a nine-patch background which resizes (only horizontally, since there is always enough vertical space). 与屏幕宽度匹配的布局,具有9个补丁背景,其大小调整(仅水平,因为总是有足够的垂直空间)。 Here is a dummy image: 这是一个虚拟图像: 水平可伸缩的九个补丁图像,左右两端有两个区域

My goal is, depending on the screen resolution, to display the image at the highest resolution possible, by using a set of different sizes, eg. 我的目标是,根据屏幕分辨率,使用一组不同的尺寸,例如,以尽可能高的分辨率显示图像。 320x45, 480x67, 600x87, 720x101, without any down-scaling. 320x45,480x67,600x87,720x101,无需任何缩小。 I'm hoping for a non-programmatic solution. 我希望有一个非程序化的解决方案。

An example with the above mentioned image sizes would be: 具有上述图像尺寸的示例将是:

  • 3.7" Nexus One (480 x 800) - the 480x67 image would look best. 3.7“Nexus One(480 x 800) - 480x67图像效果最佳。
  • 4.7" Galaxy Nexus (720 x 1280) - the 720x101 image. 4.7“Galaxy Nexus(720 x 1280) - 720x101图像。
  • 4.7" Nexus 4 (768 x 1280) - again the 720x101 image, stretching to the full 768 px width and becoming 768x101. 4.7“Nexus 4(768 x 1280) - 再次是720x101图像,拉伸至完整的768像素宽度并变为768x101。

Issue 问题

The whole Android resource allocation revolves around dp s (density-independent pixels), when in fact I want to display an image based on the actual available pixels. 整个Android资源分配围绕dp s(与密度无关的像素),实际上我想根据实际可用像素显示图像。

If I allocate the 480x67 image to res/drawable-mdpi and a 600x87 to res/drawable-hdpi, then image would display correctly on a 5.4" display of 480x800 , ie mdpi display. However, a 4" 480x800 displays qualifies as hdpi and the system would appoint the 600x87 image, which won't fit the screen . 如果我将480x67图像分配给res / drawable-mdpi,将600x87分配给res / drawable-hdpi,则图像将在5.4x800的480x显示器上正确显示 ,即mdpi显示。但是,4“480x800显示器符合hdpi和系统将指定600x87图像,这将不适合屏幕

I tried the smallestWidth parameter as described in the online guide , but that yields strange results. 我尝试了在线指南中描述的smallestWidth参数,但这会产生奇怪的结果。 For instance, a 3.7" 480 x 800 display (hdpi) uses my drawable-sw320dp image, although there is a drawable-sw480dp resource available too. 例如,一个3.7“480 x 800显示器(hdpi)使用我的drawable-sw320dp图像,尽管有一个drawable-sw480dp资源也可用。

What is the best way to assign a stretchable, width-matching image with the best possible quality? 分配具有最佳质量的可拉伸宽度匹配图像的最佳方法是什么? Isn't there any non-programmatic solution? 是不是有任何非程序化的解决方案?

Thanks in advance! 提前致谢!

I believe that by combining density and screen size resource qualifiers you can achieve a close to optimal behavior. 我相信通过组合密度和屏幕大小资源限定符,您可以实现接近最佳行为。

Lets assume this kind of resource folders structure: 让我们假设这种资源文件夹结构:

  • drawable-normal-hdpi - A normal size dictates minimum width of 320dp. drawable-normal-hdpi - normal大小规定最小宽度为320dp。 hdpi dictates 1.5X dp to pixel multiplier. hdpi指示1.5X dp到像素乘数。 So the minimum px width of the normal hdpi bucket is 480px. 因此, normal hdpi存储桶的最小px宽度为480px。 We put here a 480px wide image. 我们在这里放了480px宽的图像。
  • drawable-normal-xhdpi - Again size dictates 320dp but this time with 2X multiplier. drawable-normal-xhdpi - 再次大小指示320dp但这次使用2倍乘数。 So we use a 640px wide image. 所以我们使用640px宽的图像。
  • drawable-xlarge-mdpi - Size means at least 720dp. drawable-xlarge-mdpi - 大小意味着至少720dp。 mdpi multiplier is 1X, so we use a 720px wide image. mdpi乘数是1X,所以我们使用720px宽的图像。

Now lets look at some devices to see how they fall in with those buckets: 现在让我们看看一些设备,看看它们是如何落入这些存储桶的:

  • Nexus one - normal hdpi . Nexus one - normal hdpi Actual px width: 480px. 实际px宽度:480px。 The image fits perfectly. 图像非常适合。
  • Galaxy nexus - normal xhdpi . Galaxy nexus - normal xhdpi We could fit a 720px image, so the 640px image we use isn't optimal - but it's very close. 我们可以适应720px的图像,因此我们使用的640px图像并不是最佳的 - 但它非常接近。
  • Nexus 4 is just like the Gnex. Nexus 4就像Gnex一样。
  • Nexus 10.1 (1280X800) - xlarge mdpi . Nexus 10.1(1280X800) - xlarge mdpi We could fit 800px, our image is 720px. 我们可以适合800px,我们的图像是720px。 Again not ideal but close enough. 再次不理想但足够接近。

Worst case scenario: image used could have 5-10% better quality. 最糟糕的情况:使用的图像质量可提高5-10%。 Best case: perfect fit. 最佳表壳:完美贴合。

The main down side of this method is that you need to provide a lot of resources and folders to account for all the permutations of sizes and densities (even worse if you need to combine that with more qualifiers for locale, orientation and so on). 这种方法的主要缺点是你需要提供大量的资源和文件夹来考虑大小和密度的所有排列(如果你需要将它与更多的限定符组合用于区域设置,方向等,则更糟糕)。 However, as far as my Android understanding goes I don't think you can achieve something better than this without coding. 但是,就我的Android理解而言,我不认为你可以在没有编码的情况下取得比这更好的东西。


A remark regarding smallestWidth : Your example for the weird behavior is actually the expected behavior. 关于smallestWidth的评论:你的奇怪行为的例子实际上是预期的行为。 hdpi multiplier is 1.5 - So a 480px wide hdpi display is exactly 320dp wide. hdpi乘数为1.5 - 因此480px宽的hdpi显示器正好是320dp宽。 This makes the drawable-sw320dp the right choice, as documented. 这使得drawable-sw320dp成为正确的选择,如文档所述。 I'm not sure if you can combine the smallestWidth qualifier with the dpi qualifier. 我不确定你是否可以将smallestWidth限定符与dpi限定符组合使用。 If it's possible you might get more accurate results than just size modifiers. 如果可能的话,您可能会获得比仅仅大小修饰符更准确的结果。 But this would mean a lot more permutations for a 5% increase in image quality. 但这意味着图像质量提高5%会产生更多的排列。 Probably not worth it. 可能不值得。

Actually, your method is not how it is supposed to be. 实际上,你的方法不是它应该如何。 I will suggest 2 ways for you, one is easy but doing programmatically, other one is using a custom view. 我将为您推荐两种方法,一种是简单但以编程方式进行,另一种是使用自定义视图。

Method 1 - Programmatically 方法1 - 以编程方式

    DisplayMetrics displaymetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    int screenWidth = displaymetrics.widthPixels; 
    // this will determine "scale ratio" so using which image height and width won't matter 
    int imageOriginalHeight = 101; // your original image height        
    int imageOriginalWidth = 720; // your original image width
    int imageScaleHeight = (screenWidth*imageOriginalHeight) / imageOriginalWidth;

    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(screenWidth, imageScaleHeight);
    imageView.setLayoutParams(params);
    imageView.setImageResource(R.drawable.file);

Method 2 - Custom View 方法2 - 自定义视图

You can use a custom view called ScaleImageView which is written by Maurycy Wojtowicz. 您可以使用由Maurycy Wojtowicz编写的名为ScaleImageView的自定义视图。

Class is defined like below: 类定义如下:

This view will auto determine the width or height by determining if the height or width is set(exact size or match_parent) and scale the other dimension depending on the images dimension This view also contains an ImageChangeListener which calls changed(boolean isEmpty) once a change has been made to the ImageView 此视图将通过确定是设置高度还是宽度(精确大小或match_parent)自动确定宽度或高度,并根据图像维度缩放其他维度此视图还包含一个ImageChangeListener,一旦更改,就会调用changed(boolean isEmpty)已经对ImageView做了

Here is how you are going to implement it. 以下是您将如何实现它。

Create a class named ScaleImageView.java and copy contents of the link above. 创建一个名为ScaleImageView.java的类,并复制上面链接的内容。

In your xml file, create a ScaleImageView , just same like ImageView (the example I am writing below is for filling screenwidth, and scaling height according to that so there will be no empty spaces on right/left) 在你的xml文件中,创建一个ScaleImageView ,就像ImageView一样(下面我写的例子是填充屏幕宽度,根据它来缩放高度,所以右边/左边没有空格)

    <com.project.customview.ScaleImageView
        android:id="@+id/scaleImageView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:scaleType="fitCenter"
        android:src="@drawable/file" />

If you need to declare and set programmatically in your Activity, it is also the same as using ImageView: 如果需要在Activity中以编程方式声明和设置,它也与使用ImageView相同:

imageView = (ScaleImageView)findViewById(R.id.scaleImageView);
imageView.setImageResource(R.drawable.file);

In android you have the option hdpi, mdpi, xdpi,etc.. 在android中你有选项hdpi,mdpi,xdpi等。

folders for that , you have to create different images according your device resolution and put your images at there after confirming your device resolution and density category. 为此,您必须根据设备分辨率创建不同的图像,并在确认设备分辨率和密度类别后将图像放在那里。

for the more reference why it'll happen you can see here 为了更多的参考,为什么它会发生你可以看到这里

here i explain some chart may be helpful to you. 在这里我解释一些图表可能对您有所帮助。

Low density Small screens QVGA 240x320 (120dpi): 低密度小屏幕QVGA 240x320(120dpi):

drawable-small-ldpi (240x320) drawable-small-ldpi(240x320)
drawable-small-land-ldpi (320x240) drawable-small-land-ldpi(320x240)

Low density Normal screens WVGA400 240x400 (x432) (120dpi): 低密度普通屏幕WVGA400 240x400(x432)(120dpi):

drawable-ldpi (240 x 400 ) drawable-land-ldpi (400 x 240 ) drawable-ldpi(240 x 400)drawable-land-ldpi(400 x 240)

Medium density Normal screens HVGA 320x480 (160dpi): 中密度普通屏幕HVGA 320x480(160dpi):

drawable-mdpi (320 x 480 ) drawable-land-mdpi (480 x 320 ) drawable-mdpi(320 x 480)drawable-land-mdpi(480 x 320)

Medium density Large screens HVGA 320x480 (160dpi): 中密度大屏幕HVGA 320x480(160dpi):

drawable-large-mdpi (320 x 480 ) drawable-large-land-mdpi (480 x 320) drawable-large-mdpi(320 x 480)drawable-large-land-mdpi(480 x 320)

Galaxy Tab ( 240 dpi ): Galaxy Tab(240 dpi):

drawable-large (600 x 1024) drawable-large-land (1024 x 600) drawable-large(600 x 1024)drawable-large-land(1024 x 600)

High density Normal screens WVGA800 480x800 (x854) (240 dpi): 高密度普通屏幕WVGA800 480x800(x854)(240 dpi):

drawable-hdpi (480 x 800) drawable-land-hdpi (800 x 480) drawable-hdpi(480 x 800)drawable-land-hdpi(800 x 480)

Xoom (medium density large but 1280x800 res) (160 dpi): Xoom(中密度大,但1280x800 res)(160 dpi):

drawable-xlarge (800 x 1280) drawable-xlarge-land (1280 x 800) drawable-xlarge(800 x 1280)drawable-xlarge-land(1280 x 800)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM