I want to changed tableviewcell's data with XMSegmentedControl(https://github.com/xaviermerino/XMSegmentedControl),
and I using switch in the
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
,but it's always print
fatal error: unexpectedly found nil while unwrapping an Optional value**,and say *segmentedControl1 is nil.
let tin = ["1","2","3","4"]
let how = ["one","two","three","four"]
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var segmentedControl1: XMSegmentedControl!
override func viewDidLoad() {
super.viewDidLoad()
let segmentedControl3 = XMSegmentedControl(frame: CGRect(x: 0, y: 70, width: self.view.frame.width, height: 44), segmentTitle: ["Hello", "World", "Three"], selectedItemHighlightStyle: XMSelectedItemHighlightStyle.topEdge)
segmentedControl3.backgroundColor = UIColor(red: 22/255, green: 150/255, blue: 122/255, alpha: 1)
segmentedControl3.highlightColor = UIColor(red: 25/255, green: 180/255, blue: 145/255, alpha: 1)
segmentedControl3.tint = UIColor.white
segmentedControl3.highlightTint = UIColor.black
self.view.addSubview(segmentedControl3)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var returnValue = 0
switch(segmentedControl1.selectedSegment)
{
case 0 :
returnValue = tin.count
case 1 :
returnValue = how.count
default :
break
}
return returnValue
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
switch(segmentedControl1.selectedSegment)
{
case 0 :
cell.textLabel?.text = tin[indexPath.row]
case 1 :
cell.textLabel?.text = how[indexPath.row]
default :
break
}
return cell
}
Can anyone help me solve this problem?
Thanks!
replace your viewDidLoad() by my code.
override func viewDidLoad() {
super.viewDidLoad()
segmentedControl1 = XMSegmentedControl(frame: CGRect(x: 0, y: 70, width: self.view.frame.width, height: 44), segmentTitle: ["Hello", "World", "Three"], selectedItemHighlightStyle: XMSelectedItemHighlightStyle.topEdge)
segmentedControl1.backgroundColor = UIColor(red: 22/255, green: 150/255, blue: 122/255, alpha: 1)
segmentedControl1.highlightColor = UIColor(red: 25/255, green: 180/255, blue: 145/255, alpha: 1)
segmentedControl1.tint = UIColor.white
segmentedControl1.highlightTint = UIColor.black
self.view.addSubview(segmentedControl1)
}
put into valuechenged method of segmentControl
DispatchQueue.main.async{
self.ttblView.reloadData()
}
You have applied wrong segmentControl . You put value in segmentedControl3 so segmentedControl1 gives nil .
Related
I'm showing the data on tableview with multiple section,
when I open tableView height of section 1 should be 0. If I click a button in section 0 the height of the section 1 will be 150. For example if I click Agent button height of (want to) section cell show 150,I click builder button section hight will 0
I want to make the Section 1 visible on the button click from section 0
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath) as! postaddTableViewCell1
cell.ownerButton.addTarget(self, action: #selector(FisrtButtonClick), for: .touchUpInside)
cell.agentButton.addTarget(self, action: #selector(FisrtButtonClick), for: .touchUpInside)
cell.builderButton.addTarget(self, action: #selector(FisrtButtonClick), for: .touchUpInside)
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath) as! postaddTableViewCell2
cell.checkbutton.tag = indexPath.row
cell.checkbutton.addTarget(self, action: #selector(checkbuttonClick) , for: .touchUpInside)
return cell
}
}
#objc func FisrtButtonClick(_ sender :UIButton)
{
let indexPath = IndexPath(row: 0, section: 0)
let cell = TableView.cellForRow(at: indexPath) as? postaddTableViewCell1
print(cell?.agentButton.titleLabel as Any)
if sender.tag == 10
{
cell?.ownerButton.backgroundColor = #colorLiteral(red: 0, green: 0.7254901961, blue: 0.4588235294, alpha: 1)
cell?.agentButton.backgroundColor = #colorLiteral(red: 0.768627451, green: 0.768627451, blue: 0.768627451, alpha: 1)
cell?.builderButton.backgroundColor = #colorLiteral(red: 0.768627451, green: 0.768627451, blue: 0.768627451, alpha: 1)
}else if sender.tag == 11
{
cell?.ownerButton.backgroundColor = #colorLiteral(red: 0.768627451, green: 0.768627451, blue: 0.768627451, alpha: 1)
cell?.agentButton.backgroundColor = #colorLiteral(red: 0, green: 0.7254901961, blue: 0.4588235294, alpha: 1)
cell?.builderButton.backgroundColor = #colorLiteral(red: 0.768627451, green: 0.768627451, blue: 0.768627451, alpha: 1)
} else if sender.tag == 12
{
cell?.ownerButton.backgroundColor = #colorLiteral(red: 0.768627451, green: 0.768627451, blue: 0.768627451, alpha: 1)
cell?.agentButton.backgroundColor = #colorLiteral(red: 0.768627451, green: 0.768627451, blue: 0.768627451, alpha: 1)
cell?.builderButton.backgroundColor = #colorLiteral(red: 0, green: 0.7254901961, blue: 0.4588235294, alpha: 1)
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0
{
return 80
}
if indexPath.section == 1
{
return 0
}
return 80
}
Check if the required button is clicked in the FisrtButtonClick method and set a boolean that is accessible to heightForRowAt. After toggling the boolean you can just reload the section you require (also cleaned up your code lil bit).
var selectedAgent = false
#objc func firstButtonClick(_ sender: UIButton) {
if sender.currentTitle == "Agent" {
selectedAgent = true
tableView.reloadSections([1], with: .automatic)
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 1 && !selectedAgent {
return 0
}
return 80
}
I'm having issue with completion handler using generic function, it seems that it won't pass anything on the UITableView, unless I will put some break point on it, please check my code below:
public func requestGenericData<T: Decodable>(urlString: String, httpMethod: String?, token: String!, completion: #escaping(T) ->()) {
let fullStringUrl = url + urlString
guard let url = URL(string: fullStringUrl) else { return }
guard let token = token else { return }
var urlRequest = URLRequest(url: url)
urlRequest.setValue("application/json", forHTTPHeaderField: "accept")
urlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
urlRequest.httpMethod = httpMethod
URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
if self.isInternetAvailable() {
guard let data = data else { return }
if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode >= 200 && httpResponse.statusCode < 300 {
do {
let obj = try JSONDecoder().decode(T.self, from: data)
completion(obj)
} catch {
print("Error: \(String(describing: error))\n StatusCode: \(httpResponse.statusCode)")
}
}
}
} else {
showAlert(title: "No Internet Connect", message: "Please open your network and try again.", alertStyle: .alert, buttonTitle: "OK", buttonStyle: .default)
return
}
}.resume()
}
and this is the function that will show the list of of it's result in the table view code below:
func listOfServicesMenus() {
var jobsInCategory = [String]()
apiHelper.requestGenericData(urlString: "nothing/more/than/a/noob", httpMethod: "GET", token: token) { (noobs: Noobs) in
for job in jobs.jobCategories {
jobsInCategory.append(job.name)
for jobDetails in job.getJobs {
jobsInCategory.append(jobDetails.name)
}
}
self.listOfServices.dropView.dropDownOptions = jobsInCategory
}
}
New to swift and developing iOS, it seems that when ever I put break point on it seems working fine, how ever when not, it doesn't show anything?
Does anyone any idea on how to implement a proper completion handler with generics or do I missed something on it when try to write this code?
Thanks for those who are helping me out of this.
Update
I created a so called DropDownMenu using UIView, UITableViewDelegate, UITableViewDataSource, UITableView (which is created under the UIView for proper handling of constraints).
Update 2
Added implementation of UITableView(under UIView)
class dropDownView: UIView, UITableViewDelegate, UITableViewDataSource {
var dropDownOptions = [String]()
var tableView = UITableView()
var delegate: DropDownDelegate!
override init(frame: CGRect) {
super.init(frame: frame)
self.layer.backgroundColor = UIColor.clear.cgColor
self.backgroundColor = UIColor.clear
tableView.delegate = self
tableView.dataSource = self
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.layer.cornerRadius = 10
tableView.backgroundColor = UIColor(displayP3Red: 166/255, green: 203/255, blue: 69/255, alpha: 1.0)
self.addSubview(tableView)
tableView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let cell = UITableViewCell()
cell.contentView.backgroundColor = UIColor.clear
return dropDownOptions.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = dropDownOptions[indexPath.row]
cell.textLabel?.textColor = UIColor(displayP3Red: 166/255, green: 203/255, blue: 69/255, alpha: 1.0)
cell.layer.borderColor = UIColor(displayP3Red: 112/255, green: 112/255, blue: 112/255, alpha: 1.0).cgColor
cell.backgroundColor = UIColor(displayP3Red: 254/255, green: 252/255, blue: 215/255, alpha: 1.0)
cell.selectionStyle = .none
cell.textLabel?.textAlignment = .center
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedCell: UITableViewCell = tableView.cellForRow(at: indexPath)!
selectedCell.contentView.backgroundColor = UIColor(displayP3Red: 133/255, green: 178/255, blue: 56/255, alpha: 1.0)
selectedCell.textLabel?.textColor = UIColor.white
self.delegate.dropDownPressed(string: self.dropDownOptions[indexPath.row])
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cellToDeSelect:UITableViewCell = tableView.cellForRow(at: (indexPath))!
cellToDeSelect.contentView.layer.borderColor = UIColor(displayP3Red: 112/255, green: 112/255, blue: 112/255, alpha: 1.0).cgColor
cellToDeSelect.contentView.backgroundColor = UIColor(displayP3Red: 254/255, green: 252/255, blue: 215/255, alpha: 1.0)
cellToDeSelect.textLabel?.textColor = UIColor(displayP3Red: 166/255, green: 203/255, blue: 69/255, alpha: 1.0)
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.contentView.backgroundColor = UIColor.clear
}
Thanks to you Anil Varghese, created another function that will reload data under the dropDownView class and added this line of code:
func reloadData() {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
I am creating a seat layout and want to get the coordinates from the view controller class in the form of array using delegate but I am getting nil from the view controller while passing the coordinates and getting this error.
Here is my view controller
import UIKit
class BookViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UITableViewDelegate, UITableViewDataSource, SeatMapDelegate {
#IBOutlet weak var dropButton: UIButton!
#IBOutlet weak var dropDownOutlet: UITableView!
#IBOutlet weak var seatMapCollection: UICollectionView!
#IBOutlet weak var dateSelecterCollection: UICollectionView!
#IBOutlet weak var timeSelecterCollection: UICollectionView!
var selectedIndexPath: IndexPath!
var dateValue = ["1","2","3","4","10","6","7","8","9","5"]
var dayValue = ["Mon","Tue","Wed","Thu","Thu","Thu","Thu","Thu","Thu","Thu"]
var month = ["jan","feb","mar","apr","Thu","Thu","Thu","Thu","Thu","Thu"]
var venue = ["Smart Cinemaz, Rupnagar","Smart Cinemaz, Fatehgarh Sahib "]
var numberSection:Int = 10
var numberOfItems:Int = 15
var seatNumber = [Int]()
var columns = [[Int]]()
var rows = [[Int]]()
var col = [2,3]
var rowno = [8,9,16]
var col1 = [5,6,7,8,9,11,12]
var rowno1 = [9]
var sectionHeader: Array<Int> = [0,4,10]
var sectionHeading = ["Gold (₹180.00)","Silver (₹150.00)","Bronze (₹100.00)"]
var rowValue = ["A","B","C","D","E","F","G","H","I","J"]
var kCounter: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
self.seatMapCollection.dataSource = self
self.seatMapCollection.delegate = self
self.seatMapCollection.reloadData()
self.seatMapCollection.maximumZoomScale = 2
self.seatMapCollection.minimumZoomScale = 0.50
self.view.sendSubview(toBack: seatMapCollection)
seatMapCollection.register(UINib(nibName: "HeaderMulticolumn", bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "Header")
for seat in 0...numberOfItems-1{
seatNumber.append(seat + 1)
}
self.dateSelecterCollection.dataSource = self
self.dateSelecterCollection.delegate = self
self.timeSelecterCollection.dataSource = self
self.timeSelecterCollection.delegate = self
self.dropDownOutlet.delegate = self
self.dropDownOutlet.dataSource = self
dropButton.contentHorizontalAlignment = .left
/* let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(pinchAction(sender:)))
seatMapCollection.addGestureRecognizer(pinchGesture)*/
columns.append(col)
columns.append(col1)
rows.append(rowno)
rows.append(rowno1)
}
#IBAction func dropDown(_ sender: Any) {
self.view.bringSubview(toFront: dropDownOutlet)
if dropDownOutlet.isHidden == true{
dropDownOutlet.isHidden = false
}else {
dropDownOutlet.isHidden = true
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView.tag == 1{
return 1
}else if collectionView.tag == 2{
return 1
}else{
return 15 + 2
}
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
if collectionView.tag == 1{
return 7
}else if collectionView.tag == 2{
return 5
}
else{
return 10 + 3
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView.tag == 1 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DateSelecterCollectionViewCell", for: indexPath) as! DateSelecterCollectionViewCell
if (self.selectedIndexPath != nil && indexPath == self.selectedIndexPath){
cell.backgroundColor = UIColor.yellow
cell.dateOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.monthOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.dayOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
}
else{
cell.backgroundColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.dateOutlet.textColor = UIColor.white
cell.monthOutlet.textColor = UIColor.white
cell.dayOutlet.textColor = UIColor.white
}
return cell
}else if collectionView.tag == 2{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TimeSelecterCollectionViewCell", for: indexPath) as! TimeSelecterCollectionViewCell
if (self.selectedIndexPath != nil && indexPath == self.selectedIndexPath){
cell.backgroundColor = UIColor.yellow
cell.timeOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
}
else{
cell.backgroundColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.timeOutlet.textColor = UIColor.white
}
return cell
}
else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SeatMapCollectionViewCell", for: indexPath) as! SeatMapCollectionViewCell
cell.seatImage.isHidden = false
cell.seatImage.image = UIImage(named: "available")
for r1 in 0...rows.count-1{
for c1 in 0...columns.count-1{
if (r1 == c1){
for colum in 0...columns[c1].count-1 {
for ro in 0...rows[r1].count-1{
if indexPath.row == rows[r1][ro] && indexPath.section == columns[c1][colum]{
cell.isHidden = true
}
}
}
}
}
}
for i in 0...collectionView.numberOfSections-1{
for j in 0...sectionHeader.count-1{
// for k in 0...rowValue.count-1{
if indexPath.section != sectionHeader[j] && indexPath.row == 1{
cell.seatImage.isHidden=true
}
if indexPath.section != sectionHeader[j] && indexPath.row == 0 {
cell.seatDetail.isHidden = false
cell.seatDetail.text = rowValue[kCounter]
cell.seatDetail.textColor = UIColor.white
cell.seatImage.isHidden = true
}
if kCounter<rowValue.count-1{
kCounter=kCounter+1
}
// }
}
}
for i in 0...sectionHeader.count-1{
if indexPath.section==sectionHeader[i] && indexPath.row==0{
cell.seatDetail.isHidden=false
cell.seatDetail.text = sectionHeading[i]
cell.seatDetail.textColor = UIColor.white
cell.seatImage.isHidden = true
}
}
return cell
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView.tag == 1{
let cell = collectionView.cellForItem(at: indexPath) as! DateSelecterCollectionViewCell
if cell.isSelected == true{
cell.backgroundColor = UIColor.yellow
cell.dateOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.monthOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.dayOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
}
self.selectedIndexPath = indexPath
}else if collectionView.tag == 2 {
let cell = collectionView.cellForItem(at: indexPath) as! TimeSelecterCollectionViewCell
self.selectedIndexPath = nil
cell.backgroundColor = UIColor.yellow
cell.timeOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
}
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
if collectionView.tag == 1{
let cell = collectionView.cellForItem(at: indexPath) as! DateSelecterCollectionViewCell
self.selectedIndexPath = nil
cell.backgroundColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.dateOutlet.textColor = UIColor.white
cell.monthOutlet.textColor = UIColor.white
cell.dayOutlet.textColor = UIColor.white
}
else if collectionView.tag == 2{
let cell = collectionView.cellForItem(at: indexPath) as! TimeSelecterCollectionViewCell
self.selectedIndexPath = nil
cell.backgroundColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.timeOutlet.textColor = UIColor.white
}
}
/* #objc func pinchAction(sender:UIPinchGestureRecognizer){
var scaleValue: CGFloat!
if sender.state == .changed || sender.state == .began {
if scaleValue == nil{
seatMapCollection.transform = CGAffineTransform.init(scaleX: sender.scale, y: sender.scale)
scaleValue = sender.scale
}else{
seatMapCollection.transform = CGAffineTransform.init(scaleX: scaleValue, y: scaleValue)
}
}
}*/
//
//
//
// Drop Down Section
//
//
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return venue.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DropDownTableViewCell") as! DropDownTableViewCell
cell.venueDetails.text = "\(venue[indexPath.row])"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! DropDownTableViewCell
dropButton.setTitle(cell.venueDetails.text, for: .normal)
tableView.isHidden = true
}
func getSectionCoordinates() -> Array<Int> {
return sectionHeader
}
}
And here is my custom collection view class:
import UIKit
protocol SeatMapDelegate: class {
func getSectionCoordinates() -> Array<Int>
}
class CustomCollectionViewLayout: UICollectionViewLayout {
var delegate: SeatMapDelegate?
var CELL_HEIGHT = 20.0
var CELL_WIDTH = 20.0
let STATUS_BAR = UIApplication.shared.statusBarFrame.height
var cache = [UICollectionViewLayoutAttributes]()
var contentSize = CGSize.zero
var cellAttrsDictionary = [UICollectionViewLayoutAttributes]()
var cellPadding = 2.0
var sectionHeader1: Array<Int>!
var sectionHeader = [0,4,9]
override var collectionViewContentSize: CGSize{
return self.contentSize
}
var interItemsSpacing: CGFloat = 8
// 5
var contentInsets: UIEdgeInsets {
return collectionView!.contentInset
}
override func prepare() {
var counts: Int = 0
sectionHeader1=(delegate?.getSectionCoordinates())!
// Cycle through each section of the data source.
if collectionView!.numberOfSections > 0 {
for section in 0...collectionView!.numberOfSections-1 {
// Cycle through each item in the section.
if collectionView!.numberOfItems(inSection: section) > 0 {
for item in 0...collectionView!.numberOfItems(inSection: section)-1 {
// Build the UICollectionVieLayoutAttributes for the cell.
let cellIndex = NSIndexPath(item: item, section: section)
/* let width: Double = 35.0
let height: Double = 35.0
CELL_WIDTH = (delegate?.collectionView(Width: width))!
CELL_HEIGHT = (delegate?.collectionView(Height: height))!*/
if counts<sectionHeader1.count {
if item == 0 && section == sectionHeader1[counts]{
let xPos = 0.0
let yPos = Double(section) * CELL_HEIGHT
let frame = CGRect(x: xPos, y: yPos, width: 15 * CELL_WIDTH, height: CELL_HEIGHT)
let cellFinalAttribute = frame.insetBy(dx:CGFloat(cellPadding) ,dy:CGFloat(cellPadding))
let cellAttributes = UICollectionViewLayoutAttributes(forCellWith: cellIndex as IndexPath)
cellAttributes.frame = cellFinalAttribute
//cellAttributes.frame = CGRect(x: xPos, y: yPos, width: CELL_WIDTH, height: CELL_HEIGHT)
cellAttrsDictionary.append(cellAttributes)
counts=counts+1
break
}
}
let xPos = Double(item) * CELL_WIDTH
let yPos = Double(section) * CELL_HEIGHT
let frame = CGRect(x: xPos, y: yPos, width: CELL_WIDTH, height: CELL_HEIGHT)
let cellFinalAttribute = frame.insetBy(dx:CGFloat(cellPadding) ,dy:CGFloat(cellPadding))
let cellAttributes = UICollectionViewLayoutAttributes(forCellWith: cellIndex as IndexPath)
cellAttributes.frame = cellFinalAttribute
//cellAttributes.frame = CGRect(x: xPos, y: yPos, width: CELL_WIDTH, height: CELL_HEIGHT)
cellAttrsDictionary.append(cellAttributes)
}
}
}
}
// Update content size.
let contentWidth = Double(collectionView!.numberOfItems(inSection: 0)) * CELL_WIDTH
let contentHeight = Double(collectionView!.numberOfSections) * CELL_HEIGHT
self.contentSize = CGSize(width: contentWidth, height: contentHeight)
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
// Create an array to hold all elements found in our current view.
var attributesInRect = [UICollectionViewLayoutAttributes]()
// Check each element to see if it should be returned.
for cellAttributes in cellAttrsDictionary {
if rect.intersects(cellAttributes.frame) {
attributesInRect.append(cellAttributes)
}
}
// Return list of elements.
return attributesInRect
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cellAttrsDictionary[indexPath.row]
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return false
}
}
I am not sure what are you trying to do with that sectionHeader1=(delegate?.getSectionCoordinates())!, but you can't use the delegate like that. In your function onPrepare there is no guarantee that your delegate was already instanced and you are unwrapping it with !, that is when you are getting the exception.
I am trying to create seatMap and I want to hide the image for certain cell, but when i am doing so the image is hiding for other cells randomly not getting the issue. Suppose i hide the image for the 2nd cell the image for 4th cell is also hiding while i scroll horizontally or vertically.
Here is my ViewController Code
import UIKit
class BookViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var dropButton: UIButton!
#IBOutlet weak var dropDownOutlet: UITableView!
#IBOutlet weak var seatMapCollection: UICollectionView!
#IBOutlet weak var dateSelecterCollection: UICollectionView!
#IBOutlet weak var timeSelecterCollection: UICollectionView!
var selectedIndexPath: IndexPath!
var dateValue = ["1","2","3","4","10","6","7","8","9","5"]
var dayValue = ["Mon","Tue","Wed","Thu","Thu","Thu","Thu","Thu","Thu","Thu"]
var month = ["jan","feb","mar","apr","Thu","Thu","Thu","Thu","Thu","Thu"]
var venue = ["Smart Cinemaz, Rupnagar","Smart Cinemaz, Fatehgarh Sahib "]
var numberSection:Int = 10
var numberOfItems:Int = 15
var seatNumber = [Int]()
var columns = [[Int]]()
var rows = [[Int]]()
var col = [2,3]
var rowno = [6,7,14]
var col1 = [5,6,7,8,9,11,12]
var rowno1 = [7]
var sectionHeader = [0,4,10]
override func viewDidLoad() {
super.viewDidLoad()
self.seatMapCollection.dataSource = self
self.seatMapCollection.delegate = self
self.seatMapCollection.reloadData()
self.seatMapCollection.maximumZoomScale = 2
self.seatMapCollection.minimumZoomScale = 0.50
self.view.sendSubview(toBack: seatMapCollection)
seatMapCollection.register(UINib(nibName: "HeaderMulticolumn", bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "Header")
for seat in 0...numberOfItems-1{
seatNumber.append(seat + 1)
}
self.dateSelecterCollection.dataSource = self
self.dateSelecterCollection.delegate = self
self.timeSelecterCollection.dataSource = self
self.timeSelecterCollection.delegate = self
self.dropDownOutlet.delegate = self
self.dropDownOutlet.dataSource = self
dropButton.contentHorizontalAlignment = .left
/* let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(pinchAction(sender:)))
seatMapCollection.addGestureRecognizer(pinchGesture)*/
columns.append(col)
columns.append(col1)
rows.append(rowno)
rows.append(rowno1)
}
#IBAction func dropDown(_ sender: Any) {
self.view.bringSubview(toFront: dropDownOutlet)
if dropDownOutlet.isHidden == true{
dropDownOutlet.isHidden = false
}else {
dropDownOutlet.isHidden = true
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView.tag == 1{
return 1
}else if collectionView.tag == 2{
return 1
}else{
return 15
}
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
if collectionView.tag == 1{
return 7
}else if collectionView.tag == 2{
return 5
}
else{
return 10 + 3
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView.tag == 1 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DateSelecterCollectionViewCell", for: indexPath) as! DateSelecterCollectionViewCell
if (self.selectedIndexPath != nil && indexPath == self.selectedIndexPath){
cell.backgroundColor = UIColor.yellow
cell.dateOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.monthOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.dayOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
}
else{
cell.backgroundColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.dateOutlet.textColor = UIColor.white
cell.monthOutlet.textColor = UIColor.white
cell.dayOutlet.textColor = UIColor.white
}
return cell
}else if collectionView.tag == 2{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TimeSelecterCollectionViewCell", for: indexPath) as! TimeSelecterCollectionViewCell
if (self.selectedIndexPath != nil && indexPath == self.selectedIndexPath){
cell.backgroundColor = UIColor.yellow
cell.timeOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
}
else{
cell.backgroundColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.timeOutlet.textColor = UIColor.white
}
return cell
}
else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SeatMapCollectionViewCell", for: indexPath) as! SeatMapCollectionViewCell
for r1 in 0...rows.count-1{
for c1 in 0...columns.count-1{
if (r1 == c1){
for colum in 0...columns[c1].count-1 {
for ro in 0...rows[r1].count-1{
if indexPath.row == rows[r1][ro] && indexPath.section == columns[c1][colum]{
cell.alpha = 0
}
}
}
}
}
}
for i in 0...sectionHeader.count-1{
if indexPath.section==sectionHeader[i] && indexPath.row==0{
cell.seatDetail.alpha=1
cell.seatDetail.text = "Gold - 180"
cell.seatImage.isHidden = true
}
}
//cell.seatDetail.alpha=0
return cell
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView.tag == 1{
let cell = collectionView.cellForItem(at: indexPath) as! DateSelecterCollectionViewCell
if cell.isSelected == true{
cell.backgroundColor = UIColor.yellow
cell.dateOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.monthOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.dayOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
}
self.selectedIndexPath = indexPath
}else if collectionView.tag == 2 {
let cell = collectionView.cellForItem(at: indexPath) as! TimeSelecterCollectionViewCell
self.selectedIndexPath = nil
cell.backgroundColor = UIColor.yellow
cell.timeOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
}
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
if collectionView.tag == 1{
let cell = collectionView.cellForItem(at: indexPath) as! DateSelecterCollectionViewCell
self.selectedIndexPath = nil
cell.backgroundColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.dateOutlet.textColor = UIColor.white
cell.monthOutlet.textColor = UIColor.white
cell.dayOutlet.textColor = UIColor.white
}
else if collectionView.tag == 2{
let cell = collectionView.cellForItem(at: indexPath) as! TimeSelecterCollectionViewCell
self.selectedIndexPath = nil
cell.backgroundColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.timeOutlet.textColor = UIColor.white
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return venue.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DropDownTableViewCell") as! DropDownTableViewCell
cell.venueDetails.text = "\(venue[indexPath.row])"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! DropDownTableViewCell
dropButton.setTitle(cell.venueDetails.text, for: .normal)
tableView.isHidden = true
}
}
Here is my Custom CollectionViewlayout
import UIKit
protocol SeatMapDelegate:class {
func collectionView(Width: Double)-> Double
func collectionView(Height: Double)-> Double }
class CustomCollectionViewLayout: UICollectionViewLayout {
var delegate: SeatMapDelegate?
var CELL_HEIGHT = 35.0
var CELL_WIDTH = 35.0
let STATUS_BAR = UIApplication.shared.statusBarFrame.height
var cache = [UICollectionViewLayoutAttributes]()
var contentSize = CGSize.zero
var cellAttrsDictionary = [UICollectionViewLayoutAttributes]()
var cellPadding = 5.0
var sectionHeader = [0,4,10]
override var collectionViewContentSize: CGSize{
return self.contentSize
}
var interItemsSpacing: CGFloat = 8
// 5
var contentInsets: UIEdgeInsets {
return collectionView!.contentInset
}
override func prepare() {
var counts: Int = 0
// Cycle through each section of the data source.
if collectionView!.numberOfSections > 0 {
for section in 0...collectionView!.numberOfSections-1 {
// Cycle through each item in the section.
if collectionView!.numberOfItems(inSection: section) > 0 {
for item in 0...collectionView!.numberOfItems(inSection: section)-1 {
// Build the UICollectionVieLayoutAttributes for the cell.
let cellIndex = NSIndexPath(item: item, section: section)
/* let width: Double = 35.0
let height: Double = 35.0
CELL_WIDTH = (delegate?.collectionView(Width: width))!
CELL_HEIGHT = (delegate?.collectionView(Height: height))!*/
if counts<sectionHeader.count {
if item == 0 && section == sectionHeader[counts]{
let xPos = 0.0
let yPos = Double(section) * CELL_HEIGHT
let frame = CGRect(x: xPos, y: yPos, width: 15 * CELL_WIDTH, height: CELL_HEIGHT)
let cellFinalAttribute = frame.insetBy(dx:CGFloat(cellPadding) ,dy:CGFloat(cellPadding))
let cellAttributes = UICollectionViewLayoutAttributes(forCellWith: cellIndex as IndexPath)
cellAttributes.frame = cellFinalAttribute
//cellAttributes.frame = CGRect(x: xPos, y: yPos, width: CELL_WIDTH, height: CELL_HEIGHT)
cellAttrsDictionary.append(cellAttributes)
counts=counts+1
break
}
}
let xPos = Double(item) * CELL_WIDTH
let yPos = Double(section) * CELL_HEIGHT
let frame = CGRect(x: xPos, y: yPos, width: CELL_WIDTH, height: CELL_HEIGHT)
let cellFinalAttribute = frame.insetBy(dx:CGFloat(cellPadding) ,dy:CGFloat(cellPadding))
let cellAttributes = UICollectionViewLayoutAttributes(forCellWith: cellIndex as IndexPath)
cellAttributes.frame = cellFinalAttribute
//cellAttributes.frame = CGRect(x: xPos, y: yPos, width: CELL_WIDTH, height: CELL_HEIGHT)
cellAttrsDictionary.append(cellAttributes)
}
}
}
}
// Update content size.
let contentWidth = Double(collectionView!.numberOfItems(inSection: 0)) * CELL_WIDTH
let contentHeight = Double(collectionView!.numberOfSections) * CELL_HEIGHT
self.contentSize = CGSize(width: contentWidth, height: contentHeight)
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
// Create an array to hold all elements found in our current view.
var attributesInRect = [UICollectionViewLayoutAttributes]()
// Check each element to see if it should be returned.
for cellAttributes in cellAttrsDictionary {
if rect.intersects(cellAttributes.frame) {
attributesInRect.append(cellAttributes)
}
}
// Return list of elements.
return attributesInRect
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cellAttrsDictionary[indexPath.row]
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return false
}
}
Custom CollectionView cell class
import UIKit
class SeatMapCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var seatDetail: UILabel!
#IBOutlet weak var seatImage: UIImageView!
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
func setup() {
//self.layer.borderWidth = 1.0
// self.layer.borderColor = UIColor.gray.cgColor
// self.layer.cornerRadius = 5.0
}}
I am including my code that I have implemented to filter through sortedDiscipline names.
The problem I am having --even though it is filtering through the names-- is after the IndexPath.row is changed from the filtering, the image is incorrect for the current game, and also the cell that is populated cannot be selected because the didSelectRow does not follow the broken IndexPath.
import UIKit
import Foundation
import Alamofire
import SwiftyJSON
import Firebase
import FirebaseDatabase
class AllGamesTableViewController: UITableViewController, UISearchResultsUpdating {
let urlFront = "https://www.toornament.com/disciplines/"
let urlImagePath = "/img/icon-48x48-medium.png"
var selectedRow: Int?
var newArray = [String]()
var filteredGames = [String]()
var searchController: UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
searchController = UISearchController(searchResultsController:nil)
searchController.dimsBackgroundDuringPresentation = true
searchController.searchBar.sizeToFit()
searchController.searchResultsUpdater = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.searchBarStyle = UISearchBarStyle.minimal
// Include the search bar within the navigation bar.
navigationItem.titleView = self.searchController.searchBar
definesPresentationContext = true
tableView.reloadData()
}
override func viewWillAppear(_ animated: Bool) {
tableView.delegate = self
tableView.dataSource = self
tableView.backgroundColor = #colorLiteral(red: 0.1137254902, green: 0.168627451, blue: 0.1764705882, alpha: 1)
self.view.backgroundColor = #colorLiteral(red: 0.1137254902, green: 0.168627451, blue: 0.1764705882, alpha: 1)
self.navigationItem.setHidesBackButton(true, animated: true)
// self.navigationItem.setHidesBackButton(true, animated: true)
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (searchController?.isActive)!{
return filteredGames.count
}else{
return ApiManager.shared.sortedDisipline.count
}
}
let getID = ApiManager.shared.disciplinesID
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "allGamesCell", for: indexPath)
cell.backgroundColor = UIColor(red: 29.0/255.0, green: 43.0/255.0, blue: 45.0/255.0, alpha: 1)
cell.textLabel?.textColor = #colorLiteral(red: 1, green: 0.5763723254, blue: 0, alpha: 1)
let disciplineid = ApiManager.shared.sortedDisciplineID[indexPath.row]
if (searchController?.isActive)!{
cell.textLabel?.text = filteredGames[indexPath.row]
cell.textLabel?.textColor = UIColor(red: 255.0/255.0, green: 165.0/255.0, blue: 0.0/255.0, alpha: 1)
cell.imageView?.image = UIImage(named: "\(disciplineid).png")
}else{
cell.textLabel?.textColor = UIColor(red: 255.0/255.0, green: 165.0/255.0, blue: 0.0/255.0, alpha: 1)
cell.textLabel?.text = ApiManager.shared.sortedDisipline[indexPath.row]
cell.imageView?.image = UIImage(named: "\(disciplineid).png")
}
return cell
}
func updateSearchResults(for searchController: UISearchController) {
filteredGames.removeAll(keepingCapacity: false)
//filter through the all games
filteredGames = ApiManager.shared.sortedDisipline.filter {
game in
game.lowercased().contains(searchController.searchBar.text!.lowercased())
}
// if searchController.searchBar.text != ""{
tableView.reloadData()
}
// }
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if searchController.isActive && searchController.searchBar.text != "" {
print(indexPath.row)
let DisciplineID = filteredGames[indexPath.row]
TournamentStore.shared.currentDisciplineId = DisciplineID
performSegue(withIdentifier: "tournamentList", sender: self)
} else {
let DisciplineID = ApiManager.shared.sortedDisciplineID[indexPath.row]
print("\(DisciplineID) \("did on click")")
TournamentStore.shared.currentDisciplineId = DisciplineID
performSegue(withIdentifier: "tournamentList", sender: self)
}
}
Suggestions to solve the issues.
Do not use separate arrays for disciplinesID and sortedDisipline
Use the class or struct representing discipline for both the data source array and the filteredGames array.
Get the disciplineid always directly from the discipline object. (Solves the image issue)
In didSelectRowAt get the object depending on searchController?.isActive like in the other methods (solves the indexPath issue)
PS: Initialize the search controller lazily and non-optional. That avoids a lot of question and exclamation marks.
Migrated from my comment for more explanation.
The reason your selection is incorrect is in your didSelectRowAt indexPath if you are searching you are not using the filtered list to get the ID. This is also why the image is wrong when reloading, you need to get the ID out of the filtered array if sorting
Something like this:
let id: String
if filtering {
id = filteredGames[indexPath.row]
} else {
id = ApiManager.shared.sortedDisciplineID[indexPath.row])
}
then use that id for the image and for opening it. Essentially when you sort you are changing how the names match up with the row ID's.
Most of my problem was that
searchController.dimsBackgroundDuringPresentation was set to true....it needed to be false.