FUIAttachmentsFormCell
@IBDesignable
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
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
open class var reuseIdentifier: String { get }
-
The controller managing the attachments displayed by this cell.
Declaration
Swift
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
public var isEditable: Bool { get set }
-
isEnabled
andisEditable
are in sync.Declaration
Swift
override public var isEnabled: Bool { get set }
-
Open the item of the specified attachment at the given index.
Declaration
Swift
public func openAttachmentItem(index: Int)
Parameters
index
The index of the item.