How to hide collection view when table view is searching? - ios

I have collection view inside of my first table view cell. Search bar at the top of the table view (out of table view). Collection views showing as table view cell items count at viewDidLoad(). E.g. If table view cell items count 4 so collection view items count as same 4.
class MainViewController: UIViewController, UITableViewDataSource, UITableViewDelegate,
UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var mainTableView: UITableView!
var imageNames = [ImageNames]()
var priceFood: [Double]!
var searchFoods = [String]()
var filtered = [String]()
var searching = false
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.tabBar.isHidden = false
}
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.isHidden = true
let foodCell = Food(name: ["Hamburger big mac",
"Patates",
"Whopper",
"Steakhouse"], price: [15.0, 20.0, 25.0, 30.0])
searchBar.delegate = self
searchFoods = foodCell.name
priceFood = foodCell.price
imageNames = [
ImageNames(name: "images"),
ImageNames(name: "unnamed"),
ImageNames(name: "unnamed")
// ImageNames(name: "images"),
// ImageNames(name: "images")
]
}
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searching {
return filtered.count
} else {
return searchFoods.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainFoodTableViewCell", for: indexPath) as! MainFoodTableViewCell
// cell.mainFoodCollectionView.delegate = self
// cell.mainFoodCollectionView.dataSource = self
// cell.mainFoodCollectionView.reloadData()
cell.mainFoodCollectionView.tag = indexPath.row
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "CellForFood", for: indexPath) as! MainFoodTitleTableViewCell
if searching {
cell.titleLabel?.text = filtered[indexPath.row]
cell.priceLabel?.text = priceFood[indexPath.row].description
} else {
cell.titleLabel?.text = searchFoods[indexPath.row]
cell.priceLabel?.text = priceFood[indexPath.row].description
}
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return indexPath.section == 0 ? 130 : 65
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return indexPath.section == 0 ? 100 : 65
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageNames.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = UIScreen.main.bounds.width
return CGSize(width: width, height: 130)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MainFoodCollectionViewCell", for: indexPath) as! MainFoodCollectionViewCell
let img = imageNames[indexPath.row]
cell.mainFoodImage.image = UIImage(named: img.name)
return cell
}
}
extension MainViewController : UISearchBarDelegate {
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
self.searchBar.showsCancelButton = true
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searching = false
searchBar.showsCancelButton = false
searchBar.text = ""
searchBar.resignFirstResponder()
mainTableView.reloadData()
}
I think I did not make sense with this function
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filtered = searchText.isEmpty ? searchFoods : filtered.filter { (item: String) -> Bool in
return item.range(of: searchText, options: .caseInsensitive, range: nil, locale: nil) != nil
}
// filtered = self.searchFoods.filter ({$0.prefix(searchText.count) == searchText})
searching = true
mainTableView.reloadData()
}
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "MainFoodTableViewCell", for: indexPath) as! MainFoodTableViewCell
cell.mainFoodCollectionView.tag = indexPath.row
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "CellForFood", for: indexPath) as! MainFoodTitleTableViewCell
if searching {
cell.titleLabel?.text = filtered[indexPath.row]
cell.priceLabel?.text = priceFood[indexPath.row].description
} else {
cell.titleLabel?.text = searchFoods[indexPath.row]
cell.priceLabel?.text = priceFood[indexPath.row].description
}
return cell
}
}
Solved my problem

Related

Get TableviewCells to display different data that is extracted from firebase and show them in CollectionView

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
}

how to call popviewcontroller in UITableViewCell

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.

can't delete item from collectionView

I have simple collectionview which shows 1 column on iphone and 2 columns on iPad
There is a button which removing an item from collectionview but when I press the button I got this error:
The number of sections contained in the collection view after the update (3) must be equal to the number of sections contained in the collection view before the update (4), plus or minus the number of sections inserted or deleted (0 inserted, 0 deleted).'
And this is my code
protocol AudioListDataProtocol: class {
func search(searchText: String)
func playComposition(composition: Composition, data: [Composition], play: Bool)
func endEditing()
}
class AudioListDataAdapter: NSObject, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UISearchBarDelegate, AudioItemCellProtocol {
var delegate: AudioListDataProtocol!
var isFavoriesList = false
private var data = [Composition]()
private var collectionView: UICollectionView!
private var searchBar: UISearchBar!
private let cellIdentifier = "AudioCellIdent"
private var selectedIndexPath: IndexPath!
private var cellWidth = 0 as CGFloat
private var sectionCount = 0
private var itemCount = 0
//MARK: public methods
func initSearchBar(searchBar: UISearchBar) -> Void {
self.searchBar = searchBar
self.searchBar.delegate = self
self.searchBar.returnKeyType = .done
self.searchBar.placeholder = DicionaryManager.shared.getStringValue(dKey: AMKeys.mobile_label_search_here)
}
func initCollection(collection: UICollectionView) -> Void {
self.collectionView = collection
self.collectionView.dataSource = self
self.collectionView.delegate = self
self.collectionView.register(UINib.init(nibName: "AudioItemCell", bundle: nil), forCellWithReuseIdentifier: cellIdentifier)
}
func setListData(data: [Composition], itemsPerSection: Int, itemWidth: CGFloat) -> Void {
cellWidth = itemWidth
self.data = data
itemCount = itemsPerSection
sectionCount = Int(ceil(Double(self.data.count / itemCount)))
}
func reload() {
collectionView.reloadData()
}
//MARK: UISearchBarDelegate
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
searchBar.showsCancelButton = true
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText.characters.count >= 3 {
if let d = delegate {
d.search(searchText: searchText)
}
}
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.text = ""
if let d = delegate {
d.search(searchText: "")
d.endEditing()
}
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
if let d = delegate {
d.endEditing()
}
}
//MARK: UICollectionViewDataSource
func numberOfSections(in collectionView: UICollectionView) -> Int {
return sectionCount
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return itemCount
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as? AudioItemCell {
return cell
}
return UICollectionViewCell()
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
let c = cell as! AudioItemCell
c.setupComposition(composition: data[curItemIndex(indexPath: indexPath)])
c.indexPath = indexPath
c.favoriteState = isFavoriesList
c.delegate = self
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
PlayerManager.shared.changePlaylist()
var item: Composition
item = data[curItemIndex(indexPath: indexPath)] as Composition
item.isPlaying = true
item.showPlayer = true
collectionView.reloadItems(at: [indexPath])
selectedIndexPath = indexPath
delegate.playComposition(composition: item, data: data, play: true)
}
func playingCompositionForReload(composition: Composition) {
composition.isPlaying = true
composition.showPlayer = true
collectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: cellWidth, height: 90)
}
//MARK: helpers methods
func updateState(play: Bool) -> Void {
if (selectedIndexPath) != nil {
let item = data[curItemIndex(indexPath: selectedIndexPath)]
item.isPlaying = !item.isPlaying
} else {
selectedIndexPath = IndexPath(row: 0, section: 0)
let item = data[0]
item.isPlaying = true
item.showPlayer = true
}
collectionView.reloadItems(at: [selectedIndexPath])
}
private func curItemIndex(indexPath: IndexPath) -> Int {
return indexPath.section * itemCount + indexPath.item
}
//MARK: AudioItemCellProtocol
func removeCellAtIndexpath(indexPath: IndexPath) {
collectionView.performBatchUpdates({
self.data.remove(at: self.curItemIndex(indexPath: indexPath))
sectionCount = Int(ceil(Double(self.data.count / self.itemCount)))
self.collectionView.deleteItems(at: [indexPath])
}, completion: nil)
}
}
And this button pressed code
delegate.removeCellAtIndexpath(indexPath: indexPath)
What I did wrong here and why its crashing?
Please help I stuck on this a day.
The problem is with your numberOfItemsInSection method and the use of the itemCount property. You are returning a fixed number. You are assuming every section has the same fixed number of items. Instead, you should be returning the current number of records in your data source for the given section.
It would help a lot if you setup your data source to be an array of arrays where the outer array represents your sections and each inner array is the items in that section. Then you simply return the array count instead of some predetermined variable.

Getting the TableView Section Title from TableViewCell, swift

I have a TableView with two kind of Cells, both are filled with a CollectionView. In the TableViewController I let them them display with a simple if Statement.
My TableViewController:
import UIKit
import RealmSwift
import Alamofire
import SwiftyJSON
let myGroupLive = DispatchGroup()
let myGroupCommunity = DispatchGroup()
class HomeVTwoTableViewController: UITableViewController {
var headers = ["Live", "Channel1", "ChannelTwo", "Channel3", "Channel4", "Channel5", "Channel6"]
override func viewDidLoad() {
super.viewDidLoad()
DataController().fetchSomeDate(mode: "get")
DataController().fetchSomeOtherData(mode: "get")
}
//MARK: Custom Tableview Headers
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
}
}
//MARK: DataSource Methods
override func numberOfSections(in tableView: UITableView) -> Int {
return headers.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
//Choosing the responsible PrototypCell for the Sections
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
}
}
//Set custom cell height, has to match the CollectionView height
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 {
return 225.0
}
else {
return 120.0
}
}
}
My TableViewCellSmall:
import UIKit
import RealmSwift
var communities: Results<Community>?
class HomeVTwoTableViewCellSmall: UITableViewCell{
#IBOutlet weak var collectionView: UICollectionView!
}
extension HomeVTwoTableViewCellSmall: UICollectionViewDataSource,UICollectionViewDelegate {
//MARK: Datasource Methods
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return (communities?.count)!
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCellSmall", for: indexPath) as? HomeVTwoCollectionViewCellSmall else
{
fatalError("Cell has wrong type")
}
//Here I want my Sorting Statement to make unique content per collection view
//normal approach if no section is asked
let url : String = (communities?[indexPath.row].pictureUri)!
let name :String = (communities?[indexPath.row].communityName)!
cell.titleLbl.text = name
cell.imageView.downloadedFrom(link :"somelink")
return cell
}
//MARK: Delegate Methods
override func layoutSubviews() {
myGroupCommunity.notify(queue: DispatchQueue.main, execute: {
let realm = try! Realm()
communities = realm.objects(Community.self)
self.collectionView.dataSource = self
self.collectionView.delegate = self
})
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
do something
}
}
My Problem is now, I want the "Channel Cells" to fill with customized and different data, in the CollectionView. That means I need some sort of key to get the right data in the right cell. My approach would be to take the SectionHeader Title, but for some reasons I cant access it from the TableViewCellSmall. So I have all the data in all the Cells and cant sort them without my Key.
Thanks in Advance.
from what I understand you need to fill the collectionview of each cell with different contents and for this needs to identify the cell?
If so, I used the method below that helped me, you can try.
If in doubt let me know so I can help, I hope I have helped :)
//TableViewCell Add
var didCollectionViewCellSelect: ((Int) -> Void)?
override func setSelected(_ selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
//TabelView Add
class myClass: UITableViewController
{
var storedOffsets = [Int: CGFloat]()
override func viewDidLoad()
{
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
guard let tableViewCell = cell as? myTableViewCell else { return }
let secao = indexPath.section*1000 //Section
let linha = indexPath.row //Row
let posicao = secao+linha
tableViewCell.setCollectionViewDataSourceDelegate(self, forRow: posicao)
tableViewCell.collectionViewOffset = storedOffsets[posicao] ?? 0
}
override func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
guard let tableViewCell = cell as? myTableViewCell else { return }
let secao = indexPath.section*1000 //Section
let linha = indexPath.row //Row
let posicao = secao+linha
storedOffsets[posicao] = tableViewCell.collectionViewOffset
}
}
//CollectionView
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
let posicao = collectionView.tag
let secao = Int(collectionView.tag/1000) //Section
let linha = posicao-(secao*1000) //Row
var qtd = 0
if secao == 0 && arrStation.count > 0
{
qtd = arrStation.count
}
return qtd
}

Collectionview in a TableView - How to select item?

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
}

Resources