Hi,
What is the best way of adding buttons to a TTMSFMXNativeUITableViewItem programatically and have an onclick event that knows about the item that the button was in?
Regards,
Ken
I'm not sure what you mean with adding a button, do you mean you want to access the AccessoryView and add a native UIButton? The OnClick event could be bundled for every button which has a unique Tag property?
I have created the following component for use with the table view. It is creating a UIButton fine and when clicked does delete the item but after deleting a few items it crashes with no error when clicked.
Am I doing something wrong:
unit KenFMXTableView;
interface
uses
System.SysUtils, System.Classes, FMX.Types, FMX.Controls, FMX.Graphics,
FMX.TMSNativeUIBaseControl, FMX.TMSNativeUITableView, System.TypInfo
{$IFDEF IOS}
,iOSApi.UIKit, iOSApi.Foundation, Macapi.ObjectiveC, iOSapi.CocoaTypes, iOSapi.CoreGraphics, MacApi.ObjcRuntime
{$ENDIF}
,FMX.TMSNativeUICore;
type
{$IFDEF IOS}
IBtnDelegate=interface(NSObject)
procedure BtnPressed; cdecl;
end;
TBtnDelegate=class(TOCLocal)
private
TVItem:TTMSFMXNativeUITableViewItem;
public
constructor Create;
function GetObjectiveCClass:PTypeInfo; override;
procedure BtnPressed; cdecl;
end;
{$ENDIF}
TKenFMXTableViewItem=class(TTMSFMXNativeUITableViewItem)
private
FTitle:String;
FDescription:String;
{$IFDEF IOS}
BtnDelegate:TBtnDelegate;
{$ENDIF}
published
property Title:String read FTitle write FTitle;
property Description:String read FDescription write FDescription;
end;
TKenFMXTableViewItems=class(TTMSFMXNativeUITableViewItems)
public
function CreateItemClass:TCollectionItemClass; override;
end;
TKenFMXTableViewSection=class(TTMSFMXNativeUITableViewSection)
public
function CreateItems:TTMSFMXNativeUITableViewItems; override;
end;
TKenFMXTableViewSections=class(TTMSFMXNativeUITableViewSections)
public
function CreateItemClass:TCollectionItemClass; override;
end;
[ComponentPlatformsAttribute(pidiOSSimulator or pidiOSDevice)]
TKenFMXTableView=class(TTMSFMXNativeUITableView)
private
protected
{ Protected declarations }
public
BitmapToUse:TBitmap;
constructor Create(AOwner:TComponent); override;
function CreateSections:TTMSFMXNativeUITableViewSections; override;
function GetItemHeight(ASection,ARow:Integer):Single; override;
function GetHeightForHeaderInSection(ASection: Integer): Single; override;
function GetItemStyle(ASection,ARow:Integer):TTMSFMXNativeUITableViewItemStyle; override;
{$IFDEF IOS}
procedure DoItemCreateCell(Sender:TObject;var ACell:UITableViewCell;AItemStyle:TTMSFMXNativeUITableViewItemStyle;ASection,ARow:Integer); override;
procedure DoItemCustomizeCell(Sender:TObject;ACell:UITableViewCell;AItemStyle:TTMSFMXNativeUITableViewItemStyle;ASection,ARow: Integer); override;
{$ENDIF}
published
{ Published declarations }
end;
procedure Register;
implementation
uses
FMX.Dialogs;
{$IFDEF IOS}
constructor TBtnDelegate.Create;
begin
inherited Create;
end;
function TBtnDelegate.GetObjectiveCClass:PTypeInfo;
begin
Result:=TypeInfo(IBtnDelegate);
end;
procedure TBtnDelegate.BtnPressed;
var
S,I:Integer;
TV:TKenFMXTableView;
begin
if Assigned(TVItem) then
begin
S:=TVItem.Section.Index;
I:=TVItem.Index;
TV:=TVItem.OwnerTableView as TKenFMXTableView;
TV.BeginRefreshing;
TV.Sections[S].Items.DisposeOf;
TV.EndRefreshing;
TVItem:=Nil;
end;
end;
{$ENDIF}
function TKenFMXTableViewItems.CreateItemClass:TCollectionItemClass;
begin
Result:=TKenFMXTableViewItem;
end;
function TKenFMXTableViewSection.CreateItems:TTMSFMXNativeUITableViewItems;
begin
Result:=TKenFMXTableViewItems.Create(OwnerTableView,Self);
end;
function TKenFMXTableViewSections.CreateItemClass: TCollectionItemClass;
begin
Result:=TKenFMXTableViewSection;
end;
constructor TKenFMXTableView.Create(AOwner:TComponent);
begin
inherited;
if (csDesigning in ComponentState) and not
((csReading in Owner.ComponentState) or (csLoading in Owner.ComponentState)) then
begin
Options.Header:='Ken''s View';
Options.ToolBar:=False;
end;
end;
function TKenFMXTableView.CreateSections:TTMSFMXNativeUITableViewSections;
begin
Result:=TKenFMXTableViewSections.Create(Self);
end;
{$IFDEF IOS}
procedure TKenFMXTableView.DoItemCreateCell(Sender:TObject;var ACell:UITableViewCell;AItemStyle:TTMSFMXNativeUITableViewItemStyle;
ASection,ARow:Integer);
var
Title:UILabel;
Description:UILabel;
R:NSRect;
It:TTMSFMXNativeUITableViewItem;
KenIt:TKenFMXTableViewItem;
Btn:UIButton;
begin
R.Origin.X:=5;
R.Origin.Y:=5;
R.Size.Width:=32;
R.Size.Height:=32;
Btn:=TUIButton.Wrap(TUIButton.Wrap(TUIButton.OCClass.Alloc).InitWithFrame(R));
It:=GetItem(ASection,ARow);
if Assigned(It) and (It is TKenFMXTableViewItem) then
begin
KenIt:=It as TKenFMXTableViewItem;
KenIt.BtnDelegate:=TBtnDelegate.Create;
Btn.addTarget(KenIt.BtnDelegate.GetObjectID, // target
sel_getUid('BtnPressed'), // action
UIControlEventTouchDown); // event
end;
ACell.ContentView.AddSubview(Btn);
R.Origin.X:=5;
R.Origin.Y:=5;
R.Size.Width:=ACell.Frame.Size.Width-100;
R.Size.Height:=25;
Title:=TUILabel.Wrap(TUILabel.Wrap(TUILabel.OCClass.Alloc).InitWithFrame(R));
Title.SetFont(TUIFont.Wrap(TUIFont.OCClass.BoldSystemFontOfSize(16)));
Title.SetHighlightedTextColor(TUIColor.Wrap(TUIColor.OCClass.BlackColor));
Title.SetTextColor(TUIColor.Wrap(TUIColor.OCClass.WhiteColor));
ACell.ContentView.AddSubview(Title);
R.Origin.X:=5;
R.Origin.Y:=Title.Frame.Origin.Y+Title.Frame.Size.Height;
R.Size.Width:=ACell.Frame.Size.Width-100;
Description:=TUILabel.Wrap(TUILabel.Wrap(TUILabel.OCClass.Alloc).InitWithFrame(R));
Description.SetHighlightedTextColor(TUIColor.Wrap(TUIColor.OCClass.BlackColor));
Description.SetTextColor(TUIColor.Wrap(TUIColor.OCClass.WhiteColor));
ACell.ContentView.AddSubview(Description);
end;
procedure TKenFMXTableView.DoItemCustomizeCell(Sender:TObject;ACell: UITableViewCell;
AItemStyle:TTMSFMXNativeUITableViewItemStyle;ASection,ARow:Integer);
var
Title:UILabel;
Description:UILabel;
It:TTMSFMXNativeUITableViewItem;
KenIt:TKenFMXTableViewItem;
Str:NSString;
R:NSRect;
Img:UIImage;
Btn:UIButton;
begin
Btn:=TUIButton.Wrap(ACell.ContentView.Subviews.ObjectAtIndex(0));
Title:=TUILabel.Wrap(ACell.ContentView.Subviews.ObjectAtIndex(1));
Description:=TUILabel.Wrap(ACell.ContentView.Subviews.ObjectAtIndex(2));
It:=GetItem(ASection,ARow);
if Assigned(It) and (It is TKenFMXTableViewItem) then
begin
KenIt:=It as TKenFMXTableViewItem;
if Assigned(BitmapToUse) then
begin
if Assigned(KenIT.BtnDelegate) then
KenIT.BtnDelegate.TVItem:=It;
Img:=ImageFromBitmap(BitmapToUse,-1);
Btn.setImage(Img,0);
ACell.SetImage(Nil);
// ACell.SetImage(Img);
end else
ACell.SetImage(Nil);
if Assigned(Title) then
begin
Title.SetText(NSSTREx(KenIt.Title));
R:=Title.Frame;
if Assigned(BitmapToUse) then
R.Origin.X:=5+32+5{+Acell.Image.Size.Width}
else
R.Origin.X:=5;
Title.SetFrame(R);
end;
if Assigned(Description) then
begin
Description.SetText(NSSTREx(KenIt.Description));
R:=Description.Frame;
if Assigned(Acell.Image) then
R.Origin.X:=15+Acell.Image.Size.Width
else
R.Origin.X:=5;
Description.SetFrame(R);
end;
end;
end;
{$ENDIF}
function TKenFMXTableView.GetItemHeight(ASection,ARow:Integer):Single;
begin
Result:=Options.RowHeight;
end;
function TKenFMXTableView.GetHeightForHeaderInSection(ASection: Integer): Single;
begin
Result:=Options.SectionHeaderHeight;
end;
function TKenFMXTableView.GetItemStyle(ASection,ARow:Integer):TTMSFMXNativeUITableViewItemStyle;
begin
Result:=isTableViewCellStyleCustom;
end;
procedure Register;
begin
RegisterComponents('Ken', [TKenFMXTableView]);
end;
end.
The issue you are having is a pointer issue. The item is removed, along with the button which still holds a reference to the item. The DoItemCreateCell is only called when necessary, if the cell is being created. When scrolling, removing cells, the DoItemCustomizeCell is called to apply new properties.