
Сделано с ❤ x xmartlabs. Это воссоздание XLFIRM в Swift.
简体中文
![]() | ![]() | ![]() |
|---|
Для получения дополнительной информации посмотрите на наш пост в блоге, который представляет Eureka .
Вы можете клонировать и запустить пример проекта, чтобы увидеть примеры большинства функций Eureka.
![]() | ![]() |
|---|
Расширяя FormViewController , вы можете просто добавить разделы и строки в переменную form .
import Eureka
class MyFormViewController : FormViewController {
override func viewDidLoad ( ) {
super . viewDidLoad ( )
form +++ Section ( " Section1 " )
<<< TextRow ( ) { row in
row . title = " Text Row "
row . placeholder = " Enter text here "
}
<<< PhoneRow ( ) {
$0 . title = " Phone Row "
$0 . placeholder = " And numbers here "
}
+++ Section ( " Section2 " )
<<< DateRow ( ) {
$0 . title = " Date Row "
$0 . value = Date ( timeIntervalSinceReferenceDate : 0 )
}
}
}В примере мы создаем два раздела со стандартными строками, результатом является следующее:

Вы можете создать форму, просто настройка свойства form самостоятельно, не выходя из FormViewController , но этот метод обычно более удобен.
Чтобы изменить поведение этого, вы должны установить параметры навигации вашего контроллера. FormViewController имеет переменную navigationOptions , которая является перечислением и может иметь одно или несколько из следующих значений:
canBecomeFirstResponder() Значение по умолчанию enabled & skipCanNotBecomeFirstResponderRow
Чтобы обеспечить плавную прокрутку в строки за кадром, включите его через свойство animateScroll . По умолчанию, FormViewController сразу же прыгает между рядами, когда пользователь достигает следующих или предыдущих кнопок в навигационной навигации клавиатуры, в том числе, когда следующая строка выключена с экрана.
Чтобы установить количество места между клавиатурой и выделенной строкой после навигационного события, установите свойство rowKeyboardSpacing . По умолчанию, когда форма прокручивается до вида за пределами экрана, между верхней частью клавиатуры и нижней части строки останется место.
class MyFormViewController : FormViewController {
override func viewDidLoad ( ) {
super . viewDidLoad ( )
form = ...
// Enables the navigation accessory and stops navigation when a disabled row is encountered
navigationOptions = RowNavigationOptions . Enabled . union ( . StopDisabledRow )
// Enables smooth scrolling on navigation to off-screen rows
animateScroll = true
// Leaves 20pt of space between the keyboard and the highlighted row after scrolling to an off screen row
rowKeyboardSpacing = 20
}
} Если вы хотите изменить весь навигационный аксессуар, вам придется переопределить переменную navigationAccessoryView в вашем подклассе FormViewController .
Объект Row содержит значение определенного типа. Например, SwitchRow содержит значение Bool , в то время как TextRow содержит String значение.
// Get the value of a single row
let row : TextRow ? = form . rowBy ( tag : " MyRowTag " )
let value = row . value
// Get the value of all rows which have a Tag assigned
// The dictionary contains the 'rowTag':value pairs.
let valuesDictionary = form . values ( )Eureka включает в себя пользовательские операторы, чтобы облегчить создание формы:
form +++ Section ( )
// Chain it to add multiple Sections
form +++ Section ( " First Section " ) +++ Section ( " Another Section " )
// Or use it with rows and get a blank section for free
form +++ TextRow ( )
+++ TextRow ( ) // Each row will be on a separate sectionform +++ Section ( )
<<< TextRow ( )
<<< DateRow ( )
// Or implicitly create the Section
form +++ TextRow ( )
<<< DateRow ( ) // Append Sections into a Form
form += [ Section ( " A " ) , Section ( " B " ) , Section ( " C " ) ]
// Append Rows into a Section
section += [ TextRow ( ) , DateRow ( ) ]Eureka включает в себя строители результатов, чтобы сделать создание формы простым:
// Section + Section
form = ( Section ( " A " ) +++ {
URLRow ( " UrlRow_f1 " ) { $0 . title = " Url " }
if something {
TwitterRow ( " TwitterRow_f2 " ) { $0 . title = " Twitter " }
} else {
TwitterRow ( " TwitterRow_f1 " ) { $0 . title = " Twitter " }
}
AccountRow ( " AccountRow_f1 " ) { $0 . title = " Account " }
} )
// Form + Section
form +++ {
if something {
PhoneRow ( " PhoneRow_f1 " ) { $0 . title = " Phone " }
} else {
PhoneRow ( " PhoneRow_f2 " ) { $0 . title = " Phone " }
}
PasswordRow ( " PasswordRow_f1 " ) { $0 . title = " Password " }
} @ FormBuilder
var form : Form {
Section ( " Section A " ) { section in
section . tag = " Section_A "
}
if true {
Section ( " Section B " ) { section in
section . tag = " Section_B "
}
}
NameRow ( " NameRow_f1 " ) { $0 . title = " Name " }
}Эврика включает обратные вызовы, чтобы изменить внешний вид и поведение ряда.
Row - это абстракция, которую использует Eureka, которая содержит значение и содержит Cell представления. Cell управляет представлением и подклассами UITableViewCell .
Вот пример:
let row = SwitchRow ( " SwitchRow " ) { row in // initializer
row . title = " The title "
} . onChange { row in
row . title = ( row . value ?? false ) ? " The title expands when on " : " The title "
row . updateCell ( )
} . cellSetup { cell , row in
cell . backgroundColor = . lightGray
} . cellUpdate { cell , row in
cell . textLabel ? . font = . italicSystemFont ( ofSize : 18.0 )
} 
Onchange ()
Вызывается, когда изменяется значение строки. Возможно, вы заинтересованы в настройке некоторых параметров здесь или даже привести к появлению или исчезновения других рядов.
OncellSelection ()
Каждый раз, когда пользователь выбирается на строке, и он выбирается. Обратите внимание, что это также будет вызвано для отключенных строк, поэтому вы должны запустить свой код в этом обратном вызове с чем -то вроде guard !row.isDisabled else { return }
cellSetup ()
Называется только один раз, когда ячейка сначала настроена. Установите постоянные настройки здесь.
cellUpdate ()
Вызывается каждый раз, когда ячейка появляется на экране. Вы можете изменить внешний вид здесь, используя переменные, которые могут не присутствовать на CellSetup ().
oncellhighlightchanged ()
Вызывается всякий раз, когда ячейка или любая подвеса становятся или уходят из первого респондента.
OnRowValidationChanged ()
Вызывается всякий раз, когда ошибки проверки, связанные с изменением строки.
expandInlineRow ()
Вызвано, прежде чем расширить встроенный ряд. Применяется к рядам, соответствующим протоколу InlineRowType .
oncollapseinlinerow ()
Вызвано, прежде чем обрушиться с встроенной строкой. Применяется к рядам, соответствующим протоколу InlineRowType .
Onpresent ()
Вызван строкой непосредственно перед тем, как представить другой контроллер представления. Применяется к рядам, соответствующим протоколу PresenterRowType . Используйте его для настройки представленного контроллера.
Вы можете установить String заголовка или пользовательское View в качестве заголовка или нижнего колонтитула Section .
Section ( " Title " )
Section ( header : " Title " , footer : " Footer Title " )
Section ( footer : " Footer Title " ) Вы можете использовать пользовательский вид из файла .xib :
Section ( ) { section in
var header = HeaderFooterView < MyHeaderNibFile > ( . nibFile ( name : " MyHeaderNibFile " , bundle : nil ) )
// Will be called every time the header appears on screen
header . onSetupView = { view , _ in
// Commonly used to setup texts inside the view
// Don't change the view hierarchy or size here!
}
section . header = header
} Или пользовательский UIView созданный программно
Section ( ) { section in
var header = HeaderFooterView < MyCustomUIView > ( . class )
header . height = { 100 }
header . onSetupView = { view , _ in
view . backgroundColor = . red
}
section . header = header
}Или просто создайте представление с обратным вызовом
Section ( ) { section in
section . header = {
var header = HeaderFooterView < UIView > ( . callback ( {
let view = UIView ( frame : CGRect ( x : 0 , y : 0 , width : 100 , height : 100 ) )
view . backgroundColor = . red
return view
} ) )
header . height = { 100 }
return header
} ( )
}
В этом случае мы прячем и показываем целые разделы.
Для выполнения этого каждая строка имеет hidden переменную необязательного Condition типа, которую можно установить, используя функцию или NSPredicate .
Используя function случай Condition :
Condition . function ( [ String ] , ( Form ) - > Bool ) Массив String для прохождения должен содержать теги строк, от которых зависит эта строка. Каждый раз, когда значение любого из этих строк меняется, функция переоценена. Затем функция принимает Form и возвращает Bool указывающий, должна ли строка быть скрытой или нет. Это самый мощный способ настройки hidden свойства, поскольку оно не имеет явных ограничений того, что можно сделать.
form +++ Section ( )
<<< SwitchRow ( " switchRowTag " ) {
$0 . title = " Show message "
}
<<< LabelRow ( ) {
$0 . hidden = Condition . function ( [ " switchRowTag " ] , { form in
return ! ( ( form . rowBy ( tag : " switchRowTag " ) as? SwitchRow ) ? . value ?? false )
} )
$0 . title = " Switch is on! "
} 
public enum Condition {
case function ( [ String ] , ( Form ) -> Bool )
case predicate ( NSPredicate )
} hidden переменная также может быть установлена с помощью NSPRedicate. В строке предиката вы можете ссылаться на значения других строк по их тегам, чтобы определить, должна ли строка быть скрытой или видимой. Это будет работать только в том случае, если значения строк, которые должен проверить предикат, являются NSOBjects (строка и int будут работать, так как они преодолевают их коллеги OBJC, но перечисление не сработает). Почему тогда может быть полезно использовать предикаты, когда они более ограничены? Ну, они могут быть намного проще, короче и читаемыми, чем функции. Посмотрите на этот пример:
$0 . hidden = Condition . predicate ( NSPredicate ( format : " $switchTag == false " ) ) И мы можем написать это еще короче, так как Condition соответствует ExpressibleByStringLiteral :
$0 . hidden = " $switchTag == false "ПРИМЕЧАНИЕ: мы заменим значение строки, тег которой является «SwitchTag» вместо «$ switchTag»
Чтобы все это работало, все причастные ряды должны иметь тег, так как тег будет идентифицировать их.
Мы также можем скрыть ряд, делая:
$0 . hidden = true как Condition соответствует ExpressibleByBooleanLiteral .
Не настройка hidden переменной оставит строку всегда видимой.
Если вы вручную установили скрытое (или отключенное) условие после отображения формы, вам, возможно, придется позвонить row.evaluateHidden() чтобы заставить Эврику переоценить новое условие. Смотрите этот раздел FAQ для получения дополнительной информации.
Для разделов это работает точно так же. Это означает, что мы можем настроить hidden свойство раздела, чтобы показать/скрыть его динамически.
Чтобы отключить строки, каждая строка имеет disabled переменную, которая также является необязательным свойством типа Condition . Эта переменная также работает так же, как у hidden переменной, так что она требует, чтобы ряды имели тег.
Обратите внимание, что если вы хотите навсегда отключить строку, вы также можете установить переменную disabled в true .
Чтобы отобразить список параметров, Eureka включает в себя специальный раздел под названием SelectableSection . При создании одного вам нужно передать тип строки для использования в параметрах и selectionType . selectionType - это перечисление, которое может быть либо multipleSelection , либо singleSelection(enableDeselection: Bool) , где параметр enableDeselection определяет, могут ли выбранные строки быть отказаны или нет.
form +++ SelectableSection < ListCheckRow < String > > ( " Where do you live " , selectionType : . singleSelection ( enableDeselection : true ) )
let continents = [ " Africa " , " Antarctica " , " Asia " , " Australia " , " Europe " , " North America " , " South America " ]
for option in continents {
form . last! <<< ListCheckRow < String > ( option ) { listRow in
listRow . title = option
listRow . selectableValue = option
listRow . value = nil
}
} Чтобы создать такой раздел, вы должны создать строку, которая соответствует протоколу SelectableRowType .
public protocol SelectableRowType : RowType {
var selectableValue : Value ? { get set }
} Этот selectableValue - это то, где значение строки будет навсегда сохранено. Переменная value будет использоваться для определения того, выбран ли строка или нет, будучи «выборочной Value», если выбран или нулевой. Eureka включает в себя ListCheckRow , который используется, например. В пользовательских рядах проекта примеров вы также можете найти ImageCheckRow .
Чтобы легко получить выбранную строку/s SelectableSection есть два метода: selectedRow() и selectedRows() , которые можно вызвать, чтобы получить выбранную строку в случае, если это раздел SingleSelection или все выбранные строки, если это раздел MultipleSelection .
Кроме того, вы можете настроить список параметров, которые будут сгруппированы по разделам, используя следующие свойства SelectorViewController :
sectionKeyForValue - закрытие, которое должно вернуть ключ для определенного значения строки. Этот ключ позже используется для разрыва параметров по разделам.
sectionHeaderTitleForKey - закрытие, которое возвращает заголовок заголовка для разделения для конкретного ключа. По умолчанию возвращает сам ключ.
sectionFooterTitleForKey - закрытие, которое возвращает заголовок нижнего колонтитула для секции для конкретного ключа.
Eureka поддерживает несколько значений для определенного поля (например, телефонных номеров в контакте), используя многоваленные разделы. Это позволяет нам легко создавать вставленные, делетируемые и переупорядоченные разделы.

Чтобы создать многоцелевой раздел, мы должны использовать тип MultivaluedSection вместо обычного типа Section . MultivaluedSection расширяет Section и имеет некоторые дополнительные свойства для настройки поведения с несколькими разделами.
Давайте погрузимся в пример кода ...
form +++
MultivaluedSection ( multivaluedOptions : [ . Reorder , . Insert , . Delete ] ,
header : " Multivalued TextField " ,
footer : " .Insert adds a 'Add Item' (Add New Tag) button row as last cell. " ) {
$0 . addButtonProvider = { section in
return ButtonRow ( ) {
$0 . title = " Add New Tag "
}
}
$0 . multivaluedRowToInsertAt = { index in
return NameRow ( ) {
$0 . placeholder = " Tag Name "
}
}
$0 <<< NameRow ( ) {
$0 . placeholder = " Tag Name "
}
}Предыдущий фрагмент кода показывает, как создать мультиватный раздел. В этом случае мы хотим вставить, удалять и переупорядочить строки, как указывает аргумент в пользу мультивалеопций.
addButtonProvider позволяет нам настраивать строку кнопок, которая вставляет новую строку, когда нажав, а multivaluedOptions содержит значение .Insert
Свойство закрытия multivaluedRowToInsertAt вызывается Eureka каждый раз, когда необходимо вставить новую строку. Чтобы предоставить строку для добавления в Multivalued Cesction, мы должны установить это свойство. Eureka проходит индекс как параметр закрытия. Обратите внимание, что мы можем вернуть любую строку, даже пользовательские строки, хотя в большинстве случаев ряды сечений имеют один и тот же тип.
Eureka автоматически добавляет строку кнопок, когда мы создаем вставленную мультивалентную раздел. Мы можем настроить, как выглядит эта кнопка строка, как мы объясняли ранее. Свойство showInsertIconInAddButton указывает, должна ли кнопка плюс (вставка стиля) должна отображаться слева от кнопки, по умолчанию.
Есть некоторые соображения, которые мы должны иметь в виду при создании вставленных разделов. Любая строка, добавленная в вставленную мультиваренную секцию, должна быть размещена над строкой, которую Eureka автоматически добавляет для вставки новых строк. Это может быть легко достигнуто, добавив эти дополнительные строки в раздел изнутри закрытия инициализатора секции (последний параметр инициализатора секции), поэтому Эврика добавляет кнопку «Добавить кнопку» в конце раздела.
По умолчанию Eureka установит isEditing TableView на True только в том случае, если в форме есть многоцелевое разрешение. Это будет сделано в viewWillAppear в первый раз, когда представлена форма.
Для получения дополнительной информации о том, как использовать многоцелевые разделы, пожалуйста, посмотрите на Eureka Example Project, который содержит несколько примеров использования.
Если вы хотите использовать кнопку «Добавить», которая не является ButtonRow , вы можете использовать GenericMultivaluedSection<AddButtonType> , где AddButtonType - это тип строки, который вы хотите использовать в качестве кнопки «Добавить». Это полезно, если вы хотите использовать пользовательскую строку для изменения пользовательского интерфейса кнопки.
Пример:
GenericMultivaluedSection < LabelRow > ( multivaluedOptions : [ . Reorder , . Insert , . Delete ] , {
$0 . addButtonProvider = { section in
return LabelRow ( ) {
$0 . title = " A Label row as add button "
}
}
// ...
}Eureka 2.0.0 представляет много запрашиваемую функцию встроенной проверки.
В строке есть набор Rules и конкретную конфигурацию, которая определяет, когда должны быть оценены правила проверки.
Есть некоторые правила, предусмотренные по умолчанию, но вы также можете создавать новые самостоятельно.
Предоставленные правила:
Посмотрим, как установить правила проверки.
override func viewDidLoad ( ) {
super . viewDidLoad ( )
form
+++ Section ( header : " Required Rule " , footer : " Options: Validates on change " )
<<< TextRow ( ) {
$0 . title = " Required Rule "
$0 . add ( rule : RuleRequired ( ) )
// This could also have been achieved using a closure that returns nil if valid, or a ValidationError otherwise.
/*
let ruleRequiredViaClosure = RuleClosure<String> { rowValue in
return (rowValue == nil || rowValue!.isEmpty) ? ValidationError(msg: "Field required!") : nil
}
$0.add(rule: ruleRequiredViaClosure)
*/
$0 . validationOptions = . validatesOnChange
}
. cellUpdate { cell , row in
if !row . isValid {
cell . titleLabel ? . textColor = . systemRed
}
}
+++ Section ( header : " Email Rule, Required Rule " , footer : " Options: Validates on change after blurred " )
<<< TextRow ( ) {
$0 . title = " Email Rule "
$0 . add ( rule : RuleRequired ( ) )
$0 . add ( rule : RuleEmail ( ) )
$0 . validationOptions = . validatesOnChangeAfterBlurred
}
. cellUpdate { cell , row in
if !row . isValid {
cell . titleLabel ? . textColor = . systemRed
}
} Как вы можете видеть в предыдущем фрагменте кода, мы можем настроить столько правил, сколько хотим в ряду, вызывая add(rule:) функция.
Row также предоставляет func remove(ruleWithIdentifier identifier: String) для удаления правила. Чтобы использовать его, мы должны назначить идентификатор правилу после его создания.
Иногда коллекция правил, которые мы хотим использовать в ряду, то же самое, что мы хотим использовать во многих других рядах. В этом случае мы можем установить все правила проверки, используя RuleSet , который представляет собой набор правил проверки.
var rules = RuleSet < String > ( )
rules . add ( rule : RuleRequired ( ) )
rules . add ( rule : RuleEmail ( ) )
let row = TextRow ( ) {
$0 . title = " Email Rule "
$0 . add ( ruleSet : rules )
$0 . validationOptions = . validatesOnChangeAfterBlurred
} Eureka позволяет нам указать, когда должны быть оценены правила проверки. Мы можем сделать это, настроив свойство validationOptions Row, которое может иметь следующие значения:
.validatesOnChange - проверяет всякий раз, когда изменяется значение строки..validatesOnBlur - (значение по умолчанию) проверяет сразу после того, как ячейка ушла в отставку. Не применимо ко всем рядам..validatesOnChangeAfterBlurred - проверяет всякий раз, когда значение строки изменяется после того, как она впервые уходит в отставку..validatesOnDemand - Мы должны вручную проверить строку или форму, вызывая метод validate() . Если вы хотите проверить всю форму (все строки), вы можете вручную вызвать метод Form validate() .
Каждая строка имеет свойство validationErrors , которое можно использовать для извлечения всех ошибок проверки. Это свойство просто содержит список ошибок проверки последней выполнения проверки строки, что означает, что оно не оценивает правила проверки строки.
Как и ожидалось, правила должны использовать те же типы, что и объект строки. Будьте очень осторожны, чтобы проверить используемый тип строки. Вы можете увидеть ошибку компилятора («неверная метка Arugment в Call (есть« правило: «ожидаемый набор правил:») », которая не указывает на проблему при смешивании типов.
Используя действия trailingSwipe leadingSwipe строке. По мере того, как действия зависят от функций системы iOS, leadingSwipe доступен только на iOS 11,0+.
Давайте посмотрим, как определить смахивание действий.
let row = TextRow ( ) {
let deleteAction = SwipeAction (
style : . destructive ,
title : " Delete " ,
handler : { ( action , row , completionHandler ) in
//add your code here.
//make sure you call the completionHandler once done.
completionHandler ? ( true )
} )
deleteAction . image = UIImage ( named : " icon-trash " )
$0 . trailingSwipe . actions = [ deleteAction ]
$0 . trailingSwipe . performsFirstActionWithFullSwipe = true
//please be aware: `leadingSwipe` is only available on iOS 11+ only
let infoAction = SwipeAction (
style : . normal ,
title : " Info " ,
handler : { ( action , row , completionHandler ) in
//add your code here.
//make sure you call the completionHandler once done.
completionHandler ? ( true )
} )
infoAction . actionBackgroundColor = . blue
infoAction . image = UIImage ( named : " icon-info " )
$0 . leadingSwipe . actions = [ infoAction ]
$0 . leadingSwipe . performsFirstActionWithFullSwipe = true
} Действия с false необходимы tableView.isEditing Eureka установит это на true , если в форме будет многоцелевое разрешение (в viewWillAppear ). Если у вас есть как многоцелевые, так и действия в одной и той же форме, вы должны установить isEditing в соответствии с вашими потребностями.
Очень распространено, что вам нужен ряд, отличный от тех, которые включены в Eureka. Если это так, вам придется создать свою собственную строку, но это не должно быть сложно. Вы можете прочитать этот урок о том, как создать пользовательские строки, чтобы начать работу. Возможно, вы также захотите взглянуть на Eurekacommunity, который включает в себя некоторые дополнительные ряды, готовые к добавлению в Eureka.
Чтобы создать строку с пользовательским поведением и внешним видом, вы, вероятно, захотите создать подклассы Row и Cell .
Помните, что Row - это абстракция, которую использует Eureka, в то время как Cell является фактической UITableViewCell , отвечающей за представление. Поскольку Row содержит Cell , как Row , так и Cell должны быть определены для одного и того же типа значения .
// Custom Cell with value type: Bool
// The cell is defined using a .xib, so we can set outlets :)
public class CustomCell : Cell < Bool > , CellType {
@ IBOutlet weak var switchControl : UISwitch !
@ IBOutlet weak var label : UILabel !
public override func setup ( ) {
super . setup ( )
switchControl . addTarget ( self , action : #selector ( CustomCell . switchValueChanged ) , for : . valueChanged )
}
func switchValueChanged ( ) {
row . value = switchControl . on
row . updateCell ( ) // Re-draws the cell which calls 'update' bellow
}
public override func update ( ) {
super . update ( )
backgroundColor = ( row . value ?? false ) ? . white : . black
}
}
// The custom Row also has the cell: CustomCell and its correspond value
public final class CustomRow : Row < CustomCell > , RowType {
required public init ( tag : String ? ) {
super . init ( tag : tag )
// We set the cellProvider to load the .xib corresponding to our cell
cellProvider = CellProvider < CustomCell > ( nibName : " CustomCell " )
}
} Результат: 
Как и Callbacks CellSetup и CellUpdate, Cell имеет методы настройки и обновления, где вы можете его настроить.
Встроенная строка - это конкретный тип строки, который показывает динамически строку под ней, обычно встроенная строка изменяется между расширенным и разрушенным режимом, когда строка нажата.
Таким образом, чтобы создать встроенную строку, нам нужно 2 строка, строка, которая «всегда» видима, и строка, которая будет расширяться/обрушиться.
Другое требование состоит в том, что тип значения этих 2 строк должен быть таким же. Это означает, что если одна строка содержит String значение, то другая должна иметь String значение.
Как только у нас есть эти 2 ряда, мы должны сделать тип верхнего ряда соответствовать InlineRowType . Этот протокол требует, чтобы вы определили InlineRow и функцию setupInlineRow . Тип InlineRow будет типом строки, которая будет расширяться/обрушиться. Примите это в качестве примера:
class PickerInlineRow < T > : Row < PickerInlineCell < T > > where T : Equatable {
public typealias InlineRow = PickerRow < T >
open var options = [ T ] ( )
required public init ( tag : String ? ) {
super . init ( tag : tag )
}
public func setupInlineRow ( _ inlineRow : InlineRow ) {
inlineRow . options = self . options
inlineRow . displayValueFor = self . displayValueFor
inlineRow . cell . height = { UITableViewAutomaticDimension }
}
} InlineRowType также добавит несколько методов в ваш встроенный строк:
func expandInlineRow ( )
func collapseInlineRow ( )
func toggleInlineRow ( ) Эти методы должны работать нормально, но если вы хотите переопределить их, имейте в виду, что именно toggleInlineRow должен назвать expandInlineRow и collapseInlineRow .
Наконец, вы должны вызвать toggleInlineRow() когда выбран строка, например, переосмыслить customDidSelect :
public override func customDidSelect ( ) {
super . customDidSelect ( )
if !isDisabled {
toggleInlineRow ( )
}
}Примечание. Строка докладчика - это строка, которая представляет новый UiviewController.
Чтобы создать пользовательскую строку докладчика, вы должны создать класс, который соответствует протоколу PresenterRowType . Настоятельно рекомендуется подкласс SelectorRow поскольку он соответствует этому протоколу и добавляет другие полезные функции.
Протокол настоящего мощности определяется следующим образом:
public protocol PresenterRowType : TypedRowType {
associatedtype PresentedControllerType : UIViewController , TypedRowControllerType
/// Defines how the view controller will be presented, pushed, etc.
var presentationMode : PresentationMode < PresentedControllerType > ? { get set }
/// Will be called before the presentation occurs.
var onPresentCallback : ( ( FormViewController , PresentedControllerType ) -> Void ) ? { get set }
} OnPresentCallback будет вызвана, когда строка собирается представить другой контроллер представления. Это делается в SelectorRow , поэтому, если вы не подкладываете его, вам придется назвать это самостоятельно.
presentationMode - это то, что определяет, как представлен контроллер и какой контроллер представлен. Эта презентация может использовать идентификатор Segue, класс Segue, модульно представляющий контроллер или подталкивание к определенному контроллеру представления. Например, Custompushrow может быть определена так:
Давайте посмотрим пример ..
/// Generic row type where a user must select a value among several options.
open class SelectorRow < Cell : CellType > : OptionsRow < Cell > , PresenterRowType where Cell : BaseCell {
/// Defines how the view controller will be presented, pushed, etc.
open var presentationMode : PresentationMode < SelectorViewController < SelectorRow < Cell > > > ?
/// Will be called before the presentation occurs.
open var onPresentCallback : ( ( FormViewController , SelectorViewController < SelectorRow < Cell > > ) -> Void ) ?
required public init ( tag : String ? ) {
super . init ( tag : tag )
}
/**
Extends `didSelect` method
*/
open override func customDidSelect ( ) {
super . customDidSelect ( )
guard let presentationMode = presentationMode , !isDisabled else { return }
if let controller = presentationMode . makeController ( ) {
controller . row = self
controller . title = selectorTitle ?? controller . title
onPresentCallback ? ( cell . formViewController ( ) ! , controller )
presentationMode . present ( controller , row : self , presentingController : self . cell . formViewController ( ) ! )
} else {
presentationMode . present ( nil , row : self , presentingController : self . cell . formViewController ( ) ! )
}
}
/**
Prepares the pushed row setting its title and completion callback.
*/
open override func prepare ( for segue : UIStoryboardSegue ) {
super . prepare ( for : segue )
guard let rowVC = segue . destination as Any as? SelectorViewController < SelectorRow < Cell > > else { return }
rowVC . title = selectorTitle ?? rowVC . title
rowVC . onDismissCallback = presentationMode ? . onDismissCallback ?? rowVC . onDismissCallback
onPresentCallback ? ( cell . formViewController ( ) ! , rowVC )
rowVC . row = self
}
}
// SelectorRow conforms to PresenterRowType
public final class CustomPushRow < T : Equatable > : SelectorRow < PushSelectorCell < T > > , RowType {
public required init ( tag : String ? ) {
super . init ( tag : tag )
presentationMode = . show ( controllerProvider : ControllerProvider . callback {
return SelectorViewController < T > ( ) { _ in }
} , onDismiss : { vc in
_ = vc . navigationController ? . popViewController ( animated : true )
} )
}
}Иногда мы хотим изменить внешний вид пользовательского интерфейса одного из наших строк, но не изменяя тип строки и всю логику, связанную с одной строкой. В настоящее время есть один из способов сделать это , если вы используете ячейки, которые создаются из файлов NIB . В настоящее время ни один из основных строк Eureka не создается из файлов NIB, но некоторые из пользовательских строк в Eurekacommunity являются, в частности, pestaladdressrow, который был перемещен там.
Вам нужно сделать:
cellProvider для использования этого NIB. Вы должны сделать это в инициализаторе, либо в каждом конкретном экземпляре, либо с использованием defaultRowInitializer . Например: <<< PostalAddressRow ( ) {
$0 . cellProvider = CellProvider < PostalAddressCell > ( nibName : " CustomNib " , bundle : Bundle . main )
}Вы также можете создать новый ряд для этого. В этом случае постарайтесь унаследовать от того же суперкласса, что и ряд, который вы хотите изменить, чтобы унаследовать ее логику.
Есть некоторые вещи, которые нужно учитывать, когда вы делаете это:
Unknown class <YOUR_CLASS_NAME> in Interface Builder file , возможно, вам придется создать этот новый тип где -то в вашем коде, чтобы загрузить его во время выполнения. Вызовет let t = YourClass.self помог в моем случае. Метка ряд![]() | Кнопка строки![]() | Проверьте ряд ![]() |
Переключить ряд![]() | Слайдер ряд![]() | Шаговый ряд ![]() |
Текстовая зона строка ![]() |
Эти ряды имеют текстовое поле на правой стороне ячейки. Разница между каждым из них состоит в различной капитализации, автокоррекции и конфигурации типа клавиатуры.
![]() | Textrow Намероу Урлроу Внутренний Фонероу Пароль EmailRow Десятичный Twitterrow Учет ZipCoderow |
Все приведенные выше подтипы FieldRow имеют свойство formatter NSFormatter , которое можно установить для определения того, как следует отображать значение этой строки. Пользовательский форматер для чисел с двумя цифрами после десятичной отметки включен в Eureka ( DecimalFormatter ). Пример проекта также содержит CurrencyFormatter , который отображает число в качестве валюты в соответствии с локацией пользователя.
По умолчанию настройка formatter строки влияет только на то, как отображается значение, когда оно не редактируется. Чтобы также отформатировать значение, когда строка отредактируется, установите useFormatterDuringInput в true при инициализации строки. Форматирование значения при редактировании может потребовать обновления позиции курсора, а Eureka предоставляет следующий протокол, которому ваш формат
public protocol FormatterProtocol {
func getNewPosition ( forPosition forPosition : UITextPosition , inTextInput textInput : UITextInput , oldValue : String ? , newValue : String ? ) -> UITextPosition
} Кроме того, подтипы FieldRow имеют свойство useFormatterOnDidBeginEditing . При использовании DecimalRow с форматером, который допускает десятичные значения и соответствует локале пользователя (например, DecimalFormatter ), если useFormatterDuringInput является false , useFormatterOnDidBeginEditing должна быть установлена на true , так что десятичная отметка в редактировании значения соответствует десятичной маркетинге на клавиатуре.
Руки даты удерживают дату и позволяют нам установить новое значение через управление UIDETPICKER. Режим UIDETPICKER и то, как показан представление о выборе даты, - это то, что меняется между ними.
Строка даты ![]() Сборщик показан на клавиатуре. | Дата строка (встроенный) ![]() Ряд расширяется. | Дата строка (сборщик) ![]() Сборщик всегда виден. |
С этими 3 стилями (Normal, Inline & Picker) Eureka включает в себя:
Это строки со списком параметров, из которых должен выбирать пользователь.
<<< ActionSheetRow < String > ( ) {
$0 . title = " ActionSheetRow "
$0 . selectorTitle = " Pick a number "
$0 . options = [ " One " , " Two " , " Three " ]
$0 . value = " Two " // initially selected
} Предупреждение ряд![]() Покажет предупреждение с вариантами на выбор. | ActionSheet Row![]() Постановит лист действий с параметрами на выбор. | Толкать ряд![]() Позвольте к новому контроллеру, где выбирать параметры, перечисленные с использованием Check Rows. | Несколько селекторных строк![]() Как Pushrow, но позволяет выбирать несколько параметров. |
Сегментированный ряд![]() | Сегментированная строка (с заголовком)![]() | Пикеер Роу![]() Представляют параметры общего типа через представление сбора (Также есть Picker Conline Row) |
Дайте нам знать об этом, мы были бы рады упомянуть об этом здесь. :)

Кокоподы являются менеджером зависимостей для какао -проектов.
Укажите Eureka в Podfile вашего проекта:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios , '9.0'
use_frameworks!
pod 'Eureka'Затем запустите следующую команду:
$ pod installSwift Package Manager - это инструмент для управления распределением Swift Code.
После того, как вы настраиваете свой Package.swift Заполните файл манифеста, вы можете добавить Eureka в качестве зависимости, добавив его к значению зависимостей вашего Package.swift Swift.
Зависимости: [.package (url: "https://github.com/xmartlabs/eureka.git", от: "5.5.0")]
Карфаген - это простой децентрализованный менеджер зависимостей для какао.
Укажите Eureka в Cartfile вашего проекта:
github "xmartlabs/Eureka" ~> 5.5
$ git submodule add https://github.com/xmartlabs/Eureka.gitОткройте папку Eureka, которая была создана предыдущей командой GIT Submodule и перетащите Eureka.xcodeproj в проект навигатора проекта вашего приложения.
Выберите eureka.xcodeproj в Навигаторе проекта и проверьте целевые соответствия развертывания с целью развертывания вашего приложения.
Выберите свой проект в навигации Xcode, а затем выберите цель приложения с боковой панели. Затем выберите вкладку «Общий» и нажмите кнопку + кнопку под разделом «Встроенные двоичные файлы».
Выберите Eureka.framework , и мы закончили!
eureka-forms ).Прежде чем внести свой вклад, проверьте файл, чтобы получить дополнительную информацию.
Если вы используете Eureka в вашем приложении, мы хотели бы услышать об этом! Оставьте нам строку в Twitter.
В каждом ряду есть следующее свойство:
/// Block variable used to get the String that should be displayed for the value of this row.
public var displayValueFor : ( ( T ? ) -> String ? ) ? = {
return $0 . map { String ( describing : $0 ) }
} Вы можете установить displayValueFor в соответствии с значением строки, которое вы хотите отобразить.
Мы можем получить определенную строку, вызывая любую из следующих функций, выявленных классом Form :
public func rowBy < T : Equatable > ( tag : String ) -> RowOf < T > ?
public func rowBy < Row : RowType > ( tag : String ) -> Row ?
public func rowBy ( tag : String ) -> BaseRow ?Например:
let dateRow : DateRow ? = form . rowBy ( tag : " dateRowTag " )
let labelRow : LabelRow ? = form . rowBy ( tag : " labelRowTag " )
let dateRow2 : Row < DateCell > ? = form . rowBy ( tag : " dateRowTag " )
let labelRow2 : BaseRow ? = form . rowBy ( tag : " labelRowTag " ) let section : Section ? = form . sectionBy ( tag : " sectionTag " ) Вызов setValues(values: [String: Any?]) Который выявляется классом Form .
Например:
form . setValues ( [ " IntRowTag " : 8 , " TextRowTag " : " Hello world! " , " PushRowTag " : Company ( name : " Xmartlabs " ) ] ) Где "IntRowTag" , "TextRowTag" , "PushRowTag" - это теги ряда (каждый из них уникально идентифицирует ряд) и 8 , "Hello world!" , Company(name:"Xmartlabs") являются соответствующим значением строки для назначения.
Тип значения строки должен соответствовать типу значения соответствующего значения словаря, в противном случае NIL будет назначено.
Если форма уже была отображена, мы должны перезагрузить видимые строки, либо перезагружая таблицу View tableView.reloadData() или вызов updateCell() в каждую видимую строку.
После установки условия это условие не оценивается автоматически. Если вы хотите, чтобы это было сразу же, вы можете позвонить .evaluateHidden() или .evaluateDisabled() .
Эти функции просто вызываются, когда строка добавляется в форму, а когда в строке это зависит от изменений. Если условие изменяется при отображении строки, то оно должно быть переоценено вручную.
Посмотрите на эту проблему.
section . header = HeaderFooterView ( title : " Header title ( variable ) " ) // use String interpolation
//or
var header = HeaderFooterView < UIView > ( . class ) // most flexible way to set up a header using any view type
header . height = { 60 } // height can be calculated
header . onSetupView = { view , section in // each time the view is about to be displayed onSetupView is invoked.
view . backgroundColor = . orange
}
section . header = headersection . reload ( ) selectableRowSetup , selectableRowCellUpdate и selectableRowCellSetup предоставляются, чтобы иметь возможность настроить выборочные ячейки SelectorViewController и MultiplectorectorViewController.
let row = PushRow < Emoji > ( ) {
$0 . title = " PushRow "
$0 . options = [ ?? , ? , ?? , ? , ? , ? ]
$0 . value = ??
$0 . selectorTitle = " Choose an Emoji! "
} . onPresent { from , to in
to . dismissOnSelection = false
to . dismissOnChange = false
to . selectableRowSetup = { row in
row . cellProvider = CellProvider < ListCheckCell < Emoji > > ( nibName : " EmojiCell " , bundle : Bundle . main )
}
to . selectableRowCellUpdate = { cell , row in
cell . textLabel ? . text = " Text " + row . selectableValue! // customization
cell . detailTextLabel ? . text = " Detail " + row . selectableValue!
}
} Как мы уже говорили, типы Form и Section соответствуют MutableCollection и RangeReplaceableCollection . Форма представляет собой коллекцию разделов, а раздел - это коллекция рядов.
Расширение протокола RangeReplaceableCollection предоставляет много полезных методов для изменения сбора.
extension RangeReplaceableCollection {
public mutating func append ( _ newElement : Self . Element )
public mutating func append < S > ( contentsOf newElements : S ) where S : Sequence , Self . Element == S . Element
public mutating func insert ( _ newElement : Self . Element , at i : Self . Index )
public mutating func insert < S > ( contentsOf newElements : S , at i : Self . Index ) where S : Collection , Self . Element == S . Element
public mutating func remove ( at i : Self . Index ) -> Self . Element
public mutating func removeSubrange ( _ bounds : Range < Self . Index > )
public mutating func removeFirst ( _ n : Int )
public mutating func removeFirst ( ) -> Self . Element
public mutating func removeAll ( keepingCapacity keepCapacity : Bool )
public mutating func reserveCapacity ( _ n : Self . IndexDistance )
}Эти методы используются внутренне для реализации пользовательских операторов, как показано на рисунке:
public func +++ ( left : Form , right : Section ) -> Form {
left . append ( right )
return left
}
public func += < C : Collection > ( inout lhs : Form , rhs : C ) where C . Element == Section {
lhs . append ( contentsOf : rhs )
}
public func << < ( left : Section , right : BaseRow ) -> Section {
left . append ( right )
return left
}
public func += < C : Collection > ( inout lhs : Section , rhs : C ) where C . Element == BaseRow {
lhs . append ( contentsOf : rhs )
}Вы можете увидеть, как здесь реализованы остальные пользовательские операторы.
Вы должны решить, хотите ли вы использовать пользовательские операторы Eureka или нет.
Форма всегда отображается в UITableView . Вы можете настроить контроллер представления на раскадровке и добавить UitableView, где вы хотите, а затем подключить выход с переменной tableView FormViewController. Это позволяет вам определить пользовательскую кадр (возможно с ограничениями) для вашей формы.
Все это также может быть сделано с помощью программного изменения кадры, краев и т. Д. Соблюдения tableView вашего FormViewController.
Так что мы можем сделать Эврику еще лучше! 
Это можно найти в файле ChangeLog.md.