将多个 UICollectionViewCell 推送到同一个 UIViewController
Posted
技术标签:
【中文标题】将多个 UICollectionViewCell 推送到同一个 UIViewController【英文标题】:Push multiple UICollectionViewCell to the same UIViewController 【发布时间】:2020-03-10 11:39:08 【问题描述】:当我单击任何单元格时,我有多个 UICollectionView
和多个 UICollectionViewCell
,它应该将我推送到另一个带有 UITableView 的 UIViewController。
我想要的只是每个 UICollectionViewCell 调用基于 indexPath 的特定 API 并将响应放入 UITableView。
例子:
如果我点击“牛肉”单元格,API 会喜欢那个“https://apilink.com/recipes/random?search=beef”,其他单元格依此类推。
我根本没有使用故事板,我使用的是程序化方法。
主视图:
protocol HomeViewDidSelectActionDelegate: class
func recipesSelectionAction(indexPath: IndexPath)
class HomeView: UIView
var recipes: Recipes?
var recipesDetails = [Recipe]()
let indicator = ActivityIndicator()
weak var homeViewDidSelectActionDelegate: HomeViewDidSelectActionDelegate?
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( 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 = #colorLiteral(red: 0.9568627451, green: 0.9568627451, blue: 0.9568627451, alpha: 1)
foodTableView.delegate = self
foodTableView.dataSource = self
foodTableView.register(CategoriesTableViewCellCollectionViewCell.self, forCellReuseIdentifier: "CategoriesTableViewCellCollectionViewCell")
foodTableView.register(PopularRecipesTableViewCellCollectionViewCell.self, forCellReuseIdentifier: "PopularRecipesTableViewCellCollectionViewCell")
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()
DispatchQueue.main.async
self.fetchData()
func fetchData()
AF.request("https://api.com").responseJSON (response) in
if let error = response.error
print(error)
do
if let data = response.data
self.recipes = try JSONDecoder().decode(Recipes.self, from: data)
self.recipesDetails = self.recipes?.recipes ?? []
DispatchQueue.main.async
self.foodTableView.reloadData()
catch
print(error)
self.indicator.hideIndicatorView(self)
extension HomeView: UITableViewDelegate, UITableViewDataSource
func numberOfSections(in tableView: UITableView) -> Int
return 3
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
if section == 0
return 1
else if section == 1
return 1
else
return recipesDetails.count
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
if indexPath.section == 0
let cell = tableView.dequeueReusableCell(withIdentifier: "CategoriesTableViewCellCollectionViewCell", for: indexPath) as! CategoriesTableViewCellCollectionViewCell
cell.recipesDidselectActionDelegate = self
cell.collectionView.reloadData()
return cell
else if indexPath.section == 1
let cell = tableView.dequeueReusableCell(withIdentifier: "PopularRecipesTableViewCellCollectionViewCell", for: indexPath) as! PopularRecipesTableViewCellCollectionViewCell
cell.collectionView.reloadData()
return cell
else
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
if let readyInMin = recipesDetails[indexPath.row].readyInMinutes
cell.cookingTimeInfoLabel.text = "\(readyInMin) Minutes"
if let pricePerServing = recipesDetails[indexPath.row].pricePerServing
cell.priceInfoLabel.text = "$\(Int(pricePerServing))"
if let serving = recipesDetails[indexPath.row].servings
cell.servesInfoLabel.text = "\(serving)"
return cell
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
if section == 2
return "Random recipes"
else
return ""
func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int)
(view as! UITableViewHeaderFooterView).contentView.backgroundColor = #colorLiteral(red: 0.9568627451, green: 0.9568627451, blue: 0.9568627451, alpha: 1)
(view as! UITableViewHeaderFooterView).textLabel?.font = UIFont(name: "AvenirNext-DemiBold", size: 16)
(view as! UITableViewHeaderFooterView).textLabel?.textColor = .customDarkGray()
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
return 30.0
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
if indexPath.section == 0
return 130
else if indexPath.section == 1
return 180
else
return UITableView.automaticDimension
extension HomeView: RecipesDidselectActionDelegate
func recipesSelectionAction(indexPath: IndexPath)
homeViewDidSelectActionDelegate?.recipesSelectionAction(indexPath: indexPath)
HomeViewController:
class HomeViewController: UIViewController
var recipes: Recipes?
var recipesDetails = [Recipe]()
let indicator = ActivityIndicator()
let searchController = UISearchController(searchResultsController: nil)
let leftMenuNavigationController = SideMenuNavigationController(rootViewController: SideMenuTableViewController())
lazy var mainView: HomeView =
let view = HomeView(frame: self.view.frame)
view.homeViewDidSelectActionDelegate = self
return view
()
override func loadView()
super.loadView()
view = mainView
override func viewDidLoad()
super.viewDidLoad()
override var preferredStatusBarStyle: UIStatusBarStyle
.lightContent
override func viewWillAppear(_ animated: Bool)
super.viewWillAppear(animated)
navigationController?.isNavigationBarHidden = false
setNeedsStatusBarAppearanceUpdate()
setupNavigationWithLargeTitle()
setupLeftSideMenu()
setupNavigation()
func setupLeftSideMenu()
SideMenuManager.default.leftMenuNavigationController = leftMenuNavigationController
leftMenuNavigationController.leftSide = true
leftMenuNavigationController.statusBarEndAlpha = 0
leftMenuNavigationController.presentationStyle = .viewSlideOut
leftMenuNavigationController.allowPushOfSameClassTwice = false
leftMenuNavigationController.menuWidth = view.frame.width * (3/4)
leftMenuNavigationController.navigationBar.isHidden = true
extension HomeViewController: UISearchControllerDelegate, UISearchBarDelegate
func setupNavigationWithLargeTitle()
navigationController?.navigationBar.prefersLargeTitles = true
searchController.delegate = self
searchController.searchBar.delegate = self
searchController.searchBar.searchTextField.backgroundColor = .white
searchController.searchBar.searchTextField.textColor = .customDarkGray()
searchController.searchBar.searchTextField.font = UIFont(name: "AvenirNext-Regular", size: 14)
searchController.searchBar.tintColor = UIColor.CustomGreen()
self.navigationItem.searchController = searchController
self.title = "Home"
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.CustomGreen()]
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.CustomGreen(), .font: UIFont(name: "AvenirNext-Heavy", size: 36)!]
navigationController?.navigationBar.tintColor = .white
navigationController?.navigationBar.standardAppearance = navBarAppearance
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "heart.fill"), style: .plain, target: self, action: #selector(saveButtonTapped))
navigationItem.rightBarButtonItem?.tintColor = UIColor.CustomGreen()
navigationItem.leftBarButtonItem = UIBarButtonItem(image: UIImage(named: "menu"), style: .plain, target: self, action: #selector(menuButtonTapped))
navigationItem.leftBarButtonItem?.tintColor = UIColor.CustomGreen()
@objc func saveButtonTapped()
print("OK")
@objc func menuButtonTapped()
self.present(leftMenuNavigationController, animated: true, completion: nil)
extension HomeViewController: HomeViewDidSelectActionDelegate
func recipesSelectionAction(indexPath: IndexPath)
// Here you can push your destination View Controller
if indexPath.row == 0
let vc = RecipesTableViewDetails()
self.show(vc, sender: nil)
CategoriesTableViewCellCollectionViewCell:
protocol RecipesDidselectActionDelegate: class
func recipesSelectionAction(indexPath: IndexPath)
class CategoriesTableViewCellCollectionViewCell: UITableViewCell, UICollectionViewDelegateFlowLayout
weak var recipesDidselectActionDelegate: RecipesDidselectActionDelegate?
let categories: [String] = [
"Main course",
"Beef",
"Chicken",
"Seafood",
"Vegetarian",
"Breakfast",
"Side dish",
"Drink",
"Sauce",
"Soup",
"Snacks",
"Dessert"
]
let categoriesImages: [UIImage] = [
UIImage(named: "maincourse")!,
UIImage(named: "beef")!,
UIImage(named: "chicken")!,
UIImage(named: "seafood")!,
UIImage(named: "vegetarian")!,
UIImage(named: "breakfast")!,
UIImage(named: "sidedish")!,
UIImage(named: "drink")!,
UIImage(named: "sauce")!,
UIImage(named: "soup")!,
UIImage(named: "snacks")!,
UIImage(named: "dessert")!
]
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?)
super.init(style: style, reuseIdentifier: reuseIdentifier)
layoutUI()
selectionStyle = .none
self.backgroundColor = .clear
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-DemiBold", size: 16)
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: 8),
containerView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
containerView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
containerView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0)
])
func setupCategoriesNameLabelConstraints()
NSLayoutConstraint.activate([
categoriesNameLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
categoriesNameLabel.centerYAnchor.constraint(equalTo: seeAllCategoriesButton.centerYAnchor)
])
func setupSeeAllCategoriesButtonConstraints()
NSLayoutConstraint.activate([
seeAllCategoriesButton.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
seeAllCategoriesButton.topAnchor.constraint(equalTo: containerView.topAnchor)
])
func setupCollectionViewConstraints()
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: seeAllCategoriesButton.bottomAnchor, constant: 0),
collectionView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0),
collectionView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
collectionView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
])
func addSubviews()
addSubview(containerView)
containerView.addSubview(categoriesNameLabel)
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
cell.categoriesImage.image = categoriesImages[indexPath.row]
cell.categoryName.text = categories[indexPath.row]
return cell
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
recipesDidselectActionDelegate?.recipesSelectionAction(indexPath: indexPath)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
let w: CGFloat = self.frame.width * 0.4
let h: CGFloat = collectionView.frame.size.height - 6.0
return CGSize(width: w, height: h)
RecipesTableViewDetailsView:
class RecipesTableViewDetailsView: 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 = #colorLiteral(red: 0.9568627451, green: 0.9568627451, blue: 0.9568627451, alpha: 1)
foodTableView.delegate = self
foodTableView.dataSource = self
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()
addSubview()
setupFoodTableView()
// fetchData()
func fetchData()
indicator.setupIndicatorView(self, containerColor: .customDarkGray(), indicatorColor: .white)
AF.request("https://api.com").responseJSON (response) in
if let error = response.error
print(error)
do
if let data = response.data
self.recipes = try JSONDecoder().decode(Recipes.self, from: data)
self.recipesDetails = self.recipes?.recipes ?? []
DispatchQueue.main.async
self.foodTableView.reloadData()
catch
print(error)
self.indicator.hideIndicatorView(self)
extension RecipesTableViewDetailsView: UITableViewDelegate, UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return recipesDetails.count
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
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
if let readyInMin = recipesDetails[indexPath.row].readyInMinutes
cell.cookingTimeInfoLabel.text = "\(readyInMin) Minutes"
if let pricePerServing = recipesDetails[indexPath.row].pricePerServing
cell.priceInfoLabel.text = "$\(Int(pricePerServing))"
if let serving = recipesDetails[indexPath.row].servings
cell.servesInfoLabel.text = "\(serving)"
return cell
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
return UITableView.automaticDimension
【问题讨论】:
不清楚你在问什么。 @kjoe 每个单元格都有自己的 API,当我单击它时它必须获取它,结果将放在 UITableView 中,我想要的是如何制作它 当你说我想要的是怎么做时,它是什么?退后一步,暂时忘记你所知道的,试着从不知道你遇到什么问题的人的角度来阅读这个问题。你能指出你具体说出问题所在的部分吗? 您有代码但不清楚您想要什么?当您点击 collectionView 时,将点击的对象 ID/模型对象发送到详细视图,它将下载所需的数据 @Caleb 抱歉,如果我的问题不够清楚,我希望每个 UICollectionViewCell 都调用基于 indexPath 的特定 API 并将响应放入 UITableView。我不知道这是否足够清楚,请告诉我 【参考方案1】:您可以将 categories 数组项索引分配给 UICollectionViewCell。
然后你可以在didSelectItemAt
函数中使用cell.tag创建动态API
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
let id = collectionView.cellForItem(at: indexPath)?.tag
let link = "https://apilink.com/recipes/random?search=\(categories[id])"
【讨论】:
也许你是对的,但我不认为这对我有用,因为我使用的是不同的方法(协议方法)。以上是关于将多个 UICollectionViewCell 推送到同一个 UIViewController的主要内容,如果未能解决你的问题,请参考以下文章
将单个 UICollectionViewCell 对齐到 collectionView 的左侧
UICollectionView多个单元格(UICollectionViewCell)在Objective-C中闪烁同步
从多个 UICollectionVIews 内的 UICollectionViewCell 推送新的 UICollectionViewController
UICollectionViewCell:使用“查看更多”按钮展开文本 - AutoSizing