When searchbar is cancelled, selected row is changing - swift

I created a collection view with search bar. Rows are selectable on this collection view. Search bar is working perfectly when I search something and when I select a row. However when I clicked cancel button of search bar, the selected row is changing. For example, there are 3 row on the collection view. All of them are selectable. I'm searching for 3rd row and I'm selecting it. After the selecting this 3rd row, if I click to cancel button of search bar, selected row is changing and 1st row is being selected row. How can I handle with this issue?
import UIKit
class CollectionViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UISearchControllerDelegate, UISearchBarDelegate {
#IBOutlet weak var collectionView: UICollectionView!
let searchController = UISearchController(searchResultsController: nil)
var things = [Things]()
var filteredThings = [Things]()
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
CollectionViewController.instance = self
things = [
Things(name: "1", imageName: "firstImage", including: false),
Things(name: "2", imageName: "secondImage", including: false),
Things(name: "3", imageName: "thirdImage", including: false)
]
// Setup the Search Controller
self.searchController.searchResultsUpdater = self
self.searchController.delegate = self
self.searchController.searchBar.delegate = self
self.searchController.hidesNavigationBarDuringPresentation = false
self.searchController.dimsBackgroundDuringPresentation = true
self.searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Search for tools and resources"
searchController.searchBar.sizeToFit()
searchController.searchBar.becomeFirstResponder()
self.navigationItem.titleView = searchController.searchBar
definesPresentationContext = true
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if isFiltering() {
return filteredThings.count
}
return things.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "customCell", for: indexPath) as! CustomCollectionViewCell
let thing: Thing
if isFiltering() {
thing = filteredThings[indexPath.row]
} else {
thing = things[indexPath.row]
}
cell.imageView.image = UIImage(named: thing.imageName)
cell.labelView.text = thing.name
cell.layer.cornerRadius = 7
cell.imageView.layer.cornerRadius = 7
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
var thing: Things
if isFiltering() {
thing = filteredThings[indexPath.row]
} else {
thing = things[indexPath.row]
}
cell?.layer.cornerRadius = 5
cell?.layer.borderWidth = 3
cell?.layer.borderColor = myGreenTabBarColor.cgColor
thing.including = true
print(thing.name)
print(thing.including)
collectionView.allowsMultipleSelection = true
print("This cell is selected")
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
var thing: Things
if isFiltering() {
thing = filteredThings[indexPath.row]
} else {
thing = things[indexPath.row]
}
cell?.layer.cornerRadius = 5
cell?.layer.borderWidth = 3
cell?.layer.borderColor = UIColor.white.cgColor
thing.including = false
print(thing.including)
collectionView.allowsMultipleSelection = true
print("This cell is Deselected")
}
func searchBarIsEmpty() -> Bool {
// Returns true if the text is empty or nil
return searchController.searchBar.text?.isEmpty ?? true
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
self.dismiss(animated: true, completion: nil)
collectionView.reloadData()
}
func filterContentForSearchText(_ searchText: String, scope: String = "All") {
filteredThings = things.filter({( thing : Things) -> Bool in
return thing.name.lowercased().contains(searchText.lowercased())
})
collectionView.reloadData()
}
func isFiltering() -> Bool {
return searchController.isActive && !searchBarIsEmpty()
}
}
extension CollectionViewController: UISearchResultsUpdating {
// MARK: - UISearchResultsUpdating Delegate
func updateSearchResults(for searchController: UISearchController) {
// TODO
filterContentForSearchText(searchController.searchBar.text!)
}
}

Ok, you have 3 rows ("a" , "b", "c")
Then you search for "c"
Now you have 1 row in table with "c"
This row has Indexpath(section = 0, row = 0)
Now you select row with Indexpath(section = 0, row = 0)
cancel search - again 3 rows
And the selected row is the row with Indexpath(section = 0, row = 0). Guess what item is this? ( "a" )
I suppose you should store selected items not indexpaths and make cells selected in cellforrow method

Related

Adding a Second CollectionView

