[英]Add TSwitch to every TListView item
I haven't attempted this because I wouldn't know where to begin. 我没有尝试过,因为我不知道从哪里开始。
Is it possible to add a FMX TSwitch into a FMX TListViewitem? 是否可以将FMX TSwitch添加到FMX TListViewitem中?
Any help/suggestions would be much appreciated. 任何帮助/建议将不胜感激。
Thanks, 谢谢,
You first have to keep in mind the whole design of the TListView
control. 首先,您必须牢记TListView
控件的整个设计。 It's meant to be very lightweight for when it contains a large number of items. 当它包含大量项目时,它应该非常轻巧。 You may have a million items, you surely don't want a million switch controls instantiated. 您可能有一百万个项目,您当然不希望实例化一百万个开关控件。 Therefore, it's not meant for you to embed controls in each item as a container, such as the TListBox
allows. 因此,这并不意味着您将控件作为容器嵌入每个项目中,例如TListBox
允许的那样。
That being said, it's assumed that you perform minimal drawing on each individual list item to be consistent with the design of the TListView
. 就是说,假设您对每个单独的列表项执行的绘制最少,以与TListView
的设计保持一致。 This requires creating virtual objects inherited from TListItemObject
to be associated with each item. 这要求创建从TListItemObject
继承的虚拟对象,以与每个项目关联。 These objects are what allow the existing built-in elements of any item, such as the accessory or bitmap. 这些对象允许任何项目的现有内置元素,例如附件或位图。
Here's a very rough demo I threw together to get you started, you'd need to change the drawing how you need it to look. 这是我汇总的一个非常粗糙的演示,以帮助您入门,您需要更改图纸的外观。
Start a new FMX application, drop a TListView
, and use this unit in place of your main form's unit: 启动一个新的FMX应用程序,删除一个TListView
,并使用此单元代替您主窗体的单元:
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.
NOTE: This was written in Delphi 10 Seattle. 注意:这是用Delphi 10 Seattle写的。
Your only other options I believe are to either: 我相信您唯一的其他选择是:
TSwitch
for each item and render it using the same method as above (Very sloppy, I do not recommend) 为每个项目实例化一个TSwitch
并使用与上述相同的方法进行渲染(非常草率,我不推荐) TSwitch
using styles, again using the same method as above (which is probably the best option for performance and visual adaption) 再次使用与上述相同的方法,弄清楚如何使用样式来实现标准TSwitch
的绘图(这可能是性能和视觉适应的最佳选择) TListBox
instead, depending on how you intend to use the list (which would be very heavy on a large number of items) 取而代之的是使用TListBox
,这取决于您打算如何使用列表(在很多项目上这会非常繁琐) I went a little more in-depth about the differences between a TListView
and a TListBox
in Firemonkey in a separate question / answer . 我去深入多一点有关之间的差异TListView
和TListBox
在Firemonkey 一个单独的问题/答案 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.