Overview
Availablility
TMS iCL is a set of components for true native iOS application development and is available for Embarcadero Delphi XE11, C++Builder XE11 or newer releases.
Frameworks
Starting from version 1.2, when deploying to the device, you will encounter linker errors like the one below.
Here is a list with frameworks that need to be added to the SDK manager in order to have the components build and link correctly. The sample demonstrates how to add the ImageIO
framework.
Framework |
---|
AVKit (iOS 8 or later) |
CoreMotion |
ImageIO |
LocalAuthentication (iOS 8 or later) |
MapKit |
MessageUI |
MobileCoreServices |
MultipeerConnectivity |
Social |
WebKit |
When adding the SDK through the SDK manager you will notice that it already adds a subset of the available Frameworks in the iOS SDK such as the UIKit
and the Foundation
framework.
To fix the linker error, you will need to add a reference to the ImageIO
framework in the SDK Manager. To add a new framework, right-click on your project and choose the iOS Device target. Right-click on the target and choose “Edit SDK” from the popup menu.
After clicking the correct option in the popup menu, the SDK Manager will popup, showing you which SDK’s you have imported and which frameworks are available for each SDK.
Scroll down to the “Frameworks” section for the current SDK you are compiling / linking with. Click inside the “Frameworks” section, for example on the UIKit framework entry, and click on the new button at the top right next to the list to add a new framework entry (path item).
Enter the following information in the popup dialog
Path on remote machine
XE5: ”/System/Library/Frameworks”
XE6 and later: “$(SDKROOT)/System/Library/Frameworks”
Framework name: ImageIO
click on ok. The last step necessary for a correct linking is to update the local SDK directory with the new information. Click on “Update local file cache” at the bottom of the SDK manager:
Targetting for iOS Device should now compile and link without any issues.
View hierarchy
The TMS iCL components can be dropped directly as a child of the main application form, but can also be used as a child of another TMS FMX Native UI control. Included in the set is a TMSFMXNativeUIView
control that can be compared with a TPanel
in VCL. The view is typically used as a container control that can hold other controls. This is demonstrated below with a small sample.
Drop a TMSFMXNativeUIView
on the form and add a TMSFMXNativeUIButton
control as child of the view.
At designtime. | At runtime. |
---|---|
![]() |
![]() |
When setting the visible property of the TMSFMXNativeUIView
to false, the button will also disappear. If we have a large area of controls and need to apply scrolling, the TMSFMXNativeUIScrollView
can be used as a container for other controls. The view can be used as a container control and be linked to a TMSFMXNativeUITableView
item’s DetailView
property and be displayed when clicking on the item.
Deployment
At some point your application might have the need to access external files such as images and text files, or perhaps a database that needs to be accessed. When creating a new mobile application, clicking on the project tab and selecting deployment shows a windows where these files can be added.
The deployment window already contains files that are deployed along with your application such as the various application icons and launch images.
To add a new file, click on the add button which will popup a file open dialog.
Add the file by clicking open in the dialog. The file will be listed in the deployment window of your project and can be accessed from your application.
To access this file from your application, you need to get the root directory and apply the name of your file as listed in the deployment page. Note that the root directory is read-only, so you will be unable to write data to the file, such as text files. To gain write access to your file you need to copy the file to the documents directory. Listed below are some helper functions that allow you to access your file and access the root or documents directory.
Root Directory :
Documents Directory (requires iOSApi.Foundation and iOSApi.UIKit unit) :
function GetDocumentsDirectory: String;
var
paths: NSArray;
begin
Result := '';
paths := TNSArray.Wrap(NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, True));
if paths.count > 0 then
Result := String(TNSString.Wrap(paths.objectAtIndex(0)).UTF8String);
end;
Copy a File (requires iOSApi.Foundation and iOSApi.UIKit units):
procedure CopyFile(ASource, ADestination: String);
var
fileManager: NSFileManager;
error: NSError;
begin
fileManager := TNSFileManager.Create;
fileManager.copyItemAtPath(NSStr(ASource), NSStr(ADestination), Error);
end;
iOS Simulator vs Device
The TMS iCL package supports deployment to simulator and to a real device. The simulator can be helpful in debugging and creating your application without the need to go through the device each time your application is modified. The process of going through the deployment phase is slower when targeting a real device.
We, however, strongly suggest testing your application on a real device at regular intervals during application development, to make sure that the application behaves like it has been developed. There are known limitations and issues in the simulator in terms of look and feel, and it is important to make sure that these limitations do not occur on a real device since the device will be used in the final stage of development and deployment.
Resources
TMSFMXNativeUITableViewMail source
{********************************************************************}
{ }
{ written by TMS Software }
{ copyright © 2014 }
{ Email : info@tmssoftware.com }
{ Web : http://www.tmssoftware.com }
{ }
{ The source code is given as is. The author is not responsible }
{ for any possible damage done due to the use of this code. }
{ The complete source code remains property of the author and may }
{ not be distributed, published, given or sold in any form as such. }
{ No parts of the source code can be included in any other component }
{ or application without written authorization of the author. }
{********************************************************************}
unit FMX.TMSNativeUITableViewMail;
interface
uses
Classes, FMX.TMSNativeUITableView, SysUtils
{$IFDEF IOS}
,iOSApi.UIKit, iOSApi.Foundation
{$ENDIF}
;
type
TTMSFMXNativeUITableViewMailItem = class(TTMSFMXNativeUITableViewItem)
private
FDate: TDateTime;
FTitle: String;
FDescription: string;
FSender: String;
FUnread: Boolean;
procedure SetUnread(const Value: Boolean);
published
property Sender: String read FSender write FSender;
property Date: TDateTime read FDate write FDate;
property Title: String read FTitle write FTitle;
property Description: string read FDescription write FDescription;
property Unread: Boolean read FUnread write SetUnread;
end;
TTMSFMXNativeUITableViewMailItems = class(TTMSFMXNativeUITableViewItems)
public
function CreateItemClass: TCollectionItemClass; override;
end;
TTMSFMXNativeUITableViewMailSection = class(TTMSFMXNativeUITableViewSection)
public
function CreateItems: TTMSFMXNativeUITableViewItems; override;
end;
TTMSFMXNativeUITableViewMailSections = class(TTMSFMXNativeUITableViewSections)
public
function CreateItemClass: TCollectionItemClass; override;
end;
[ComponentPlatformsAttribute(pidiOSSimulator or pidiOSDevice)]
TTMSFMXNativeUITableViewMail = class(TTMSFMXNativeUITableView)
public
constructor Create(AOwner: TComponent); override;
function CreateSections: TTMSFMXNativeUITableViewSections; override;
function GetItemHeight(ASection, ARow: 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}
end;
implementation
{ TTMSFMXNativeUITableViewMailItems }
function TTMSFMXNativeUITableViewMailItems.CreateItemClass: TCollectionItemClass;
begin
Result := TTMSFMXNativeUITableViewMailItem;
end;
{ TTMSFMXNativeUITableViewMailSection }
function TTMSFMXNativeUITableViewMailSection.CreateItems: TTMSFMXNativeUITableViewItems;
begin
Result := TTMSFMXNativeUITableViewMailItems.Create(OwnerTableView, Self);
end;
{ TTMSFMXNativeUITableViewMailSections }
function TTMSFMXNativeUITableViewMailSections.CreateItemClass: TCollectionItemClass;
begin
Result := TTMSFMXNativeUITableViewMailSection;
end;
{ TTMSFMXNativeUITableViewMail }
constructor TTMSFMXNativeUITableViewMail.Create(AOwner: TComponent);
begin
inherited;
if (csDesigning in ComponentState) and not
((csReading in Owner.ComponentState) or (csLoading in Owner.ComponentState)) then
begin
Options.Header := 'Mail';
Options.ToolBar := True;
end;
end;
function TTMSFMXNativeUITableViewMail.CreateSections: TTMSFMXNativeUITableViewSections;
begin
Result := TTMSFMXNativeUITableViewMailSections.Create(Self);
end;
{$IFDEF IOS}
procedure TTMSFMXNativeUITableViewMail.DoItemCreateCell(Sender: TObject;
var ACell: UITableViewCell; AItemStyle: TTMSFMXNativeUITableViewItemStyle;
ASection, ARow: Integer);
var
title: UILabel;
senderName: UILabel;
description: UILabel;
date: UILabel;
r: NSRect;
begin
r.origin.x := 5;
r.origin.y := 5;
r.size.width := ACell.frame.size.width - 100;
r.size.height := 15;
senderName := TUILabel.Wrap(TUILabel.Wrap(TUILabel.OCClass.alloc).initWithFrame(r));
senderName.setFont(TUIFont.Wrap(TUIFont.OCClass.systemFontOfSize(12)));
senderName.setTextColor(TUIColor.Wrap(TUIColor.OCClass.orangeColor));
senderName.setHighlightedTextColor(TUIColor.Wrap(TUIColor.OCClass.whiteColor));
ACell.contentView.addSubview(senderName);
r.origin.x := Acell.frame.size.width - 100;
r.origin.y := 5;
r.size.width := 100;
r.size.height := 15;
date := TUILabel.Wrap(TUILabel.Wrap(TUILabel.OCClass.alloc).initWithFrame(r));
date.setFont(TUIFont.Wrap(TUIFont.OCClass.boldSystemFontOfSize(12)));
date.setTextAlignment(UITextAlignmentRight);
date.setTextColor(TUIColor.Wrap(TUIColor.OCClass.blueColor));
date.setHighlightedTextColor(TUIColor.Wrap(TUIColor.OCClass.whiteColor));
ACell.contentView.addSubview(date);
r.origin.x := 5;
r.origin.y := senderName.frame.size.height + senderName.frame.origin.y;
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.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.whiteColor));
ACell.contentView.addSubview(description);
end;
procedure TTMSFMXNativeUITableViewMail.DoItemCustomizeCell(Sender: TObject;
ACell: UITableViewCell; AItemStyle: TTMSFMXNativeUITableViewItemStyle;
ASection, ARow: Integer);
var
title: UILabel;
senderName: UILabel;
description: UILabel;
date: UILabel;
it: TTMSFMXNativeUITableViewItem;
mailit: TTMSFMXNativeUITableViewMailItem;
str: NSString;
r: NSRect;
begin
senderName := TUILabel.Wrap(ACell.contentView.subviews.objectAtIndex(0));
date := TUILabel.Wrap(ACell.contentView.subviews.objectAtIndex(1));
title := TUILabel.Wrap(ACell.contentView.subviews.objectAtIndex(2));
description := TUILabel.Wrap(ACell.contentView.subviews.objectAtIndex(3));
it := GetItem(ASection, ARow);
if Assigned(it) and (it is TTMSFMXNativeUITableViewMailItem) then
begin
mailit := it as TTMSFMXNativeUITableViewMailItem;
if mailit.Unread then
begin
str := NSStr(ExtractFilePath(ParamStr(0)) + 'unread_mail.png');
ACell.setImage(TUIImage.Wrap(TUIImage.OCClass.imageWithContentsOfFile(str)));
end
else
ACell.setImage(nil);
if Assigned(senderName) then
begin
senderName.setText(NSStr(mailit.Sender));
r := senderName.frame;
if Assigned(Acell.image) then
r.origin.x := 15 + Acell.image.size.width
else
r.origin.x := 5;
senderName.setFrame(r);
end;
if Assigned(title) then
begin
title.setText(NSStr(mailit.Title));
r := title.frame;
if Assigned(Acell.image) then
r.origin.x := 15 + Acell.image.size.width
else
r.origin.x := 5;
title.setFrame(r);
end;
if Assigned(description) then
begin
description.setText(NSStr(mailit.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;
if Assigned(date) then
begin
date.setText(NSStr(DateToStr(mailit.Date)));
end;
end;
end;
{$ENDIF}
function TTMSFMXNativeUITableViewMail.GetItemHeight(ASection,
ARow: Integer): Single;
begin
Result := 75;
end;
function TTMSFMXNativeUITableViewMail.GetItemStyle(ASection,
ARow: Integer): TTMSFMXNativeUITableViewItemStyle;
begin
Result := isTableViewCellStyleCustom;
end;
{ TTMSFMXNativeUITableViewMailItem }
procedure TTMSFMXNativeUITableViewMailItem.SetUnread(const Value: Boolean);
begin
FUnread := Value;
UpdateSectionAtRow(Section.Index, Index);
end;
end.