Реализация различных типов ячеек - PullRequest
0 голосов
/ 05 мая 2018

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

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

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

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

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
    }
}

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

1 Ответ

0 голосов
/ 05 мая 2018

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

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)
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...