簡體   English   中英

[以編程方式]選擇嵌入在 collectionView 單元格中的 tableView 行時推送 viewController

[英][Programmatically]Push a viewController when selecting tableView row embedded in a collectionView cell

當用戶單擊 tableView 單元格時,我想推送一個視圖 controller 顯示用戶任務的詳細視圖。 我嘗試使用彈出視圖,因為我不知道如何從 collectionView 單元中推送 viewController,但我無法將 didselect 連接到 MyTasksDetailController 布局視圖。 這是我的代碼:

MyTasksCollectionCell

class MyTasksCollectionCell: UICollectionViewCell, UITableViewDelegate, UITableViewDataSource {

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
                 tableView.deselectRow(at: indexPath, animated: true)

    let detailView = MyTasksDetailController()
    UIApplication.shared.keyWindow?.addSubview(detailView)

// I want the detailViewController to show these two (descriptionTitleLabel + titleLabel)  
//          print("\(task.descriptionTitleLabel)") 
//          print("\(task.titleLabel)") 

}
extension UIApplication {
    
    var keyWindow: UIWindow? {
        // Get connected scenes
        return UIApplication.shared.connectedScenes
            // Keep only active scenes, onscreen and visible to the user
            .filter { $0.activationState == .foregroundActive }
            // Keep only the first `UIWindowScene`
            .first(where: { $0 is UIWindowScene })
            // Get its associated windows
            .flatMap({ $0 as? UIWindowScene })?.windows
            // Finally, keep only the key window
            .first(where: \.isKeyWindow)
    }
}

MyTasksDetailController

class MyTasksDetailController: UIView  {
    
    var setTitleLabel: String? {
        didSet {
            titleLabel.text = setTitleLabel ?? ""
        }
    }
    var setdescriptionTitleLabel: String? {
        didSet {
            descriptionTitleLabel.text = setdescriptionTitleLabel ?? ""
        }
    }
     let titleLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont.systemFont(ofSize: 28, weight: .bold)
        label.textAlignment = .center
        return label
    }()
    
     let descriptionTitleLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont.systemFont(ofSize: 18, weight: .bold)
        label.textAlignment = .center
        label.numberOfLines = 3
        return label
    }()
    
     let container: UIView = {
        let v = UIView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.clipsToBounds = true
        v.backgroundColor = .white
        v.backgroundColor =
            // 1
            UIColor { traitCollection in
              // 2
              switch traitCollection.userInterfaceStyle {
              case .dark:
                // 3
                 v.layer.borderColor = UIColor.label.cgColor
                return UIColor.systemBackground
                
              default:
                // 4
                 v.layer.borderColor = UIColor.black.cgColor
                return UIColor.systemBackground
              }
            }
        return v
    }()
    
     lazy var stack: UIStackView = {
        let stack = UIStackView(arrangedSubviews: [titleLabel, descriptionTitleLabel])
        stack.translatesAutoresizingMaskIntoConstraints = false
        stack.axis = .vertical
        return stack
    }()
    @objc func animateOut() {
        UIView.animate(withDuration: 0.7, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: .curveEaseOut, animations: {
            self.container.transform = CGAffineTransform(translationX: self.frame.height, y: 0)
            self.alpha = 0
        }) { (complete) in
            if complete {
                self.removeFromSuperview()
            }
        }
    }
    @objc func animateIn() {
        self.container.transform = CGAffineTransform(translationX: self.frame.height, y: 0)
        self.alpha = 1
        UIView.animate(withDuration: 0.7, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: .curveEaseOut, animations: {
            self.container.transform = .identity
            self.alpha = 1
        })
    }
    override init(frame: CGRect) {
        super.init(frame: frame)
         self.frame = UIScreen.main.bounds
        self.addSubview(container)

        self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(animateOut)))
        container.topAnchor.constraint(equalTo:  self.topAnchor, constant: 0).isActive = true
        container.bottomAnchor.constraint(equalTo:  self.bottomAnchor, constant: 0).isActive = true
        container.widthAnchor.constraint(equalTo: self.widthAnchor).isActive = true

         
        container.addSubview(stack)
        stack.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true
        stack.trailingAnchor.constraint(equalTo: container.trailingAnchor).isActive = true
        stack.centerYAnchor.constraint(equalTo: container.centerYAnchor).isActive = true
        stack.heightAnchor.constraint(equalTo: container.heightAnchor, multiplier: 0.5).isActive = true
        animateIn()
     }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

