2016-05-06 3 views
1

Je n'ai pas essayé cela parce que je ne saurais par où commencer.Ajouter TSwitch à chaque élément TListView

Est-il possible d'ajouter un commutateur FMX dans un TListViewitem FMX?

Toute aide ou suggestion serait grandement appréciée.

Merci,

+0

J'ai essayé de le faire, et je ne vois pas de moyen facile de le faire au moment du design. Peut-être qu'il existe une option d'exécution. –

Répondre

4

Vous devez d'abord garder à l'esprit la conception de l'ensemble du contrôle TListView. Il est conçu pour être très léger lorsqu'il contient un grand nombre d'éléments. Vous pouvez avoir un million d'éléments, vous ne voulez certainement pas un million de contrôles de commutateur instanciés. Par conséquent, il n'est pas fait pour vous d'intégrer des contrôles dans chaque élément en tant que conteneur, comme le permet le TListBox. Cela étant dit, il est supposé que vous effectuez un dessin minimal sur chaque élément de liste pour être cohérent avec la conception du TListView. Cela nécessite de créer des objets virtuels hérités de TListItemObject pour être associés à chaque élément. Ces objets autorisent les éléments intégrés existants de tout élément, tel que l'accessoire ou le bitmap.

Voici un démodé démo J'ai jeté ensemble pour vous aider à démarrer, vous auriez besoin de changer le dessin dont vous avez besoin pour regarder.

Démarrer une nouvelle application FMX, laissez tomber un TListView, et utiliser cet appareil en place de l'unité de votre principale forme:

unit Unit1; 

interface 

uses 
    System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, 
    FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, 
    FMX.ListView.Types, FMX.ListView.Appearances, FMX.ListView.Adapters.Base, 
    FMX.ListView, FMX.Controls.Presentation, FMX.StdCtrls; 

type 

    TListItemSwitch = class(TListItemSimpleControl) 
    private 
    FIsChecked: Boolean; 
    FOnSwitch: TNotifyEvent; 
    procedure SetIsChecked(const AValue: Boolean); 
    protected 
    function MouseDown(const Button: TMouseButton; const Shift: TShiftState; const MousePos: TPointF): Boolean; 
     override; 
    procedure DoSwitch; virtual; 
    public 
    constructor Create(const AOwner: TListItem); override; 
    destructor Destroy; override; 

    procedure Render(const Canvas: TCanvas; const DrawItemIndex: Integer; const DrawStates: TListItemDrawStates; 
     const SubPassNo: Integer = 0); override; 

    public 
    property IsChecked: Boolean read FIsChecked write SetIsChecked; 
    property OnSwitch: TNotifyEvent read FOnSwitch write FOnSwitch; 
    end; 

    TForm1 = class(TForm) 
    ListView1: TListView; 
    procedure ListView1UpdateObjects(const Sender: TObject; 
     const AItem: TListViewItem); 
    procedure FormCreate(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.fmx} 

{ TListItemSwitch } 

constructor TListItemSwitch.Create(const AOwner: TListItem); 
begin 
    inherited; 

end; 

destructor TListItemSwitch.Destroy; 
begin 

    inherited; 
end; 

procedure TListItemSwitch.DoSwitch; 
begin 
    FIsChecked:= not FIsChecked; 
    if Assigned(OnSwitch) then 
    OnSwitch(Self); 
end; 

function TListItemSwitch.MouseDown(const Button: TMouseButton; 
    const Shift: TShiftState; const MousePos: TPointF): Boolean; 
begin 
    if (Button = TMouseButton.mbLeft) and Enabled then begin 
    DoSwitch; 
    end; 
    inherited; 
end; 

procedure TListItemSwitch.Render(const Canvas: TCanvas; 
    const DrawItemIndex: Integer; const DrawStates: TListItemDrawStates; 
    const SubPassNo: Integer); 
var 
    R, R2: TRectF; 
begin 
    inherited; 

    R:= Self.LocalRect; 
    R2:= R; 

    Canvas.BeginScene; 
    try 

    Canvas.Stroke.Kind:= TBrushKind.None; 
    Canvas.Fill.Kind:= TBrushKind.Solid; 
    Canvas.Fill.Color:= TAlphaColorRec.Skyblue; 
    Canvas.FillRect(R, 8, 8, 
     [TCorner.TopLeft, TCorner.TopRight, TCorner.BottomLeft, TCorner.BottomRight], 
     1.0, TCornerType.Round); 

    if IsChecked then begin 
     R2.Left:= R.Right - 20; 
     R2.Width:= 20; 
    end else begin 
     R2.Left:= R.Left; 
     R2.Width:= 20; 
    end; 

    Canvas.Fill.Color:= TAlphaColorRec.Black; 
    Canvas.FillRect(R2, 8, 8, 
     [TCorner.TopLeft, TCorner.TopRight, TCorner.BottomLeft, TCorner.BottomRight], 
     1.0, TCornerType.Round); 

    finally 
    Canvas.EndScene; 
    end; 

end; 

procedure TListItemSwitch.SetIsChecked(const AValue: Boolean); 
begin 
    FIsChecked:= AValue; 
end; 

{ TForm1 } 

procedure TForm1.FormCreate(Sender: TObject); 
var 
    I: TListViewItem; 
begin 
    I:= ListView1.Items.Add; 
    I:= ListView1.Items.Add; 
    I:= ListView1.Items.Add; 
    I:= ListView1.Items.Add; 
    I:= ListView1.Items.Add; 
    I:= ListView1.Items.Add; 
    I:= ListView1.Items.Add; 
    I:= ListView1.Items.Add; 
    I:= ListView1.Items.Add; 

end; 

procedure TForm1.ListView1UpdateObjects(const Sender: TObject; 
    const AItem: TListViewItem); 
var 
    S: TListItemSwitch; 
begin 
    S:= AItem.Objects.FindObject('Switch') as TListItemSwitch; 
    if S = nil then begin 
    S:= TListItemSwitch.Create(AItem); 
    S.Name:= 'Switch'; 
    S.Align:= TListItemAlign.Trailing; 
    S.VertAlign:= TListItemAlign.Center; 
    S.Width:= 50; 
    S.Height:= 20; 
    S.IsChecked:= False; 
    end; 

end; 

end. 

Screenshot

NOTE: Ceci a été écrit en Delphi 10 Seattle.

Vos seules autres options que je crois, sont soit:

  1. instancier un TSwitch pour chaque élément et de le rendre en utilisant la même méthode que ci-dessus (très bâclée, je ne recommande pas)
  2. Figure comment pour implémenter le dessin de la norme TSwitch en utilisant des styles, toujours en utilisant la même méthode que ci-dessus (qui est probablement la meilleure option pour la performance et l'adaptation visuelle)
  3. À la place, en fonction de la façon dont vous comptez utiliser la liste (ce qui serait très lourd sur un grand nombre bre d'articles)

je suis allé un peu plus en profondeur sur les différences entre un TListView et un TListBox dans FireMonkey en a separate question/answer.

+0

Sur le plan positif, c'est beaucoup plus efficace que le dessin standard, sans animations, et fiable au clic (parce que le 'TSwitch' a quelques problèmes étranges). Cependant, il y a un autre problème où simplement sélectionner une ligne va basculer l'interrupteur. –

+0

Merci beaucoup @Jerry, exactement ce que je cherche. –

+0

@ 6String_Coder Voici une bonne implémentation sans la complexité que j'ai déjà ajoutée: http://stackoverflow.com/questions/37083809/click-events-being-caught-by-list-view-parent-item Long histoire courte, je crée un composant de contrôleur de vue liste qui vous permet de "concevoir" les éléments de vue de la liste dans un éditeur de composant au moment du design. –