• 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 понравилось это

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


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

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

    • Автор: Роман Фил
      Привет ребят, созрел такой вопрос который меня мучает ! Вобщем пытаюсь загрузить картинку по прямой слыке с сервера. Картинка не грузится, не сохраняется не отображается. 
      Конечная платформа - Андроид. Пишу на Delphi xe 10 seatle.
      Что я делаю? при нажатии на сам компонент TImage (созданный динамически), должна грузится картинка по адресу преждевременно записанное в hint (TImage) при создании вида (http://блаблабла.jpg)
      Раньше код ниже работал сейчас нет не пойму что не так. Почему стал ковырять? потому что форма встает колом при загрузке изображений.
       
      var s: string; fs: TFileStream; begin fs := TFileStream.Create(tpath.Combine(tpath.GetDownloadsPath, 'load.jpg'), fmCreate); NetHTTPClient1.Get((Sender as TImage).Hint, fs); fs.Free; (Sender as TImage).MultiResBitmap.Bitmaps[1].LoadFromFile (tpath.Combine(tpath.GetDownloadsPath, 'load.jpg')); подключал еще pas нашел на этом форуме FMX.Features.Bitmap.Helpers.pas
      (Sender as TImage).MultiResBitmap.Bitmaps[1].LoadFromUrl ((Sender as TImage).Hint); как проще сделать посоветуете чтоб и грузилось и форма не висла?
    • Автор: ENERGY
      Upd:
      Пожалуйста проголосуйте. Думаю это всех касается, т.к. проблема связана и с TImageList и с TImage. 
      https://quality.embarcadero.com/browse/RSP-18210
       
       
      Сейчас столкнулся с большой проблемой перед самым релизом для заказчика..
      17 картинок, разного размера. Сейчас в TImageList  сетка рисуется постоянно при обновлении Source каждой картинки. C каждым разом становится сетка четче.  Если раньше я просто обновлял на новые картинки, и таким образом решал проблему, то сейчас после обновления source картинок сетка остается на многих картинках, причем я даже не закрываю TImageList . Только начинаю замещать одни картинки, на других появляется сетка..
      И вот что теперь делать незнаю..
       
      Да кстати картинки портятся и в TImage со временем в Design Time.
      Сетка означает что картинку много раз масштабируют. Но почему не сохраняют оригинал, это мне не понятно..
      Что тут можно придумать?
       
      Delphi Berlin Update 2
    • Автор: Anasazi
      Всем доброго времени суток. Возникла необходимость решить такую задачу: в таблице базы MySQL хранится список изображений и их URL. Необходимо получить этот список массивом. Затем загрузить изображения и поочередно с интервалом показать их в TImage.
      Понимаю, что получить список изображений правильнее при помощи PHP скрипта, но в каком виде скрип должен вернуть данные, чтобы в Delphi получить из них массив не знаю.
      Раньше для получения изображений использовал такую процедуру. Но вопрос, где хранить изображения перед демонстрацией их в TImage? Создавать несколько MemoryStream?
      procedure LoadWebImage(url: string; image: TBitmap);
      var
        idhttp : TNetHTTPClient;
        ms : TMemoryStream;
      begin
       IdHTTP := TNetHTTPClient.Create(nil);
        ms := TMemoryStream.Create;
        try
          idhttp.Get(url, ms);
          ms.Position := 0;
          image.LoadFromStream(ms);
        finally
          ms.Free;
          idhttp.Free;
        end;
      end;
    • Автор: denprox
      Доброго времени суток! Подскажите, как узнать оригинальный размер картинки, загруженной в TImage ?
    • Автор: ENERGY
      Меня это проблема преследует со времен 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)
  • Сейчас на странице   0 пользователей

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