Last active
March 4, 2020 15:46
-
-
Save DonMag/e70610ab127adcc426f90a91a26d4149 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
class TableCollectionViewController: UIViewController { | |
let homeView: HomeView = { | |
let v = HomeView() | |
return v | |
}() | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
view.backgroundColor = .systemYellow | |
view.addSubview(homeView) | |
homeView.translatesAutoresizingMaskIntoConstraints = false | |
let g = view.safeAreaLayoutGuide | |
NSLayoutConstraint.activate([ | |
homeView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0), | |
homeView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -40.0), | |
homeView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0), | |
homeView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0), | |
]) | |
} | |
} | |
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() | |
} | |
} | |
class CategoriesTableViewCellCollectionViewCell: UITableViewCell, UICollectionViewDelegateFlowLayout { | |
let categories = [ | |
"italian food", | |
"chinese food", | |
"korean food", | |
"german food", | |
"swedish food", | |
"spanish food", | |
"french food", | |
"japanese food", | |
"american food", | |
"brazilian food", | |
"mexican food", | |
"canadian 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), | |
containerView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -16), | |
]) | |
} | |
func setupCategoriesNameLabelConstraints() { | |
NSLayoutConstraint.activate([ | |
categoriesNameLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor), | |
// seeAllCategoriesButton, with default size, will be taller than categoriesNameLabel | |
// so constrain centerY to seeAllCategoriesButton centerY | |
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), | |
// constrain height to desired height -- this will also determine the | |
// height of the cells AND the height of this table row | |
collectionView.heightAnchor.constraint(equalToConstant: 100.0), | |
]) | |
} | |
func addSubviews() { | |
addSubview(containerView) | |
containerView.addSubview(categoriesNameLabel) | |
containerView.addSubview(seeAllCategoriesButton) | |
containerView.addSubview(collectionView) | |
} | |
func layoutUI() { | |
addSubviews() | |
setupCollectionViewConstraints() | |
setupContainerViewConstraints() | |
setupCategoriesNameLabelConstraints() | |
setupSeeAllCategoriesButtonConstraints() | |
// it can help to set background colors during dev | |
// to easily see the frames at run-time | |
//collectionView.backgroundColor = .red | |
//containerView.backgroundColor = .cyan | |
//categoriesNameLabel.backgroundColor = .yellow | |
//seeAllCategoriesButton.backgroundColor = .lightGray | |
} | |
} | |
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.categoryName.text = categories[indexPath.item] | |
return cell | |
} | |
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { | |
let w: CGFloat = self.frame.width * 0.5 | |
let h: CGFloat = collectionView.frame.size.height - 16.0 | |
return CGSize(width: w, height: h) | |
} | |
} | |
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 | |
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 favouriteButton: UIButton = { | |
var favouriteButton = UIButton() | |
favouriteButton.setImage(UIImage(systemName: "heart"), for: .normal) | |
favouriteButton.tintColor = .red | |
favouriteButton.translatesAutoresizingMaskIntoConstraints = false | |
favouriteButton.setContentHuggingPriority(.required, for: .horizontal) | |
favouriteButton.setContentCompressionResistancePriority(.required, for: .horizontal) | |
return favouriteButton | |
}() | |
lazy var foodTitle: UILabel = { | |
let foodTitle = UILabel() | |
foodTitle.textColor = UIColor(red: 0.0, green: 0.5, blue: 0.0, alpha: 1.0) // .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: 160), | |
]) | |
} | |
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: favouriteButton.leadingAnchor, constant: -16) | |
]) | |
} | |
func setupFavouriteButtonConstraints() { | |
NSLayoutConstraint.activate([ | |
favouriteButton.centerYAnchor.constraint(equalTo: foodTitle.centerYAnchor), | |
favouriteButton.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -16) | |
]) | |
} | |
func addSubview() { | |
addSubview(containerView) | |
containerView.addSubview(foodImage) | |
containerView.addSubview(foodTitle) | |
containerView.addSubview(favouriteButton) | |
} | |
func layoutUI() { | |
addSubview() | |
setupContainerView() | |
setupFoodImage() | |
setupFoodTitle() | |
setupFavouriteButtonConstraints() | |
// it can help to set background colors during dev | |
// to easily see the frames at run-time | |
//containerView.backgroundColor = .cyan | |
//foodImage.backgroundColor = .lightGray | |
//foodTitle.backgroundColor = .yellow | |
//favouriteButton.backgroundColor = .blue | |
} | |
} | |
struct Recipe { | |
var image: String = "" | |
var title: String = "" | |
} | |
class HomeView: UIView { | |
//var recipes: Recipes? | |
var recipesDetails = [Recipe]() | |
let indicator = UIActivityIndicatorView() // 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 | |
// .estimatedRowHeight is not really necessary since we're not showing the scroll indicator | |
//foodTableView.estimatedRowHeight = 200 | |
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() { | |
// dummy sample data | |
recipesDetails = [ | |
Recipe(image: "url", title: "Recipe 1"), | |
Recipe(image: "url", title: "Recipe 2"), | |
Recipe(image: "url", title: "Recipe 3"), | |
Recipe(image: "url", title: "Recipe 4"), | |
Recipe(image: "url", title: "Recipe 5"), | |
] | |
DispatchQueue.main.async { | |
self.foodTableView.reloadData() | |
} | |
// 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.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 | |
return cell | |
} | |
// heightForRowAt is not needed when cells are properly configured with constraints for auto-sizing | |
// func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { | |
// if indexPath.row == 0 { | |
// return 160 | |
// | |
// } else { | |
// return 250 | |
// } | |
// | |
// } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment