How to Implement UITextView inside UITableView inside UITableView Swift

前端 未结 2 1842
青春惊慌失措
青春惊慌失措 2021-01-29 04:10

how to implement UITextView inside UITableView inside UITableView ??

(1) If you type text in \'UITextView\', the height of \'UITableViewCell2\' is automatically

2条回答
  •  灰色年华
    2021-01-29 04:52

    You might want to give this a try...

    It using a single-section table view. Each cell contains a UIStackView that arranges the (variable) UITextViews.

    No @IBOutlet or @IBAction or prototype cell connections... just assign a standard UIViewController custom class to TableTextViewsViewController:

    //
    //  TableTextViewsViewController.swift
    //  Created by Don Mag on 3/10/20.
    //
    
    import UIKit
    
    class TextViewsCell: UITableViewCell, UITextViewDelegate {
    
        let frameView: UIView = {
            let v = UIView()
            v.backgroundColor = .clear
    
            v.layer.borderColor = UIColor(red: 0.0, green: 0.5, blue: 0.0, alpha: 1.0).cgColor
            v.layer.borderWidth = 1
    
            v.translatesAutoresizingMaskIntoConstraints = false
            return v
        }()
    
        let stackView: UIStackView = {
            let v = UIStackView()
            v.axis = .vertical
            v.spacing = 8
            v.translatesAutoresizingMaskIntoConstraints = false
            return v
        }()
    
        let stackViewPadding: CGFloat = 8.0
    
        var textViewCosure: ((Int, String)->())?
    
        override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            commonInit()
        }
    
        required init?(coder: NSCoder) {
            super.init(coder: coder)
            commonInit()
        }
    
        func commonInit() -> Void {
    
            let g = contentView.layoutMarginsGuide
    
            contentView.addSubview(frameView)
            frameView.addSubview(stackView)
    
            // bottom constraint needs to be less than 1000 (required) to avoid auot-layout warnings
            let frameViewBottomConstrait = frameView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0)
            frameViewBottomConstrait.priority = UILayoutPriority(rawValue: 999)
    
            NSLayoutConstraint.activate([
    
                frameView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
                frameView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
                frameView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
                frameViewBottomConstrait,
    
                stackView.topAnchor.constraint(equalTo: frameView.topAnchor, constant: stackViewPadding),
                stackView.leadingAnchor.constraint(equalTo: frameView.leadingAnchor, constant: stackViewPadding),
                stackView.trailingAnchor.constraint(equalTo: frameView.trailingAnchor, constant: -stackViewPadding),
                stackView.bottomAnchor.constraint(equalTo: frameView.bottomAnchor, constant: -stackViewPadding),
    
            ])
    
        }
    
        override func prepareForReuse() {
            super.prepareForReuse()
            stackView.arrangedSubviews.forEach {
                $0.removeFromSuperview()
            }
        }
    
        func fillData(_ strings: [String]) -> Void {
            strings.forEach {
                let v = UITextView()
    
                v.font = UIFont.systemFont(ofSize: 16.0)
                v.isScrollEnabled = false
    
                // hugging and compression resistance set to required for cell expansion animation
                v.setContentHuggingPriority(.required, for: .vertical)
                v.setContentCompressionResistancePriority(.required, for: .vertical)
    
                v.text = $0
    
                // frame the text view
                v.layer.borderColor = UIColor.blue.cgColor
                v.layer.borderWidth = 1
    
                v.delegate = self
                stackView.addArrangedSubview(v)
            }
        }
    
        func textViewDidChange(_ textView: UITextView) {
            guard let idx = stackView.arrangedSubviews.firstIndex(of: textView) else {
                fatalError("Shouldn't happen, but couldn't find the textView index")
            }
            textViewCosure?(idx, textView.text)
        }
    
    }
    
    class TableTextViewsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
        let topLabel: UILabel = {
            let v = UILabel()
            v.text = "Top Label"
            v.translatesAutoresizingMaskIntoConstraints = false
            return v
        }()
    
        let tableView: UITableView = {
            let v = UITableView()
    
            v.layer.borderColor = UIColor.red.cgColor
            v.layer.borderWidth = 1
    
            v.translatesAutoresizingMaskIntoConstraints = false
            return v
        }()
    
        var myData: [[String]] = [[String]]()
        var textViewsInRows: [Int] = [
            3, 4, 2, 6, 1, 4, 3,
        ]
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // generate some dummy data
            var i = 1
            textViewsInRows.forEach {
                var s: [String] = [String]()
                for j in 1...$0 {
                    s.append("Table Row: \(i) TextView \(j)")
                }
                myData.append(s)
                i += 1
            }
    
            view.addSubview(topLabel)
            view.addSubview(tableView)
    
            let g = view.safeAreaLayoutGuide
    
            NSLayoutConstraint.activate([
    
                topLabel.topAnchor.constraint(equalTo: g.topAnchor, constant: 8.0),
                topLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
                topLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
    
                tableView.topAnchor.constraint(equalTo: topLabel.bottomAnchor, constant: 8.0),
                tableView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
                tableView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
                tableView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -8.0),
    
            ])
    
            tableView.dataSource = self
            tableView.delegate = self
    
            tableView.separatorStyle = .none
            tableView.keyboardDismissMode = .onDrag
    
            tableView.register(TextViewsCell.self, forCellReuseIdentifier: "TextViewsCell")
    
        }
    
        // MARK: - Table view data source
    
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return myData.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "TextViewsCell", for: indexPath) as! TextViewsCell
    
            cell.fillData(myData[indexPath.row])
    
            cell.textViewCosure = { [weak self] idx, str in
                // update our data
                self?.myData[indexPath.row][idx] = str
                // update table view cell height
                self?.tableView.beginUpdates()
                self?.tableView.endUpdates()
            }
    
            return cell
        }
    
    }
    

    Result - red border is the tableView, green border is each cell's contentView, blue border is each textView:

提交回复
热议问题