首先,如果你想展示你的MyTasksDetailController ,它必須是UIViewController ,而不是UIView

你可以這樣展示它(從你的主視圖控制器):

// instantiate MyTasksDetailController
let vc = MyTasksDetailController()
// set the title and description string properties
vc.titleString = "Some title"
vc.descriptionString = "Some description"
// present it
self.present(vc, animated: true, completion: nil)

要從集合視圖單元格中獲取選定的表格行,您可以使用closure

在您的集合視圖單元格 class 中,定義閉包:

var myClosure: ((MyTasksCollectionCell, Int) -> ())?

當你 select 在表格視圖中的一行時:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    // when a row is selected, use the
    //  Closure to inform the controller
    myClosure?(self, indexPath.row)
}

你的cellForItemAt函數看起來像這樣:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "myTasksCollectionCell", for: indexPath) as! MyTasksCollectionCell
    
    cell.label.text = myData[indexPath.item].title
    cell.tableData = myData[indexPath.item].tasks
    
    // set closure
    cell.myClosure = { [weak self] theCell, theRow in
        guard let self = self,
              let theIndexPath = self.collectionView.indexPath(for: theCell)
        else {
            return
        }
        // instantiate MyTasksDetailController
        let vc = MyTasksDetailController()
        // set the title and description string properties
        vc.titleString = self.myData[theIndexPath.item].title
        vc.descriptionString = self.myData[theIndexPath.item].tasks[theRow]
        // present it
        self.present(vc, animated: true, completion: nil)
    }
    return cell
}

這是一個完整的示例,您可以運行和使用...

您的詳細信息 controller 的修改版本

class MyTasksDetailController: UIViewController  {
    
    var titleString: String = ""
    var descriptionString: String = ""
    
    let titleLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont.systemFont(ofSize: 28, weight: .bold)
        label.textAlignment = .center
        label.backgroundColor = .green
        return label
    }()
    
    let descriptionTitleLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont.systemFont(ofSize: 18, weight: .bold)
        label.textAlignment = .center
        label.numberOfLines = 3
        label.backgroundColor = .cyan
        return label
    }()
    
    let container: UIView = {
        let v = UIView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.clipsToBounds = true
        v.backgroundColor = .white
        v.backgroundColor =
        // 1
        UIColor { traitCollection in
            // 2
            switch traitCollection.userInterfaceStyle {
            case .dark:
                // 3
                v.layer.borderColor = UIColor.label.cgColor
                return UIColor.systemBackground
                
            default:
                // 4
                v.layer.borderColor = UIColor.black.cgColor
                return UIColor.systemBackground
            }
        }
        return v
    }()
    
    lazy var stack: UIStackView = {
        let stack = UIStackView(arrangedSubviews: [titleLabel, descriptionTitleLabel])
        stack.translatesAutoresizingMaskIntoConstraints = false
        stack.axis = .vertical
        return stack
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        view.addSubview(container)
        
        view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(dismissMe)))
        
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            container.topAnchor.constraint(equalTo: g.topAnchor, constant: 0),
            container.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0),
            container.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0),
            container.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0),
        ])
        
        container.addSubview(stack)
        NSLayoutConstraint.activate([
            stack.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 0),
            stack.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: 0),
            stack.centerYAnchor.constraint(equalTo: container.centerYAnchor, constant: 0),
            stack.heightAnchor.constraint(equalTo: container.heightAnchor, multiplier: 0.5),
        ])

        titleLabel.text = titleString
        descriptionTitleLabel.text = descriptionString
    }
    
    @objc func dismissMe() {
        dismiss(animated: true, completion: nil)
    }
    
}

簡單的數據結構

struct MyTask {
    var title: String = ""
    var tasks: [String] = []
}

“主”視圖 controller (保存集合視圖):

class MyTasksViewController: UIViewController {
    
    var myData: [MyTask] = []
    
    let colors: [UIColor] = [
        .systemRed, .systemGreen, .systemBlue,
        .systemPink, .systemYellow, .systemTeal,
    ]
    
    var collectionView: UICollectionView!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        let tableStrings: [[String]] = [
            ["red", "green", "blue", "cyan", "magenta", "yellow"],
            ["one", "two", "three"],
            ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
            ["Bob", "Joe", "Steve", "Mary"],
            ["Car", "Boat", "Train", "Airplane", "Bicycle"],
        ]
        
        // fill myData array with some data
        for i in 0..<tableStrings.count {
            let mt: MyTask = MyTask(title: "Cell Title \(i)", tasks: tableStrings[i])
            myData.append(mt)
        }
        
        let cvl = UICollectionViewFlowLayout()
        cvl.itemSize = CGSize(width: 200, height: 240)
        cvl.minimumLineSpacing = 10
        cvl.minimumInteritemSpacing = 0
        cvl.scrollDirection = .horizontal
        
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: cvl)
        
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        
        view.addSubview(collectionView)
        
        let g = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            
            collectionView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            collectionView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
            collectionView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
            collectionView.heightAnchor.constraint(equalToConstant: 240.0),
            
        ])
        
        collectionView.dataSource = self
        collectionView.delegate = self
        
        collectionView.register(MyTasksCollectionCell.self, forCellWithReuseIdentifier: "myTasksCollectionCell")
        
    }
    
}

extension MyTasksViewController: UICollectionViewDataSource, UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return myData.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "myTasksCollectionCell", for: indexPath) as! MyTasksCollectionCell
        cell.contentView.backgroundColor = colors[indexPath.item % colors.count]
        
        cell.label.text = myData[indexPath.item].title
        cell.tableData = myData[indexPath.item].tasks
        
        // set closure
        cell.myClosure = { [weak self] theCell, theRow in
            guard let self = self,
                  let theIndexPath = self.collectionView.indexPath(for: theCell)
            else {
                return
            }
            // instantiate MyTasksDetailController
            let vc = MyTasksDetailController()
            // set the title and description string properties
            vc.titleString = self.myData[theIndexPath.item].title
            vc.descriptionString = self.myData[theIndexPath.item].tasks[theRow]
            // present it
            self.present(vc, animated: true, completion: nil)
        }
        return cell
    }
}

簡單表格視圖單元格

// simple table cell with a centered-text label
class MyTasksTableCell: UITableViewCell {
    let label: UILabel = {
        let v = UILabel()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.textAlignment = .center
        return v
    }()
    
    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 {
        contentView.addSubview(label)
        let g = contentView.layoutMarginsGuide
        NSLayoutConstraint.activate([
            label.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
            label.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
            label.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
            label.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
        ])
    }
}

帶有“頂部標簽”和 tableView 的集合視圖單元格

// collection view cell with
//  label at the top and
//  table view below the label
class MyTasksCollectionCell: UICollectionViewCell {
    
    // closure to tell the controller that a tableView row was selected
    var myClosure: ((MyTasksCollectionCell, Int) -> ())?
    
    var tableData: [String] = [] {
        didSet {
            tableView.reloadData()
        }
    }
    
    let label: UILabel = {
        let v = UILabel()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
        v.textAlignment = .center
        return v
    }()
    
    let tableView: UITableView = {
        let v = UITableView()
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        contentView.addSubview(label)
        contentView.addSubview(tableView)
        
        let g = contentView.layoutMarginsGuide
        NSLayoutConstraint.activate([
            label.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
            label.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
            label.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
            label.heightAnchor.constraint(equalToConstant: 30.0),
            
            tableView.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 0.0),
            tableView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
            tableView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
            tableView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
        ])
        
        tableView.separatorInset = .zero
        tableView.register(MyTasksTableCell.self, forCellReuseIdentifier: "myTasksTableCell")
        tableView.dataSource = self
        tableView.delegate = self
    }
}
extension MyTasksCollectionCell: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return tableData.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let c = tableView.dequeueReusableCell(withIdentifier: "myTasksTableCell", for: indexPath) as! MyTasksTableCell
        c.label.text = tableData[indexPath.row]
        return c
    }
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        // when a row is selected, use the
        //  Closure to inform the controller
        myClosure?(self, indexPath.row)
    }
}

這是它的樣子,集合視圖向右滾動了幾個單元格:

在此處輸入圖像描述

當我們 select 一行時我們得到什么:

在此處輸入圖像描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM