Перейти к содержанию
Fire Monkey от А до Я
  • 0

Как использовать иконки разного качества для экранов с разным DPI?


Andrey Efimov

Вопрос

  • Модераторы

Здравствуйте.

Возник вопрос, какого размера должны быть иконки в приложении, чтобы оно выглядело одинаково на разных разрешениях/устройствах?

 

Вопрос вроде не сложный, но я что-то запутался…

 

Читал http://developer.android.com/design/style/iconography.html, но так и не понял какой размер использовать для иконок.

 

Пример ситуации: Нам нужно добавить иконку к пункту в ListBox’е, так чтобы иконка одинаково смотрелась на разных разрешениях экрана.

 

Из статьи я понял, что иконки могут быть:

  1. MDPI: 32x32
  2. HDPI: 48x48
  3. XHDPI: 64x64
  4. XXHDPI: 96x96

Но все 4-и вида запихнуть в один листбокситем нельзя. Поэтому и возник вопрос.

 

Я пришёл к выводу, что лучше использовать для иконки xxhdpi: 96x96, т.е. максимальный размер, предположив, что на большом или маленьком разрешении она будет ресайзиться сама. Правильно ли я всё понял? Если да, то тогда я не понимаю зачем делать(в том числе и гугл) 4-е вида иконок, если можно сделать одну xxhdpi: 96x96.

 

P.S. Очень нужно понять это, т.к. для приложения, которое я пишу, нужно нарисовать иконки (делаю это впервые). Жаль, что гугл даёт так мало стандартных иконок и в паке нет даже простейшей иконки файла.

P.S.2 Решил использовать пока HDPI: 48x48 (http://developer.android.com/design/style/metrics-grids.html)

Изменено пользователем admin
Ссылка на комментарий

Рекомендуемые сообщения

  • 0
  • Администраторы

Здесь есть много решений. Но я приведу на мой взгляд самый оптимальный вариант по простоте и производительности с использованием TStyleBook в качестве TImageList.

 

Основное нововведение для изображений в мобильных платформах - это использование экранов разной плотности пикселей. Что приводит к тому, что одно и тоже изображение на разных (с разным dpi) экранах имеет разные физические размеры. Подробнее об этом можно прочитать тут: Получаем разрешение экрана устройства, логические и физические размеры экрана в FireMonkey . Если коротко, то это значит, чтобы картинка была четкой на всех экранах нам нужно иметь в своем наборе несколько вариантов этой картинки для основных типов экранов (слева класс экрана - справа коэффициент масштабирования):

  1. MDPI - 1X
  2. HDPI - 1,5X
  3. XHDPI - 2X
  4. XXHDPI - 3X

Например, если у нас есть картинка 48х48 точек для обычного экрана (MDPI - 1X), то нам нужно по хорошему иметь еще три варианта этой картинки других размеров:

post-1-0-68276800-1391201197_thumb.jpg

Иначе, картинка или будет сжата, или растянута, что приведет к потере ее качества. Вариант загрузки одного большого изображения не хорош тем, что автоматическое сжатие изображение влечет за собой потерю качества, обычно выраженную в размытии картинки. Попробуйте вручную уменьшать размер изображения, и вы увидите, что в конечном итоге картинка будет либо размытой, либо искаженной в зависимости от алгоритма сжатия. Поэтому как раз и предлагается иметь несколько вариантов исходной картинки, адаптированной под разные варианты экраны.

 

Теперь на практике. FireMonkey специально для мобильных платформ поддерживает задание нескольких вариантов качества (dpi) одного изображения. Для этого в FireMonkey существует специальный класс TMultiResBitmap (Using Multi-Resolution Bitmaps). Который позволяет указать картинки для разных Scale. Он автоматически вернет картинку нужного качества для текущего устройства. Этот класс используется в TImage. 

 

1. Делаем форму с лист боксом:

post-1-0-30192400-1391201197_thumb.jpg

 

2. Создаем на основе TStyleBook хранилище картинок TImageList по руководству, представленному здесь: Есть ли в fmx класс TImageList?

 

3. Загружаем для каждой TImage несколько вариантов одного и того же изображения (MultiResBitmap Editor):

post-1-0-53587800-1391201197_thumb.jpg

 

4. Далее в режиме выполнения, запрашиваем картинку у ImageBook: TStyleBook. Обратите внимание, что при запросе картинке через TImage.Bitmap - этот метод вернет битмап нужного dpi.

function TForm5.GetImage(const AImageName: string): TBitmap;
var
  StyleObject: TFmxObject;
  Image: TImage;
begin
  StyleObject := ImageBook.Style.FindStyleResource(AImageName);
  if (StyleObject <> nil) and (StyleObject is TImage) then
  begin
    Image := StyleObject as TImage;
    // Здесь мы получим картинку нужного dpi (Scale)
    Result := Image.Bitmap;
  end
  else
    Result := nil;
end;

4. Используя полученную картинку присваиваем ее TListBoxItem:

const
  COUNT_ITEMS = 10;
var
  ItemTmp: TListBoxItem;
  BitmapCloud: TBitmap;
  I: Integer
begin
  BitmapCloud := GetImage('cloud');

  ListBox.BeginUpdate;
  try
    ListBox.Clear;
    for I := 1 to COUNT_ITEMS do
    begin
      ItemTmp := TListBoxItem.Create(Self);
      ItemTmp.Parent := ListBox;
      ItemTmp.Text := 'Item' + I.ToString;
      if BitmapCloud <> nil then
        ItemTmp.ItemData.Bitmap.Assign(BitmapCloud);
    end;
  finally
    ListBox.EndUpdate;
  end;
end;

P.S. На устройстве не проверял, но код должен работать. Чуть позже проверю на Nexus 4.

 

Полезные ссылки

  1. Получаем разрешение экрана устройства, логические и физические размеры экрана в FireMonkey
  2. Есть ли в fmx класс TImageList?
  3. Using Multi-Resolution Bitmaps
  4. MultiResBitmap Editor
Изменено пользователем admin
Обновлен код на основании комментариев ниже
Ссылка на комментарий
  • 0
  • Модераторы

Сейчас попробую и спать, а то уже 1:30))

Есть ещё вопрос: как-то можно достать стандартный стиль андроида, который используется по дефолту?

 

UPD. Попробовал, но не получилось. Ошибку выдаёт. Сейчас ещё посмотрю, может опять я...

UPD.2. От ошибки избавился, но картинки так и не грузит, всё перепроверил...

Ссылка на комментарий
  • 0
  • Администраторы
  1. Что за ошибка? Можно использовать ItemTmp.ItemData.Bitmap.Assign вместо варианта с IBitmapLink
  2. Вопрос про дефолтный стиль оформите отдельной темой.
Ссылка на комментарий
  • 0
  • Модераторы

Ошибка была из-за прошлых экспериментов со стилями, забыл очистить свойство формы StyleBook.

 

Про этот способ ItemTmp.ItemData.Bitmap.Assign знаю, уже попробовал, не хочет подгружать картинки и всё. Надо попробовать на чистом приложении.

 

p.s. Ярослав, спасибо вам за помощь и терпение!

 

UPD.(2:32) Точно надо было идти спать... Нашёл свой косяк. У меня было TImage.StyleName:='folders', а запрашивал я 'folder'. Картинки не грузит… Всё я спать, лучше завтра со свежей головой разберусь с этим. Ещё раз спасибо!

UPD.2.(2:36) Понял в чём косяк, ваш код отказывается у меня работать, а именно сточка (ItemTmp.ItemData.Bitmap as IBitmapLink).SetResourceBitmap(BitmapCloud);, получилось с ItemTmp.ItemData.Bitmap.Assign.

Ссылка на комментарий
  • 0
  • Администраторы

Завтра все равно попробую с IBitmapLink.

 

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

Ссылка на комментарий
  • 0
  • Модераторы

По поводу иконок, решил за базовый размер взять 48x48, т.е. по схеме:

MDPI - 1X - 48x48

HDPI - 1,5X - 64x64

XHDPI - 2X - 96x96

 

если взять за основу 32x32, т.е.

MDPI - 1X - 32x32

HDPI - 1,5X - 48x48

XHDPI - 2X - 64x64

 

то на моём Samsung Galaxy S2 иконки подгружаются размером 32x32 и выглядит это немного забавно, т.к. рядом расположена кнопка SpeedButton со свойством "StyleLookup:=organizetoolbutton" и она явно больше по размерам  :). Пример ниже.

 

За оригинальное решение и помощь спасибо! Если вдруг надо будет ещё что-то проверить, пишите.

 

post-19-0-00568300-1391240205.png

Ссылка на комментарий
  • 0
  • Администраторы

Завтра все равно попробую с IBitmapLink.

 

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

 

Вариант с заданием картинки через IBitmapLink нельзя использовать.

Ссылка на комментарий
Гость
Эта тема закрыта для публикации ответов.
×
×
  • Создать...