• 0
Andrey Efimov

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

Вопрос

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

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

 

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

 

Читал 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

7 ответов на этот вопрос

  • 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
Обновлен код на основании комментариев ниже
Andrey Efimov понравилось это

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

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

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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0
  1. Что за ошибка? Можно использовать ItemTmp.ItemData.Bitmap.Assign вместо варианта с IBitmapLink
  2. Вопрос про дефолтный стиль оформите отдельной темой.
Andrey Efimov понравилось это

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 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.

Brovin Yaroslav понравилось это

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

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

 

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

Andrey Efimov понравилось это

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 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 нельзя использовать.

Andrey Efimov понравилось это

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Гость
Эта тема закрыта для публикации сообщений.

  • Похожие публикации

    • Автор: denprox
      Доброго времени суток! Подскажите, как узнать оригинальный размер картинки, загруженной в TImage ?
    • Автор: ENRGY
      Меня это проблема преследует со времен VCL...
      Подскажите как же ее решить...
      FMX TListView - ItemAppearanceName = ImageListItem.   Лежит fmx TimageList, в настройках указано 16x16 и прорачный цвет clNone, добавил одну иконку 16x16 с прозрачностью. Если запустить под Windows 10  все ок. Если запустить под Android то при выделении (selected) вместо прозрачности белый цвет. В результате иконка некрасиво обрамлена в белом квадрате.. Иконку делал в Axiallis IconWorkShop, сохранил как ico,  Пробовал заливать белым вместо прозрачного, и затем ставить в TimageList белый как прозрачный - тоже самое...
      Что же делать...
    • Автор: chaplin.u@gmail.com
      При добавлении новых итемов в листбокс у него появляются скролы но самого итема не видно. как сделать автоскролинг чтобы активный итем был виден ?
      CurListBoxItem->SetFocus() не делает этого.
    • Автор: chaplin.u@gmail.com
      Столкнулся с разницей в нумерации индексов ( в Вин32 начинается с 0 а в Анроиде с 1 ). Решил при запуске программы находить минимальный индекс.
      Поставил на каждый TListBoxItem  Tag > 0 ( 1,2...) . Написал функцию а она рушит апликацию на старте. Не могу понять что ей не нравится.

       Imin определил как глобальную переменную  - int Imin = 0;
      если убираю эту функцию - программа стартует нормально.
       
       
    • Автор: Satellite
      Возможно ли вывести 9-patch в Timage? Если нет, то куда можно импортировать изображение такого формата? 
    • Автор: AlexG
      Возник следующий вопрос:
      Допустим есть "сложная" форма, внешний вид которой должен быть нестандартным и на которой расположено N-ное количество компонент (исходим из того, что их много, некоторые из них - динамические, например - вывод видео с камеры).
      "Нестандартный вид" подразумевает: наличие тени у формы, измененный внешний вид, отличный от вида по умолчанию в любой ОС.
      Непосредственно вопрос звучит так.
      Какая из двух следующих реализаций будет работать быстрее (отрисовка/обновление этой формы при обновлении компонент: текста, списков, вывод видео и т.д.):
      Оба вида форм предопределяются в стиле.
      ВАРИАНТ 1.
      - Тень формы реализована в виде компонента TImage с подгруженным PNG изображением.
      - Контур формы реализован компонентом TRectangle с "окантовкой" и заливкой прямоугольника заданным цветом (все без градиентов)
      - Шапка формы реализована вторым прямоугольником TRectangle без "окантовки", но с заливкой другим цветом (без градиента)
      ВАРИАНТ 2. Вся форма задана одним объектом TStyleObject в котором в качестве свойств установлены:
      - SourceLookup - ссылка на PNG-изображение в данном стиле
      - SourceLink - создан TBitmapLink, у которого заданы свойства CapInsets и SourceRect
      Внешний вид у них будет практически одинаковый (хотя во втором случае он будет более корректным на любой ОС и при использовании любой видео-карты, чего не скажешь о первом варианте).
      Однако, интересует именно СКОРОСТЬ отрисовки в обеих случаях!
      Интересует именно теория, с точки зрения реализации самой FMX.
      З.Ы. Предполагаю, что вопрос больше к разработчикам FMX, но возможно у кого-то уже есть опыт работы с подобными задачами...
    • Автор: RoschinSpb
      Статья: http://community.embarcadero.com/blogs/entry/timagelist101ru-1 Автор: Сергей Рощин Обзор новых возможностей, которые появились в компоненте и редакторе TImageList для Delphi R101 (2016 год, Version 24)
    • Автор: umkes
      Добрый день, возникла проблема при работе с TImage;
      У меня компонент TImage - imgRing и есть в TImageList. 
      Я динамически формирую Bitmap из копий картинки из TImageList и асайню его в TImage. На Windows все работает прекрасно, а на андроиде картинка все время пустая... Может кто-то подскажет, где я не прав
      //============================================================================== procedure TMainForm.DrawRing; //------------------------------------------------------------------------------ var bmp1, bmp2 : TBitmap; i : integer; str : TMemoryStream; begin bmp2 := TBitmap.Create; bmp2.Assign(ImageList.Source.Items[3].MultiResBitmap.Items[0].Bitmap); bmp1 := TBitmap.Create; bmp1.Assign(bmp2); bmp1.Width := ClientWidth + bmp2.Width * 10; i := 0; bmp1.Canvas.BeginScene(); while (i * bmp2.Width) < bmp1.Width do begin bmp1.Canvas.DrawBitmap(bmp2, RectF(0, 0, bmp2.Width, bmp2.Height), RectF(i * bmp2.Width, 0, (i + 1) * bmp2.Width, bmp2.Height), 1 ); inc(i); end{ while }; bmp1.Canvas.EndScene; str := TMemoryStream.Create; bmp1.SaveToStream(str); str.Position := 0; imgRing.BeginUpdate; imgRing.Bitmap.CreateFromStream(str); imgRing.EndUpdate; end{ procedure TMainForm.DrawRings }; Делаю такое потому-что TImage.WrapMode.Tile не подходит для моей задачи.
    • Автор: FAN
      Очень нравится timagelist, большое спасибо!
      Но хотелось бы иметь возможность выбрать несколько destination images и отредактировать их свойства
      Также хотелось бы добавлять destination images не по одиночке а группами с заданными свойствами
       
       
       
    • Автор: Ra72
      Уважаемые эксперты!
      Хочу написать свой редактор стилей для мобильных платформ.
      Для полного счастья не хватает знаний каким образом из TStyleBook.Style выгрузить его изменения в TStyleBook.Resource для последующего сохранения в файл.
       
  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу