Перейти к содержанию
  • Регистрация
  • 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

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


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

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

  • 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 нельзя использовать.

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


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

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

    • От krapotkin
      А также Cannot find style resource fir Windows.
      Воспроизведение
      1. создать новое FMX приложение
      2. кинуть TSyleBook
      3. зайти по двойному щелчку
      4. попытаться добавить платформу
      результат (1)

      5. добавить Windows, Android. Удалить Default. закрыть StyleBook editor
      6. Положить кнопку, ПКМ, Edit Custom Style
      7. Результат

       
      если же просто сначала кинуть кнопку, сделать ПКМ, Edit custom Style, то картина совсем другая

      поэтому и не находит ни Windows ни Android   Соответственно Workaround - найти в FMX Platform = 'Android' и заменить на Platform = 'AndroidL Light' Platform = 'Windows' тоже возможно надо будет заменить, но с ней проблем вроде нет пока.     Все это делал на Windows 7 x64 Pro SP1  
    • От Павел Блажеев
      Добрый день. Очень нужна Ваша помощь. 
      Мне необходимо сделать координатную сетку в виде точек. При масштабировании панели количество точек должно изменяться . 
      Хочу все это сделать на канве панели. Унаследовал класс и переопределил procedure   Paint; override;
        Tfield = class(TPanel)
            Constructor Create( parent: TFmxObject);
              procedure   Paint; override;
              Procedure   OnMyClick (Sender: TObject);
          end;

      В теле метода я пробовал рисовать. Экспериментировал и столкнулся с такой проблемой. Ничего не отображается. Нет никаких изменений.
      Если я наследую не от Tpanel а от Timage то часть кода работает а часть работает очень криво. Очень хочу разобраться почему .
      {Отображается сразу}
      for a:=1 to 1000 do
            begin
              self.Canvas.Fill.Color:=  TAlphaColors.Crimson;
               self.Canvas.FillEllipse(rect(1,1,10,10),self.AbsoluteOpacity);
               self.Canvas.FillEllipse(rect(round(self.Width-9),round(self.Height-9),round(self.Width), round(self.Height)),self.AbsoluteOpacity);
               self.Canvas.FillEllipse(rect(round(self.Width-9),1,round(self.Width), 9),self.AbsoluteOpacity);
               self.Canvas.FillEllipse(rect(1,round(self.Height-9),10, round(self.Height)),self.AbsoluteOpacity);
            end;
       
      {Отображается только после того как я проскролю Scrollbox на котором лежит панель в крайнее нижнее правое положение}
            self.Canvas.Stroke.Color:=  TAlphaColors.Crimson;
            self.Canvas.Stroke.Thickness:=7;
             Canvas.BeginScene;
            self.Canvas.DrawLine(PointF(20, 20), PointF(100, 50), self.AbsoluteOpacity);
             Canvas.EndScene;
      Подскажите пожалуйста, почему не работает такое с панелью?  Как правильно рисовать на панели? 
      Почему в случае с имейджем все работает так некорректно?  Почему работает только после скрола? 
      Каким способом мне лучше сделать координатную сетку? состоящую из точек как в режиме Design?

       


    • От Serg Sib
      RAD 10.2.3 Delphi , Win 10x64 Pro 1803
      Подскажите, с помощью чего можно осуществить трансформацию изображения по опорным точкам (по углам)?
      Возможно, что не напрямую сам TImage, а при помощи работы с Canvas на его Bitmap.
      Пока удалось добиться подобной трансформации, заполнив нужным изображением полигон и, меняя координаты его вершин, делать нужные корректировки.
      var MyBrushBitmap: TBrushBitmap; Image1.Bitmap.Canvas.Fill.Kind := TBrushKind.Bitmap; Image1.Bitmap.Canvas.Fill.Bitmap := MyBrushBitmap; Image1.Bitmap.Canvas.Fill.Bitmap.WrapMode := TWrapMode.TileStretch; Image1.Bitmap.Canvas.FillPolygon(MyPolygon, 50); Однако, изображение частично обрезается при этом.
      В интернете поиском находил пример подобной трансформации на VCL, (перетаскиванием вершин мышью), но не смог приспособить этот пример для платформы FireMonkey.
    • От genakust
      Здравствуйте,
      я создал свой ListBoxItem (FMX) который выглядит следующим образом:

      затем я добавил Items динамически в ListBox и получилось следующее:

      Когда я запускаю программу на Windows 10 и выбираю мышкой Item он селектируется, а если запускаю на Андроид- таблете, то я не могу выбрать (селектировать) Item.
      Подскажите пожалуйста, какие могут быть причины длы такого поведения.
      Заранее спасибо.
       
    • От Barbanel
      Всем хай.
      Пол дня бьюсь, уже с ума начинаю сходить, и как назло не с кем посоветоваться сегодня. Выручайте)
      Суть:
      Есть TListBox. В него динамически из кода создаются TListBoxItem.
      Каждому итему в поле TagObject присваивается некий объект, хранящий дополнительные данные.
      По клику на итем, вытаскивается этот объект и в зависимости от данных, выполняются разные действия.
      Проблема:
      Под Windows ее собсно нет)
      Под Android при клике на TListBoxItem оказывается что TagObject = nil.
      Голова уже дымится, у меня закончились мысли, что это может быть...
      Код, на всякий:
      while not query.Eof do begin item := TListBoxItem.Create(lbTeilLeistungsArten); lbTeilLeistungsArten.AddObject(item); item.StyleLookup := 'listboxitemTL'; item.Height := 60; item.Text := query.FieldByName('Bezeichnung').AsString; item.OnClick := OnTeilleistungenClick; item.Tag := query.FieldByName('ID').AsInteger; item.DisableDisappear := true; item.ApplyStyleLookup(); lStObj := TStoreObject.CreateTL(query.FieldByName('ID').AsInteger); lStObj.TeilLeistung.Name := query.FieldByName('Bezeichnung').AsString; item.TagObject := lStObj; query.Next(); end; Всем заранее спасибо!
    • От 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.
    • От yooSee
      Привет ребят, созрел такой вопрос который меня мучает ! Вобщем пытаюсь загрузить картинку по прямой слыке с сервера. Картинка не грузится, не сохраняется не отображается. 
      Конечная платформа - Андроид. Пишу на 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); как проще сделать посоветуете чтоб и грузилось и форма не висла?
  • Последние посетители   0 пользователей онлайн

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

×
×
  • Создать...