FUIAttachmentsFormCell
@IBDesignable
@MainActor
open class FUIAttachmentsFormCell : FUIInlineValidationTableViewCell
- The reusable UI component implemented as an UITableViewCell to manage selecting attachments.
FUIAttachmentsFormCell uses a FUIAttachmentsViewController to display the title of the cell
and a collection of icons to represent the attachments. The attachment icon size may change,
depends on the system font size settings. The controller arranges the attachment icons in
such a manner that as many icons to be fitted in a row, and as many rows to display all the
attachment icons. It will also try to make the row spacing equal to the spacing between icons.
However, the row spacing is limited to 20 pixels maximum.
Developers should use the property attachmentsController to provide attachment information;
the delegate, the dataSource and the list of FUIAttachmentAction implementations for the
desired type of attachments. The app can use the built-in types or implement additional types as desired.
Color settings:
Setting tintColor for add button for a state using setTintColor(_:for:) api. Currently normal and .selected are supported.
cell.setTintColor(UIColor.red, for: .normal)
There are three built-in FUIAttachmentAction:
FUIAddPhotoAttachmentAction: Choose photo from the photo library.FUITakePhotoAttachmentAction: Take photo using the camera.FUIDocumentPickerAttachmentAction: Select file using standardUIDocumentPickerViewController.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: FUIAttachmentsFormCell.reuseIdentifier, for: indexPath) as! FUIAttachmentsFormCell
cell.attachmentsController.delegate = self
cell.attachmentsController.dataSource = self
cell.attachmentsController.showAlertWhenDeleting = true
let addPhotoAction = FUIAddPhotoAttachmentAction()
addPhotoAction.delegate = self
cell.attachmentsController.addAttachmentAction(addPhotoAction)
let takePhotoAction = FUITakePhotoAttachmentAction()
takePhotoAction.delegate = self
cell.attachmentsController.addAttachmentAction(takePhotoAction)
let filePickerAction = FUIDocumentPickerAttachmentAction()
filePickerAction.delegate = self
cell.attachmentsController.addAttachmentAction(filePickerAction)
return cell
}
var attachmentURLs: [URL] = [URL]()
// MARK: FUIAttachmentsViewControllerDataSource methods
func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, iconForAttachmentAtIndex index: Int) -> (image: UIImage, contentMode: UIViewContentMode)? {
let urlString = self.attachmentURLs[index].absoluteString
guard let image = self.attachmentThumbnails[urlString] else {
return nil
}
return (image!, .scaleAspectFill)
}
func numberOfAttachments(in attachmentsViewController: FUIAttachmentsViewController) -> Int {
return attachmentURLs.count
}
func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, urlForAttachmentAtIndex index: Int) -> URL? {
return attachmentURLs[index]
}
func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, titleForAttachmentAtIndex index: Int) -> (image: UIImage, contentMode: UIViewContentMode)? {
return "attachment title"
}
func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, subtitleForAttachmentAtIndex index: Int) -> (image: UIImage, contentMode: UIViewContentMode)? {
return "attachment subtitle"
}
func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, footnoteForAttachmentAtIndex index: Int) -> (image: UIImage, contentMode: UIViewContentMode)? {
return "attachment footnote"
}
// MARK: FUIAttachmentsViewControllerDelegateMethods
func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, couldNotPresentAttachmentAtIndex index: Int) {
}
func attachmentsViewController(_ attachmentsViewController: FUIAttachmentsViewController, didPressDeleteAtIndex index: Int) {
self.attachmentURLs.remove(at: index)
self.tableView.reloadSections(IndexSet(integer:attachmentSection), with: .automatic)
}
func focusOnNewAttachment() {
DispatchQueue.main.async {
if let cell = self.tableView.visibleCells.last as? FUIAttachmentsFormCell { // find the attachment cell
if let newDoc = cell.accessibilityElements?.last {
UIAccessibility.post(notification: .layoutChanged, argument: newDoc)
}
}
}
}
//MARK: FUIAddPhotoAttachmentActionDelegate
func addPhotoAttachmentAction(_ action: FUIAddPhotoAttachmentAction, didSelectPhoto asset: PHAsset, at url: URL) {
setupThumbnails(url, with: asset)
self.addAttachmentURL(url)
}
//MARK: FUITakePhotoAttachmentActionDelegate
func takePhotoAttachmentAction(_ action: FUITakePhotoAttachmentAction, didTakePhoto asset: PHAsset, at url: URL) {
setupThumbnails(url, with: asset)
self.addAttachmentURL(url)
}
func addAttachmentURL(_ url: URL) {
self.attachmentURLs.append(url)
DispatchQueue.main.async {
self.tableView.reloadSections(IndexSet(integer:self.attachmentSection), with: .automatic)
self.tableView.scrollToRow(at: IndexPath(row: 0, section: self.attachmentSection) , at: .middle, animated: true)
if UIAccessibility.isVoiceOverRunning {
focusOnNewAttachment()
}
}
}
func setupThumbnails(_ url: URL, with asset: PHAsset) {
let imageManager = PHImageManager.default()
imageManager.requestImage(for: asset, targetSize: CGSize(width: 80, height: 80), contentMode: .default, options: nil, resultHandler: { image, array in
self.attachmentThumbnails[url.absoluteString] = image
DispatchQueue.main.async {
self.tableView.reloadSections(IndexSet(integer:self.attachmentSection), with: .automatic)
self.tableView.scrollToRow(at: IndexPath(row: 0, section: self.attachmentSection) , at: .middle, animated: true)
}
})
}
//MARK: FUIDocumentPickerAttachmentActionDelegate {
var documentPicker: UIDocumentPickerViewController {
return UIDocumentPickerViewController(documentTypes: ["public.data"], in: .import)
}
func documentPickerAttachmentAction(_ action: FUIDocumentPickerAttachmentAction, didPickFileAt url: URL) {
if let savedUrl = saveFileToTempFolder(url) {
self.addAttachmentURL(savedUrl)
}
self.tableView.reloadSections(IndexSet(integer:self.attachmentSection), with: .automatic)
if UIAccessibility.isVoiceOverRunning {
focusOnNewAttachment()
}
}
## Theming
Supported TEXT class paths:
fdlFUIAttachmentsFormView_attachmentTitleLabel {}
fdlFUIAttachmentsViewController_alertActionTitle {}
fdlFUIFileThumbnailCollectionItemView_titleLabel {}
fdlFUIThumbnailCollectionItemView_subtitle {}
fdlFUIThumbnailCollectionItemView_footnote {}
Supported TEXT properties:
font-color: Color;
font-style: UIFontTextStyle;
Supported IMAGE class paths:
fdlFUIFileThumbnailCollectionItemView_detailImageView {}
Supported IMAGE properties:
tint-color: Color;
Supported BUTTON class paths:
fdlFUIAddButtonCell_addButton {}
Supported BUTTON properties:
image: Image;
tint-color: Color;
Supported CELL class paths:
fdlFUIAttachmentsFormCell_thumbnailCell {}
fdlFUIAttachmentsFormCell_addButtonCell {}
Supported CELL properties:
border-color: Color;
border-width: Integer;
corner-radius: Integer;
Supported style classes
-
The default cell reuse identifier.
Declaration
Swift
@MainActor open class var reuseIdentifier: String { get } -
The controller managing the attachments displayed by this cell.
Declaration
Swift
@MainActor open private(set) var attachmentsController: FUIAttachmentsViewController { get } -
Indicates if user can add attachment or not. If this is true, there will be a “+” button shown. When user tapped that button, it will bring up the “Add Attachment” pop-up for user to select additional attachment. Otherwise, the “+” button will not be shown. The default is true.
Declaration
Swift
@MainActor public var isEditable: Bool { get set } -
isEnabledandisEditableare in sync.Declaration
Swift
@MainActor override public var isEnabled: Bool { get set } -
Indicates whether the cell is a mandatory field.
The default value is
false.Declaration
Swift
@MainActor open var isRequired: Bool { get set } -
:nodc:
Declaration
Swift
@MainActor open override var accessibilityIdentifier: String? { get set } -
Undocumented
Declaration
Swift
@MainActor open override var preferredFocusEnvironments: [UIFocusEnvironment] { get } -
Open the item of the specified attachment at the given index.
Declaration
Swift
@MainActor public func openAttachmentItem(index: Int)Parameters
indexThe index of the item.