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

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


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

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


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

  • Похожий контент

    • От x11
      Не могу понять, что случилось в проекте с TDataModule.
      Проект мультиплатформенный. В прошлый раз сохранил, закрыл, ничего необычного. Сегодня открываю, а мне ошибку Delphi Berlin показывает.
       
      И действительно, у TImageList отсутствует свойство source. Открываю, а он выглядит по-другому, как будто из VCL.
      Закрываю проект, создаю мультиплатформенную форму, кладу TImageList на форму и о чудо - совершенно другой TImageList и свойство Source есть.
      Что случилось с моим TDataModule? Как среде дать понять, что это мультиплатформенный проект?

    • От x11
      Не знаю, куда правильно задать вопрос. Решил здесь.
      Обычная стандартная связка TImageList + TActionList+TSpeedButton.
      в TImageList загрузил картинку 32*32.
      Всё связал и она появилась у кнопки на панели.
      Обратил внимание, что картинка 32*32 маловата и я решил загрузить картинку 48*48.
      Удалил из TImageList картинку и загрузил новую. Но размер картинки на кнопке остался 32*32.
      А потом ещё и исчезла картинка из TActionList.
       
      В TImageList только одна картинка.
      Delphi Berlin.


    • От DrMzi
      Доброго времени суток!
      Собираю тестовый проект под Win, иконки вижу.
      C:\Users\Public\Documents\Embarcadero\Studio\19.0\Samples\Object Pascal\Multi-Device Samples\User Interface\ListView\ListViewImageIndex
      Собираю тестовый проект под Android, иконок нет.
      Что я делаю не так ?

      Поправка. Такое поведение у apk на xiaomi mi5, запустил на Philips Xenium - иконки есть. 
       
    • От Tumaso
      Столкнулся со следующей проблемой - TImage игнорирует установленные значения XRadius и YRadius у TRectangle (10.1 Berlin with update 2)
       
      Суть - мне необходимо, чтобы у TRectangle углы были немного скругленные, для этого я устанавливаю XRadius и YRadius. Внутри TRectangle расположен TImage (левый верхний угол 0,0, ширина и высота совпадают с размерами TRectangle). Когда я загружаю картинку в TImage (что в дизайнере, что программно), получается что TImage отображается с прямыми углами, игнорируя XRadius и YRadius своего родителя. Свойство ClipChildren у TRectangle установлен.
      Как сделать так, чтобы TImage скруглялся по углам? Что интересно, TCircle в этом плане работает, обрезая TImage.
    • От Роман Фил
      Привет ребят, созрел такой вопрос который меня мучает ! Вобщем пытаюсь загрузить картинку по прямой слыке с сервера. Картинка не грузится, не сохраняется не отображается. 
      Конечная платформа - Андроид. Пишу на 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() не делает этого.
  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу