Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Leanback (https://www.delphipraxis.net/201680-leanback.html)

Peter666 15. Aug 2019 11:45

Leanback
 
Ich wollte mich seit längerem wieder mit Firemonkey beschäftigen und ein Grid-View ähnlich wie die Leanback Effekte bei Amazon Prime, Netflix oder Android TV umsetzen.Also im Endeffekt so etwas: https://www.youtube.com/watch?v=DGkvp7O2aAY

Versteht mich nicht falsch, es ist jetzt nicht so dass ich das nicht in einer eigenen Klasse (basierend auf TControl) selber umsetzen kann und ich fürchte ich komme da nicht drum herum, aber prinzipiell sollte das doch auch mit Bordmitteln gehen? Mein Ansatz war ein quadratisches TRectangle mit XRadius,YRadius von 10 Pixeln als Basis. Das Hintergrundbild in den Fill Brush und noch ein TRectangle als Child unten in dem eigentlichen Rechteck, wo dann der Text eingezeichnet wird. Das erste Problem ist, dass in dem Child-Rechteck nicht die unteren Ecken beschnitten werden. ClipChildren ist natürlich gesetzt.
Danach habe ich ein TShadowEffect auf das Basisrechteck gelegt. Mit FloatAnimation ändere ich Scale.X und Scale.Y und Position.X und .Y, da ich sowas wie Zoom nicht gefunden habe. Beim Zoomen gibt es jetzt aber Probleme mit TShadowEffect, da der den Schatten irgendwie nachzieht.
Spaßeshalber habe ich das ganze mal auf einem Mac gestartet und autsch ist das quälend lahm. Wohlgemerkt ich hab bis jetzt nur ein Tile und von den weiteren Animationen will ich noch gar nicht reden.

Wie würdet ihr das machen?

Peter

stahli 15. Aug 2019 12:36

AW: Leanback
 
Helfen kann ich nicht, aber würde gerne (nur Interesse halber) mal sehen, wie weit Du bist und wie weit Du kommst.

Falls Du einen Screenrecorder (und Zeit und Lust) hast, wäre mal ein kurzes Video nett...

Peter666 15. Aug 2019 13:30

AW: Leanback
 
Liste der Anhänge anzeigen (Anzahl: 2)
Klar gerne,


anbei der Quellcode zu dem Test. Die Idee ist, dass ich ein eigenes Control habe in dem das gewünschte Bild und der Text gespeichert ist. Diesen rendere ich entweder in eine Bitmap, oder über Paint auf die Anzeige. Für das Scrollen werde ich dann je nach Rubrik verschiedene PresentedScrollbox Container verwenden.
Vielleicht hast du ja eine Idee, wie ich zu dem gewünschten Element scrolle. Für das Vergrößern des ausgewählten Elements würde ich TAnimationFloat verwenden, aber mir missfällt da für Position.X, Y und Width, Height in Summe 4 TAnimationFloat Klassen zu erstellen.
Die Panels mit unserer Bundeskanzlerin habe ich nur als Referenz drin. Idee ist es dass im Fokus befindliche Textfeld mit #FF0096A6 im ausgewählten und #FF0096A6 im nicht ausgewählten Zustand darzustellen.

Ich habe das ganze mal als Mockup in einem Grafikprogramm zusammengestellt.

Peter

stahli 15. Aug 2019 14:04

AW: Leanback
 
Danke, anschauen kann ich das erst heute Abend zu Hause.

Zu FMX kann ich nichts sagen. Habe ich vor ein paar Jahren aufgegeben.

Ich arbeite an einer eigenen GUI (derzeit allerdings unterbrochen), die auch Ebenen unterstützen soll. Hier mal eine Demo, wie das aussieht: https://youtu.be/sKfh7SaHt7s?t=11m43s
(Die herausgehobenen Zellen machen so natürlich keinen Sinn, aber in ähnlicher Weise wird das funktionieren, wenn man eine Spalte verschiebt -> Spalte hochheben, schieben, fallen lassen.)

stahli 15. Aug 2019 22:14

AW: Leanback
 
Helfen kann ich Dir da leider nicht.
Aber ich würde die Animationen nach Möglichkeit etwas verlangsamen, so dass eine Markierung ca. eine halbe oder dreiviertel Sekunde dauert.
Im FMX konnte man ja so etwas m.E. ganz einfach einstellen.

Peter666 28. Aug 2019 20:08

AW: Leanback
 
Hallo,

ich habe heute mal etwas Zeit gehabt mit Firemonkey zu spielen. Folgender Code erstellt 11 bunte Tiles die, wenn Sie den Focus bekommen animiert sich vergrößern bzw. verkleinern. Das funktioniert auf allen Plattformen, sowohl via Touch, als auch mit Tastatur. Mein Problem ist, dass ich nicht weiß wie man die Scrollbox möglichst angenehm auf den fokussierten Eintrag anpasst. Hat da jemand eine Idee? Das ist so ziemlich das einzigste Problem was ich an dem Code noch habe. Aktuell lade ich in einem Thread die Grafiken habe mehrere Scrollboxen als Rubriken untereinander. Lediglich das horizontale und vertikale scrollen bekomme ich schlichtweg nicht hin.

Delphi-Quellcode:
unit UMain;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes,
  System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Layouts;

type
  TTileItem = class(TControl)
  protected
    FZoomFactor: Single;
    FBackgroundColor: TAlphaColor;

    procedure Paint; override;
    procedure DoEnter; override;
    procedure DoExit; override;

    procedure SetZoomFactor(AValue: Single);
    procedure SetBackgroundColor(AValue: TAlphaColor);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property BackgroundColor: TAlphaColor read FBackgroundColor
      write SetBackgroundColor;
    property ZoomFactor: Single read FZoomFactor write SetZoomFactor;
  end;

  TForm3 = class(TForm)
    HorzScrollBox1: THorzScrollBox;
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form3: TForm3;

implementation

uses FMX.Ani;

{$R *.fmx}

const
  cZoomIn = 0.9;
  cZoomOut = 1.0;
  cZoomTime = 0.4;

constructor TTileItem.Create(AOwner: TComponent);
begin
  inherited;
  CanFocus := true;
  ZoomFactor := 0;
  FBackgroundColor := TAlphaColors.Gray;
end;

destructor TTileItem.Destroy;
begin
  inherited;
end;

procedure TTileItem.DoEnter;
begin
  BringToFront;
  TAnimator.AnimateFloat(self, 'ZoomFactor', cZoomOut, cZoomTime,
    TAnimationType.Out, TInterpolationType.Quartic);
end;

procedure TTileItem.DoExit;
begin
  SendToBack;
  TAnimator.AnimateFloat(self, 'ZoomFactor', cZoomIn, cZoomTime,
    TAnimationType.Out, TInterpolationType.Quartic);
end;

procedure TTileItem.SetBackgroundColor(AValue: TAlphaColor);
begin
  if FBackgroundColor <> AValue then
  begin
    FBackgroundColor := AValue;
    repaint;
  end;
end;

procedure TTileItem.SetZoomFactor(AValue: Single);
begin
  if AValue < cZoomIn then
    AValue := cZoomIn;
  if AValue > cZoomOut then
    AValue := cZoomOut;

  if FZoomFactor <> AValue then
  begin
    FZoomFactor := AValue;
    repaint;
  end;
end;

procedure TTileItem.Paint;
var
  w, h: Single;
  R: TRectF;

begin
  if Locked then
    Exit;

  w := Width * FZoomFactor;
  h := Height * FZoomFactor;
  R := RectF((Width - w) / 2, (Height - h) / 2, w, h);

  Canvas.Fill.Color := FBackgroundColor;
  Canvas.FillRect(R, 5, 5, AllCorners, AbsoluteOpacity);
end;

const
  ModernUIColors: Array [0 .. 10] of TAlphaColor = ($FFFF0097, $FF1BA1E2,
    $FFA200FF, $FF00ABA9, $FF8CBF26, $FFA05000, $FFE671B8, $FFF09609, $FFE51400,
    $FF339933, $FFFFFFFF);

procedure TForm3.FormCreate(Sender: TObject);
var
  i: integer;
  w, h: Single;
  item: TTileItem;
begin
  w := 150;
  h := HorzScrollBox1.Height - 20;

  for i := 0 to high(ModernUIColors) do
  begin
    item := TTileItem.Create(self);
    with item do
    begin
      BackgroundColor := ModernUIColors[i];
      Parent := HorzScrollBox1;
      Position.Point := PointF(i * 0.9 * w, 0);
      Width := w;
      Height := h;
    end;
  end;
end;

end.

Rollo62 29. Aug 2019 07:27

AW: Leanback
 
Hallo Peter,

bin icht ganz sicher was genau Du erreichen willst.
Aber das Scrollen bekomment man durch die InteractiveGestures aktiviert.
Im HorizScrollBox Object-Inspektor unter Touch\InteractiveGestures\Zoom diese Checkbox setzen.

Dann kann man den Eventhandler hinzufügen, z.B. so

Delphi-Quellcode:

procedure TForm3.HorzScrollBox1Gesture(Sender: TObject; const EventInfo: TGestureEventInfo; var Handled: Boolean);
var
    LScrollBox: TCustomScrollBox;
    LScaleNew: Single;
begin

   if not (Sender is TCustomScrollBox) then
       Exit;

   if EventInfo.GestureID = igiZoom then
   begin
      LScrollBox := Sender as TCustomScrollBox;

      if not(TInteractiveGestureFlag.gfBegin in EventInfo.Flags) then
      begin
        LScaleNew := ( (LScrollBox.ClientWidth + EventInfo.Distance - FLastDIstance) /
                        LScrollBox.ClientWidth);

        LScrollBox.Scale.X := LScrollBox.Scale.X * LScaleNew;
        LScrollBox.RealignContent;

      end;

      FLastDIstance := EventInfo.Distance;
    end;

end;

Peter666 29. Aug 2019 11:07

AW: Leanback
 
Danke,

ich wollte, wenn ich auf einen Eintrag mit Tab bzw. Shift+Tab gehe, dass dieser selektierte Eintrag in der Scrollbox den Fokus bekommt. So etwas wie bei einer Liste bei der ich über ScrollTo zu dem gewählten Element scrolle. Und dass möglichst animiert :)

Peter

Rollo62 30. Aug 2019 13:51

AW: Leanback
 
Das mach es ja so, es zoomed einen Block bei Click größer, und man kann das Ganze dann noch manuell zoomen.

Peter666 6. Sep 2019 14:16

AW: Leanback
 
Liste der Anhänge anzeigen (Anzahl: 1)
Danke,

aber ich stehe ein bisschen auf dem Schlauch. Ich möchte im Prinzip das aktive Tile in der Scrollbox fokussieren. Wahlweise über anklicken, scrollen oder mittels Links/Rechts.

Ich habe mal den Testcode an den Post gehängt.

Peter

Peter666 9. Sep 2019 12:48

AW: Leanback
 
Delphi-Quellcode:
unit FMX.TilesGrid;

interface

uses System.SysUtils, System.Classes, System.Types, System.UITypes,
  FMX.Graphics, FMX.Types, FMX.Controls, FMX.Layouts;

type
    TTileItem = class(TControl)
  protected
    FZoomFactor: Single;
    FBackgroundColor: TAlphaColor;

    procedure Paint; override;
    procedure DoEnter; override;
    procedure DoExit; override;

    procedure SetZoomFactor(AValue: Single);
    procedure SetBackgroundColor(AValue: TAlphaColor);

    function GetBarPos: Single;
    procedure SetBarPos(const AValue: Single);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property BackgroundColor: TAlphaColor read FBackgroundColor
      write SetBackgroundColor;
    property ZoomFactor: Single read FZoomFactor write SetZoomFactor;
    property BarPos: Single read GetBarPos write SetBarPos;
  end;

implementation

uses FMX.Ani, FMX.Stdctrls;

const
  cZoomIn = 0.9;
  cZoomOut = 1.0;
  cZoomTime = 0.2;

type TCustomScrollBoxCracker = class(TCustomScrollBox);

constructor TTileItem.Create(AOwner: TComponent);
begin
  inherited;
  CanFocus := true;
  ZoomFactor := 0;
  FBackgroundColor := TAlphaColors.Gray;
end;

destructor TTileItem.Destroy;
begin
  inherited;
end;

function TTileItem.GetBarPos: Single;
begin
  if Owner is TCustomScrollBox then
   result := TCustomScrollBoxCracker(Owner).HScrollBar.Value else
   result := 0;
end;

procedure TTileItem.SetBarPos(const AValue: Single);
begin
  if Owner is TCustomScrollBox then
    TCustomScrollBoxCracker(Owner).HScrollBar.Value := AValue;
end;

procedure TTileItem.DoEnter;
var
 NewScrollViewPos: single;
 MinWidth, MinHeight: Single;
begin
  BringToFront;
  TAnimator.AnimateFloat(self, 'ZoomFactor', cZoomOut, cZoomTime,
    TAnimationType.Out, TInterpolationType.Quadratic);

   NewScrollViewPos := BarPos;
    MinWidth := 0;
    MinHeight := 0;
   if (BoundsRect.Left - NewScrollViewPos < MinWidth) then
    NewScrollViewPos := BoundsRect.Left;

   if (BoundsRect.Left - NewScrollViewPos < MinHeight) then
    NewScrollViewPos := BoundsRect.Right - TCustomScrollBox(Owner).Width;

   if (BoundsRect.Right - NewScrollViewPos > TCustomScrollBox(Owner).Width) then
    NewScrollViewPos := BoundsRect.Right - TCustomScrollBox(Owner).Width;

   TAnimator.AnimateFloat(self, 'BarPos', NewScrollViewPos, cZoomTime,
    TAnimationType.In, TInterpolationType.Linear);
end;

procedure TTileItem.DoExit;
begin
  SendToBack;
  TAnimator.AnimateFloat(self, 'ZoomFactor', cZoomIn, cZoomTime,
    TAnimationType.In, TInterpolationType.Linear);
end;

procedure TTileItem.SetBackgroundColor(AValue: TAlphaColor);
begin
  if FBackgroundColor <> AValue then
  begin
    FBackgroundColor := AValue;
    repaint;
  end;
end;

procedure TTileItem.SetZoomFactor(AValue: Single);
begin
  if AValue < cZoomIn then
    AValue := cZoomIn;
  if AValue > cZoomOut then
    AValue := cZoomOut;

  if FZoomFactor <> AValue then
  begin
    FZoomFactor := AValue;
    repaint;
  end;
end;

procedure TTileItem.Paint;
var
  w, h: Single;
  R: TRectF;

begin
  if Locked then
    Exit;

  w := Width * FZoomFactor;
  h := Height * FZoomFactor;
  R := RectF((Width - w) / 2, (Height - h) / 2, w, h);

  Canvas.Fill.Color := FBackgroundColor;
  Canvas.FillRect(R, 5, 5, AllCorners, AbsoluteOpacity);
end;

end.
Ich hab das jetzt wie folgt gemacht. Das DoEnter macht den ganzen "magischen" Kram. So richtig schön finde ich das mit den Scrollen nicht, aber es geht. @Rollo: Vielleicht hast du ja eine bessere Idee.

Peter

CHackbart 9. Sep 2019 19:55

AW: Leanback
 
Liste der Anhänge anzeigen (Anzahl: 1)
Das ist ja ne coole Idee. Ich war so frei und hab das mal etwas weitergesponnen.

Delphi-Quellcode:
unit UTilesGrid;

interface

uses System.SysUtils, System.Classes, System.Types, System.UITypes,
  FMX.Graphics, FMX.Types, FMX.Controls, FMX.Layouts, FMX.StdCtrls,
  System.Generics.Collections;

type
  TTileItem = class(TControl)
  protected
    FZoomFactor: Single;
    FBackgroundColor: TAlphaColor;
    FOnPaint: TNotifyEvent;

    procedure Paint; override;
    procedure DoEnter; override;
    procedure DoExit; override;

    procedure SetZoomFactor(AValue: Single);
    procedure SetBackgroundColor(AValue: TAlphaColor);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property BackgroundColor: TAlphaColor read FBackgroundColor
      write SetBackgroundColor;
    property ZoomFactor: Single read FZoomFactor write SetZoomFactor;
    property OnPaint: TNotifyEvent read FOnPaint write FOnPaint;
  end;

  TTileRow = class(TControl)
  protected
    FTiles: TObjectList<TTileItem>;
    FItemIndex: Integer;
    FScrollBox: THorzScrollBox;
    FTitle: TLabel;
    FSelected: TTileItem;

    function GetCount: Integer;
    function GetItem(AIndex: Integer): TTileItem;

    procedure SetItemIndex(AIndex: Integer);

    function GetScrollPos: Single;
    procedure SetScrollPos(const AValue: Single);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    function Add: TTileItem;
    procedure Delete(const AIndex: Integer);

    procedure ScrollIntoView(const AItem: TTileItem);

    property Items[index: Integer]: TTileItem read GetItem; default;
    property Count: Integer read GetCount;
    property ItemIndex: Integer read FItemIndex write SetItemIndex;

  published
    property ScrollPos: Single read GetScrollPos write SetScrollPos;
    property Title: TLabel read FTitle;
    property Scale;
  end;

  TTileGrid = class(TControl)
  protected
    FRows: TObjectList<TTileRow>;
    FItemIndex: Integer;

    FScrollBox: TVertScrollBox;
    function GetItem(AIndex: Integer): TTileRow;
    function GetCount: Integer;
    procedure SetItemIndex(AIndex: Integer);

    function GetScrollPos: Single;
    procedure SetScrollPos(const AValue: Single);

  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    procedure ScrollIntoView(const AItem: TTileRow);

    function Add: TTileRow;
    procedure Delete(const AIndex: Integer);

    property Items[index: Integer]: TTileRow read GetItem; default;
    property Count: Integer read GetCount;
    property ItemIndex: Integer read FItemIndex write SetItemIndex;
  published
    property ScrollPos: Single read GetScrollPos write SetScrollPos;
    property Scale;
  end;

implementation

uses FMX.Ani;

const
  cZoomIn = 0.9;
  cZoomOut = 1.0;
  cZoomTime = 0.2;

type
  TCustomScrollBoxCracker = class(TCustomScrollBox);

function IfThen(const AState: Boolean; const ATrue, AFalse: Integer)
  : Integer; inline;
begin
  if AState then
    result := ATrue
  else
    result := AFalse;
end;

{ TTileItem }
constructor TTileItem.Create(AOwner: TComponent);
begin
  inherited;
  CanFocus := true;
  ZoomFactor := 0;
  FBackgroundColor := TAlphaColors.Gray;
end;

destructor TTileItem.Destroy;
begin
  inherited;
end;

procedure TTileItem.DoEnter;
begin
  BringToFront;
  TAnimator.AnimateFloat(self, 'ZoomFactor', cZoomOut, cZoomTime,
    TAnimationType.Out, TInterpolationType.Quadratic);

  if Owner is TTileRow then
    TTileRow(Owner).ScrollIntoView(self);
end;

procedure TTileItem.DoExit;
begin
  SendToBack;
  TAnimator.AnimateFloat(self, 'ZoomFactor', cZoomIn, cZoomTime, TAnimationType.
    In, TInterpolationType.Linear);
end;

procedure TTileItem.SetBackgroundColor(AValue: TAlphaColor);
begin
  if FBackgroundColor <> AValue then
  begin
    FBackgroundColor := AValue;
    repaint;
  end;
end;

procedure TTileItem.SetZoomFactor(AValue: Single);
begin
  if AValue < cZoomIn then
    AValue := cZoomIn;
  if AValue > cZoomOut then
    AValue := cZoomOut;

  if FZoomFactor <> AValue then
  begin
    FZoomFactor := AValue;
    repaint;
  end;
end;

procedure TTileItem.Paint;
var
  w, h: Single;
  R: TRectF;

begin
  if Locked then
    Exit;

  w := Width * FZoomFactor;
  h := Height * FZoomFactor;
  R := RectF((Width - w) / 2, (Height - h) / 2, w, h);

  Canvas.Fill.Color := FBackgroundColor;
  Canvas.FillRect(R, 5, 5, AllCorners, AbsoluteOpacity);
  if assigned(FOnPaint) then
    FOnPaint(self);
end;

{ TTileRow }
constructor TTileRow.Create(AOwner: TComponent);
begin
  inherited;
  Height := 300;

  FTiles := TObjectList<TTileItem>.Create(true);
  FItemIndex := -1;
  FTitle := TLabel.Create(self);
  FTitle.Parent := self;
  FTitle.Align := TAlignLayout.Top;
  FTitle.Text := 'RowTitle';

  FScrollBox := THorzScrollBox.Create(self);
  FScrollBox.Parent := self;
  FScrollBox.Align := TAlignLayout.Client;
  FScrollBox.ShowScrollBars := false;
  HitTest := true;
end;

destructor TTileRow.Destroy;
begin
  FTiles.Free;
  FScrollBox.Free;
  inherited;
end;

function TTileRow.GetCount: Integer;
begin
  result := FTiles.Count;
end;

function TTileRow.Add: TTileItem;
begin
  result := TTileItem.Create(self);
  result.Parent := FScrollBox;
  FTiles.Add(result);
end;

function TTileRow.GetScrollPos: Single;
begin
  if assigned(TCustomScrollBoxCracker(FScrollBox).HScrollBar) then
    result := TCustomScrollBoxCracker(FScrollBox).HScrollBar.Value;
end;

procedure TTileRow.SetScrollPos(const AValue: Single);
begin
  if assigned(TCustomScrollBoxCracker(FScrollBox).HScrollBar) then
    TCustomScrollBoxCracker(FScrollBox).HScrollBar.Value := AValue;
end;

procedure TTileRow.ScrollIntoView(const AItem: TTileItem);
var
  NewScrollViewPos: Single;
  MinWidth, MinHeight: Single;
begin
  if FSelected <> AItem then
  begin
    NewScrollViewPos := ScrollPos;
    MinWidth := 0;
    MinHeight := 0;

    if (AItem.BoundsRect.Left - NewScrollViewPos < MinWidth) then
      NewScrollViewPos := AItem.BoundsRect.Left;

    if (AItem.BoundsRect.Right - NewScrollViewPos > FScrollBox.Width) then
      NewScrollViewPos := AItem.BoundsRect.Right - FScrollBox.Width;

    TAnimator.AnimateFloat(self, 'ScrollPos', NewScrollViewPos, cZoomTime,
      TAnimationType.In, TInterpolationType.Linear);

    FItemIndex := FTiles.IndexOf(AItem);

    FSelected := AItem;
  end;

  if Owner is TTileGrid then
    TTileGrid(Owner).ScrollIntoView(self);

end;

procedure TTileRow.Delete(const AIndex: Integer);
begin
  FTiles.Delete(AIndex);
end;

function TTileRow.GetItem(AIndex: Integer): TTileItem;
begin
  if (AIndex >= 0) and (AIndex < FTiles.Count) then
    result := FTiles[AIndex]
  else
    result := nil;
end;

procedure TTileRow.SetItemIndex(AIndex: Integer);
begin
  if AIndex < 0 then
    AIndex := Count - 1
  else if AIndex >= Count then
    AIndex := 0;

  FTiles[AIndex].SetFocus;
end;

{ TTileGrid }

constructor TTileGrid.Create(AOwner: TComponent);
begin
  inherited;
  FRows := TObjectList<TTileRow>.Create;
  FItemIndex := -1;
  FScrollBox := TVertScrollBox.Create(self);
  FScrollBox.Parent := self;
  FScrollBox.Align := TAlignLayout.Client;
  FScrollBox.ShowScrollBars := false;
  HitTest := true;
end;

destructor TTileGrid.Destroy;
begin
  FRows.Free;
  FScrollBox.Free;
  inherited;
end;

function TTileGrid.GetItem(AIndex: Integer): TTileRow;
begin
  result := FRows[AIndex];
end;

function TTileGrid.GetCount: Integer;
begin
  result := FRows.Count;
end;

function TTileGrid.Add: TTileRow;
begin
  result := TTileRow.Create(self);
  FRows.Add(result);

  result.Parent := FScrollBox;
  result.Align := TAlignLayout.Top;
end;

procedure TTileGrid.Delete(const AIndex: Integer);
begin
  FRows.Delete(AIndex);
end;

procedure TTileGrid.SetItemIndex(AIndex: Integer);
begin
  if AIndex < 0 then
    AIndex := Count - 1
  else if AIndex >= Count then
    AIndex := 0;

  with FRows[AIndex] do
    ItemIndex := IfThen(ItemIndex = -1, 0, ItemIndex);
end;

function TTileGrid.GetScrollPos: Single;
begin
  if assigned(TCustomScrollBoxCracker(FScrollBox).VScrollBar) then
    result := TCustomScrollBoxCracker(FScrollBox).VScrollBar.Value;
end;

procedure TTileGrid.SetScrollPos(const AValue: Single);
begin
  if assigned(TCustomScrollBoxCracker(FScrollBox).VScrollBar) then
    TCustomScrollBoxCracker(FScrollBox).VScrollBar.Value := AValue;
end;

procedure TTileGrid.ScrollIntoView(const AItem: TTileRow);
var
  NewScrollViewPos: Single;
  MinWidth, MinHeight: Single;
  i: Integer;
begin
  NewScrollViewPos := ScrollPos;
  MinWidth := 0;
  MinHeight := 0;

  if (AItem.BoundsRect.Top - NewScrollViewPos < MinHeight) then
    NewScrollViewPos := AItem.BoundsRect.Top;

  if (AItem.BoundsRect.Bottom - NewScrollViewPos > FScrollBox.Height) then
    NewScrollViewPos := AItem.BoundsRect.Bottom - FScrollBox.Height;

  TAnimator.AnimateFloat(self, 'ScrollPos', NewScrollViewPos, cZoomTime,
    TAnimationType.In, TInterpolationType.Linear);

  AItem.SetFocus;
  FItemIndex := FRows.IndexOf(AItem);
end;

end.
Die Tiles zeichne ich bei dem OnPaint Notify und lade das selbe Bild als Hintergrund von dem TTileGrid. Man könnte die aktive Reihe noch mittels Scale Property vergrößern, aber so schaut es auch schon schick aus. Danke für den Ansatz.

Christian
PS: Das ganze geht auch noch einfacher und sauberer, aber ich dachte probiere ich einfach mal 100 Reihen mit jeweils 100 Einträgen. Die Idee war abzuschätzen, ob sich das wirklich lohnt so umzusetzen und es geht erstaunlich gut. Beim vertikalen Scrollen auf einem Touchpad ist das ganze jedoch etwas unschön. Da bleibt das Scrollen gerne hängen, wenn sich ein Icon in der Reihe in den Focus bewegt.

stahli 10. Sep 2019 09:15

AW: Leanback
 
Kann man da mal etwas kurzes bewegtes sehen?

CHackbart 10. Sep 2019 09:25

AW: Leanback
 
Liste der Anhänge anzeigen (Anzahl: 1)
Klar, gerne.

Das ist jetzt ohne Grafiken. Es ist denke ich das was Peter bewerkstelligen wollte. Die Tiles mit Bildern und Texten zu versehen ist ja denke ich nur Fleißarbeit. Ich bin eigentlich nicht der Mensch der Labels und sonstige Komponenten in eine Komponente hämmert, aber ich glaube bei Firemonkey ist das in Ordnung.

Christian

stahli 10. Sep 2019 09:34

AW: Leanback
 
Habe jetzt kein Delphi. Schaue ich mir heute Abend unbedingt an.
GUI-Ideen finde ich immer spannend. :-)

CHackbart 10. Sep 2019 10:01

AW: Leanback
 
Das ist jetzt kein hübsches Beispiel, aber sowas ist das Leanback: https://www.youtube.com/watch?v=j8R7FEg8rzw


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:36 Uhr.

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