Aplikasi seluler tidak selalu sederhana dan ringkas, karena kami pengembang menyukainya. Aplikasi lain dibuat untuk memecahkan masalah pengguna yang kompleks dan mengandung banyak layar dan skrip. Misalnya, aplikasi untuk melakukan tes, kuesioner, dan survei - di mana pun Anda perlu mengisi banyak formulir dalam proses. Aplikasi ini akan dibahas dalam artikel ini.

Kami mulai mengembangkan aplikasi mobile untuk agen yang terlibat dalam pendaftaran polis asuransi di tempat. Mereka mengisi formulir besar dalam aplikasi dengan data pelanggan: informasi tentang mobil, pemilik, pengemudi, dll. Meskipun setiap formulir memiliki bagian, sel, dan strukturnya sendiri, dan setiap item kuesioner membutuhkan tipe data unik (string, tanggal, dokumen terlampir), bentuk layarnya cukup mirip. Tapi yang utama adalah jumlah mereka ... Tidak ada yang ingin terlibat dalam pengulangan visualisasi dan pemrosesan elemen yang sama berkali-kali.
Untuk menghindari berjam-jam pekerjaan manual membuat formulir, Anda perlu menerapkan sedikit kecerdikan dan banyak konstruksi UI yang dinamis. Dalam artikel ini, kami ingin membagikan bagaimana kami memecahkan masalah ini.
Untuk solusi elegan untuk masalah ini, kami menggunakan mekanisme untuk menghasilkan objek - ViewModels, yang digunakan untuk membangun formulir kustom menggunakan tabel.

Dalam pekerjaan normal, untuk setiap tabel individual yang ingin dilihat pengembang di layar, kelas ViewModel yang terpisah harus dibuat. Ini mendefinisikan komponen visual dari tabel. Kami memutuskan untuk naik satu tingkat lebih tinggi dan menghasilkan ViewModels dan Model sendiri secara dinamis, menggunakan deskripsi sederhana dari struktur melalui bidang Enum.
Bagaimana cara kerjanya
Semuanya dimulai dengan enum. Untuk setiap profil kami membuat enum unik - ini adalah bagian dari profil kami. Salah satu metodenya adalah mengembalikan array sel di bagian ini.
Sel-sel dalam tabel juga akan enum dengan fungsi tambahan yang akan menjelaskan sifat-sifat sel. Dalam fungsi seperti itu, kami menetapkan nama sel, nilai awal. Kemudian ditambahkan parameter seperti
- periksa tampilan: beberapa sel harus disembunyikan,
- daftar sel "induk": sel yang bergantung pada nilai, validasi, atau tampilan sel ini,
- tipe sel: sel-sel sederhana dengan nilai-nilai, sel-sel dalam saklar, sel-sel dengan fungsi menambahkan elemen, dll.
Kami berlangganan semua bagian ke protokol QuestionnaireSectionCellType umum untuk mengecualikan pengikatan ke bagian tertentu, kami akan melakukan hal yang sama dengan semua sel tabel (QuestionnaireCellType).
protocol QuestionnaireSectionCellType { var title: String { get } var sectionCellTypes: [QuestionnaireCellType] { get } } protocol QuestionnaireCellType { var title: String { get } var initialValue: Any? { get } var isHidden: Bool { get } var parentFields: [QuestionnaireCellType] { get } … }
Model seperti itu akan sangat mudah diisi. Kami cukup menjalankan semua bagian, di setiap bagian kami menjalankan melalui array sel dan menambahkannya ke model array.
Pada contoh layar pemegang polis (enum with section - InsurantSectionType):
final class InsurantModel: BaseModel<QuestionnaireCellType> { override init() { super.init() initParameters() } private func initParameters() { InsurantSectionType.allCases.forEach { type in type.sectionCellTypes.forEach { if let valueModel = ValueModel(type: $0, parentFields: $0.parentFields, value: $0.initialValue) { valueModels.append(valueModel) } } } } }
Selesai! Sekarang kita memiliki tabel dengan nilai awal. Tambahkan metode untuk membaca nilai dengan kunci QuestionnaireCellType dan menyimpannya ke elemen array yang diinginkan.
Beberapa model mungkin memiliki bidang opsional, jadi kami menambahkan array dengan tombol opsional. Selama validasi model, kunci-kunci ini mungkin tidak mengandung nilai, tetapi model itu akan dianggap diisi.
Lebih lanjut, untuk kenyamanan, semua nilai dalam ValueModel kami berlangganan protokol StringRepresentable protokol umum untuk membatasi daftar nilai yang mungkin dan menambahkan metode untuk menampilkan nilai dalam sel.
protocol StringRepresentable { var stringValue: String? { get } }
Fungsionalitas tumbuh, dan banyak properti dan metode lain muncul dalam model: membersihkan model (nilai awal harus ditetapkan dalam beberapa model), dukungan untuk array nilai dinamis (nilai: Array), dll.
Pendekatan ini ternyata sangat nyaman untuk menyimpan dalam database menggunakan Realm. Untuk mengisi kuesioner, dimungkinkan untuk memilih model yang sudah disimpan sebelumnya. Untuk memperpanjang kebijakan CTP, agen tidak perlu lagi mengisi dokumen pengguna, driver yang dilampirkan olehnya, dan data TCP untuk yang baru. Sebagai gantinya, Anda dapat menggunakannya kembali untuk mengisi yang sudah ada.
Untuk mengubah atau menambah tabel, Anda hanya perlu menemukan ViewModel yang terkait dengan layar tertentu, menemukan enum yang diperlukan yang bertanggung jawab untuk menampilkan blok yang diinginkan dan menambahkan atau memperbaiki beberapa kasus. Semuanya, tabel akan mengambil bentuk yang diperlukan!
Mengisi formulir dengan nilai tes juga sangat mudah dan cepat. Dengan cara ini Anda dapat dengan cepat menghasilkan data uji apa pun. Dan jika Anda menambahkan file terpisah dengan data awal, dari mana program akan mengambil nilai ke setiap bidang spesifik dari kuesioner, maka bahkan seorang pemula dapat menghasilkan kuesioner yang sudah jadi tanpa pergi ke dan membongkar sisa kode, kecuali untuk file tertentu.
Ketergantungan
Tugas terpisah yang kami selesaikan selama proses pengembangan adalah penanganan ketergantungan. Beberapa elemen kuesioner saling berhubungan. Jadi, nomor dokumen tidak dapat diisi tanpa memilih jenis dokumen ini sendiri, nomor rumah tidak dapat ditunjukkan tanpa menunjukkan kota dan jalan, dll.

Kami membuat pembaruan nilai-nilai kuesioner dengan membersihkan semua bidang dependen (misalnya, menghapus atau mengubah jenis dokumen, kami menghapus bidang "nomor dokumen"):
func updateValueModel(value: StringRepresentable?, for type: QuestionnaireCellType) { guard let model = valueModels.first(where: { $0.type.equal(to: type) }) else { return } model.value = value clearRelativeValues(type: type) } func clearRelativeValues(type: QuestionnaireCellType) { _ = valueModels.filter { $0.parentFields.contains(where: { $0.equal(to: type) }) } .compactMap { $0.type } .compactMap { updateValueModel(value: nil, for: $0) } }
Perangkap yang harus kami pecahkan selama pengembangan, dan bagaimana kami mengelola
Jelas bahwa metode ini nyaman untuk layar dengan fungsi yang sama (mengisi kolom), tetapi tidak begitu nyaman jika elemen atau fungsi unik muncul di satu layar terpisah yang tidak ada di layar lain. Dalam aplikasi kami, ini adalah:
- Layar dengan tenaga mesin, yang harus dihasilkan secara terpisah, itulah sebabnya mengapa fungsinya berbeda. Pada layar ini, permintaan akan hilang dan nilai dari server secara otomatis diganti. Saya harus secara terpisah membuat kelas untuk itu yang akan bertanggung jawab untuk menampilkan, memuat, memvalidasi, memuat dari server dan mengganti nilai dalam bidang kosong, tanpa mengganggu pengguna jika yang terakhir memutuskan untuk memasukkan nilainya sendiri.
- Layar nomor registrasi, di mana satu-satunya adalah sakelar, yang memengaruhi tampilan atau menyembunyikan bidang teks. Untuk kasus ini, kondisi tambahan harus dibuat, yang secara terprogram akan menentukan kasus dengan posisi sakelar aktif sebagai nilai kosong.
- Daftar dinamis, seperti daftar driver yang harus disimpan dan diikat ke formulir, yang juga keluar dari konsep.
- Jenis validasi data yang unik. Bisa jadi banyak topeng yang dicampur dengan regex'ami. Dan validasi tanggal untuk berbagai bidang, di mana validasi berbeda secara dramatis (pembatasan nilai minimum / maksimum), dll.
- Layar entri data dibuat sebagai sel collectionView. (Itu diperlukan oleh desain!) Karena itu, menampilkan modal windows memerlukan kontrol yang tepat atas indeks yang dipilih. Saya harus memeriksa bidang yang tersedia untuk diisi, dan mengecualikan dari daftar yang tidak boleh dilihat pengguna.
- Untuk menampilkan data dalam tabel dengan benar, perlu dilakukan perubahan pada metode model beberapa layar. Sel-sel seperti nama dan alamat ditampilkan dalam tabel sebagai elemen tunggal, tetapi membutuhkan beberapa layar pop-up untuk diisi penuh.
Kesimpulan
Pengalaman ini memungkinkan kami di True Engineering dengan cepat mengimplementasikan aplikasi seluler yang mudah dirawat. Keserbagunaan memungkinkan Anda untuk secara cepat menghasilkan tabel dengan berbagai jenis data input: kami membuat 20 jendela hanya dalam seminggu. Pendekatan ini juga mempercepat proses pengujian aplikasi. Dalam waktu dekat, kami akan menggunakan kembali pabrik yang sudah jadi untuk dengan cepat menghasilkan tabel baru dan fungsionalitas baru.