
Dibuat dengan ❤️ oleh xmartlabs. Ini adalah penciptaan ulang XLForm di Swift.
简体中文
![]() | ![]() | ![]() |
|---|
Untuk informasi lebih lanjut, lihat posting blog kami yang memperkenalkan Eureka .
Anda dapat mengkloning dan menjalankan contoh proyek untuk melihat contoh sebagian besar fitur Eureka.
![]() | ![]() |
|---|
Dengan memperluas FormViewController Anda kemudian dapat cukup menambahkan bagian dan baris ke variabel 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 )
}
}
}Dalam contoh kami membuat dua bagian dengan baris standar, hasilnya adalah ini:

Anda dapat membuat formulir dengan hanya menyiapkan properti form sendiri tanpa memperluas dari FormViewController tetapi metode ini biasanya lebih nyaman.
Untuk mengubah perilaku ini, Anda harus mengatur opsi navigasi pengontrol Anda. FormViewController memiliki variabel navigationOptions yang merupakan enum dan dapat memiliki satu atau lebih nilai -nilai berikut:
canBecomeFirstResponder() Nilai default enabled & skipCanNotBecomeFirstResponderRow
Untuk mengaktifkan pengguliran yang halus ke baris di luar layar, memungkinkannya melalui properti animateScroll . Secara default, FormViewController langsung melompat di antara baris ketika pengguna mengenai tombol berikutnya atau sebelumnya di aksesori navigasi keyboard, termasuk ketika baris berikutnya keluar layar.
Untuk mengatur jumlah ruang antara keyboard dan baris yang disorot mengikuti acara navigasi, atur properti rowKeyboardSpacing . Secara default, ketika formulir bergulir ke tampilan offscreen tidak ada ruang yang akan dibiarkan di antara bagian atas keyboard dan bagian bawah baris.
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
}
} Jika Anda ingin mengubah seluruh tampilan aksesori navigasi, Anda harus mengganti variabel navigationAccessoryView di subclass of FormViewController Anda.
Objek Row memegang nilai jenis tertentu. Misalnya, SwitchRow memegang nilai Bool , sedangkan TextRow memegang nilai 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 termasuk operator khusus untuk membuat pembuatan formulir mudah:
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 termasuk pembangun hasil untuk membuat pembuatan formulir mudah:
// 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 " }
}Eureka termasuk panggilan balik untuk mengubah penampilan dan perilaku barisan.
Row adalah abstraksi yang digunakan Eureka yang memiliki nilai dan berisi Cell tampilan. Cell mengelola tampilan dan subkelas UITableViewCell .
Inilah contohnya:
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 ()
Dipanggil saat nilai baris berubah. Anda mungkin tertarik untuk menyesuaikan beberapa parameter di sini atau bahkan membuat beberapa baris lain muncul atau menghilang.
OncellSelection ()
Dipanggil setiap kali pengguna mengetuk pada baris dan dipilih. Perhatikan bahwa ini juga akan dipanggil untuk barisan yang dinonaktifkan sehingga Anda harus memulai kode Anda di dalam panggilan balik ini dengan sesuatu seperti guard !row.isDisabled else { return }
cellsetup ()
Dipanggil hanya sekali saat sel pertama kali dikonfigurasi. Atur pengaturan permanen di sini.
cellupdate ()
Dipanggil setiap kali sel muncul di layar. Anda dapat mengubah penampilan di sini menggunakan variabel yang mungkin tidak ada di CellSetup ().
OncellHighlightChanged ()
Disebut setiap kali sel atau subview menjadi atau mengundurkan diri dari responden pertama.
OnrowValidationChanged ()
Disebut setiap kali kesalahan validasi yang terkait dengan perubahan baris.
onexpandinlinerow ()
Dipanggil sebelum memperluas baris sebaris. Berlaku untuk baris yang sesuai dengan protokol InlineRowType .
Oncollapsinlinerow ()
Dipanggil sebelum runtuh baris inline. Berlaku untuk baris yang sesuai dengan protokol InlineRowType .
OnPresent ()
Dipanggil dengan baris tepat sebelum menghadirkan pengontrol tampilan lain. Berlaku untuk baris yang sesuai dengan protokol PresenterRowType . Gunakan untuk mengatur pengontrol yang disajikan.
Anda dapat mengatur String judul atau View khusus sebagai header atau footer Section .
Section ( " Title " )
Section ( header : " Title " , footer : " Footer Title " )
Section ( footer : " Footer Title " ) Anda dapat menggunakan tampilan khusus dari file .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
} Atau custom UIView dibuat secara terprogram
Section ( ) { section in
var header = HeaderFooterView < MyCustomUIView > ( . class )
header . height = { 100 }
header . onSetupView = { view , _ in
view . backgroundColor = . red
}
section . header = header
}Atau hanya membangun tampilan dengan panggilan balik
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
} ( )
}
Dalam hal ini kami bersembunyi dan menunjukkan seluruh bagian.
Untuk mencapai ini, setiap baris memiliki variabel hidden dari Condition tipe opsional yang dapat diatur menggunakan fungsi atau NSPredicate .
Menggunakan Kasus function Condition :
Condition . function ( [ String ] , ( Form ) - > Bool ) Array String yang akan diteruskan harus berisi tag dari barisan baris ini tergantung. Setiap kali nilai dari salah satu baris tersebut berubah, fungsi tersebut dievaluasi kembali. Fungsi kemudian mengambil Form dan mengembalikan Bool yang menunjukkan apakah baris harus disembunyikan atau tidak. Ini cara paling kuat untuk menyiapkan properti hidden karena tidak memiliki batasan eksplisit tentang apa yang dapat dilakukan.
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 )
} Variabel hidden juga dapat diatur dengan nspredicate. Dalam string predikat Anda dapat merujuk nilai baris lain dengan tag mereka untuk menentukan apakah baris harus disembunyikan atau terlihat. Ini hanya akan berfungsi jika nilai -nilai baris yang harus diperiksa oleh predikat adalah nsobjects (String dan int akan berfungsi karena mereka dijembatani ke rekan -rekan OBJC mereka, tetapi enum tidak akan berhasil). Mengapa mungkin berguna untuk menggunakan predikat ketika mereka lebih terbatas? Nah, mereka bisa jauh lebih sederhana, lebih pendek dan dapat dibaca daripada fungsi. Lihatlah contoh ini:
$0 . hidden = Condition . predicate ( NSPredicate ( format : " $switchTag == false " ) ) Dan kita dapat menulisnya bahkan lebih pendek karena Condition sesuai dengan ExpressibleByStringLiteral :
$0 . hidden = " $switchTag == false "Catatan: Kami akan mengganti nilai baris yang tagnya adalah 'switchtag' bukan '$ switchtag'
Agar semua ini berhasil, semua baris yang terlibat harus memiliki tag karena tag akan mengidentifikasi mereka.
Kami juga dapat menyembunyikan barisan dengan melakukan:
$0 . hidden = true karena Condition sesuai dengan ExpressibleByBooleanLiteral .
Tidak mengatur variabel hidden akan membuat baris selalu terlihat.
Jika Anda secara manual mengatur kondisi tersembunyi (atau dinonaktifkan) setelah formulir ditampilkan, Anda mungkin harus menelepon row.evaluateHidden() . Lihat bagian FAQ ini untuk info lebih lanjut.
Untuk bagian ini berfungsi sama. Itu berarti kita dapat mengatur bagian properti hidden untuk menampilkan/menyembunyikannya secara dinamis.
Untuk menonaktifkan baris, setiap baris memiliki variabel disabled yang juga merupakan properti tipe Condition opsional. Variabel ini juga berfungsi sama dengan variabel hidden sehingga membutuhkan baris untuk memiliki tag.
Perhatikan bahwa jika Anda ingin menonaktifkan baris secara permanen, Anda juga dapat mengatur variabel disabled ke true .
Untuk menampilkan daftar opsi, Eureka menyertakan bagian khusus yang disebut SelectableSection . Saat membuat satu, Anda perlu melewati jenis baris untuk digunakan di opsi dan selectionType . selectionType adalah enum yang dapat berupa multipleSelection atau singleSelection(enableDeselection: Bool) di mana parameter enableDeselection menentukan apakah baris yang dipilih dapat dipilih atau tidak.
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
}
} Untuk membuat bagian seperti itu, Anda harus membuat baris yang sesuai dengan protokol SelectableRowType .
public protocol SelectableRowType : RowType {
var selectableValue : Value ? { get set }
} selectableValue ini adalah tempat nilai baris akan disimpan secara permanen. Variabel value akan digunakan untuk menentukan apakah baris dipilih atau tidak, menjadi 'SelectableValue' jika dipilih atau nol sebaliknya. Eureka termasuk ListCheckRow yang digunakan misalnya. Dalam baris khusus dari proyek contoh, Anda juga dapat menemukan ImageCheckRow .
Untuk dengan mudah mendapatkan baris/s yang dipilih dari sebuah SelectableSection ada dua metode: selectedRow() dan selectedRows() yang dapat dipanggil untuk mendapatkan baris yang dipilih jika itu adalah bagian seleksi SingleSelection atau semua baris yang dipilih jika merupakan bagian MultipleSelection .
Selain itu, Anda dapat mengatur daftar opsi yang akan dikelompokkan berdasarkan bagian menggunakan properti berikut dari SelectorViewController :
sectionKeyForValue - Penutupan yang harus mengembalikan kunci untuk nilai baris tertentu. Kunci ini kemudian digunakan untuk memecahkan opsi berdasarkan bagian.
sectionHeaderTitleForKey - Penutupan yang mengembalikan judul header untuk bagian untuk kunci tertentu. Secara default mengembalikan kunci itu sendiri.
sectionFooterTitleForKey - Penutupan yang mengembalikan judul footer untuk bagian untuk kunci tertentu.
Eureka mendukung beberapa nilai untuk bidang tertentu (seperti nomor telepon dalam kontak) dengan menggunakan bagian multivalued. Ini memungkinkan kami untuk dengan mudah membuat bagian yang dapat dimasukkan, dihapus, dan dapat dipesan ulang.

