将 TSwitch 添加到每个 TListView 项目
Add TSwitch to every TListView item
我还没有尝试过这个,因为我不知道从哪里开始。
是否可以将 FMX TSwitch 添加到 FMX TListViewitem 中?
任何 help/suggestions 将不胜感激。
谢谢,
您首先必须记住 TListView
控件的整个设计。当它包含大量项目时,它意味着非常轻巧。您可能有一百万个项目,您肯定不希望实例化一百万个开关控件。因此,并不意味着您可以将控件作为容器嵌入到每个项目中,例如 TListBox
允许的那样。
也就是说,假设您对每个单独的列表项执行最少的绘制以与 TListView
的设计保持一致。这需要创建从 TListItemObject
继承的虚拟对象以与每个项目相关联。这些对象允许任何项目的现有内置元素,例如附件或位图。
这里有一个非常粗糙的演示,我拼凑在一起让你开始,你需要改变你需要的图形。
启动一个新的 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.
注意:本文写于 Delphi 10 西雅图。
我认为您唯一的其他选择是:
- 为每个项目实例化一个
TSwitch
并使用与上述相同的方法渲染它(非常草率,我不推荐)
- 找出如何使用样式实现标准
TSwitch
的绘图,再次使用与上述相同的方法(这可能是性能和视觉适应的最佳选择)
- 改为使用
TListBox
,具体取决于您打算如何使用该列表(这对于大量项目来说会非常繁重)
我在 a separate question / answer.
中更深入地了解了 Firemonkey 中 TListView
和 TListBox
之间的区别
我还没有尝试过这个,因为我不知道从哪里开始。
是否可以将 FMX TSwitch 添加到 FMX TListViewitem 中?
任何 help/suggestions 将不胜感激。
谢谢,
您首先必须记住 TListView
控件的整个设计。当它包含大量项目时,它意味着非常轻巧。您可能有一百万个项目,您肯定不希望实例化一百万个开关控件。因此,并不意味着您可以将控件作为容器嵌入到每个项目中,例如 TListBox
允许的那样。
也就是说,假设您对每个单独的列表项执行最少的绘制以与 TListView
的设计保持一致。这需要创建从 TListItemObject
继承的虚拟对象以与每个项目相关联。这些对象允许任何项目的现有内置元素,例如附件或位图。
这里有一个非常粗糙的演示,我拼凑在一起让你开始,你需要改变你需要的图形。
启动一个新的 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.
注意:本文写于 Delphi 10 西雅图。
我认为您唯一的其他选择是:
- 为每个项目实例化一个
TSwitch
并使用与上述相同的方法渲染它(非常草率,我不推荐) - 找出如何使用样式实现标准
TSwitch
的绘图,再次使用与上述相同的方法(这可能是性能和视觉适应的最佳选择) - 改为使用
TListBox
,具体取决于您打算如何使用该列表(这对于大量项目来说会非常繁重)
我在 a separate question / answer.
中更深入地了解了 Firemonkey 中TListView
和 TListBox
之间的区别