The current structure is
firstViewController -> pushViewController(SecondViewController)
-UIViewController ->filename : secondViewController
-UITableView
-UITableViewCell (custom cell) ->filename : secondTableViewCell
-UICollectionView
-UICollectionViewCell (custom cell) ->filename : secondCollectionViewCell
When 'didSelectItemAt' is done in the 'UICollectionView'
I would like to call the 'popviewcontroller' from UIViewController.
And I want to pass the data on the selected item to firstViewController.
but i don't know how
** ViewController **
struct cellStat{
var opened = Bool()
var title = String()
var sectionData = [ItemModel]()
}
//선물 카테고리 리스트 보여주는 모달
class GiftCategoryModalVC: UIViewController {
#IBOutlet weak var tableView: UITableView!
private var categoryTitleModels: [ItemModel] = []
private var giftItemModels: [ItemModel] = []
private var titleCellData: [cellStat] = []
//LIFE CYCLE
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.register(UINib(nibName: GiftCategoryTBCell.reusableIdentifier, bundle: nil), forCellReuseIdentifier: GiftCategoryTBCell.reusableIdentifier)
tableView.register(UINib(nibName: GiftCategoryListTBCell.reusableIdentifier, bundle: nil), forCellReuseIdentifier: GiftCategoryListTBCell.reusableIdentifier)
//get gift categofy title
GiftPageAPIService.shared.selectCode(code: "CD005") { (itemModels) in
self.categoryTitleModels = itemModels
itemModels.forEach { (itemModel) in
self.titleCellData.append(cellStat(opened: false, title: itemModel.codeNm!, sectionData: []))
}
self.tableView.reloadData()
}
setupLayout()
}
//LAYOUT
fileprivate func setupLayout(){
setNavbar()
}
fileprivate func setNavbar(){
self.navigationItem.leftBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "icon_arrow_left"), style: UIBarButtonItemStyle.plain, target: self, action: #selector(handleEndButton))
self.navigationController?.navigationBar.barTintColor = UIColor.init(hex: 0xececec)
self.navigationController?.navigationBar.tintColor = UIColor.init(hex: 0x979797)
}
//MAKR:- ACTION
#objc func handleEndButton(){
self.navigationController?.popViewController(animated: true)
}
}
extension GiftCategoryModalVC: UITableViewDelegate, UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if titleCellData[section].opened == true{
return 2
}else{
return 1
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return titleCellData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0{
let cell = tableView.dequeueReusableCell(withIdentifier: GiftCategoryTBCell.reusableIdentifier, for: indexPath) as! GiftCategoryTBCell
cell.setCategotyNm = categoryTitleModels[indexPath.section].codeNm
if titleCellData[indexPath.section].opened == true{
cell.setImgView = UIImage(named: "arrow_up")
}else{
cell.setImgView = UIImage(named: "arrow_down")
}
return cell
}else{
//this cell is call tableCell
let cell = tableView.dequeueReusableCell(withIdentifier: GiftCategoryListTBCell.reusableIdentifier, for: indexPath) as! GiftCategoryListTBCell
cell.setItems = titleCellData[indexPath.section].sectionData
return cell
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0{
if titleCellData[indexPath.section].opened == true{
titleCellData[indexPath.section].opened = false
let sections = IndexSet.init(integer: indexPath.section)
tableView.reloadSections(sections, with: .automatic)
}else{
titleCellData[indexPath.section].opened = true
GiftPageAPIService.shared.selectCode(code: categoryTitleModels[indexPath.section].codeCd!) { (items) in
self.titleCellData[indexPath.section].sectionData = items
let sections = IndexSet.init(integer: indexPath.section)
tableView.reloadSections(sections, with: .automatic)
}
}
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0{
return 50
}else{
let cellHeight: Int = (titleCellData[indexPath.section].sectionData.count + 2) / 3
return self.view.frame.height * 0.24 * CGFloat(cellHeight)
}
}
}
** TableViewCell **
class GiftCategoryListTBCell: UITableViewCell {
#IBOutlet weak var collectionView: UICollectionView!
var items: [ItemModel]?
var category: ItemModel?
var setCategory: ItemModel?{
didSet{
self.category = setCategory!
getCategoryData()
}
}
var setItems: [ItemModel]?{
didSet{
self.items = setItems!
collectionView.reloadData()
}
}
let flowlayout = UICollectionViewFlowLayout()
override func awakeFromNib() {
super.awakeFromNib()
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UINib(nibName: GiftItemCVCell.reusableIdentifier, bundle: nil), forCellWithReuseIdentifier: GiftItemCVCell.reusableIdentifier)
setupLayout()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
//MARK:- LAYOUT
fileprivate func setupLayout(){
collectionView.backgroundColor = UIColor.init(hex: 0xf7f7f7)
collectionView.isScrollEnabled = false
}
fileprivate func getCategoryData(){
GiftPageAPIService.shared.selectCode(code: (category?.codeCd)!) { (items) in
self.items = items
self.collectionView.reloadData()
}
}
}
extension GiftCategoryListTBCell: UICollectionViewDataSource,UICollectionViewDelegate{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if items == nil{
return 0
}else{
return (items?.count)!
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: GiftItemCVCell.reusableIdentifier, for: indexPath) as! GiftItemCVCell
cell.setItem = items?[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
/*
I tried to do the work here.
*/
}
}
extension GiftCategoryListTBCell: UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: contentView.frame.width * 0.07, left: contentView.frame.width * 0.07, bottom: contentView.frame.width * 0.07, right: contentView.frame.width * 0.07)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return contentView.frame.width * 0.03
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = (contentView.frame.width) * 0.25
return CGSize(width: width, height: width * 1.5)
}
}
try this :
let window = UIApplication.shared.keyWindow
window?.topMostWindowController?.navigationController?.popViewController(animated: true)
You mean something like this?
Create a protocol in the tableviewcell file
class myTableCell: UITableViewCell{
var myString = "mystring"
var delegate = myNewDelegate?
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
delegate?.didSelect(text: self.myString)
}
}
protocol myNewDelegate {
func didSelect(text: String)
}
This goes in the view controller class that the table cell is in.
class MyTableViewController: UITableViewController, myNewDelegate{
var stringToPass = String()
func didSelectText(text: String){
stringToPass = text
self.performSegue(withIdentifier: "editProfileSegue", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "editProfileSegue"{
let viewcontroller = segue.destination as! FirstViewController
viewcontroller.myPassedString = self.stringToPass
}
}
}
And then id the receiving class
class FirstViewController: UIViewController{
var myPassedString = String()
}
I understand what your mean.
If you want to pop your controller to previous controller in tablecell just to get its viewcontroller which control the cell and try to pop and if you try this method, why not override delegate func in your viewcontroller ?May a little bit hard to read the code, but useful, and you can use
self.navigationcontroller?.popViewController
If you have already use the viewcontroller to delegate the other tableview, just to judge the tableview name in your delegate func
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView == blah blah
{
do what you want
}
}
And if you need to pass the data between the different viewController especially pass the data to pre-viewController you need to write delegate, or need to __block callback.
Related
This is the complete code which configures the tableView controller.
class SearchViewControllerTableViewController: UITableViewController, UISearchBarDelegate, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
var users = [User]()
var filteredUsers = [User]()
var searchBar = UISearchBar()
var inSearchMode = false
var collectionView: UICollectionView!
var collectionViewEnabled = true
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(SearchUserCellTableViewCell.self, forCellReuseIdentifier: reusableIdentifier)
tableView.separatorStyle = .none
tableView.alwaysBounceVertical = true
tableView.keyboardDismissMode = .onDrag
configureSearchBar()
configureCollectionView()
fetchUsers()
print("Collection View \(collectionView.isHidden)")
}
This is the code for configuring collectionView.
func configureCollectionView() {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
let frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height - (tabBarController?.tabBar.frame.height)! - (navigationController?.navigationBar.frame.height)!)
collectionView = UICollectionView(frame: frame, collectionViewLayout: layout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.alwaysBounceVertical = true
collectionView.backgroundColor = .white
tableView.addSubview(collectionView)
collectionView.register(SearchPostCell.self, forCellWithReuseIdentifier: reusableIdentifierCollectionView)
}
This is code for tableView. Which loads up some users in the app.
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if inSearchMode {
return filteredUsers.count
} else {
return users.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: reusableIdentifier, for: indexPath) as! SearchUserCellTableViewCell
var user: User!
if inSearchMode {
user = filteredUsers[indexPath.row]
} else {
user = users[indexPath.row]
}
cell.user = user
cell.selectionStyle = .none
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 69
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
var user: User!
if inSearchMode {
user = filteredUsers[indexPath.row]
} else {
user = users[indexPath.row]
}
// Instance for user profile VC
let userProfileView = UserProfileCollectionViewController(collectionViewLayout: UICollectionViewFlowLayout())
// Assign the selected user.
userProfileView.user = user
// Navigate to the selected user's profile
navigationController?.pushViewController(userProfileView, animated: true)
userProfileView.setNavigationBar()
}
This is the code for collectionView dataSource and delegate.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = (view.frame.width - 2) / 3
return CGSize(width: width, height: width)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 15
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reusableIdentifierCollectionView, for: indexPath) as! SearchPostCell
return cell
}
On top of the tableView I want to add a CollectionView which should be hidden by default.
But the collectionView is not showing up. But on loading up the view "collectionView.isHidden" returns false
You should not try to add subviews directly to table views or collection views.
This line: tableView.addSubview(collectionView) won't work.
Further, UITableViewController and UICollectionViewController are very specialized view controllers that will only manage a table view/collection view. You can't add other subviews to those view controller classes.
I have this two structs, the data I am getting from a Firebase Database and I don't know how to get each tableview cell to display a different collection view, I have both cells (TableviewCell and CollectionViewCell) in xib Files but can't get them the way I want it to.
I have attached my ViewController where they are both in and the TableViewCell class. Please help
struct Clothes {
var price: Double
var imgClUrl: String
var id: String
var isActive: Bool = true
var timeStamp: Timestamp
var stock: Double
var name: String
init(data : [String : Any]) {
self.price = data["price"] as? Double ?? 0
self.imgClUrl = data["imgClUrl"] as? String ?? ""
self.id = data["id"] as? String ?? ""
self.isActive = data["isActive"] as? Bool ?? true
self.timeStamp = data["timeStamp"] as? Timestamp ?? Timestamp()
self.stock = data["stock"] as? Double ?? 0
self.name = data["name"] as? String ?? ""
}
}
struct TypesOfCLothing {
var title : String
var id : String
var clothes : [Clothes]
init (data : [String : Any]){
self.title = data["title"] as? String ?? ""
self.id = data["id"] as? String ?? ""
self.clothes = data["Clothes"] as! [Clothes]
}
}
class eachStoreTableViewCell: UITableViewCell{
#IBOutlet weak var eachRowCollView: UICollectionView!
#IBOutlet weak var eachRowLbl: UILabel!
var clothes = [Clothes]()
override func awakeFromNib() {
super.awakeFromNib()
eachRowCollView?.reloadData()
eachRowCollView?.delegate = self
eachRowCollView?.dataSource = self
self.eachRowCollView?.register(UINib(nibName: "RowColectionView", bundle: nil), forCellWithReuseIdentifier: Identifiers.ClothesCell)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func configureCell(clothingType: TypesOfCLothing) {
eachRowLbl?.text = clothingType.title}}
extension eachStoreTableViewCell: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return clothes.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Identifiers.ClothesCell, for: indexPath) as? RowColectionView{
cell.configureCell(clothes: clothes[indexPath.item])
return cell
}
return UICollectionViewCell()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 160, height: 180)
}
class EachStoreVC: UIViewController {
#IBOutlet weak var StoreTblView: UITableView!
var typesOfClothing = [TypesOfCLothing]()
var tienda: Tiendas!
let db = Firestore.firestore()
var listener : ListenerRegistration!
override func viewDidLoad() {
super.viewDidLoad()
// StoreTblView?.delegate = self
// StoreTblView?.dataSource = self
StoreTblView?.register(UINib(nibName: "eachStoreTblViewCell", bundle: nil), forCellReuseIdentifier: Identifiers.ClothingTypeCell)
StoreTblView?.cellLayoutMarginsFollowReadableWidth = false
}
override func viewDidAppear(_ animated: Bool) {
}
override func viewDidDisappear(_ animated: Bool) {
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}}
extension EachStoreVC : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return typesOfClothing.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: Identifiers.ClothingTypeCell, for: indexPath) as? eachStoreTableViewCell {
cell.configureCell(clothingType: typesOfClothing[indexPath.row])
cell.frame = CGRect(x: 0, y: 0, width: StoreTblView.frame.size.width, height: cell.frame.size.height)
return cell
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 200
}}
EDIT
The collectionView and Tableview now show fine but I'm having trouble getting the data from firebase, I have an array of document references inside each TypesOfClothing document, the code is as follows. I have also updated my 2 Structs.
func getRowData(){
listener = db.collection("TypesOfClothing").addSnapshotListener({ (snap, error) in
if let error = error {
debugPrint(error.localizedDescription)
return
}
snap?.documentChanges.forEach({ (change) in
let data = change.document.data()
let typesOfClothing = TypesOfCLothing.init(data: data)
switch change.type {
case.added:
self.onDocumentAdded(change: change, category: typesOfClothing)
case.modified:
self.onDocumentModified(change: change, category: typesOfClothing)
case.removed:
self.onDocumentRemoved(change: change)
}
})
}) }
func onDocumentAdded(change: DocumentChange, category: TypesOfCLothing){
let newIndex = Int(change.newIndex)
typesOfClothing.insert(category, at: newIndex)
StoreTblView?.insertRows(at: [IndexPath(row: newIndex, section: 0)], with: UITableView.RowAnimation.left)
}
func onDocumentModified(change: DocumentChange, category: TypesOfCLothing){
if change.newIndex == change.oldIndex {
let index = Int(change.newIndex)
typesOfClothing[index] = category
StoreTblView?.reloadRows(at: [IndexPath(row: index, section: 0)], with: UITableView.RowAnimation.left)
} else {
let oldIndex = Int(change.oldIndex)
let newIndex = Int(change.newIndex)
typesOfClothing.remove(at: oldIndex)
typesOfClothing.insert(category, at: newIndex)
StoreTblView?.moveRow(at: IndexPath(row: oldIndex, section: 0), to: IndexPath(row: newIndex, section: 0))
}
}
func onDocumentRemoved(change: DocumentChange){
let oldIndex = Int(change.oldIndex)
typesOfClothing.remove(at: Int(oldIndex))
StoreTblView?.deleteRows(at: [IndexPath(row: oldIndex, section: 0)], with: UITableView.RowAnimation.fade)
}
Struct use like this:
struct TypesOfClothing {
var title : String
var clothes: [Clothes]
}
struct Clothes {
var price: Double
var imgClUrl: String
var id: String
var isActive: Bool = true
var timeStamp: Timestamp
var stock: Double
var name: String
}
in Main View controller: try code like this:
var typesOfClothing: [TypesOfClothing] = []
in numberOfRowsInSection
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return typesOfClothing.count
}
in cellForRowAt
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: Identifiers.ClothingTypeCell, for: indexPath) as? eachStoreTableViewCell {
if indexPath.row < typesOfClothing?.count ?? 0 {
let cellData = typesOfClothing?[indexPath.row]
cell.configureCell(cellData)
}
return cell
}
return UITableViewCell()
}
in UITableViewCell class try like this:
class eachStoreTableViewCell: UITableViewCell{
#IBOutlet weak var eachRowCollView: UICollectionView!
#IBOutlet weak var eachRowLbl: UILabel!
var clothes = [Clothes]()
override func awakeFromNib() {
super.awakeFromNib()
eachRowCollView?.delegate = self
eachRowCollView?.dataSource = self
self.eachRowCollView?.register(UINib(nibName: "RowColectionView", bundle: nil), forCellWithReuseIdentifier: Identifiers.ClothesCell)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func configureCell(_ clothingType: TypesOfClothing) {
eachRowLbl?.text = clothingType.title
clothes = clothingType.clothes
eachRowCollView?.reloadData()
}
}
extension eachStoreTableViewCell: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return clothes.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Identifiers.ClothesCell, for: indexPath) as? RowColectionView{
cell.configureCell(clothes: clothes[indexPath.item])
return cell
}
return UICollectionViewCell()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 160, height: 180)
}
}
it'll help you.
You can make one structs for load tableView Data
struct ClothingData
{
var typesOfClothing : String = ""
var clothes : [Clothes] = []
}
Load this structArray for tabelView
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return ClothingData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: Identifiers.ClothingTypeCell, for: indexPath) as? eachStoreTableViewCell
let row = ClothingData[indexPath.row]
cell.eachRowLbl?.text = row.typesOfClothing
cell.clothes = row.clothes
// Here you can pass clothesList to tabelViewCell for load collectionView
return cell
}
I am trying to make a collectionView header become hidden when a button is tapped but I cant seem to access this property from inside of the IBAction function.
button function
var buttonPressed:Bool = true
#IBAction func changeView(_ sender: Any) {
if buttonPressed{
UIView.animate(withDuration: 0.05){
self.buttonPressed = !self.buttonPressed
print("Ive been expanded")
}
}
else{
UIView.animate(withDuration: 0.05){
self.buttonPressed = !self.buttonPressed
}
}
}
}
Code in its entirety
import UIKit
class ViewController: UIViewController,UICollectionViewDataSource,UICollectionViewDelegate {
#IBOutlet weak var animateCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
animateCollectionView.dataSource = self
animateCollectionView.delegate = self
animateCollectionView.backgroundColor = UIColor.blue
animateCollectionView.frame = CGRect(x: 0, y: 100, width: 600, height: 1000)
let layout = animateCollectionView.collectionViewLayout as? UICollectionViewFlowLayout
layout?.sectionHeadersPinToVisibleBounds = true
self.view.sendSubview(toBack: self.animateCollectionView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 200
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = self.animateCollectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! customCell
cell.cellLabel.text = "\(indexPath.item)"
cell.backgroundColor = UIColor.orange
return cell
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
// returning the search bar for header
let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "headerCell", for: indexPath) as! customHeader
header.backgroundColor = UIColor.purple
return header
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
// if section is above search bar we need to make its height 0
if section == 0 {
return CGSize(width: 0, height: 0)
}
// for section header i.e. actual search bar
return CGSize(width: animateCollectionView.frame.width, height: 50)
}
var buttonPressed:Bool = true
#IBAction func changeView(_ sender: Any) {
if buttonPressed{
UIView.animate(withDuration: 0.05){
self.buttonPressed = !self.buttonPressed
print("Ive been expanded")
}
}
else{
UIView.animate(withDuration: 0.05){
}
}
}
}
class customCell :UICollectionViewCell{
#IBOutlet weak var cellLabel: UILabel!
}
class customHeader: UICollectionReusableView{
}
As #SPatel mentioned, set the size to zero.
Then set up a delegate method from the cell to the VC so that the VC knows to invalidate layouts.
For instance:
Cell Class
protocol HideHeaderViewDelegate {
func hideHeaderView(hide: Bool)
}
class HeaderView: UICollectionReusableView {
var delegate: HideHeaderViewDelegate?
#IBOutlet weak var hideButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
}
#IBAction func hideButtonAction(_ sender: Any) {
self.frame.size = CGSize.zero
guard let delegate = delegate else { return }
delegate.hideHeaderView(hide: true)
}
}
View Controller
extension ViewController: HideHeaderView {
func hideHeaderView(hide: Bool) {
if hide == true {
print(hide)
// invalidate your layout here
}
}
}
Don't forget to set the delegate
func collectionView(_ collectionView: UICollectionView,
viewForSupplementaryElementOfKind kind: String,
at indexPath: IndexPath) -> UICollectionReusableView {
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader,
withReuseIdentifier: "headerView", for: indexPath) as! HeaderView
headerView.delegate = self
return headerView
}
I have made a CollectionView in a TableView for vertical and horizontal scrolling and customisable cells. This works so far. The problem is: I can't select an item of the CollectionView. I think the problem could be something with the delegate outlets but I could't find a solution.
I'm pretty new with Swift, so maybe I overlook something obvious.
My TableViewController:
import UIKit
class HomeVTwoTableViewController: UITableViewController {
var headers = ["Live", "Friends", "Last commented"]
#IBAction func cancelBtnPressed(_ sender: UIBarButtonItem) {
self.dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return headers[section]
}
override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int){
view.tintColor = UIColor.black
let header = view as! UITableViewHeaderFooterView
if section == 0 {
header.textLabel?.textColor = UIColor.black
view.tintColor = UIColor.white
}
else {
view.tintColor = UIColor.groupTableViewBackground
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return headers.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellBig", for: indexPath) as! HomeVTwoTableViewCell
return cell
}
else if indexPath.section == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellSmall", for: indexPath) as! HomeVTwoTableViewCellSmall
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellSmall", for: indexPath) as! HomeVTwoTableViewCellSmall
return cell
}
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 {
return 225.0
}
else {
return 120.0
}
}
}
My TableViewCell with the CollectionView:
import UIKit
class HomeVTwoTableViewCell: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet weak var collectionView: UICollectionView!
fileprivate var images = [UIImage]()
{
didSet
{
self.collectionView.reloadData()
}
}
func setup(for images: [UIImage])
{
self.images = images
}
override func layoutSubviews() {
collectionView.dataSource = self
}
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return communityName.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return communityName.count
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("didSelect")
selectedCommunity = communityId[indexPath.row]
let home = HomeViewController()
home.showCommunityDetail()
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCellBig", for: indexPath) as? HomeVTwoCollectionViewCell else
{
fatalError("Cell has wrong type")
}
//cell.imageView.image = image
cell.titleLbl.text = communityName[indexPath.row]
cell.imageView.downloadedFrom(link :"deleted because privat")
return cell
}
}
My CollectionViewCell:
import UIKit
class HomeVTwoCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var titleLbl: UILabel!
}
You need to set delegate and dataSource like this
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
collectionView.dataSource = self
collectionView.delegate = self
}
I think you missed this line. Just add, it will work fine collectionView.delegate = self
You have not confirm delegate of collection view.
override func layoutSubviews() {
collectionView.dataSource = self
collectionView.delegate = self
}
I'm really new in iOS/Swift and i'm in a small project. In this project i have a UITableView inside ViewController. And i have another file custom CollectionViewCell in side UITableViewCell.
I want when user click a cell in collectionview it will open another ViewController and it get data from this collectionviewcell.
This is my uitableview swift file:
class IndexRow: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
var names:[String] = ["Movie 1","Movie 2","Movie 3","Movie 4","Movie 5","Movie 6"]
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
collectionView.registerClass(indexOneMovie.self, forCellWithReuseIdentifier: "onemovie")
let nib = UINib(nibName: "indexOneMovie",bundle: nil)
collectionView.registerNib(nib, forCellWithReuseIdentifier: "onemovie")
self.collectionView.backgroundColor = UIColor.clearColor()
self.collectionView.delegate = self
self.collectionView.dataSource = self
print("Hello")
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return names.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = self.collectionView.dequeueReusableCellWithReuseIdentifier("onemovie", forIndexPath: indexPath) as! indexOneMovie
cell.poster.image = UIImage(named: "poster.jpg")
cell.name.text = names[indexPath.row]
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print(indexPath.item)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let itemsPerRow:CGFloat = 2
let hardCodedPadding:CGFloat = 0
let itemWidth = (collectionView.bounds.width / itemsPerRow) - hardCodedPadding
let itemHeight = collectionView.bounds.height - (hardCodedPadding)
return CGSize(width: itemWidth, height: itemHeight)
}
How i can do it?
ok i have recently implemented the same in my app these are the links where i refered initially -
https://ashfurrow.com/blog/putting-a-uicollectionview-in-a-uitableviewcell-in-swift/
http://www.thorntech.com/2015/08/want-your-swift-app-to-scroll-in-two-directions-like-netflix-heres-how/
you are making uicollectionview delegate confirms to uitableview cell so you cannot present or push to other view controller.
here is my code hope it will help you
homeController.swift which contains uitableview
extension HomeController : UITableViewDelegate {
func tableView(tableView: UITableView,willDisplayCell cell: UITableViewCell,forRowAtIndexPath indexPath: NSIndexPath) {
guard let tableViewCell = cell as? TableViewCell else { return }
//here setting the uitableview cell contains collectionview delgate conform to viewcontroller
tableViewCell.setCollectionViewDataSourceDelegate(self, forRow: indexPath.row, andForSection: indexPath.section)
tableViewCell.collectionViewOffset = storedOffsets[indexPath.row] ?? 0
}
func tableView(tableView: UITableView,didEndDisplayingCell cell: UITableViewCell,forRowAtIndexPath indexPath: NSIndexPath) {
guard let tableViewCell = cell as? TableViewCell else { return }
storedOffsets[indexPath.row] = tableViewCell.collectionViewOffset
}
}
extension HomeController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(collectionView: UICollectionView,numberOfItemsInSection section: Int) -> Int {
let element : [CollectionViewElement] = self.returnCollectionViewElementAccordingToIndex(collectionView.tag)
return element.count
}
func collectionView(collectionView: UICollectionView,cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell",forIndexPath: indexPath) as! horizontalCollectionViewCell
let element : [CollectionViewElement] = self.returnCollectionViewElementAccordingToIndex(collectionView.tag)
cell.cellTitleLabel.text = element[indexPath.row].videos.title
cell.cellGenerLabel.text = element[indexPath.row].videos.gener
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath){
print("collectionviewtag:\(collectionView.tag) + indexpathrow:\(indexPath.row)")
//from here you can do push or present to anyview controller
// collectionviewtag is tableView cell row value and indexpathrow return collectionView cell row value.
}
}
TableViewCell.swift :custom UITableViewCell which contains collectionView
class TableViewCell: UITableViewCell {
#IBOutlet private weak var collectionView: UICollectionView!
#IBOutlet weak var cellLabel: UILabel!
#IBOutlet weak var cellButton: UIButton!
#IBAction func CellButtonActionTry(sender: UIButton) {
print("Dude \(cellButton.tag)")
}
var collectionViewOffset: CGFloat {
get {
return collectionView.contentOffset.x
}
set {
collectionView.contentOffset.x = newValue
}
}
func setCollectionViewDataSourceDelegate<D: protocol<UICollectionViewDataSource, UICollectionViewDelegate>>
(dataSourceDelegate: D, forRow row: Int , andForSection section : Int) {
collectionView.delegate = dataSourceDelegate
collectionView.dataSource = dataSourceDelegate
collectionView.tag = row // tableView indexpathrow equals cell tag
collectionView.reloadData()
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
You can do it like this :
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
print(indexPath.item)
let name = names[indexPath.item]
let distinationViewController = DistinationViewController()
distinationViewController.name = name
if let navVC: UINavigationController = UIApplication.sharedApplication().keyWindow?.rootViewController as? UINavigationController {
navVC.pushViewController(distinationViewController, animated: true)
}
}
This is just a way to do it i dont know which view you want to push or what your names array contains so kindly change those things accordingly.
get root navigationcontroller from uiapplication and perform push on it.