我正在尝试更改Eureka中MultivaluedSection的“添加”按钮。当前的行为是,当您单击“添加”按钮时,它将在MultivaluedSection中创建一个新的空单元格。
我想要实现的是,当用户单击“添加”按钮时,它会显示一个PushRow,供用户选择单元格的初始值。
尝试获得此行为的两种方式中的任何一种我都没有运气。
我首先尝试创建一个自定义类,在其中可以完全更改MultivaluedSecion行为:
class ExerciseMultivaluedSection : MultivaluedSection {
override public var addButtonProvider: ((MultivaluedSection) -> ButtonRow) = { _ in
let button = ButtonRow {
$0.title = "MyCustomAddButton"
$0.cellStyle = .value1
}.cellUpdate { cell, _ in
cell.textLabel?.textAlignment = .left
}
// Here i would link my button to a function
// that would trigger a PushRow, maybe through a segue ?
return button
}
required public init() {
super.init()
}
required public init<S>(_ elements: S) where S : Sequence, S.Element == BaseRow {
super.init(elements)
}
required public init(multivaluedOptions: MultivaluedOptions, header: String, footer: String, _ initializer: (MultivaluedSection) -> Void) {
super.init(header: header, footer: footer, {section in initializer(section as! ExerciseMultivaluedSection) })
}
}
但是,由于以下错误,它不起作用:“无法使用存储的属性'addButtonProvider'覆盖”
然后,我尝试在运行时更改addButtonProvider,但是它什么也没做:
let exerciseSection = MultivaluedSection(multivaluedOptions:[.Delete,.Reorder,.Insert],header:"Exercises")
exerciseSection.tag = "exercise"
exerciseSection.multivaluedRowToInsertAt = {idx in
let newRow = LabelRow(){row in
row.value = "TestValue"
let deleteAction = SwipeAction(style: .destructive, title: "DEL"){action,row,completion in
completion?(true)
}
row.trailingSwipe.actions = [deleteAction]
}
return newRow
}
exerciseSection.addButtonProvider = {section in
let addBtn = ButtonRow("Test add"){ row in
row.title = "Custom add button"
}
print("Custom add button" )
return addBtn
}
即使在那之后,我的添加按钮仍然显示“添加”,并且我的打印功能从未被调用。为什么会这样?
此外,这两种方法之一是好的吗?如果没有,实现该目标的“正确方法”是什么?
我在iOS 11.4上使用XCode 9.4.1
答案 0 :(得分:0)
如果您愿意分叉并略微更改Eureka源代码,则只需进行很少的更改即可在MultiValuedSection中使用PushRow,自定义ButtonRow或任何其他行作为AddButtonProvider。
在以下GitHub提交中记录了一些必要的更改,该更改显示了源代码更改之前和之后: https://github.com/TheCyberMike/Eureka/commit/bfcba0dd04bf0d11cb6ba526235ae4c10c2d73fd
尤其是,使用PushRow作为添加按钮可能会比较棘手。我在以下问题的注释中向Eureka GitHub网站添加了信息和示例代码: https://github.com/xmartlabs/Eureka/issues/1812 Eureka的其他用户可能会在此处添加后续注释。
===来自#1812评论===
我在应用程序的分叉中对Eureka进行了非常简单的更改,以允许将任何Row用作Add行。它允许默认的ButtonRow照原样使用并自动处理。但是它还允许将其他任何行(例如PushRow)用作AddButtonProvider。
在我的应用中的多个位置,当最终用户按下添加按钮时,我会向他们显示可能添加的选项的弹出列表。他们选择一个,然后我将该选择添加到MultiValuedSection。
简单的更改是在我的应用程序中的此分叉的Eureka提交中: https://github.com/TheCyberMike/Eureka/commit/bfcba0dd04bf0d11cb6ba526235ae4c10c2d73fd
尽管我尚未在自己的应用程序中对其进行测试,但此更改还应支持允许为MVS使用自定义ButtonRow。但是我认为您需要在自己的代码中为自定义ButtonRow在.onCellSelection中处理表格视图的.insert。上面的提交代码和下面的示例中都需要执行此操作。
使用PushRow作为AddButtonProvider有点棘手,因为PushRow调用一个单独的视图控制器来显示列表,然后返回到原始表单的视图控制器。
因此,当从PushRow视图控制器返回viewWillAppear()和viewDidAppear()时,必须确保不要重建原始表单及其MultiValuedSection。
此外,选择本身在PushRow视图控制器中进行。 PushRow处理从PushRow视图控制器保留该选择的操作。但是,在PushRow视图控制器仍处于活动状态时,将调用.onChange。我使用DispatchQueue.main.async闭包来处理将tableview .insert调用推迟到原始表单的视图控制器处于活动状态时进行。
为防止PushRow显示在其最右边的灰色附件字段中做出的最后选择,必须取消其.value。但是,这也会触发.onChange,如果您不小心可能会导致无限循环。我只是使用一个简单的if语句来确保PushRow的值不为nil以防止该循环(是的,它也可以是一个保护语句)。
请确保使用[弱自我]防止内存泄漏。
下面是我的eContact Collect应用(https://github.com/TheCyberMike/eContactCollect-iOS)中使用代码的改编示例,其中从预定义列表中选择了语言,数据输入字段和电子邮件帐户之类的内容。同样,除非对引用的源代码进行更改,否则该代码将无效。
self.mForm = form
form +++ MultivaluedSection(multivaluedOptions: [.Insert, .Delete, .Reorder], header: NSLocalizedString("Shown languages in order to-be-shown", comment:"")) { mvSection in
mvSection.tag = "mvs_langs"
mvSection.showInsertIconInAddButton = false
mvSection.addButtonProvider = { [weak self] section in
return PushRow(){ row in
// REMEMBER: CANNOT rebuild the form from viewWillAppear() ... the form must remain intact during the PushRow's view
// controller life cycle for this to work
row.title = NSLocalizedString("Select new language to add", comment:"")
row.tag = "add_new_lang"
row.selectorTitle = NSLocalizedString("Choose one", comment:"")
row.options = langOptionsArray
}.onChange { [weak self] chgRow in
// PushRow has returned a value selected from the PushRow's view controller;
// note our context is still within the PushRow's view controller, not the original FormViewController
if chgRow.value != nil { // this must be present to prevent an infinite loop
guard let tableView = chgRow.cell.formViewController()?.tableView, let indexPath = chgRow.indexPath else { return }
DispatchQueue.main.async {
// must dispatch this so the PushRow's SelectorViewController is dismissed first and the UI is back at the main FormViewController
// this triggers multivaluedRowToInsertAt() below
chgRow.cell.formViewController()?.tableView(tableView, commit: .insert, forRowAt: indexPath)
}
}
}
} // end of addButtonProvider
mvSection.multivaluedRowToInsertAt = { [weak self] index in
// a verified-new langRegion code was chosen by the end-user; get it from the PushRow
let fromPushRow = self!.mForm!.rowBy(tag: "add_new_lang") as! PushRow
let langRegionCode:String = fromPushRow.value!
// create a new ButtonRow based upon the new entry
let newRow = self!.makeLangButtonRow(forLang: langRegionCode)
fromPushRow.value = nil // clear out the PushRow's value so this newly chosen item does not remain "selected"
fromPushRow.reload() // note this will re-trigger .onChange in the PushRow so must ignore that re-trigger else infinite loop
return newRow // self.rowsHaveBeenAdded() will get invoked after this point
}
}