[英][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.