Распределение изображения лучшего качества из ресурсов на основе разрешения / плотности
Я борюсь с довольно тривиальной задачей в домене 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)