UICollectionView 不在 UITableViewCell 内滚动 [英] UICollectionView doesn't scroll inside UITableViewCell
问题描述
我在 UITableViewCell 内滚动 UICollectionView 时遇到问题.
I'm having an issue with UICollectionView scrolling inside UITableViewCell.
不幸的是,CollectionView 根本不滚动.当我尝试禁用其他 UITableViewCells 时,它可以正常工作,反之亦然.
Unfortunately, the CollectionView doesn't scroll at all. When I'm trying to disable other UITableViewCells it works without any problem and vice versa.
CollectionViewCell:
import UIKit
class CategoriesCollectionViewCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
layoutUI()
}
required init(coder adecoder: NSCoder) {
fatalError("init(codeer:) has not been implemented")
}
lazy var categoriesImage: UIImageView = {
let categoriesImage = UIImageView()
categoriesImage.contentMode = .scaleToFill
categoriesImage.layer.cornerRadius = 8.0
categoriesImage.image = UIImage(named: "pizza")
categoriesImage.layer.cornerRadius = 8.0
categoriesImage.layer.masksToBounds = true
categoriesImage.translatesAutoresizingMaskIntoConstraints = false
return categoriesImage
}()
lazy var containerView: UIView = {
let containerView = UIView()
containerView.backgroundColor = .black
containerView.alpha = 0.7
containerView.translatesAutoresizingMaskIntoConstraints = false
return containerView
}()
lazy var categoryName: UILabel = {
let categoryName = UILabel()
categoryName.textColor = .white
categoryName.font = UIFont(name: "AvenirNext-DemiBold", size: 16)
categoryName.text = "Soup"
categoryName.textAlignment = .left
categoryName.translatesAutoresizingMaskIntoConstraints = false
return categoryName
}()
lazy var recipesNumber: UILabel = {
let recipesNumber = UILabel()
recipesNumber.textColor = .white
recipesNumber.font = UIFont(name: "AvenirNext-Regular", size: 16)
recipesNumber.text = "33"
recipesNumber.textAlignment = .left
recipesNumber.translatesAutoresizingMaskIntoConstraints = false
return recipesNumber
}()
func setupcategoriesImageConstraints() {
NSLayoutConstraint.activate([
categoriesImage.topAnchor.constraint(equalTo: topAnchor),
categoriesImage.bottomAnchor.constraint(equalTo: bottomAnchor),
categoriesImage.leadingAnchor.constraint(equalTo: leadingAnchor),
categoriesImage.trailingAnchor.constraint(equalTo: trailingAnchor),
])
}
func setupContainerViewConstraints() {
NSLayoutConstraint.activate([
containerView.topAnchor.constraint(equalTo: categoriesImage.topAnchor),
containerView.bottomAnchor.constraint(equalTo: categoriesImage.bottomAnchor),
containerView.leadingAnchor.constraint(equalTo: categoriesImage.leadingAnchor),
containerView.trailingAnchor.constraint(equalTo: categoriesImage.trailingAnchor)
])
}
func setupCategoryNameConstraints() {
NSLayoutConstraint.activate([
categoryName.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 16),
categoryName.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 16),
categoryName.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: 16)
])
}
func setuprecipesNumberConstraints() {
NSLayoutConstraint.activate([
recipesNumber.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -16),
recipesNumber.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 16),
recipesNumber.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: 16)
])
}
func addSubviews() {
addSubview(categoriesImage)
categoriesImage.addSubview(containerView)
containerView.addSubview(categoryName)
containerView.addSubview(recipesNumber)
}
func layoutUI() {
addSubviews()
setupcategoriesImageConstraints()
setupContainerViewConstraints()
setupCategoryNameConstraints()
setuprecipesNumberConstraints()
}
}
CollectionViewInTableViewCell:
import UIKit
class CategoriesTableViewCellCollectionViewCell: UITableViewCell, UICollectionViewDelegateFlowLayout {
let categories = ["italian food", "chinese food", "korean food", "italian food", "chinese food", "korean food", "italian food", "chinese food", "korean food", "italian food", "chinese food", "korean food"]
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
layoutUI()
selectionStyle = .none
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var containerView: UIView = {
let containerView = UIView()
containerView.backgroundColor = .clear
containerView.translatesAutoresizingMaskIntoConstraints = false
return containerView
}()
lazy var categoriesNameLabel: UILabel = {
let categoriesNameLabel = UILabel()
categoriesNameLabel.text = "Categories"
categoriesNameLabel.textColor = .customDarkGray()
categoriesNameLabel.textAlignment = .left
categoriesNameLabel.font = UIFont(name: "AvenirNext-Regular", size: 14)
categoriesNameLabel.translatesAutoresizingMaskIntoConstraints = false
return categoriesNameLabel
}()
lazy var seeAllCategoriesButton: UIButton = {
let seeAllCategoriesButton = UIButton()
seeAllCategoriesButton.setTitle("See all", for: .normal)
seeAllCategoriesButton.setTitleColor(.CustomGreen(), for: .normal)
seeAllCategoriesButton.titleLabel?.font = UIFont(name: "AvenirNext-Regular", size: 14)
seeAllCategoriesButton.translatesAutoresizingMaskIntoConstraints = false
seeAllCategoriesButton.addTarget(self, action: #selector(test), for: .touchUpInside)
return seeAllCategoriesButton
}()
@objc func test() {
print("Test worked")
}
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.backgroundColor = .clear
collectionView.showsHorizontalScrollIndicator = false
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(CategoriesCollectionViewCell.self, forCellWithReuseIdentifier: "CategoriesCollectionViewCell")
return collectionView
}()
func setupContainerViewConstraints() {
NSLayoutConstraint.activate([
containerView.topAnchor.constraint(equalTo: topAnchor, constant: 16),
containerView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
containerView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
containerView.heightAnchor.constraint(equalTo: categoriesNameLabel.heightAnchor)
])
}
func setupCategoriesNameLabelConstraints() {
NSLayoutConstraint.activate([
categoriesNameLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
categoriesNameLabel.centerYAnchor.constraint(equalTo: containerView.centerYAnchor)
])
}
func setupSeeAllCategoriesButtonConstraints() {
NSLayoutConstraint.activate([
seeAllCategoriesButton.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
seeAllCategoriesButton.centerYAnchor.constraint(equalTo: containerView.centerYAnchor)
])
}
func setupCollectionViewConstraints() {
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: categoriesNameLabel.topAnchor, constant: 16),
collectionView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 16),
collectionView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
collectionView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
])
}
func addSubviews() {
addSubview(categoriesNameLabel)
addSubview(containerView)
containerView.addSubview(seeAllCategoriesButton)
containerView.addSubview(collectionView)
}
func layoutUI() {
addSubviews()
setupCollectionViewConstraints()
setupContainerViewConstraints()
setupCategoriesNameLabelConstraints()
setupSeeAllCategoriesButtonConstraints()
}
}
extension CategoriesTableViewCellCollectionViewCell: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return categories.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CategoriesCollectionViewCell", for: indexPath) as! CategoriesCollectionViewCell
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: self.frame.width / 2, height: self.frame.width / 4)
}
}
TableViewCell:
import UIKit
class HomeTableViewCell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
layoutUI()
selectionStyle = .none
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var containerView: UIView = {
let containerView = UIView()
containerView.backgroundColor = .white
containerView.translatesAutoresizingMaskIntoConstraints = false
containerView.layer.shadowColor = UIColor.black.cgColor
containerView.layer.shadowOpacity = 1
containerView.layer.shadowOffset = .init(width: 2, height: 2)
containerView.layer.shadowRadius = 7.0
containerView.layer.cornerRadius = 8.0
// containerView.clipsToBounds = true
return containerView
}()
lazy var foodImage: UIImageView = {
let foodImage = UIImageView()
foodImage.translatesAutoresizingMaskIntoConstraints = false
foodImage.contentMode = .scaleAspectFill
foodImage.clipsToBounds = true
foodImage.layer.cornerRadius = 8.0
return foodImage
}()
lazy var foodTitle: UILabel = {
let foodTitle = UILabel()
foodTitle.textColor = .CustomGreen()
foodTitle.numberOfLines = 0
foodTitle.translatesAutoresizingMaskIntoConstraints = false
return foodTitle
}()
func setupContainerView() {
NSLayoutConstraint.activate([
containerView.topAnchor.constraint(equalTo: topAnchor, constant: 16),
containerView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -16),
containerView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
containerView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
])
}
func setupFoodImage() {
NSLayoutConstraint.activate([
foodImage.topAnchor.constraint(equalTo: containerView.topAnchor),
foodImage.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
foodImage.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
foodImage.heightAnchor.constraint(equalToConstant: 250)
])
}
func setupFoodTitle() {
NSLayoutConstraint.activate([
foodTitle.topAnchor.constraint(equalTo: foodImage.bottomAnchor, constant: 16),
foodTitle.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -16),
foodTitle.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 16),
foodTitle.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -16)
])
}
func addSubview() {
addSubview(containerView)
containerView.addSubview(foodImage)
containerView.addSubview(foodTitle)
}
func layoutUI() {
addSubview()
setupContainerView()
setupFoodImage()
setupFoodTitle()
}
}
家庭视图:
class HomeView: UIView {
var recipes: Recipes?
var recipesDetails = [Recipe]()
let indicator = ActivityIndicator()
override init( frame: CGRect) {
super.init(frame: frame)
layoutUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var foodTableView: UITableView = {
let foodTableView = UITableView()
foodTableView.translatesAutoresizingMaskIntoConstraints = false
foodTableView.backgroundColor = .white
foodTableView.delegate = self
foodTableView.dataSource = self
foodTableView.register(CategoriesTableViewCellCollectionViewCell.self, forCellReuseIdentifier: "CategoriesTableViewCellCollectionViewCell")
foodTableView.register(HomeTableViewCell.self, forCellReuseIdentifier: "HomeTableViewCell")
foodTableView.rowHeight = UITableView.automaticDimension
// foodTableView.estimatedRowHeight = 100
foodTableView.showsVerticalScrollIndicator = false
foodTableView.separatorStyle = .none
return foodTableView
}()
func setupFoodTableView() {
NSLayoutConstraint.activate([
foodTableView.topAnchor.constraint(equalTo: topAnchor),
foodTableView.bottomAnchor.constraint(equalTo: bottomAnchor),
foodTableView.leadingAnchor.constraint(equalTo: leadingAnchor),
foodTableView.trailingAnchor.constraint(equalTo: trailingAnchor)
])
}
func addSubview() {
addSubview(foodTableView)
}
func layoutUI() {
indicator.setupIndicatorView(self, containerColor: .customDarkGray(), indicatorColor: .white)
addSubview()
setupFoodTableView()
fetchData()
}
func fetchData() {
AF.request("https://api.url").responseJSON { (response) in
if let error = response.error {
print(error)
}
do {
self.recipes = try JSONDecoder().decode(Recipes.self, from: response.data!)
self.recipesDetails = self.recipes?.recipes ?? []
DispatchQueue.main.async {
self.foodTableView.reloadData()
}
} catch {
print(error)
}
self.indicator.hideIndicatorView()
}
}
}
extension HomeView: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return recipesDetails.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "CategoriesTableViewCellCollectionViewCell", for: indexPath) as! CategoriesTableViewCellCollectionViewCell
cell.layoutIfNeeded()
cell.collectionView.reloadData()
return cell
}
let cell = tableView.dequeueReusableCell(withIdentifier: "HomeTableViewCell", for: indexPath) as! HomeTableViewCell
let url = URL(string: recipesDetails[indexPath.row].image ?? "Error")
cell.foodImage.kf.setImage(with: url)
cell.foodTitle.text = recipesDetails[indexPath.row].title
cell.layoutIfNeeded()
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0 {
return 160
} else {
return 250
}
}
}
谁能告诉我问题出在哪里或我做错了什么?
Can anyone tell me what is the problem or what I did wrong?
谢谢.
推荐答案
您无法滚动您的集合视图,因为它超出了其超级视图的范围.在您的代码中,您有这一行:
You cannot scroll your collection view because it is outside the bounds of its superview. In your code, you have this line:
containerView.heightAnchor.constraint(equalTo: categoriesNameLabel.heightAnchor)
这使您的 containerView
高度 仅 大约 20 pts,但您也将集合视图作为 containerView 的子视图代码>.
以下是您的代码查找我的方式(几乎原样):
Here is how your code looks for me (pretty much as-is):
而且,我无法滚动集合视图.
And, I cannot scroll the collection view.
您可以通过给 containerView
一个背景颜色(我使用青色)来确认它在 containerView
边界之外:
You can confirm it is outside the containerView
bounds by giving containerView
a background color (I used cyan):
也可以通过设置containerView.clipsToBounds = true
来确认:
You can also confirm it by setting containerView.clipsToBounds = true
:
现在,我们甚至看到集合视图.
Now, we don't even see the collection view.
您还有其他一些约束问题,但它们与无法滚动集合视图并没有真正的关系.
You have a couple other constraint issues, but they don't really relate to being unable to scroll the collection view.
你的布局也有点令人困惑,因为你有你的Categories
标签outside你的containerView
... 似乎在 containerView
中拥有该标签 +查看全部"按钮 + 集合视图 all 会更有意义.
Your layout is also a little confusing, in that you have your Categories
label outside your containerView
... it seems it would make much more sense to have that label + the "See All" button + the collection view all inside the containerView
.
我对您的 CategoriesTableViewCellCollectionViewCell
进行了一些编辑,从而解决了该问题 -- 我认为已接近您的最终目标.您可能需要做一些调整,但希望它能给您一个好的方向.
I made a few edits to your CategoriesTableViewCellCollectionViewCell
which resolves that issue -- and I think is close to your ultimate goal. You may need to do a little tweaking, but hopefully it will give you a good direction.
class CategoriesTableViewCellCollectionViewCell: UITableViewCell, UICollectionViewDelegateFlowLayout {
let categories = ["italian food", "chinese food", "korean food", "italian food", "chinese food", "korean food", "italian food", "chinese food", "korean food", "italian food", "chinese food", "korean food"]
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
layoutUI()
selectionStyle = .none
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var containerView: UIView = {
let containerView = UIView()
containerView.backgroundColor = .clear
containerView.translatesAutoresizingMaskIntoConstraints = false
return containerView
}()
lazy var categoriesNameLabel: UILabel = {
let categoriesNameLabel = UILabel()
categoriesNameLabel.text = "Categories"
categoriesNameLabel.textColor = .gray // .customDarkGray()
categoriesNameLabel.textAlignment = .left
categoriesNameLabel.font = UIFont(name: "AvenirNext-Regular", size: 14)
categoriesNameLabel.translatesAutoresizingMaskIntoConstraints = false
return categoriesNameLabel
}()
lazy var seeAllCategoriesButton: UIButton = {
let seeAllCategoriesButton = UIButton()
seeAllCategoriesButton.setTitle("See all", for: .normal)
// seeAllCategoriesButton.setTitleColor(.CustomGreen(), for: .normal)
seeAllCategoriesButton.setTitleColor(UIColor(red: 0.0, green: 0.5, blue: 0.0, alpha: 1.0), for: .normal)
seeAllCategoriesButton.titleLabel?.font = UIFont(name: "AvenirNext-Regular", size: 14)
seeAllCategoriesButton.translatesAutoresizingMaskIntoConstraints = false
seeAllCategoriesButton.addTarget(self, action: #selector(test), for: .touchUpInside)
return seeAllCategoriesButton
}()
@objc func test() {
print("Test worked")
}
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.backgroundColor = .clear
collectionView.showsHorizontalScrollIndicator = false
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(CategoriesCollectionViewCell.self, forCellWithReuseIdentifier: "CategoriesCollectionViewCell")
return collectionView
}()
func setupContainerViewConstraints() {
NSLayoutConstraint.activate([
containerView.topAnchor.constraint(equalTo: topAnchor, constant: 16),
containerView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
containerView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
// should not be constrained to categoriesNameLabel height
//containerView.heightAnchor.constraint(equalTo: categoriesNameLabel.heightAnchor)
// constrain 16-pts from bottom of cell
containerView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -16)
])
}
func setupCategoriesNameLabelConstraints() {
NSLayoutConstraint.activate([
categoriesNameLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
// centerY to seeAllCategoriesButton
categoriesNameLabel.centerYAnchor.constraint(equalTo: seeAllCategoriesButton.centerYAnchor)
])
}
func setupSeeAllCategoriesButtonConstraints() {
NSLayoutConstraint.activate([
seeAllCategoriesButton.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
// constrain top to containerView top
seeAllCategoriesButton.topAnchor.constraint(equalTo: containerView.topAnchor)
])
}
func setupCollectionViewConstraints() {
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: seeAllCategoriesButton.bottomAnchor, constant: 0),
collectionView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -16),
collectionView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
collectionView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
])
}
func addSubviews() {
// but categoriesNameLabel inside containerView
//addSubview(categoriesNameLabel)
addSubview(containerView)
containerView.addSubview(categoriesNameLabel)
containerView.addSubview(seeAllCategoriesButton)
containerView.addSubview(collectionView)
}
func layoutUI() {
addSubviews()
setupCollectionViewConstraints()
setupContainerViewConstraints()
setupCategoriesNameLabelConstraints()
setupSeeAllCategoriesButtonConstraints()
}
}
结果如下所示 - 您可以看到我稍微滚动了集合视图:
The result looks like this - and you can see that I have scrolled the collection view a bit:
这篇关于UICollectionView 不在 UITableViewCell 内滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!