Реализация различных типов ячеек

Мне нужна помощь в выяснении того, как я могу предоставить каждой строке UITableView настраиваемую ячейку, т.е. первая ячейка имеет заголовок «Имя», вторая ячейка - заголовок «Электронная почта» и т. д.

Как я могу добиться этого, используя протоколы и одновременно следуя MVVM?

Мое текущее решение выглядит следующим образом:

У меня есть 1 ViewModel, 1 контроллер и 1 атм UITableViewCell.

struct ProfileNameViewModel
{

}

extension ProfileNameViewModel: TextPresentable
{
    var text: String
    {
        return "Name"
    }
}


import UIKit

class ProfileController: UIViewController
{
    // VARIABLES
    let profileView = ProfileView()
    let profileTableView: UITableView =
    {
        let tableView = UITableView()
        tableView.tableFooterView = UIView(frame: .zero)
        tableView.translatesAutoresizingMaskIntoConstraints = false

        return tableView
    }()

    private var profileCellViewControllers = [UIViewController]()
    let testVC = UIViewController()

    // FUNCTIONS
    override func viewDidLoad()
    {
        super.viewDidLoad()

        view.backgroundColor = UIColor.white

        navigationItem.title = "Profile"

        // profileTableView initialization
        setupProfileTableView()
    }

    private func setupProfileTableView()
    {
        profileTableView.delegate = self
        profileTableView.dataSource = self

        profileTableView.register(ProfileTableViewCell<ProfileNameViewModel>.self, forCellReuseIdentifier: ProfileTableViewCell<ProfileNameViewModel>.reuseIdentifier)

        view.addSubview(profileTableView)

        profileTableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
        profileTableView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
        profileTableView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
        profileTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
    }

    private func setupProfileViewLayout()
    {
        profileView.setupAnchors(top: view.safeAreaLayoutGuide.topAnchor,
                                 bottom: view.safeAreaLayoutGuide.bottomAnchor,
                                 left: view.leftAnchor,
                                 right: view.rightAnchor)
    }
}

extension ProfileController: UITableViewDataSource, UITableViewDelegate
{
    // Table view header setup
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
    {
        if (section == 0)
        {
            return "Profile"
        }

        return "Foo"
    }

    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
    {
        return 50
    }

    // Table view sections setup
    func numberOfSections(in tableView: UITableView) -> Int
    {
        return 2
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        if (section == 1)
        {
            return 3
        }

        return 5
    }

    // Table view cell setup
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        let cell = tableView.dequeueReusableCell(withIdentifier: ProfileTableViewCell<ProfileNameViewModel>.reuseIdentifier, for: indexPath) as! ProfileTableViewCell<ProfileNameViewModel>

        let viewModel = ProfileNameViewModel()
        cell.configure(withDelegate: viewModel)

        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            print(indexPath.row)
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
    {
        return 50
    }
}


import UIKit

class ProfileTableViewCell<T>: UITableViewCell where T: TextPresentable
{

    // VARIABLES
    let containerView = UIView()
    var arrowImageView = UIImageView()
    var cellTitle: UILabel!
    var userInformationText: UILabel!

    private var delegate: T?

    // FUNCTIONS
    func configure(withDelegate viewModel: T)
    {
        // Setup relavant views
        cellTitle = UILabel()
        userInformationText = UILabel()
        arrowImageView = setupImageView(imageName: "testImage", contentMode: .scaleAspectFit, imageTintColor: .black)
        setupContainer()

        delegate = viewModel

        cellTitle?.text = viewModel.text
        cellTitle.font = viewModel.textFont
        cellTitle.textColor = viewModel.textColor

        userInformationText.text = "Test"
    }

    private func setupContainer()
    {
        addSubview(containerView)
        containerView.addSubview(cellTitle)
        containerView.addSubview(userInformationText)
        containerView.addSubview(arrowImageView)

        // Container view for each cell
        containerView.setupAnchors(top: topAnchor,
                               bottom: bottomAnchor,
                               left: leftAnchor,
                               right: rightAnchor,
                               padding: .init(top: 3, left: 0, bottom: 3, right: 0))

        // Views inside the container view
        cellTitle.setupAnchors(top: nil,
                           bottom: containerView.bottomAnchor,
                           left: containerView.leftAnchor,
                           right: nil,
                           padding: .init(top: 0, left: 15, bottom: 7, right: 0))

        arrowImageView.setupAnchors(top: nil,
                                bottom: containerView.bottomAnchor,
                                left: nil,
                                right: containerView.rightAnchor,
                                padding: .init(top: 0, left: 0, bottom: 13, right: 5),
                                size: .init(width: 10, height: 10))

        userInformationText.setupAnchors(top: nil,
                                     bottom: containerView.bottomAnchor,
                                     left: nil,
                                     right: arrowImageView.leftAnchor,
                                     padding: .init(top: 0, left: 0, bottom: 7, right: 10))
    }

    private func setupImageView(imageName: String, contentMode: UIViewContentMode, imageTintColor: UIColor) -> UIImageView
    {
        let arrowImage: UIImage = UIImage(named: imageName)!
        let arrowImageView: UIImageView = UIImageView(image: arrowImage)
        arrowImageView.contentMode = contentMode
        arrowImageView.imageTintColor(color: imageTintColor)

        return arrowImageView
    }
}

Я пытался следовать примеру, предоставленному ссылкой это, чтобы реализовать правильное решение, однако добавляется только одна ячейка, и я не могу понять, как реализовать вторую ячейку в следующих строках. Должен ли я создать новую модель представления для каждой отдельной ячейки, которую я хотел бы использовать? Если это так, не могли бы вы привести пример?

Могу я порекомендовать вам отредактировать код для более ясного примера? Отсутствуют части, из-за которых ваш код не компилируется и, в то же время, не имеет отношения к вопросу. Сведите все к чему-то более простому, что компилирует.

Eppilo 05.05.2018 22:29

Конечно, я могу это сделать. Дайте мне немного времени, и я отредактирую код до рабочего примера.

atiesh 06.05.2018 09:04

Круто Я правда думаю, что вы задаете важный вопрос. Проблема, с которой вы сталкиваетесь, является повторяющейся в сообществе iOS, и можно создавать представления таблиц, которые принимают общие ячейки, выразительно соединенные вместе. Если вы видите мой ответ, есть пример, который предлагает способ сделать это. И это не проблема, связанная строго с MVVM как архитектурой, это более общая проблема.

Eppilo 06.05.2018 23:24
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
74
1

Ответы 1

Попробуйте использовать «коробку», чтобы содержать код генерации вашей ячейки. Не регистрируйте идентификатор ячейки до того, как ячейка понадобится. Придумать рабочий пример немного сложно, поэтому возьмите в качестве примера следующий код:

import UIKit

protocol CellBox {

    func getCell(for tableView: UITableView) -> UITableViewCell
}

struct MyCellBox: CellBox {

    private let id = "my_cell_id"

    func getCell(for tableView: UITableView) -> UITableViewCell {
        if let cell = tableView.dequeueReusableCell(withIdentifier: id) {
            return cell
        } else {
            return UITableViewCell(style: .default, reuseIdentifier: id)
        }
    }
}

class MyDataSource: NSObject, UITableViewDataSource {

    var boxes: [CellBox] = []
    // This is just a hack for compiling...
    // ...the idea is that you need to have a reference to your real table view somewhere
    let tableView = UITableView()

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return boxes.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        return boxes[indexPath.row].getCell(for: tableView)
    }
}

Я действительно рекомендую вам сократить вопрос до более управляемого примера, однако в качестве улучшения вышеупомянутого MyCellBox есть шанс, что это близко к тому, что вы хотите:

struct MyCellBox: CellBox {

    private let id = "my_cell_id"

    func getCell(for tableView: UITableView) -> UITableViewCell {
        if let cell = tableView.dequeueReusableCell(withIdentifier: id) {
            return cell
        } else {
            let viewModel = MyViewModel(text: "WOW", font: UIFont(name: "Whatever", size: 10)!, color: UIColor.black)
            let cell = ProfileTableViewCell<MyViewModel>()
            cell.configure(withDelegate: viewModel)
            return UITableViewCell(style: .default, reuseIdentifier: id)
        }
    }
}

Другие вопросы по теме