In my attempt to add a second CollectionView I have became lost. Here is my future project and I was essentially trying to duplicate that (The reason for the Second collectionView is so that I will have 4 rows, but the top two and bottom two will scroll independently).
Here is the storyboard for reference.
I however get this error here (Second Photo): here
Here is my code for the originally ViewController (WORKING)
Followed by the SecondViewController code, which has caused the app to display the message above.
import UIKit
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet var collectionViewButtons: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
collectionViewButtons.delegate = self
collectionViewButtons.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 6 //number of buttons
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! ButtonCollectionViewCell
cell.buttonLive.setTitle("Handling a Breakup", for: .normal) //set button title
cell.buttonLive.titleLabel!.font = UIFont(name: "Marker Felt", size: 20)
cell.buttonLive.layer.cornerRadius = 10
cell.buttonLive.clipsToBounds = true
cell.buttonLive.layer.borderWidth = 1.0
cell.buttonLive.layer.borderColor = UIColor.white.cgColor
if indexPath.item == 0 { //first button
cell.buttonLive.backgroundColor = UIColor.darkGray //set button background
}
else if indexPath.item == 1 { //second button
cell.buttonLive.backgroundColor = UIColor.systemGray
cell.buttonLive.setTitle("Good Work", for: .normal)
}
else if indexPath.item == 2 { //3rd button
cell.buttonLive.backgroundColor = UIColor.darkGray
}
else { // for remaining buttons
cell.buttonLive.backgroundColor = UIColor.darkGray
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.item == 0 { // opens any page by clicking button 1
// let vc = storyboard?.instantiateViewController(withIdentifier: "anyVC1") as! ViewController1
// navigationController?.pushViewController(vc, animated: true)
// }
// else if indexPath.item == 1 {
// let vc = storyboard?.instantiateViewController(withIdentifier: "anyVC2") as! ViewController2
// navigationController?.pushViewController(vc, animated: true)
}
// else if indexPath.item == 2 {
// let vc = storyboard?.instantiateViewController(withIdentifier: "anyVC3") as! ViewController3
// navigationController?.pushViewController(vc, animated: true)
}
// else {
// let vc = storyboard?.instantiateViewController(withIdentifier: "anyVC4") as! ViewController4
// navigationController?.pushViewController(vc, animated: true)
}
// }
//}
// You can return any number of buttons by changing return 6 to any required num
SECOND VIEW CONTROLLER:
import UIKit
class SecondViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 6 //number of buttons
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let SecondCell = collectionView.dequeueReusableCell(withReuseIdentifier: "SecondCell", for: indexPath) as! ButtonCollectionViewCell
SecondCell.buttonTwo.setTitle("Handling a Breakup", for: .normal) //set button title
SecondCell.buttonLive.titleLabel!.font = UIFont(name: "Marker Felt", size: 20)
SecondCell.buttonTwo.layer.cornerRadius = 10
SecondCell.buttonTwo.clipsToBounds = true
SecondCell.buttonTwo.layer.borderWidth = 1.0
SecondCell.buttonTwo.layer.borderColor = UIColor.white.cgColor
if indexPath.item == 0 { //first button
SecondCell.buttonTwo.backgroundColor = UIColor.darkGray //set button background
}
else if indexPath.item == 1 { //second button
SecondCell.buttonTwo.backgroundColor = UIColor.systemGray
SecondCell.buttonTwo.setTitle("Good Work", for: .normal)
}
else if indexPath.item == 2 { //3rd button
SecondCell.buttonTwo.backgroundColor = UIColor.darkGray
}
else { // for remaining buttons
SecondCell.buttonTwo.backgroundColor = UIColor.darkGray
}
return SecondCell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.item == 0 { // opens any page by clicking button 1
// let vc = storyboard?.instantiateViewController(withIdentifier: "anyVC1") as! ViewController1
// navigationController?.pushViewController(vc, animated: true)
// }
// else if indexPath.item == 1 {
// let vc = storyboard?.instantiateViewController(withIdentifier: "anyVC2") as! ViewController2
// navigationController?.pushViewController(vc, animated: true)
}
// else if indexPath.item == 2 {
// let vc = storyboard?.instantiateViewController(withIdentifier: "anyVC3") as! ViewController3
// navigationController?.pushViewController(vc, animated: true)
}
// else {
// let vc = storyboard?.instantiateViewController(withIdentifier: "anyVC4") as! ViewController4
// navigationController?.pushViewController(vc, animated: true)
}
// }
//}
// You can return any number of buttons by changing return 6 to any required num
Notes:
I have also gone through and done the following to no success:
Changed all "collectionView" writings to say "SecondCollection" because that is what my second collectionView is named.
I have set a Collection IBOutlet for both collectionView.
I have set a separate IBOutlet for both buttons.
If you want two (or more) collection views, you don't want two controllers... you need to check which collection view is requesting data (or being interacted with) and return the appropriate information.
So, your class will look something like this:
class TwoCollectionsViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet var firstCV: UICollectionView!
#IBOutlet var secondCV: UICollectionView!
let firstData: [String] = [
"Btn 1", "Btn 2", "Btn 3", "Btn 4", "Btn 5",
]
let secondData: [String] = [
"Second 1", "Second 2", "Second 3", "Second 4"
]
override func viewDidLoad() {
super.viewDidLoad()
firstCV.dataSource = self
firstCV.delegate = self
secondCV.dataSource = self
secondCV.delegate = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// if it's the First Collection View
if collectionView == firstCV {
return firstData.count
}
// it's not the First Collection View, so it's the Second one
return secondData.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// if it's the First Collection View
if collectionView == firstCV {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "firstCell", for: indexPath) as! FirstCollectionViewCell
cell.buttonOne.setTitle(firstData[indexPath.item], for: [])
return cell
}
// it's not the First Collection View, so it's the Second one
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "secondCell", for: indexPath) as! SecondCollectionViewCell
cell.buttonTwo.setTitle(secondData[indexPath.item], for: [])
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// if it's the First Collection View
if collectionView == firstCV {
// do what you want because a cell in the First Collection View was selected
return
}
// it's not the First Collection View, so it's the Second one
// do what you want because a cell in the Second Collection View was selected
}
}

How to reload Section in UICollection view

So i'm trying to implement a searchbar to search over different categories. After looking online a bit, I took a tutorial for UITableView and adapted it to my UICollectionView.
The searching works fine, as I am able to print the search results which go into the filteredCategories array.
Where I am having trouble is reloading the UICollectionView using the new filteredCategories array. I tried collectionView.reloadData() as well as collectionView.reloadSections(NSIndexSet(index: 1) as IndexSet) but with no success.
It seems as if the values are passed only once when the section is being built, and that I cannot change it.
Here is my code:
import UIKit
class ViewController: UIViewController {
var collectionView: UICollectionView!
let categories: [String] = ["Technology", "Science", "Entertainment", "Business", "Health", "Sports"]
var filteredCategories: [String] = ["none"]
var count = 0
var filteredCount = 6
var ready: [String] = ["none"]
var readyCount = 0
func filterIt() {
if isFiltering {
ready = filteredCategories
readyCount = filteredCategories.count
} else {
ready = categories
readyCount = categories.count
}
print("second", ready)
}
lazy var sections: [Section] = [
TitleSection(title: "NewsStand"),
// SearchSection(),
BasicGridSection(categories: ready, count: readyCount)
]
lazy var collectionViewLayout: UICollectionViewLayout = {
var sections = self.sections
let layout = UICollectionViewCompositionalLayout { (sectionIndex, environment) -> NSCollectionLayoutSection? in
return sections[sectionIndex].layoutSection()
}
return layout
}()
let searchController = UISearchController(searchResultsController: nil)
var isSearchBarEmpty: Bool {
return searchController.searchBar.text?.isEmpty ?? true
}
func filterContentForSearchText(_ searchText: String) {
filteredCategories = categories.filter { (category: String) -> Bool in
print("filtered", filteredCategories)
return category.lowercased().contains(searchText.lowercased())
}
filterIt()
collectionView.reloadData()
setupCollectionView()
collectionView.reloadSections(NSIndexSet(index: 1) as IndexSet)
}
var isFiltering: Bool {
return searchController.isActive && !isSearchBarEmpty
}
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Compositional Layout"
self.view.backgroundColor = UIColor.white
self.title = "NewsStand"
setupCollectionView()
filterIt()
// 1
searchController.searchResultsUpdater = self
// 2
searchController.obscuresBackgroundDuringPresentation = false
// 3
searchController.searchBar.placeholder = "Search"
// 4
navigationItem.searchController = searchController
// 5
definesPresentationContext = true
}
func setupCollectionView() {
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: collectionViewLayout)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.backgroundColor = UIColor.white
collectionView.register(UINib(nibName: "TitleCell", bundle: .main), forCellWithReuseIdentifier: TitleCell.identifier)
collectionView.register(UINib(nibName: "GridCell", bundle: .main), forCellWithReuseIdentifier: GridCell.identifier)
collectionView.register(UINib(nibName: "SearchCell", bundle: .main), forCellWithReuseIdentifier: SearchCell.identifier)
self.view.addSubview(collectionView)
collectionView.reloadData()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
collectionView.reloadData()
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
collectionView.reloadData()
}
}
extension ViewController: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
sections.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
sections[section].numberOfItems
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
sections[indexPath.section].configureCell(collectionView: collectionView, indexPath: indexPath)
}
}
extension ViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let articlesView = storyboard?.instantiateViewController(withIdentifier: "articleViewController") as? ArticleViewController else {
print("error")
return
}
// set the post id for the comments
articlesView.set(index: indexPath.item)
// present(articlesView, animated: true, completion: nil)
self.navigationController!.pushViewController(articlesView, animated: true)
}
}
extension ViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
let searchBar = searchController.searchBar
filterContentForSearchText(searchBar.text!)
}
}
and Section:
struct BasicGridSection: Section {
// TODO: create a constant for the title of the header of type String
var categories: [String]
var numberOfItems: Int
// TODO: create an initializer to set the title
init(categories: [String], count: Int) {
self.categories = categories
self.numberOfItems = count
}
func layoutSection() -> NSCollectionLayoutSection? {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.1), heightDimension: .fractionalHeight(0.8))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(0.4))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 2)
let section = NSCollectionLayoutSection(group: group)
return section
}
func configureCell(collectionView: UICollectionView, indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: GridCell.self), for: indexPath) as? GridCell
cell!.set(label:categories[indexPath.row])
return cell!
}
}
Thanks!

I really don't know why my collectionViewCell disappear

I making a calendar so first I make a array like this [0,0,0,0,1,2,3,4,...,31] by thing.optimize(month: 5). in this array, the reason I make 0 in front of 1,2,3,...,31 is
when I make cell, I'm using an if statement so if cell.text == 0 then I set cell.isHidden = true.
When I select the one cell I reload both of collectionView(collectionView,nextMonthCollectionView) and make round red shape.
When I select another button, a problem occurs,
suddenly the cell disappears. I added a photo of this.
First, this is my code.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var nowMonthName: UILabel!
#IBOutlet weak var nextMonthName: UILabel!
#IBOutlet weak var collectionView: UICollectionView!
#IBOutlet weak var nextMonthCollectionView: UICollectionView!
var thing = realOptimaize()
var selectedIndex : IndexPath?
var items = [UIBarButtonItem]()
var forCollectionViewCount : Int?
var monthData : Array<Int>?
var nextMonthData : Array<Int>?
override func viewDidLoad() {
monthData = thing.optimaize(month: 5)
nextMonthData = thing.optimaize(month: 6)
self.title = String(CalenderBrain.init().curruntYear)
nowMonthName.text = String(CalenderBrain.init().curruntMonthName())
nextMonthName.text = String(CalenderBrain.init().nextMonthName())
self.collectionView.dataSource = self
self.collectionView.delegate = self
self.nextMonthCollectionView.dataSource = self
self.nextMonthCollectionView.delegate = self
self.collectionView.register(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier : "MyCell")
self.nextMonthCollectionView.register(UINib(nibName: "NextMonthCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "MyCell2")
//이해가 잘 안가는 부분!!!
if let layout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout{
layout.minimumInteritemSpacing = -0.2
}
if let layout2 = self.nextMonthCollectionView.collectionViewLayout as? UICollectionViewFlowLayout{
layout2.minimumInteritemSpacing = -0.2
}
}
}
`extension ViewController : UICollectionViewDataSource, UICollectionViewDelegate,` UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == self.nextMonthCollectionView {
forCollectionViewCount = nextMonthData!.count
return forCollectionViewCount!
} else {
forCollectionViewCount = monthData!.count
return forCollectionViewCount!
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { if collectionView == self.nextMonthCollectionView{
let forCollectionViewCell = nextMonthCollectionView.dequeueReusableCell(withReuseIdentifier: "MyCell2", for: indexPath) as! NextMonthCollectionViewCell
// forCollectionViewCell.button.tag = indexPath.item
if nextMonthData![indexPath.row] == 0 {
forCollectionViewCell.isHidden = true
} else {
forCollectionViewCell.Label.text = String(nextMonthData![indexPath.row])
}
return forCollectionViewCell
} else {
let forCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! CollectionViewCell
// forCollectionViewCell.button.tag = indexPath.item + 100
if monthData![indexPath.row] == 0 {
forCollectionViewCell.isHidden = true
} else {
forCollectionViewCell.Label.text = String(monthData![indexPath.row])
}
return forCollectionViewCell
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView == nextMonthCollectionView {
return .init(width: 53.25 , height: 67)
} else{
return .init(width: 53.25 , height: 67)
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView == self.nextMonthCollectionView {
let forCollectionViewCell = collectionView.cellForItem(at: indexPath) as! NextMonthCollectionViewCell
self.collectionView.reloadData()
collectionView.reloadData()
forCollectionViewCell.Label.textColor = .white
forCollectionViewCell.Label2.backgroundColor = .red
forCollectionViewCell.Label2.layer.cornerRadius = 0.5 * forCollectionViewCell.Label2.bounds.size.width
forCollectionViewCell.Label2.clipsToBounds = true
}else{
let forCollectionViewCell = collectionView.cellForItem(at: indexPath) as! CollectionViewCell
self.nextMonthCollectionView.reloadData()
collectionView.reloadData()
forCollectionViewCell.Label.textColor = .white
forCollectionViewCell.Label2.backgroundColor = .red
forCollectionViewCell.Label2.layer.cornerRadius = 0.5 * forCollectionViewCell.Label2.bounds.size.width
forCollectionViewCell.Label2.clipsToBounds = true
}
}
}
and this is my photo. this first photo is before I press any cell.
enter image description here
and this second photo is right after I press 13cell.
I really don't know why this happens.
I searched google looking for this information, but I didn't find an answer.
enter image description here
ps) when I don't use reloadData() function.. I did not get error.. but
I have to use reloadData.. because I have to clean my collectionView and then make a newly selected cell round red cell.
`if nextMonthData![indexPath.row] == 0 {
forCollectionViewCell.isHidden = true
} else {
forCollectionViewCell.isHidden =false
forCollectionViewCell.Label.text = String(nextMonthData![indexPath.row])
}
return forCollectionViewCell
}
`
setting else condition that will solve your problem.
The reason behind it is when collection view dequeuing cell may be that cell is already hidden that's why its disappearing.

How can I set my DropDelegate and DragDelegate for my TableView nested in my CollectionView?

I have been working at this for a while. I am not sure if it is the best approach but I have created a collectionView with a custom UICollectionViewCell to include a tableView within. So far everything is working fine, but now I am trying to add drag interaction but can't seem to get that working.
I am trying to achieve having a interactive tableView within each CollectionViewCell if that is possible.
I did try to set my delegates here but it gave me:
Cannot assign value of type 'CommodityCropCardCell' to type 'UITableViewDropDelegate?'
Here is my UICollectionViewCell Code (CommodityCropCardCell):
class CommodityCropCardCell : UICollectionViewCell {
static var identifier : String = "CommodityCropCardCell"
weak var cropCardTableView : UITableView!
var cropItems : [cropCardInputs]!
override init(frame:CGRect){
super.init(frame:frame)
let cropCards = UITableView()
let cropItems : [cropCardInputs] = []
self.contentView.addSubview(cropCards)
self.cropCardTableView = cropCards
self.cropItems = cropItems
cropCards.dataSource = self
cropCards.delegate = self
// cropCards.dragInteractionEnabled = true
// cropCards.dragDelegate = self
// cropCards.dropDelegate = self
cropCards.register(cropCardsCell.self, forCellReuseIdentifier: "cropCardsCell")
cropCards.reloadData()
cropCards.dragInteractionEnabled = true
casesLabel.isHidden = true
self.reset()
}
required init?(coder: NSCoder) {
fatalError("init code error")
}
override func prepareForReuse() {
super.prepareForReuse()
self.reset()
}
func reset(){
print("resetting")
}
}
Here is my CropCardsViewController : UICollectionViewDataSource:
extension CropCardsViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.data.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionCropCard.dequeueReusableCell(withReuseIdentifier: CommodityCropCardCell.identifier, for: indexPath) as! CommodityCropCardCell
let data = self.data[indexPath.item]
cell.titleLabel.text = data.title
cell.casesLabel.text = "\(data.cases)"
cell.cropItems = data.cards
cell.backgroundColor = .white
cell.layer.cornerRadius = 5.0
cell.layer.masksToBounds = true
return cell
}
}

Swift - Return array data in tableView with custom filter

I have a UITableView within a UIViewController that loads the ranking of users. Having only one ranking list was a little bit too limited, so I have added a custom bar to load different rankings (weekly, monthly and yearly). The reason why I chose to do it this way is because it gave me a lot of control over my layout constraints - segmented control does not.
The current problem is that I don't exactly know how to return the right array based on the selected tab in my menu bar. As of now I use a fourth empty array to copy the data of one of the other three when the tab is selected, but how do I send this data back to my initial view so that I can return the count in my tableView's numberOfRowsInSection?
ViewController & TableViewController
class Rank: NSObject{
var name: String
var points: Int
init(name: String, points: Int) {
self.name = name
self.points = points
}
}
var rankingArrayWeek = [Rank]()
var rankingArrayMonth = [Rank]()
var rankingArrayTotal = [Rank]()
var filteredRanking = [Rank]()
class RankingController: UIViewController, UITableViewDelegate {
weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
setupMenuBar()
tableView?.delegate = self
rankingArrayWeek = [
Rank(name: "Name1", points: 200)
]
rankingArrayMonth = [
Rank(name: "Name1", points: 300),
Rank(name: "Name2", points: 200),
]
rankingArrayTotal = [
Rank(name: "Name1", points: 500),
Rank(name: "Name2", points: 400),
Rank(name: "Name3", points: 300),
]
let rankingTableViewController = RankingTableViewController()
self.addChildViewController(rankingTableViewController)
rankingTableViewController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(rankingTableViewController.view)
rankingTableViewController.view.topAnchor.constraint(equalTo: view.topAnchor, constant: 50).isActive = true
rankingTableViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 10).isActive = true
rankingTableViewController.view.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
rankingTableViewController.view.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
}
lazy var menuBar: MenuBar = {
let menuBar = MenuBar()
menuBar.rankingController = self
return menuBar
}()
private func setupMenuBar() {
navigationController?.hidesBarsOnSwipe = true
view.addSubview(menuBar)
view.addConstraintsWithFormat("H:|[v0]|", views: menuBar)
view.addConstraintsWithFormat("V:|[v0(50)]", views: menuBar)
}
}
// MARK: TableViewController
class RankingTableViewController: UITableViewController {
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
tableView?.register(RankCell.self, forCellReuseIdentifier: cellId)
tableView?.tableFooterView = UIView(frame: CGRect.zero)
tableView?.rowHeight = 60
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredRanking.count
}
}
My custom menubar
class MenuBar: UIView, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.isScrollEnabled = false
collectionView.backgroundColor = .white
collectionView.dataSource = self
collectionView.delegate = self
return collectionView
}()
let cellId = "cellId"
let names = ["Week", "Month", "Total"]
var rankingController: RankingController?
override init(frame: CGRect) {
super.init(frame: frame)
collectionView.register(MenuCell.self, forCellWithReuseIdentifier: cellId)
addSubview(collectionView)
addConstraintsWithFormat("H:|[v0]|", views: collectionView)
addConstraintsWithFormat("V:|[v0]|", views: collectionView)
let selectedIndexPath = NSIndexPath(item: 2, section: 0)
collectionView.selectItem(at: selectedIndexPath as IndexPath, animated: false, scrollPosition: .centeredHorizontally)
setupHorizontalBar()
}
var horizontalBarLeftAnchorConstraint: NSLayoutConstraint?
func setupHorizontalBar() {
let horizontalBarView = UIView()
horizontalBarView.backgroundColor = Constants.MAIN_THEME_COLOR
horizontalBarView.translatesAutoresizingMaskIntoConstraints = false
addSubview(horizontalBarView)
horizontalBarLeftAnchorConstraint = horizontalBarView.leftAnchor.constraint(equalTo: self.leftAnchor)
horizontalBarLeftAnchorConstraint?.isActive = true
horizontalBarView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
horizontalBarView.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 1/3).isActive = true
horizontalBarView.heightAnchor.constraint(equalToConstant: 4).isActive = true
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let x = CGFloat(indexPath.item) * frame.width / 3
horizontalBarLeftAnchorConstraint?.constant = x
UIView.animate(withDuration: 0.75, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: { self.layoutIfNeeded()
}, completion: nil)
if indexPath.item == 0 {
filteredRanking = rankingArrayWeek
print(filteredRanking.count)
} else if indexPath.item == 1 {
filteredRanking = rankingArrayMonth
print(filteredRanking.count)
} else {
filteredRanking = rankingArrayTotal
print(filteredRanking.count)
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! MenuCell
cell.buttonView.text = "\(names[indexPath.item])"
cell.buttonView.textColor = Constants.MAIN_THEME_COLOR
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: frame.width / 3, height: frame.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}
Updated code:
To preselect the first row, I also added this to my cellForItemAt indexPath:
if (cell.isSelected == false) {
didSelect?(kinds[0])
}
Suggest that you add a callback on your menu bar that says what kind of rank has been selected. You can also use this "Kind" to drive the display of the menu bar.
enum RankKind: String {
case week = "Week"
case month = "Month"
case total = "Total"
}
class MenuBar {
let kinds = [RankKind.week, .month, .total]
var didSelect: ((RankKind)->())?
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return kinds.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
cell.buttonView.text = kinds[indexPath.item].rawValue)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
didSelect?(kinds[indexPath.item])
}
}
Then the RankingController can set itself up to know when the menu has changed kind.
class RankingController {
func viewDidLoad() {
menuBar.didSelect = { kind in
rankingTableViewController.rankingArray = self.rankingArrayFor(kind: kind)
}
}
func rankingArrayFor(kind: RankKind) -> [Rank] {
switch kind {
case .week: return rankingArrayWeek
case .month: return rankingArrayMonth
case .total:return rankingArrayTotal
}
}
}
Lastly, the RankingTableViewController exposes its model (an array), and reloads its tableview when that model is reset.
class RankingTableViewController: UITableViewController {
var rankingArray: [Rank] = [] {
didSet {
self.tableView.reloadData()
}
}
}
The above code is additional to the original question's code existing for brevity, i.e it is not stand alone.