简体   繁体   English

[以编程方式]选择嵌入在 collectionView 单元格中的 tableView 行时推送 viewController

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

When a user click on a tableView cell i want to push a view controller showing a detailed view of the user's task.当用户单击 tableView 单元格时,我想推送一个视图 controller 显示用户任务的详细视图。 I tried using a pop-up view because i don't know how to push a viewController from a collectionView cell but i can't connect the didselect to the MyTasksDetailController layout view.我尝试使用弹出视图,因为我不知道如何从 collectionView 单元中推送 viewController,但我无法将 didselect 连接到 MyTasksDetailController 布局视图。 Here's my code:这是我的代码:

MyTasksCollectionCell 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 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")
    }
}

First, if you want to present your MyTasksDetailController , it needs to be a UIViewController , not a UIView .首先,如果你想展示你的MyTasksDetailController ,它必须是UIViewController ,而不是UIView

You can present it like this (from your main view controller):你可以这样展示它(从你的主视图控制器):

// 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)

To get the selected table row from the collection view cell, you can use a closure .要从集合视图单元格中获取选定的表格行,您可以使用closure

In your collection view cell class, define the closure with:在您的集合视图单元格 class 中,定义闭包:

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

when you select a row in the table view:当你 select 在表格视图中的一行时:

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

and your cellForItemAt func looks like this:你的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
}

Here is a complete example you can run and play with...这是一个完整的示例,您可以运行和使用...

Modified version of your Detail controller您的详细信息 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)
    }
    
}

simple Data struct简单的数据结构

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

"main" view controller (holds the collection view): “主”视图 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 view 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),
        ])
    }
}

Collection View Cell with "top label" and tableView带有“顶部标签”和 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)
    }
}

And here's what it looks like, with collection view scrolled to the right a few cells:这是它的样子,集合视图向右滚动了几个单元格:

在此处输入图像描述

and what we get when we select a row:当我们 select 一行时我们得到什么:

在此处输入图像描述

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 以编程方式从CollectionView单元推送viewController不起作用 - swift - Push viewController from CollectionView cell programmatically not working - swift 当点击collectionView单元格内的按钮时,如何获取表格视图行并从位于tableViewCell内的collectionView推送到viewController - how to get table view row and push to viewController from collectionView that's inside a tableViewCell when tapped button inside collectionView cell 单击 tableView 单元格时如何推送新的 viewController? - How to push a new viewController when clicking on a tableView cell? 在 ViewController 中设置 TableView 和 collectionView - Set TableView and collectionView in ViewController 如何从xib tableview Cell推送ViewController? - how to push ViewController from xib tableview Cell? 如何将值从嵌入式collectionView中的选定单元格传递到另一个viewController? - How to pass value from a selected cell in embedded collectionView to another viewController? 以编程方式从collectionView Cell didSelectItemAt推送到新的ViewController-Swift - Pushing to new ViewController from collectionView Cell didSelectItemAt programmatically - swift 在tableView中滚动时,如何隐藏collectionView(知道此ViewCOntroller是tableview的一半,collectionview的一半) - How can I hide a collectionView when scrolling in my tableView (knowing that this ViewCOntroller is half tableview and half collectionview) 与Swift在同一ViewController中的TableView和CollectionView - TableView and CollectionView in the same ViewController with Swift 通过编程选择后在表视图中取消选择行 - Deselect row in tableview after programmatically selecting
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM