J'écris un objet de commutation personnalisé à utiliser dans le contrôle TListView
de Firemonkey par article. Tout fonctionne comme prévu, sauf pour un pépin étrange. Lorsque l'utilisateur clique sur l'un des éléments, mais pas sur l'objet de commutateur particulier, il bascule quand même le commutateur. Je suppose que l'événement MouseDown
est déclenché lorsque l'utilisateur clique sur l'élément de la liste, et pas nécessairement mon "contrôle" particulier dessiné dessus. Comment puis-je limiter l'événement de clic à ne s'appliquer que lorsque l'utilisateur clique sur le commutateur réel?Les événements Click sont interceptés par l'élément parent de la vue Liste
Comment?
JD.ListViewObjects.pas
unit JD.ListViewObjects;
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;
type
TLISwitchThumbStyle = (tsRect, tsRoundRect, tsElipse);
TListItemSwitch = class(TListItemSimpleControl)
private
FIsChecked: Boolean;
FOnSwitch: TNotifyEvent;
FThumbStyle: TLISwitchThumbStyle;
FThumbWidth: Single;
FThumbHeight: Single;
FThumbRound: Single;
procedure SetIsChecked(const AValue: Boolean);
procedure SetThumbStyle(const Value: TLISwitchThumbStyle);
procedure SetThumbWidth(const Value: Single);
procedure SetThumbHeight(const Value: Single);
procedure SetThumbRound(const Value: Single);
protected
function MouseDown(const Button: TMouseButton; const Shift: TShiftState; const MousePos: TPointF): Boolean;
override;
procedure DoSwitch; virtual;
procedure Render(const Canvas: TCanvas; const DrawItemIndex: Integer; const DrawStates: TListItemDrawStates;
const SubPassNo: Integer = 0); override;
public
constructor Create(const AOwner: TListItem); override;
destructor Destroy; override;
public
property IsChecked: Boolean read FIsChecked write SetIsChecked;
property ThumbWidth: Single read FThumbWidth write SetThumbWidth;
property ThumbHeight: Single read FThumbHeight write SetThumbHeight;
property ThumbStyle: TLISwitchThumbStyle read FThumbStyle write SetThumbStyle;
property ThumbRound: Single read FThumbRound write SetThumbRound;
property OnSwitch: TNotifyEvent read FOnSwitch write FOnSwitch;
end;
implementation
{ TListItemSwitch }
constructor TListItemSwitch.Create(const AOwner: TListItem);
begin
inherited;
Width:= 50;
Height:= 20;
FIsChecked:= False;
FThumbWidth:= 15;
FThumbHeight:= 15;
FThumbRound:= 3;
end;
destructor TListItemSwitch.Destroy;
begin
inherited;
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.DoSwitch;
begin
FIsChecked:= not FIsChecked;
if Assigned(OnSwitch) then
OnSwitch(Self);
Invalidate;
end;
procedure TListItemSwitch.SetIsChecked(const AValue: Boolean);
begin
FIsChecked:= AValue;
Invalidate;
end;
procedure TListItemSwitch.SetThumbWidth(const Value: Single);
begin
FThumbWidth := Value;
Invalidate;
end;
procedure TListItemSwitch.SetThumbHeight(const Value: Single);
begin
FThumbHeight := Value;
Invalidate;
end;
procedure TListItemSwitch.SetThumbRound(const Value: Single);
begin
FThumbRound := Value;
Invalidate;
end;
procedure TListItemSwitch.SetThumbStyle(const Value: TLISwitchThumbStyle);
begin
FThumbStyle := Value;
Invalidate;
end;
procedure TListItemSwitch.Render(const Canvas: TCanvas;
const DrawItemIndex: Integer; const DrawStates: TListItemDrawStates;
const SubPassNo: Integer);
var
R, R2: TRectF;
D: Single;
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, FThumbRound, FThumbRound,
[TCorner.TopLeft, TCorner.TopRight, TCorner.BottomLeft, TCorner.BottomRight],
1.0, TCornerType.Round);
R2.Top:= R.Top + (R.Height/2) - (FThumbHeight/2);
R2.Height:= FThumbHeight;
D:= R2.Top - R.Top;
if IsChecked then begin
R2.Left:= R.Right - FThumbWidth - D;
end else begin
R2.Left:= R.Left + D;
end;
R2.Width:= FThumbWidth;
Canvas.Fill.Color:= TAlphaColorRec.Black;
Canvas.FillRect(R2, FThumbRound, FThumbRound,
[TCorner.TopLeft, TCorner.TopRight, TCorner.BottomLeft, TCorner.BottomRight],
1.0, TCornerType.Round);
finally
Canvas.EndScene;
end;
end;
end.
uListViewSwitchTest.pas
unit uListViewSwitchTest;
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,
JD.ListViewObjects;
type
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}
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
var
X: Integer;
function A: TListViewItem;
begin
Result:= ListView1.Items.Add;
end;
begin
ListView1.Align:= TAlignLayout.Client;
for X := 1 to 50 do
A;
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;
end;
end;
end.
Il devrait ressembler à ceci:
La signature de TListItemDrawable.Render a changé dans 10.1 Berlin, mais cela ne semble pas affecter la fonctionnalité. Avec le changement de Dalija Prasnikar (ci-dessous) mis en œuvre, cela fonctionne bien. – nolaspeaker