我正在開發一個 UICollectionView,它可以水平滾動,下面有一個 UITableView:

我的目標是,每當我在 TableView 中滾動時,CollectionView 將以與 Tableview 完全相同的速度和相同的量/方向移動,反之亦然。
所以我需要以某種方式連接它們。我嘗試了獲取myTableView.contentOffset.y并將此值放入 CollectionView 中 myCollectionView.setContentOffset(CGPoint(x: offset, y: 0), animated: true)。
然而,這個函式需要在盡可能短的時間間隔內一直被呼叫,并且它不是真正同步,也不是平滑和快速的。
有沒有其他可能來實作這一目標?
感謝您提供任何意見!
uj5u.com熱心網友回復:
“這個函式需要在盡可能短的時間間隔內一直被呼叫”并不是真的。您只需要在滾動 tableView(或 collectionView)時同步滾動。
為此,請實施scrollViewDidScroll.
但是,您將有幾個問題需要處理...
首先,除非您的行與單元格的高度相同,否則您不能.contentOffset.y直接使用。
例如,如果您的行高 50 磅,而您的單元格寬 100 磅,當您向下滾動 10 行時,.contentOffset.y將是 500。如果您將.contentOffset.xcollectionView設定為 500,它將只滾動 5 個單元格10。
因此,您需要使用偏移百分比——計算起來并不難。
然而...
根據您發布的圖片,您顯示了大約 13 行和大約 3 個單元格。當您向下滾動時,轉換為百分比偏移,當第 2 行位于頂部時,單元格 2 將位于左邊緣。當第 3 行位于頂部時,單元格 3 將位于左邊緣。等等......這很棒。
直到您一直向下滾動。現在,如果您總共有 100 行,則頂行將是第 87 行,而 collectionView 中的可見單元格將是 87、88 和 89……無法到達單元格 90 到 100。
下面是一些示例代碼,顯示同步滾動并顯示到達表格底部時的問題(使用 50 個資料項):
class CvTvViewController: UIViewController {
var myData: [String] = []
let colors: [UIColor] = [
.systemRed, .systemGreen, .systemBlue,
.systemPink, .systemYellow, .systemTeal,
]
var collectionView: UICollectionView!
var tableView: UITableView!
var tableViewActive: Bool = false
var cvCellWidth: CGFloat = 120
let tvRowHeight: CGFloat = 50
override func viewDidLoad() {
super.viewDidLoad()
// fill myData array with 50 strings
myData = (1...50).map { "Data: \($0)" }
let cvl = UICollectionViewFlowLayout()
cvl.itemSize = CGSize(width: cvCellWidth, height: 100)
cvl.minimumLineSpacing = 0
cvl.minimumInteritemSpacing = 0
cvl.scrollDirection = .horizontal
collectionView = UICollectionView(frame: .zero, collectionViewLayout: cvl)
tableView = UITableView()
tableView.rowHeight = tvRowHeight
collectionView.translatesAutoresizingMaskIntoConstraints = false
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(collectionView)
view.addSubview(tableView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
collectionView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
collectionView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
collectionView.heightAnchor.constraint(equalToConstant: 100.0),
tableView.topAnchor.constraint(equalTo: collectionView.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)
])
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(MyCVCell.self, forCellWithReuseIdentifier: "cvCell")
tableView.dataSource = self
tableView.delegate = self
tableView.register(MyTVCell.self, forCellReuseIdentifier: "tvCell")
}
}
extension CvTvViewController: UIScrollViewDelegate {
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
tableViewActive = scrollView == tableView
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if tableViewActive && scrollView == tableView {
let pctOffset = tableView.contentOffset.y / (CGFloat(myData.count) * tableView.rowHeight)
let xOffset = (CGFloat(myData.count) * cvCellWidth) * pctOffset
collectionView.contentOffset.x = xOffset
}
if !tableViewActive && scrollView == collectionView {
let pctOffset = collectionView.contentOffset.x / (CGFloat(myData.count) * cvCellWidth)
let xOffset = (CGFloat(myData.count) * tvRowHeight) * pctOffset
tableView.contentOffset.y = xOffset
}
}
}
extension CvTvViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let c = tableView.dequeueReusableCell(withIdentifier: "tvCell", for: indexPath) as! MyTVCell
c.label.text = myData[indexPath.row]
return c
}
}
extension CvTvViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return myData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let c = collectionView.dequeueReusableCell(withReuseIdentifier: "cvCell", for: indexPath) as! MyCVCell
c.contentView.backgroundColor = colors[indexPath.item % colors.count]
c.label.text = myData[indexPath.item]
return c
}
}
class MyTVCell: UITableViewCell {
let label: UILabel = {
let v = UILabel()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
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)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
label.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
])
}
}
class MyCVCell: UICollectionViewCell {
let label: UILabel = {
let v = UILabel()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
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)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
label.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
])
}
}
它在啟動時看起來像這樣:

滾動一點后就像這樣:

當我們一直向下滾動時,就像這樣:

編輯如果您希望能夠一直滾動到最后一行/專案(這可能有點令人不安,因為這不是用戶習慣的,但是......),添加以下代碼:
// track the table view frame height and
// collection view frame width
var tvHeight: CGFloat = 0
var cvWidth: CGFloat = 0
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// we only want to call this if
// the tableView height or
// the collectionView width changes
if tvHeight != tableView.frame.height || cvWidth != collectionView.frame.width {
tvHeight = tableView.frame.height
cvWidth = collectionView.frame.width
var edge = tableView.contentInset
edge.bottom = tableView.frame.height - tvRowHeight
tableView.contentInset = edge
edge = collectionView.contentInset
edge.right = collectionView.frame.width - cvCellWidth
collectionView.contentInset = edge
}
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/381614.html
