Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Cross-Platform-Entwicklung (https://www.delphipraxis.net/91-cross-platform-entwicklung/)
-   -   Android Listview mit Bitmap (https://www.delphipraxis.net/188554-android-listview-mit-bitmap.html)

greenmile 15. Mär 2016 19:34

Android Listview mit Bitmap
 
Hallo,

gibt es eigentlich in der FMX Android Listview eine einfache Möglichkeit, bei Bedarf statt ".Text" ein Bitmap anzuzeigen? Also mal so, mal so? Oder muss ich dafür einen Style anlegen und irgendwie importieren?

AndyDF 16. Mär 2016 07:27

AW: Android Listview mit Bitmap
 
Hallo,

ich selbst verwende kaum noch die Properties von .Text / .Image von ItemObjects der ListView.

Ich konstruiere mir stattdessen das ListViewItem in ListView.OnUpdateObjects selbst:

Code:
procedure TFrmOverview.lvUpdateObjects(const Sender: TObject; const AItem: TListViewItem);
var
  TextLabel: TListItemText;
  Image: TListItemImage;
begin
  Image := AItem.View.FindDrawable(c_ItemDrawable_Image) as TListItemImage;
  if Image = nil then
  begin
    Image := TListItemImage.Create(AItem);
    Image.Name := c_ItemDrawable_Image;
    Image.Align := TListItemAlign.Leading;
    Image.VertAlign := TListItemAlign.Leading;
    Image.Height := c_EventImage_Heigth;
    Image.Width := c_EventImage_Width;
    Image.PlaceOffset.Y := 7;
    Image.PlaceOffset.X := 12;
    Image.ScalingMode := TImageScalingMode.Stretch;
  end;

  TextLabel := AItem.Objects.FindDrawable(c_ItemDrawable_TextHeader) as TListItemText;
  if TextLabel = nil then
  begin
    TextLabel:= TListItemText.Create(AItem);
    TextLabel.Name:= c_ItemDrawable_TextHeader;
    TextLabel.Align:= TListItemAlign.Leading;
    TextLabel.VertAlign:= TListItemAlign.Leading;
    TextLabel.TextAlign:= TTextAlign.Leading;
    TextLabel.PlaceOffset.X:= 120;
    TextLabel.PlaceOffset.Y:= 7;
    TextLabel.Font.Size:= 23;
    TextLabel.Font.Style := [TFontStyle.fsBold];
    TextLabel.Width:= 600;
    TextLabel.Height:= 30;
    TextLabel.WordWrap := false;
    TextLabel.Text:= '';
  end;
end;
Zugriff dann so:
Code:
var
  Drawable: TListItemDrawable;
begin
    Drawable := AListItem.Objects.FindDrawable(ADrawableName);

    if Assigned(Drawable) and (Drawable is TListItemText) then
      (Drawable as TListItemText).Text := AText;
end;
Vorteil, den ich da sehe: Man kann sehr flexibel sein ListViewItem aufbauen. Es ist auch möglich per .Visible einzelne Drawables auszublenden. Somit kannst du jede Zelle auch individuell gestalten.
Hoff das hilft dir.

Viele Grüße, Andy

greenmile 16. Mär 2016 20:03

AW: Android Listview mit Bitmap
 
Super, vielen Dank. Nur leider zeichnet er unter Windows das Image nicht links sondern addiert was dazu. Der ursprüngliche Test wird leider nicht entfernt (AItem.Text := ''). Und unter Android wird garnichts gezeichnet:

Code:
Function TfrmMain.GetBitmap(Name: String; var Target: TBitmap): Boolean;
  var
    Size: TSize;
    Item: TCustomBitmapItem;
begin
  If imgList.BitmapItemByName(Lowercase(Name), Item, Size) then begin
    Target.Assign(Item.Bitmap);
    Result := true;
  end else Result := false;
end;

...

var
   TextLabel: TListItemText;
   Image: TListItemImage;
   MyBitmap: TBitmap;
const
  c_ItemDrawable_Image = 'ItemImage';
  c_ItemDrawable_TextHeader = 'ItemText';
  c_EventImage_Heigth = 25;
  c_EventImage_Width = 100;
begin
  MyBitmap := TBitmap.Create;
  If GetBitmap(AItem.Text, MyBitmap) then begin
    Image := AItem.View.FindDrawable(c_ItemDrawable_Image) as TListItemImage;
    if (Image=nil)then begin
      Image          := TListItemImage.Create(AItem);
      Image.Name     := c_ItemDrawable_Image;
      Image.Align    := TListItemAlign.Leading;
      Image.VertAlign := TListItemAlign.Leading;
      Image.Height   := c_EventImage_Heigth;
      Image.Width    := MyBitmap.Width;
      Image.PlaceOffset.X := 30;
      Image.PlaceOffset.Y := 10;
      If not Assigned(Image.Bitmap) then Image.Bitmap := TBitmap.Create;
      Image.OwnsBitmap := false;
      Image.Bitmap.Assign(MyBitmap);
    end;
    AItem.Text := '';
    AItem.Invalidate;
    Exit;
  end;

  TextLabel := AItem.Objects.FindDrawable(c_ItemDrawable_TextHeader) as TListItemText;
  if TextLabel = nil then begin
    TextLabel:= TListItemText.Create(AItem);
    TextLabel.Name:= c_ItemDrawable_TextHeader;
    TextLabel.Align:= TListItemAlign.Leading;
    TextLabel.VertAlign:= TListItemAlign.Leading;
    TextLabel.TextAlign:= TTextAlign.Leading;
    TextLabel.PlaceOffset.X:= 40;
    TextLabel.PlaceOffset.Y:= 4;
    TextLabel.Font.Size:= 23;
    TextLabel.Font.Style := [TFontStyle.fsBold];
    TextLabel.Width:= 600;
    TextLabel.Height:= 30;
    TextLabel.WordWrap := false;
    TextLabel.Text:= AItem.Text;
    AItem.Text := '';
    AItem.Invalidate;
  end;

Sir Rufo 16. Mär 2016 20:41

AW: Android Listview mit Bitmap
 
Euch ist schon bewusst dass ihr hier das Gleiche macht wie mit den Styles - nur wesentlich umständlicher :stupid:

Warum nehmt ihr die Code-Tags und nicht die Delphi-Tags?

greenmile 16. Mär 2016 20:53

AW: Android Listview mit Bitmap
 
Naja umständlicher vielleicht, aber ich habe so meine Erfahrung mit den Styles. Gebranntes Kind scheut das Feuer und bis vor kurzem war diese ganze Style-Brühe mehr als Schrott. Vielleicht haben sie sich inzwischen gemausert, keine Ahnung, aber nachdem ich schon einige Male in der Vergangenheit Properties verloren habe, sie plötzlich beim Neu-Laden des Projektes anders aussahen oder einfach verloren gegangen sind, weil ich die Delphi Version aktualisiert habe ... Ne danke. Firemonkey ist eine Zicke. An sich ganz cool wenn man weiß, wie man mit ihr umgehen muss.

Anyway möchte ich nicht immer Bitmaps verwenden und so kann ich gezielt und einfach im Source ein Bitmap einblenden oder eben auch nicht.

BTW: In Android sind sie nicht sichtbar. Andy, hast Du da ev eine Idee?

AndyDF 17. Mär 2016 14:11

AW: Android Listview mit Bitmap
 
Ich habe mir deinen Code nochmal angesehen. Also ich habe überhaupt keine Probleme mit iOS oder Android. Unter Windows schaut es manchmal nicht so aus wie ich es gerne hätte. Aber das ist in diesem Fall bei mir auch keine Zielplattform. iOS u. Android passt perfekt.

Zu Styles: Für meinen Fall muss ich ehrlich sagen, fahre ich auf diese Weise sehr gut. Da meine Oberfläche recht flexibel sein muss kann ich hier ganz gut reagieren.

Letztendlich mache ich nichts anderes als in "TFrmOverview.lvUpdateObjects" das Item zu "designen" und in einer eigenen Methode "DataToGui" das Item zu befüllen. Das funktioniert bei mir.

Ein paar Hinweise, die mir als Unterschiede auffallen:

- "TFrmOverview.lvUpdateObjects" mach immer das Selbe bei mir! Das Bitmap wird nicht in dieser Methode gesetzt. Wenn ich das Bild dann später nicht sehen will, setze ich .Visible auf false (in DataToGui). Bzw. ich weise gar kein TBitmap zu. Wenn das Objekt nil bleibt ist nichts zu sehen.
- Atem.Invalidate -> wofür?
- Die Reihenfolge in "TFrmOverview.lvUpdateObjects" ist entscheidend! In dieser Reihenfolge wird es übereinander gezeichnet.
- je nachdem woher du das Bild bekommst, musst du "OwnsBitmap" entsprechen setzen. Aber das machst du ja schon.
- ListView.ItemAppearance.ItemAppearance ist bei mir auf Custom. ItemHeight ist auch passend gesetzt.
- Ja das ist richtig, die standard Properties .Text / .Image werden immer noch angezeigt. Hierzu habe ich im Eigenschaftenexplorer alle auf Visible := false gesetzt! Die bleiben dann bei mir einfach unbeachtet, da ich das Item komplett selbst aufbaue.
- Für die Positionierung auch unbedingt ListView.ItemSpaces berücksichtigen! Meiner Erfahrung nach muss der Wert für Top und Bottom sogar in der ItemHeight mit einbezogen werden.

Hier noch meine Methode zum Setzen des Bitmaps (aus DataToGui() heraus):

Delphi-Quellcode:
class procedure TListViewHelper.SetListItemImage(const AListItem: TListViewItem; const ADrawableName: String; const ABitmap: TBitmap; const AOwnsBitmap: Boolean);
var
  Drawable: TListItemDrawable;
begin
  if Assigned(AListItem) then
  begin
    Drawable := AListItem.Objects.FindDrawable(ADrawableName);

    if Assigned(Drawable) and (Drawable is TListItemImage) then
    begin
      (Drawable as TListItemImage).BeginUpdate;
      try
        (Drawable as TListItemImage).Bitmap := nil;
        (Drawable as TListItemImage).OwnsBitmap := AOwnsBitmap;
        (Drawable as TListItemImage).Bitmap := ABitmap;
      finally
        (Drawable as TListItemImage).EndUpdate;
      end;
    end;
  end;
end;
Ab jetzt nehme ich die Delphi Tags ;)

greenmile 17. Mär 2016 20:06

AW: Android Listview mit Bitmap
 
Sehr geil! Vielen Dank, das hat mir wirklich weiter geholfen. Habe allerdings eine kleine Änderung, damit die Bilder auch wirklich Leading sind:

Zitat:

Zitat von AndyDF (Beitrag 1333181)
Delphi-Quellcode:
class procedure TListViewHelper.SetListItemImage(const AListItem: TListViewItem; const ADrawableName: String; const ABitmap: TBitmap; const AOwnsBitmap: Boolean);
var
  Drawable: TListItemDrawable;
begin
  if Assigned(AListItem) then
  begin
    Drawable := AListItem.Objects.FindDrawable(ADrawableName);

    if Assigned(Drawable) and (Drawable is TListItemImage) then
    begin
      (Drawable as TListItemImage).BeginUpdate;
      try
        (Drawable as TListItemImage).Bitmap := nil;
        (Drawable as TListItemImage).OwnsBitmap := AOwnsBitmap;
        (Drawable as TListItemImage).Bitmap := ABitmap;
--->
         If Assigned(ABitmap) then begin
           (Drawable as TListItemImage).Width := ABitmap.Width;
         end;
--->
      finally
        (Drawable as TListItemImage).EndUpdate;
      end;
    end;
  end;
end;
Ab jetzt nehme ich die Delphi Tags ;)


AndyDF 18. Mär 2016 15:30

AW: Android Listview mit Bitmap
 
Super wenn es geklappt hat und danke noch für die Erweiterung.

Benötige ich aber in meinem Fall nicht, da ich die Bitmaps schon mit der richtigen Größe definiere bzw. den ScalingMode entsprechend setze:

Delphi-Quellcode:
Image.ScalingMode := TImageScalingMode.Stretch;

greenmile 18. Mär 2016 18:20

AW: Android Listview mit Bitmap
 
Klappt 1a und löst ein schon länger vorhandenes Problem, das Bier geht auf mich!

Einzig der dynamische Label (TListItemText) bereitet mir noch Sorgen. Ich möchte gerne die Schriftgröße von einem Original-Eintrag setzen, finde aber nicht raus, wie groß die ist. Ist die konstant, kann ich also immer Font.Size 20 nehmen? Kann ich mir kaum vorstellen, sonst wäre die Größe auf einem Tablet ja identisch mit der auf einem Handy.

Den Original Text musste ich auch über den Objektinspektor ausblenden. Wenn ich es per Source mache, ist der manchmal nach einem Refresh (Gerät Lock/Unlock) plötzlich wieder da.

AndyDF 19. Mär 2016 08:54

AW: Android Listview mit Bitmap
 
Das mit der "(Default)" Font-Size hatte ich mich auch schon mal gefragt. Wie ist diese definiert? Gibt es hierfür Konstanten?

Was mir hier spontan als möglicher Workaround einfällt:
Lege doch ein TLabel auf die Form und mach dieses Visible := False. Von diesem kannst du dir dann die Font-Size holen und bei deinem TListItemText setzen. Dann müsste es doch die Default-Size sein oder?


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:40 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz