我有一個包含 UiCollectionView 的單元格的 tableView。當我觸摸 collectionView 上的單元格時,我的 didSelect tableView 的委托沒有被呼叫。我認為是我的 collectionView 得到了觸摸。您是否有任何優雅的解決方案來保持在我的 collectionView 上啟用滾動但禁用選擇并將其傳遞給 tableview ?
這是我的 tableView 宣告:
private lazy var tableView:UITableView = { [weak self] in
$0.register(TestTableViewCell.self, forCellReuseIdentifier: "identifier")
$0.delegate = self
$0.dataSource = self
return $0
}(UITableView())
這是我的委托和資料源方法:
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) as! TestTableViewCell
return cell
}
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
print(indexPath)
}
這是我的手機:
public class TestTableViewCell : UITableViewCell {
private lazy var collectionViewFlowLayout:UICollectionViewFlowLayout = {
$0.scrollDirection = .horizontal
$0.minimumLineSpacing = 0
$0.minimumInteritemSpacing = 0
return $0
}(UICollectionViewFlowLayout())
private lazy var collectionView:UICollectionView = {
$0.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "identifier")
$0.delegate = self
$0.dataSource = self
return $0
}(UICollectionView(frame: .zero, collectionViewLayout: collectionViewFlowLayout))
public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(collectionView)
collectionView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell:UICollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: cell:"identifier", for: indexPath) as! cell:UICollectionViewCell
return cell
}
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return collectionView.frame.size
}
}
如果您發現任何編譯錯誤,請原諒,這是匿名復制/過去。我的應用程式運行無誤。
如果您想了解我正在嘗試做的事情的示例,您可以查看 AirBnb 的應用程式。帶有單元格和內部圖片集合視圖的一些房屋的 TableView。如果你觸摸 collectionView,tableView 選擇單元格......
謝謝
uj5u.com熱心網友回復:
我不相信有一種“直接”的方式來做你所要求的。集合視圖將回應手勢,因此它們不能在不使用閉包或協議/委托模式的情況下“流經”到表視圖/單元格。
這是一種方法......
我們繼承UICollectionView并touchesBegan呼叫一個閉包來告訴表視圖選擇行。
scrollViewWillBeginDragging除了集合視圖“點擊”之外,我們還可以實作選擇集合視圖滾動上的行。
所以...
視圖控制器類
class TableColTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
// number of items in the collection view for each row
let myData: [Int] = [
12, 15, 8, 21, 17, 14,
16, 10, 5, 13, 20, 19,
]
let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: g.topAnchor, 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.register(SomeTableCell.self, forCellReuseIdentifier: "someTableCell")
tableView.dataSource = self
tableView.delegate = self
}
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: "someTableCell", for: indexPath) as! SomeTableCell
cell.rowTitleLabel.text = "Row \(indexPath.row)"
cell.numItems = myData[indexPath.row]
// closure for the cell to tell us to select it
// because its collection view was tapped
cell.passThroughSelect = { [weak self] theCell in
guard let self = self,
let pth = self.tableView.indexPath(for: theCell)
else { return }
self.tableView.selectRow(at: pth, animated: true, scrollPosition: .none)
// selecting a row programmatically does NOT trigger didSelectRowAt
// so we'll call our own did select func
self.myDidSelect(pth)
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// pass this on to our own did select func
// so it matches what happens when programmatically selecting the row
myDidSelect(indexPath)
}
func myDidSelect(_ indexPath: IndexPath) {
print("Table View - didSelectRowAt", indexPath)
// do something because the row was selected
}
}
表視圖單元格類
class SomeTableCell: UITableViewCell {
// callback closure
var passThroughSelect: ((UITableViewCell) -> ())?
var rowTitleLabel = UILabel()
var collectionView: SubCollectionView!
var numItems: Int = 0 {
didSet {
collectionView.reloadData()
}
}
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() {
let fl = UICollectionViewFlowLayout()
fl.scrollDirection = .horizontal
fl.estimatedItemSize = CGSize(width: 120.0, height: 52.0)
fl.minimumLineSpacing = 12
fl.minimumInteritemSpacing = 12
collectionView = SubCollectionView(frame: .zero, collectionViewLayout: fl)
rowTitleLabel.translatesAutoresizingMaskIntoConstraints = false
collectionView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(rowTitleLabel)
contentView.addSubview(collectionView)
let g = contentView.layoutMarginsGuide
// avoid auto-layout complaints
let c = collectionView.heightAnchor.constraint(equalToConstant: 60.0)
c.priority = .required - 1
NSLayoutConstraint.activate([
rowTitleLabel.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
rowTitleLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
rowTitleLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
rowTitleLabel.heightAnchor.constraint(equalToConstant: 30.0),
collectionView.topAnchor.constraint(equalTo: rowTitleLabel.bottomAnchor, constant: 4.0),
collectionView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
collectionView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
collectionView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
c,
])
collectionView.register(SomeCollectionCell.self, forCellWithReuseIdentifier: "someCollectionCell")
collectionView.dataSource = self
collectionView.delegate = self
collectionView.passThroughTouch = { [weak self] in
guard let self = self else { return }
self.passThroughSelect?(self)
}
collectionView.backgroundColor = .systemYellow
}
}
extension SomeTableCell: UICollectionViewDataSource, UICollectionViewDelegate {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return numItems
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "someCollectionCell", for: indexPath) as! SomeCollectionCell
cell.label.text = "Cell \(indexPath.item)"
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Collection View - didSelectItemAt", indexPath)
}
}
extension SomeTableCell: UIScrollViewDelegate {
// if you only want the table cell selected on TAP, don't implement this
// if you want the table cell selected on CollectionView SCROLL, implement this
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
self.passThroughSelect?(self)
}
}
UICollectionView 子類
class SubCollectionView: UICollectionView {
var passThroughTouch: (() -> ())?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// this allows the collection view cell to be selected
super.touchesBegan(touches, with: event)
// this tells the controller (the table view cell)
// that the collection view was tapped
passThroughTouch?()
}
}
UICollectionView 單元類
class SomeCollectionCell: UICollectionViewCell {
var label = UILabel()
var styleView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
styleView.translatesAutoresizingMaskIntoConstraints = false
label.translatesAutoresizingMaskIntoConstraints = false
styleView.addSubview(label)
contentView.addSubview(styleView)
let g = contentView
NSLayoutConstraint.activate([
styleView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
styleView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
styleView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
styleView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
label.topAnchor.constraint(equalTo: styleView.topAnchor, constant: 8.0),
label.leadingAnchor.constraint(equalTo: styleView.leadingAnchor, constant: 8.0),
label.trailingAnchor.constraint(equalTo: styleView.trailingAnchor, constant: -8.0),
label.bottomAnchor.constraint(equalTo: styleView.bottomAnchor, constant: -8.0),
])
label.textColor = .white
styleView.backgroundColor = UIColor(white: 0.5, alpha: 1.0)
styleView.layer.borderColor = UIColor.white.cgColor
styleView.layer.borderWidth = 1
styleView.layer.cornerRadius = 6
}
override var isSelected: Bool {
didSet {
label.textColor = isSelected ? .red : .white
styleView.backgroundColor = isSelected ? UIColor(white: 0.95, alpha: 1.0) : UIColor(white: 0.5, alpha: 1.0)
styleView.layer.borderColor = isSelected ? UIColor.red.cgColor : UIColor.white.cgColor
}
}
}
uj5u.com熱心網友回復:
您可以執行以下操作
首先,在
didSelectItem您的 collectionView 委托中列印一些內容,以確保您的 collectionView 單元格被點擊。如果步驟 1 執行正確,請在您的中添加委托屬性
UICollectionViewClass并呼叫委托。DidSelectItem在您的 UITableViewController 中,您有一個函式
cellForRowAtIndexPath,在這里為關聯單元格添加委托屬性。如果你可以在你的委托函式中列印一些東西,那么你就到了最后一步了。
super.didSelect..使用您的 indexPath呼叫,因為現在您可以手動呼叫 didSelect。
uj5u.com熱心網友回復:
我不知道您的代碼的詳細資訊,但以下操作可能會解決您的問題。
如果您不使用任何UICollectionViewDelegate協議功能,例如didSelect, shouldSelectItemAtext. collectionview.delegate = self只需在您的單元格類中洗掉即可。這將有助于觸發tableview's didSelect而不是觸發collectionView didSelect
uj5u.com熱心網友回復:
也許您想嘗試 UICollectionView 的 allowsSelection 屬性。如果將此屬性設定為 false,則不再選擇您的集合視圖單元格。
而且我認為 tableView didSelect 可以捕獲用戶互動。如果 UITableView 仍然無法捕獲 didSelect,您可以將委托交給 collectionView,并通過在 UICollectionView 上添加點擊手勢來在點擊時觸發它。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/536750.html
