Распределение изображения лучшего качества из ресурсов на основе разрешения / плотности

Я борюсь с довольно тривиальной задачей в домене Android с несколькими размерами экрана.

Чего я пытаюсь достичь

Макет, соответствующий ширине экрана, с фоном из девяти пятен, который изменяет размеры (только по горизонтали, так как вертикального пространства всегда достаточно). Вот фиктивное изображение: растянутое по горизонтали изображение с девятью пятнами с двумя областями на левом и правом концах

Моя цель, в зависимости от разрешения экрана, отображать изображение с максимально возможным разрешением, используя набор разных размеров, например. 320x45, 480x67, 600x87, 720x101, без масштабирования. Я надеюсь на непрограммное решение.

Пример с вышеупомянутыми размерами изображения будет:

  • 3,7" Nexus One (480 x 800) - изображение 480x67 будет выглядеть лучше.
  • 4,7" Galaxy Nexus (720 x 1280) - изображение 720x101.
  • 4,7" Nexus 4 (768 x 1280) - снова изображение 720x101, растянутое до полной ширины 768 пикселей и ставшее 768x101.

вопрос

Все распределение ресурсов Android вращается вокруг dp s (независимые от плотности пикселей), когда на самом деле я хочу отобразить изображение на основе фактически доступных пикселей.

Если я выделю изображение 480x67 для res/drawable-mdpi, а 600x87 - для res / drawable-hdpi, то изображение будет правильно отображаться на 5,4 -дюймовом дисплее с разрешением 480x800, то есть на дисплее с разрешением mdpi. Однако 4-дюймовое изображение с разрешением 480x800 квалифицируется как hdpi и система назначит изображение 600x87, которое не будет соответствовать экрану.

Я попробовал smallestWidth параметр, как описано в онлайн-руководстве, но это дает странные результаты. Например, 3,7-дюймовый дисплей с разрешением 480 x 800 (hdpi) использует мое изображение drawable-sw320dp, хотя также доступен ресурс drawable-sw480dp.

Каков наилучший способ назначить растягиваемое изображение, соответствующее ширине, с наилучшим возможным качеством? Нет ли какого-либо непрограммного решения?

Заранее спасибо!

3 ответа

Решение

Я считаю, что, комбинируя квалификаторы ресурсов с плотностью и размером экрана, вы можете достичь поведения, близкого к оптимальному.

Предположим, что это структура папок ресурсов:

  • drawable-normal-hdpi - А normal Размер диктует минимальную ширину 320dp. hdpi диктует 1,5X дп к пиксельному множителю. Таким образом, минимальная ширина пикселя normal hdpi ведро 480px. Мы помещаем сюда изображение шириной 480px.
  • drawable-normal-xhdpi - Опять же размер диктует 320dp, но на этот раз с множителем 2X. Поэтому мы используем изображение шириной 640 пикселей.
  • drawable-xlarge-mdpi - Размер означает, по крайней мере, 720dp. mdpi множитель 1X, поэтому мы используем изображение шириной 720px.

Теперь давайте посмотрим на некоторые устройства, чтобы увидеть, как они попадают в эти корзины:

  • Нексус один - normal hdpi, Фактическая ширина в пикселях: 480 пикселей. Изображение подходит идеально.
  • Galaxy Nexus - normal xhdpi, Мы могли бы разместить изображение с разрешением 720px, поэтому используемое нами изображение с разрешением 640px не является оптимальным, но оно очень близко.
  • Nexus 4 похож на Gnex.
  • Nexus 10.1 (1280X800) - xlarge mdpi, Мы могли бы уместить 800 пикселей, наше изображение - 720 пикселей. Опять не идеально, но достаточно близко.

Наихудший сценарий: используемое изображение может иметь на 5-10% лучшее качество. Лучший случай: идеально подходит.

Основным недостатком этого метода является то, что вам необходимо предоставить много ресурсов и папок для учета всех сочетаний размеров и плотностей (что еще хуже, если вам нужно объединить это с большим количеством определителей для локали, ориентации и т. Д.). Однако, насколько мне известно об Android, я не думаю, что вы можете достичь чего-то лучшего, чем это без кодирования.


Замечание относительно smallestWidthВаш пример странного поведения на самом деле - ожидаемое поведение. множитель hdpi равен 1,5 - таким образом, дисплей hdpi шириной 480px имеет ширину ровно 320 dp. Это делает drawable-sw320dp правильным выбором, как задокументировано. Я не уверен, что вы можете объединить smallestWidth классификатор с определителем dpi. Если это возможно, вы можете получить более точные результаты, чем просто модификаторы размера. Но это будет означать гораздо больше перестановок для повышения качества изображения на 5%. Наверное, не стоит.

На самом деле, ваш метод не такой, каким он должен быть. Я предложу вам два способа: один простой, но программный, другой - пользовательский вид.

Метод 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);

Способ 2 - Пользовательский вид

Вы можете использовать пользовательское представление ScaleImageView, написанное Maurycy Wojtowicz.

Класс определяется как показано ниже:

Это представление будет автоматически определять ширину или высоту, определяя, установлена ​​ли высота или ширина (точный размер или match_parent), и масштабировать другое измерение в зависимости от измерения изображений. Это представление также содержит ImageChangeListener, который вызывает change (boolean isEmpty) после изменения был сделан для ImageView

Вот как вы собираетесь это реализовать.

Создайте класс с именем ScaleImageView.java и скопируйте содержимое ссылки выше.

В вашем 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" />

Если вам нужно объявить и установить программно в вашей деятельности, это также как использование ImageView:

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

В Android у вас есть опция hdpi, mdpi, xdpi и т.д..

папки для этого, вы должны создавать разные изображения в соответствии с разрешением вашего устройства и помещать туда свои изображения после подтверждения разрешения вашего устройства и категории плотности.

для более подробной информации, почему это произойдет, вы можете увидеть здесь

Здесь я объясняю, что некоторые диаграммы могут быть вам полезны.

Малые экраны низкой плотности QVGA 240x320 (120 точек на дюйм):

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

Нормальные экраны низкой плотности WVGA400 240x400 (x432) (120 точек на дюйм):

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

Нормальные экраны средней плотности HVGA 320x480 (160 точек на дюйм):

Drawable-MDPI (320 х 480) Drawable Land-MDI (480 х 320)

Средняя плотность Большие экраны HVGA 320x480 (160 точек на дюйм):

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

Galaxy Tab (240 точек на дюйм):

большой для рисования (600 x 1024) большой для рисования (1024 x 600)

Нормальные экраны высокой плотности WVGA800 480x800 (x854) (240 т / д):

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

Xoom (средняя плотность, большая, но разрешение 1280x800) (160 точек на дюйм):

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

Другие вопросы по тегам