Untuk membuat bagian multivalued, kami harus menggunakan tipe MultivaluedSection alih -alih jenis Section biasa. MultivaluedSection memperluas Section dan memiliki beberapa properti tambahan untuk mengonfigurasi perilaku bagian multivalued.
Mari selami contoh kode ...
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 "
}
}Cuplikan kode sebelumnya menunjukkan cara membuat bagian multivalued. Dalam hal ini kami ingin memasukkan, menghapus dan memesan ulang baris seperti yang ditunjukkan oleh argumen MultivaluedOptions.
addButtonProvider memungkinkan kami untuk menyesuaikan baris tombol yang menyisipkan baris baru saat disadap dan multivaluedOptions berisi nilai .Insert Insert.
multivaluedRowToInsertAt Properti Penutupan Dipanggil oleh Eureka Setiap kali baris baru perlu dimasukkan. Untuk memberikan baris untuk ditambahkan ke bagian multivalued, kami harus mengatur properti ini. Eureka melewati indeks sebagai parameter penutupan. Perhatikan bahwa kita dapat mengembalikan setiap jenis baris, bahkan baris khusus, meskipun dalam kebanyakan kasus baris bagian multinasikan memiliki jenis yang sama.
Eureka secara otomatis menambahkan baris tombol saat kami membuat bagian multinum yang dapat dimasukkan. Kita dapat menyesuaikan bagaimana baris tombol ini terlihat seperti yang kita jelaskan sebelumnya. Properti showInsertIconInAddButton menunjukkan jika tombol Plus (Sisipkan Gaya) akan muncul di sebelah kiri tombol, benar secara default.
Ada beberapa pertimbangan yang perlu kita pikirkan saat membuat bagian yang dapat dimasukkan. Setiap baris yang ditambahkan ke bagian multivalued yang dapat dimasukkan harus ditempatkan di atas baris yang ditambahkan Eureka secara otomatis untuk memasukkan baris baru. Ini dapat dengan mudah dicapai dengan menambahkan baris tambahan ini ke bagian dari dalam penutupan inisialisasi bagian (parameter terakhir dari inisialisasi bagian) sehingga Eureka menambahkan tombol Tambah Sisipkan di akhir bagian.
Secara default, Eureka akan mengatur isEditing tableView menjadi true hanya jika ada bagian multivalued dalam formulir. Ini akan dilakukan di viewWillAppear pertama kali formulir disajikan.
Untuk informasi lebih lanjut tentang cara menggunakan bagian multivalued, silakan lihat Proyek Contoh Eureka yang berisi beberapa contoh penggunaan.
Jika Anda ingin menggunakan tombol Tambah yang bukan ButtonRow , maka Anda dapat menggunakan GenericMultivaluedSection<AddButtonType> , di mana AddButtonType adalah jenis baris yang ingin Anda gunakan sebagai tombol tambah. Ini berguna jika Anda ingin menggunakan baris khusus untuk mengubah UI tombol.
Contoh:
GenericMultivaluedSection < LabelRow > ( multivaluedOptions : [ . Reorder , . Insert , . Delete ] , {
$0 . addButtonProvider = { section in
return LabelRow ( ) {
$0 . title = " A Label row as add button "
}
}
// ...
}Eureka 2.0.0 memperkenalkan fitur validasi bawaan yang banyak diminta.
Baris memiliki kumpulan Rules dan konfigurasi spesifik yang menentukan kapan aturan validasi harus dievaluasi.
Ada beberapa aturan yang disediakan secara default, tetapi Anda juga dapat membuat yang baru sendiri.
Aturan yang disediakan adalah:
Mari kita lihat cara mengatur aturan validasi.
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
}
} Seperti yang dapat Anda lihat di cuplikan kode sebelumnya, kami dapat mengatur aturan sebanyak yang kami inginkan berturut -turut dengan memanggil Row add(rule:) Fungsi.
Row juga menyediakan func remove(ruleWithIdentifier identifier: String) untuk menghapus aturan. Untuk menggunakannya, kita harus menetapkan ID ke aturan setelah membuatnya.
Terkadang kumpulan aturan yang ingin kami gunakan secara berturut -turut adalah sama yang ingin kami gunakan pada banyak baris lainnya. Dalam hal ini kita dapat mengatur semua aturan validasi menggunakan RuleSet yang merupakan kumpulan aturan validasi.
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 memungkinkan kami untuk menentukan kapan aturan validasi harus dievaluasi. Kita dapat melakukannya dengan mengatur properti ROW validationOptions , yang dapat memiliki nilai -nilai berikut:
.validatesOnChange - memvalidasi setiap kali nilai baris berubah..validatesOnBlur - (nilai default) memvalidasi tepat setelah sel mengundurkan diri dari responden pertama. Tidak berlaku untuk semua baris..validatesOnChangeAfterBlurred - memvalidasi setiap kali nilai baris berubah setelah mengundurkan diri dari responder pertama untuk pertama kalinya..validatesOnDemand - Kita harus memvalidasi baris atau formulir secara manual dengan memohon metode validate() . Jika Anda ingin memvalidasi seluruh formulir (semua baris), Anda dapat secara manual memohon metode validate() .
Setiap baris memiliki properti validationErrors yang dapat digunakan untuk mengambil semua kesalahan validasi. Properti ini hanya memegang daftar kesalahan validasi dari eksekusi validasi baris terbaru, yang berarti tidak mengevaluasi aturan validasi baris.
Seperti yang diharapkan, aturan harus menggunakan tipe yang sama dengan objek baris. Berhati -hatilah untuk memeriksa jenis baris yang digunakan. Anda mungkin melihat kesalahan kompiler ("Label Arismment yang salah dalam panggilan (memiliki 'aturan:' yang diharapkan 'aturan:')" yang tidak menunjukkan masalah saat mencampur jenis.
Dengan menggunakan aksi swipe, kita dapat mendefinisikan beberapa leadingSwipe dan aksi trailingSwipe per baris. Karena tindakan gesek tergantung pada fitur sistem iOS, leadingSwipe tersedia hanya pada iOS 11.0+ saja.
Mari kita lihat bagaimana mendefinisikan tindakan gesek.
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
} Tindakan gesek membutuhkan tableView.isEditing diatur ke false . Eureka akan mengatur ini ke true jika ada bagian multivalued dalam bentuk (di viewWillAppear ). Jika Anda memiliki tindakan multivalued dan tindakan gesek dalam bentuk yang sama, Anda harus mengatur isEditing sesuai dengan kebutuhan Anda.
Sangat umum Anda membutuhkan barisan yang berbeda dari yang termasuk dalam Eureka. Jika ini masalahnya, Anda harus membuat baris Anda sendiri tetapi ini seharusnya tidak sulit. Anda dapat membaca tutorial ini tentang cara membuat baris khusus untuk memulai. Anda mungkin juga ingin melihat -lihat komunitas eureKac yang mencakup beberapa baris tambahan yang siap ditambahkan ke Eureka.
Untuk membuat baris dengan perilaku dan penampilan khusus, Anda mungkin ingin membuat subclass dari Row dan Cell .
Ingatlah bahwa Row adalah abstraksi yang digunakan Eureka, sedangkan Cell adalah UITableViewCell yang sebenarnya bertanggung jawab atas tampilan. Karena Row berisi Cell , Row dan Cell harus ditentukan untuk tipe nilai yang sama.
// 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 " )
}
} Hasilnya: 
Sama seperti Callbacks CellSetup dan CellUpdate, Cell memiliki metode pengaturan dan perbarui di mana Anda dapat menyesuaikannya.
Baris inline adalah jenis baris tertentu yang menunjukkan secara dinamis baris di bawahnya, biasanya baris inline berubah antara mode yang diperluas dan runtuh setiap kali baris disadap.
Jadi untuk membuat baris sebaris kita membutuhkan 2 baris, baris yang "selalu" terlihat dan baris yang akan mengembang/runtuh.
Persyaratan lain adalah jenis nilai dari 2 baris ini harus sama. Ini berarti jika satu baris memegang nilai String maka yang lain harus memiliki nilai String juga.
Setelah kami memiliki 2 baris ini, kami harus membuat tipe baris atas sesuai dengan InlineRowType . Protokol ini mengharuskan Anda untuk mendefinisikan Typealias InlineRow dan fungsi setupInlineRow . Jenis InlineRow akan menjadi jenis baris yang akan berkembang/runtuh. Ambil ini sebagai contoh:
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 juga akan menambahkan beberapa metode ke baris inline Anda:
func expandInlineRow ( )
func collapseInlineRow ( )
func toggleInlineRow ( ) Metode -metode ini harus bekerja dengan baik tetapi jika Anda ingin mengesampingkannya, perlu diingat bahwa toggleInlineRow yang harus memanggil expandInlineRow dan collapseInlineRow .
Akhirnya Anda harus memohon toggleInlineRow() saat baris dipilih, misalnya mengesampingkan customDidSelect :
public override func customDidSelect ( ) {
super . customDidSelect ( )
if !isDisabled {
toggleInlineRow ( )
}
}Catatan: Baris presenter adalah baris yang menyajikan UIViewController baru.
Untuk membuat baris presenter kustom, Anda harus membuat kelas yang menyesuaikan protokol PresenterRowType . Sangat disarankan untuk SelectorRow subkelas karena itu sesuai dengan protokol itu dan menambahkan fungsionalitas lain yang berguna.
Protokol PresenterRowType didefinisikan sebagai berikut:
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 akan dipanggil ketika baris akan menghadirkan pengontrol tampilan lain. Ini dilakukan di SelectorRow jadi jika Anda tidak menagihnya, Anda harus menyebutnya sendiri.
presentationMode adalah apa yang mendefinisikan bagaimana pengontrol disajikan dan pengontrol mana yang disajikan. Presentasi ini dapat menggunakan pengidentifikasi segue, kelas segue, menghadirkan pengontrol secara modal atau mendorong ke pengontrol tampilan tertentu. Misalnya CustomPushrow dapat didefinisikan seperti ini:
Mari kita lihat contoh ..
/// 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 )
} )
}
}Terkadang kami ingin mengubah tampilan UI dari salah satu baris kami tetapi tanpa mengubah jenis baris dan semua logika yang terkait dengan satu baris. Saat ini ada salah satu cara untuk melakukan ini jika Anda menggunakan sel yang dipakai dari file nib . Saat ini, tidak ada baris inti Eureka yang dipakai dari file nib tetapi beberapa baris khusus dalam komunitas eureKac, khususnya postaladdressrow yang dipindahkan ke sana.
Yang harus Anda lakukan adalah:
cellProvider untuk menggunakan nib ini. Anda harus melakukan ini di Initialiser, baik di setiap instantiasi konkret atau menggunakan defaultRowInitializer . Misalnya: <<< PostalAddressRow ( ) {
$0 . cellProvider = CellProvider < PostalAddressCell > ( nibName : " CustomNib " , bundle : Bundle . main )
}Anda juga dapat membuat baris baru untuk ini. Dalam hal ini cobalah untuk mewarisi dari superclass yang sama dengan baris yang ingin Anda ubah untuk mewarisi logikanya.
Ada beberapa hal yang perlu dipertimbangkan saat Anda melakukan ini:
Unknown class <YOUR_CLASS_NAME> in Interface Builder file , mungkin Anda harus membuat instantiasi jenis baru di suatu tempat dalam kode Anda untuk memuatnya di runtime. Memanggil let t = YourClass.self membantu dalam kasus saya. Baris label![]() | Baris tombol![]() | Periksa baris ![]() |
Beralih baris![]() | Slider Row![]() | Baris stepper ![]() |
Baris Area Teks ![]() |
Baris -baris ini memiliki lapangan teks di sisi kanan sel. Perbedaan antara masing -masing dari mereka terdiri dari kapitalisasi yang berbeda, koreksi autokoreksi dan tipe keyboard.
![]() | Textrow Namerow Urlrow Introw Phonerow Kata sandi Emailrow Desimalrow Twitterrow Accountrow Zipcoderow |
Semua subtipe FieldRow di atas memiliki properti formatter tipe NSFormatter yang dapat diatur untuk menentukan bagaimana nilai baris itu harus ditampilkan. Formatter khusus untuk angka dengan dua digit setelah tanda desimal disertakan dengan eureka ( DecimalFormatter ). Contoh proyek juga berisi CurrencyFormatter yang menampilkan angka sebagai mata uang sesuai dengan lokal pengguna.
Secara default, mengatur formatter baris hanya mempengaruhi bagaimana nilai ditampilkan saat tidak diedit. Untuk juga memformat nilai saat baris sedang diedit, atur useFormatterDuringInput ke true saat menginisialisasi baris. Memformat nilai karena sedang diedit mungkin memerlukan memperbarui posisi kursor dan eureka memberikan protokol berikut yang harus sesuai dengan formatter Anda untuk menangani posisi kursor:
public protocol FormatterProtocol {
func getNewPosition ( forPosition forPosition : UITextPosition , inTextInput textInput : UITextInput , oldValue : String ? , newValue : String ? ) -> UITextPosition
} Selain itu, subtipe FieldRow memiliki properti useFormatterOnDidBeginEditing . Saat menggunakan DecimalRow dengan formatter yang memungkinkan nilai desimal dan sesuai dengan lokal pengguna (misalnya DecimalFormatter ), jika useFormatterDuringInput false , useFormatterOnDidBeginEditing harus diatur ke true sehingga tanda desimal dalam nilai yang diedit cocok dengan tanda desimal pada keyboard.
Tanggal baris tahan tanggal dan memungkinkan kami untuk mengatur nilai baru melalui kontrol uateDPicker. Mode uidatePicker dan cara bagaimana tampilan pemetik tanggal ditampilkan adalah apa yang berubah di antara mereka.
Baris Tanggal ![]() Picker ditampilkan di keyboard. | Tanggal baris (inline) ![]() Baris mengembang. | Baris Tanggal (Pemilih) ![]() Pemilih selalu terlihat. |
Dengan 3 gaya (normal, inline & picker), Eureka mencakup:
Ini adalah baris dengan daftar opsi yang terkait dari mana pengguna harus memilih.
<<< ActionSheetRow < String > ( ) {
$0 . title = " ActionSheetRow "
$0 . selectorTitle = " Pick a number "
$0 . options = [ " One " , " Two " , " Three " ]
$0 . value = " Two " // initially selected
} Baris Peringatan![]() Akan menunjukkan peringatan dengan opsi untuk dipilih. | Tindakan ActionSheet![]() Akan menampilkan lembar tindakan dengan opsi untuk dipilih. | Dorong baris![]() Akan mendorong ke pengontrol baru dari tempat memilih opsi yang tercantum menggunakan check rows. | Beberapa baris pemilih![]() Seperti Pushrow tetapi memungkinkan pemilihan beberapa opsi. |
Baris tersegmentasi![]() | Baris tersegmentasi (w/judul)![]() | Baris pemilih![]() Menyajikan opsi jenis generik melalui tampilan pemetik (Ada juga baris inline Picker) |
Beri tahu kami tentang itu, kami akan senang menyebutkannya di sini. :)

Cocoapods adalah manajer ketergantungan untuk proyek kakao.
Tentukan eureka ke dalam Podfile proyek Anda:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios , '9.0'
use_frameworks!
pod 'Eureka'Kemudian jalankan perintah berikut:
$ pod installSwift Package Manager adalah alat untuk mengelola distribusi kode Swift.
Setelah Anda mengatur file manifes Package.swift Anda, Anda dapat menambahkan Eureka sebagai ketergantungan dengan menambahkannya ke nilai dependensi Package.swift Anda.
Ketergantungan: [.package (url: "https://github.com/xmartlabs/eureka.git", dari: "5.5.0")]
Carthage adalah manajer ketergantungan sederhana dan terdesentralisasi untuk kakao.
Tentukan eureka ke dalam Cartfile proyek Anda:
github "xmartlabs/Eureka" ~> 5.5
$ git submodule add https://github.com/xmartlabs/Eureka.gitBuka folder eureka yang dibuat oleh perintah submodule git sebelumnya dan seret eureka.xcodeproj ke navigator proyek proyek XCODE aplikasi Anda.
Pilih eureka.xcodeproj di proyek navigator dan verifikasi kecocokan target penyebaran dengan target penyebaran aplikasi Anda.
Pilih proyek Anda di navigasi XCode dan kemudian pilih target aplikasi Anda dari bilah samping. Selanjutnya pilih tab "Umum" dan klik tombol + di bawah bagian "Binari Tertanam".
Pilih Eureka.framework dan kami selesai!
eureka-forms ).Sebelum berkontribusi, periksa file yang berkontribusi untuk info lebih lanjut.
Jika Anda menggunakan Eureka di aplikasi Anda, kami ingin mendengarnya! Kirimkan kami antrean di Twitter.
Setiap baris memiliki properti berikut:
/// 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 ) }
} Anda dapat mengatur displayValueFor sesuai dengan nilai string yang ingin Anda tampilkan.
Kita bisa mendapatkan baris tertentu dengan memohon salah satu fungsi berikut yang diekspos oleh kelas Form :
public func rowBy < T : Equatable > ( tag : String ) -> RowOf < T > ?
public func rowBy < Row : RowType > ( tag : String ) -> Row ?
public func rowBy ( tag : String ) -> BaseRow ?Misalnya:
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 " ) Memanggil setValues(values: [String: Any?]) Mana yang diekspos oleh kelas Form .
Misalnya:
form . setValues ( [ " IntRowTag " : 8 , " TextRowTag " : " Hello world! " , " PushRowTag " : Company ( name : " Xmartlabs " ) ] ) Di mana "IntRowTag" , "TextRowTag" , "PushRowTag" adalah tag baris (masing -masing secara unik mengidentifikasi barisan) dan 8 , "Hello world!" , Company(name:"Xmartlabs") adalah nilai baris yang sesuai untuk ditetapkan.
Jenis nilai suatu baris harus cocok dengan jenis nilai dari nilai kamus yang sesuai jika tidak, nol akan ditetapkan.
Jika formulir sudah ditampilkan, kami harus memuat ulang baris yang terlihat baik dengan memuat ulang tabel tampilan tableView.reloadData() atau memohon updateCell() ke setiap baris yang terlihat.
Setelah menetapkan suatu kondisi, kondisi ini tidak dievaluasi secara otomatis. Jika Anda ingin melakukannya segera, Anda dapat menelepon .evaluateHidden() atau .evaluateDisabled() .
Fungsi ini baru saja dipanggil ketika baris ditambahkan ke formulir dan ketika baris itu tergantung pada perubahan. Jika kondisi diubah ketika baris ditampilkan maka harus dievaluasi kembali secara manual.
Lihatlah masalah ini.
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 , properti selectableRowCellUpdate dan selectableRowCellSetup disediakan untuk dapat menyesuaikan sel yang dapat dipilih selectorview controller dan MultipleselectorViewController.
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!
}
} Seperti yang telah kami katakan, jenis Form dan Section sesuai dengan MutableCollection dan RangeReplaceableCollection . Formulir adalah kumpulan bagian dan bagian adalah kumpulan baris.
Ekstensi Protokol RangeReplaceableCollection menyediakan banyak metode yang berguna untuk memodifikasi pengumpulan.
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 )
}Metode -metode ini digunakan secara internal untuk mengimplementasikan operator khusus seperti yang ditunjukkan di bawah:
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 )
}Anda dapat melihat bagaimana operator khusus lainnya diimplementasikan di sini.
Terserah Anda untuk memutuskan apakah Anda ingin menggunakan operator khusus Eureka atau tidak.
Formulir selalu ditampilkan di UITableView . Anda dapat mengatur pengontrol tampilan di storyboard dan menambahkan uItableView di mana Anda menginginkannya dan kemudian menghubungkan outlet ke variabel tableView FormViewController. Ini memungkinkan Anda untuk menentukan bingkai khusus (mungkin dengan kendala) untuk formulir Anda.
Semua ini juga dapat dilakukan dengan mengubah bingkai yang berubah secara terprogram, margin, dll. Dari tableView dari FormViewController Anda.
Jadi kita bisa membuat Eureka lebih baik! 
Ini dapat ditemukan di file changelog.md.