Access Parent tableViewCell from Child CollectionViewCell - ios

Image Depicting One tableViewCell. Inside One tableViewCell there is some content and One CollectionView(Gray color area showing dates).
Depending on dates in collection view and their scrolling I have to show Year and Month("December 2018" : It is static in image).
This is my JTAppleCalender cellForItemAt method :
func calendar(_ calendar: JTAppleCalendarView, cellForItemAt date: Date, cellState: CellState, indexPath: IndexPath) -> JTAppleCell {
let cell = calendar.dequeueReusableJTAppleCell(withReuseIdentifier: "CalenderCell", for: indexPath) as! CalenderCell
cell.lblDate.text = cellState.text
formatter.dateFormat = "EEE"
cell.lblDay.text = formatter.string(from: cellState.date)
formatter.dateFormat = "MMMM YYYY"
print(formatter.string(from: cellState.date))
formatter.dateFormat = "dd-MM-yyyy"
print(formatter.string(from: cellState.date))
if(pickup_dates .contains(formatter.string(from: cellState.date))){
let index = pickup_dates.index(of: formatter.string(from: cellState.date))
let dictinfoDelivery = self.infoDelivery.object(at: index) as! NSDictionary
cell.lblPrice.text = dictinfoDelivery .value(forKey: "total_price_format") as? String
cell.isUserInteractionEnabled = true
}
else{
cell.lblPrice.text = ""
cell.isUserInteractionEnabled = false
}
return cell
}
I am trying to access tableView label("December 2018") from inside of this method but was unable to do so.
How to access this TableViewCell label from child collectionViewCell?
My Requirement is to Change 2-3 contents in tableViewCell (Price,quantity) wrt Date Selected in Child CollectionView.

please try this
guard let lbl = (self.yourTableView.cellForRow(at: [NSIndexPath(row: 0, section: 0) as IndexPath]) as! yourCellNameInTableView).labelName else {
return
}
lbl.text = "Your text"
Please pass your row number and section number. It may helps to you.Thanks you

Related

Weird behaviour setting tableView row height and scrollPosition Swift

In the same viewController I have a calendarTableViewthat represent the month's days. At cellForRowAti select the row corresponding to current day and call a function to populate timeSlotCollectionView. It all work but I have a little strange situation.
Case 1: Row height = auto and scrollPosition.none = timeSlotCollectionView don't follow cornerRadius
Case2: Row height = auto and scrollPosition.middle = Thread 1: EXC_BAD_ACCESS (code=2, address=0x659ef4) on calendarTableViewcell definition
Case3: Row height = 44 and scrollPosition.none = calendarTableViewcell don't follow cornerRadius
Case 4: Row height = 44 and scrollPosition.middle = calendarTableViewcell don't follow cornerRadius
Case 5: Row height = 60 and scrollPosition.none = calendarTableViewcell DOES follow cornerRadius
Case 6: Row height = 60 and scrollPosition.middle = calendarTableViewcell DON'T follow cornerRadius again..
I wouldn't mind row height of 60, but scrollPositionhas to be.middle or I wouldn't see the current day row..
Can you see what I'm doing wrong? I've searched other posts but I couldn't find anything that gave me a clue on what the problem was.
Many thanks as usual.
This is the calendarTableViewfunction:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "calendarCell", for: indexPath) as! CalendarTableViewCell
// Configure the cell...
let date = datesArray[indexPath.row]
print(date)
let calendar = Calendar.current
let components = calendar.dateComponents([.year, .month, .day, .weekday], from: date)
cell.dayLabel.text = "\(String(describing: components.day!))" + " " + "\(dayNamesArray[components.weekday! - 1])"
cell.cellWeekday = components.weekday!
print("cell weekday is: \(cell.cellWeekday!)") // prints correct weekday
cell.cellId = "\(String(format:"%04d", components.year!))" + "\(String(format:"%02d", components.month!))" + "\(String(format:"%02d", components.day!))"
self.selectedDate = cell.cellId // used for time slots cellId
print("##################### selectedDate in tableview is :\(self.selectedDate) ")
// highlighting current day cell
if indexPath.row == self.actualDay - 1 && self.actualMonth == self.displayedMonth {
cell.dayLabel.backgroundColor = UIColor.red.withAlphaComponent(0.3)
// emulate user selecting the cell
tableView.selectRow(at: indexPath, animated: false, scrollPosition: UITableViewScrollPosition.none) // changing to .middle makes the tableview go looping
print(" ########################## selected cell weekday is: \(cell.cellWeekday!) #################### ")
// self.updateTimeSlots(selectedCell: cell)
// self.actualWeekday = cell.cellWeekday! // nil error
self.selectedDate = cell.cellId
// calculateOpenTimeSlots()
}
// let cornerRadius: CGFloat = 5
// cell.layer.cornerRadius = cornerRadius
// cell.clipsToBounds = true
// self.updateTimeSlots(selectedCell: cell)
return cell
}
I decided not to select the today row but only scroll calendarTableViewto have in that middle position instead. I also declare row height directly in heightForRowAt. calendarTableView now behaves as expected and cell is not directly selected, but highlighted as I actually wanted.
I hope that this will help others.
The final function is:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "calendarCell", for: indexPath) as! CalendarTableViewCell
let cornerRadius: CGFloat = 5
cell.layer.backgroundColor = UIColor.white.cgColor
cell.layer.cornerRadius = cornerRadius
cell.clipsToBounds = true
cell.dayLabel.textColor = UIColor.white
cell.dayLabel.layer.backgroundColor = UIColor.blue.withAlphaComponent(0.3).cgColor
cell.dayLabel.layer.cornerRadius = cornerRadius
cell.dayLabel.clipsToBounds = true
// Configure the cell...
let date = datesArray[indexPath.row]
print(date)
let calendar = Calendar.current
let components = calendar.dateComponents([.year, .month, .day, .weekday], from: date)
cell.dayLabel.text = "\(String(describing: components.day!))" + " " + "\(dayNamesArray[components.weekday! - 1])"
cell.cellWeekday = components.weekday!
print("cell weekday is: \(cell.cellWeekday!)") // prints correct weekday
cell.cellId = "\(String(format:"%04d", components.year!))" + "\(String(format:"%02d", components.month!))" + "\(String(format:"%02d", components.day!))"
self.selectedDate = cell.cellId // used for time slots cellId
print("##################### selectedDate in tableview is :\(self.selectedDate) ")
// highlighting current day cell
if indexPath.row == self.actualDay - 1 && self.actualMonth == self.displayedMonth {
// cell.layer.backgroundColor = UIColor.red.withAlphaComponent(0.3).cgColor
cell.dayLabel.layer.backgroundColor = UIColor.red.withAlphaComponent(0.3).cgColor
// emulate user selecting the cell
// tableView.selectRow(at: indexPath, animated: false, scrollPosition: UITableViewScrollPosition.middle)
tableView.scrollToRow(at: indexPath, at: UITableViewScrollPosition.middle, animated: true)
print(" ########################## selected cell weekday is: \(cell.cellWeekday!) #################### ")
self.updateTimeSlots(selectedCell: cell)
// self.actualWeekday = cell.cellWeekday! // nil error
self.selectedDate = cell.cellId
}
return cell
}

Trying to update a collection view when tableview cell matches a criteria Swift

I have In the same view controller a calendarTableview that represent a month and a timeSlotCollectionView that represent the current day opening time divided in 30 min slots. My intent is that at loading the view controller inside calendarTableview cellForRowAt I check if it's current day and set it as selected, and load the timeSlotCollectionViewwith again a certain criteria. It all works es expected only when I physically select the row, triggering didSelectRowAtbut not on first load. All the updating is done by a function that I call in both cellForRowAtand didSelectRowAt, but on load is not updating timeSlotCollectionView. I had a similar problem in the next stage of my app, when you actually select a time slot and with my previous question has been solved, but I can't apply that in this scenario. Can you see where I'm mistaking this time?
The functions are:
for calendarTableView
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "calendarCell", for: indexPath) as! CalendarTableViewCell
// Configure the cell...
let date = datesArray[indexPath.row]
print(date)
let calendar = Calendar.current
let components = calendar.dateComponents([.year, .month, .day, .weekday], from: date)
cell.dayLabel.text = "\(String(describing: components.day!))" + " " + "\(dayNamesArray[components.weekday! - 1])"
cell.cellWeekday = components.weekday!
print("cell weekday is: \(cell.cellWeekday!)") // prints correct weekday
cell.cellId = "\(String(format:"%04d", components.year!))" + "\(String(format:"%02d", components.month!))" + "\(String(format:"%02d", components.day!))"
self.selectedDate = cell.cellId // used for time slots cellId
// highlighting current day cell
if indexPath.row == self.actualDay - 1 && self.actualMonth == self.displayedMonth {
cell.dayLabel.backgroundColor = UIColor.red.withAlphaComponent(0.3)
// emulate user selecting the cell
tableView.selectRow(at: indexPath, animated: false, scrollPosition: UITableViewScrollPosition.none) // changing to .middle makes the tableview go looping
print(" ########################## selected cell weekday is: \(cell.cellWeekday!) #################### ")
self.updateTimeSlots(selectedCell: cell)
// self.actualWeekday = cell.cellWeekday!
// self.selectedDate = cell.cellId
// calculateOpenTimeSlots()
}
let cornerRadius: CGFloat = 5
cell.layer.cornerRadius = cornerRadius
cell.clipsToBounds = true
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! CalendarTableViewCell
self.updateTimeSlots(selectedCell: cell)
// self.actualWeekday = cell.cellWeekday!
// self.selectedDate = cell.cellId
// print(" selected cell weekday is: \(cell.cellWeekday!)")
// calculateOpenTimeSlots()
}
for timeSlotCollectionView:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "timeSlotCell", for: indexPath) as! TimeSlotCollectionViewCell
// let booking = self.fetchedResultController.object(at: indexPath)
// Configure the cell
cell.timeLabel.text = timeSlotArray[indexPath.row]
cell.cellId = Int64("\(String(describing: self.selectedDate))" + self.timeStringToStringConvert(timeSlotArray[indexPath.row]))!
// method two USING fetchResultController
if (self.fetchedResultController.fetchedObjects?.count)! > 0 {
for value in self.fetchedResultController.fetchedObjects! {
if Int64(value.bookingId!) == cell.cellId {
print(" match found")
print("Index is: \(index)")
print("cell time is: \(timeSlotArray[indexPath.row])")
print("time slot cell id is: \(String(describing: cell.cellId))")
print("booking id: \(bookingId)")
// cell.backgroundColor = UIColor.red.withAlphaComponent(0.8)
cell.bookingState.backgroundColor = UIColor.red.withAlphaComponent(0.8)
}
}
}
print(" cell.cellId is : \(String(describing: cell.cellId!))")
print(" #################################### time slot created ################################ ")
// Method one : USING ARRAY works in realtime
// if bookedTimeSlotsArray.count > 0 {
// for index in 0...bookedTimeSlotsArray.count - 1 {
// let bookingId = bookedTimeSlotsArray[index].bookingId
//
// if cell.cellId == bookingId {
// print(" match found")
// print("Index is: \(index)")
// print("cell time is: \(timeSlotArray[indexPath.row])")
// print("time slot cell id is: \(String(describing: cell.cellId))")
// print("booking id: \(bookingId)")
//// cell.backgroundColor = UIColor.red.withAlphaComponent(0.8)
// cell.bookingState.backgroundColor = UIColor.red.withAlphaComponent(0.8)
// }
// }
// }
return cell
}
and the values updating :
func updateTimeSlots(selectedCell: CalendarTableViewCell) {
self.actualWeekday = selectedCell.cellWeekday!
self.selectedDate = selectedCell.cellId
print(" selected cell weekday is: \(selectedCell.cellWeekday!)")
fetchBookings()
calculateOpenTimeSlots()
}
Can it be a time lag between the cells creation of the two? In my other question this was the case. Many thanks as always.
I found what the problem was. I was refreshing timeSlotCollectionViewin a function that calculated the booked time slots. I guess that there was I little time gap between the array being populated from that function and timeSlotCollectionViewreading from that array to draw its cells, resulting in plain cells. I modified cellForItemAt so I can perform the check for condition directly from fetched results and that way I could bypass that function. Now the correct cell in calendarTableView gets selected and timeSlotCollectionViewgets populated with correct cells.
I hope that this could help others facing the same problem.
This is the new function:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "timeSlotCell", for: indexPath) as! TimeSlotCollectionViewCell
// let booking = self.fetchedResultController.object(at: indexPath)
// Configure the cell
cell.timeLabel.text = timeSlotArray[indexPath.row]
cell.cellTime = timeSlotArray[indexPath.row]
cell.cellId = Int64("\(String(describing: self.selectedDate))" + self.timeStringToStringConvert(timeSlotArray[indexPath.row]))!
// method two USING fetchResultController
if (self.fetchedResultController.fetchedObjects?.count)! > 0 {
for valueStart in self.fetchedResultController.fetchedObjects! {
// booking start match
if timeStringToStringConvert(cell.cellTime) == timeStringToStringConvert(valueStart.bookingStart!) {//} && cell.cellTime <= timeStringToStringConvert(valueStart.bookingEnd!) {
print(" match found")
// print("Index is: \(index)")
print("cell time is: \(timeSlotArray[indexPath.row])")
print("time slot cell id is: \(String(describing: cell.cellId))")
print("booking id: \(valueStart.bookingId!)")
// cell.backgroundColor = UIColor.red.withAlphaComponent(0.8)
cell.bookingState.backgroundColor = UIColor.red.withAlphaComponent(0.8)
cell.backgroundColor = UIColor.red.withAlphaComponent(0.25)
}
else if timeStringToStringConvert(cell.cellTime) > timeStringToStringConvert(valueStart.bookingStart!) && timeStringToStringConvert(cell.cellTime) < timeStringToStringConvert(valueStart.bookingEnd!){
print(" Mid slot found")
print(" mid slot id is: \(String(describing: cell.cellId))")
cell.bookingState.backgroundColor = UIColor.red.withAlphaComponent(0.3)
cell.backgroundColor = UIColor.red.withAlphaComponent(0.15)
cell.isUserInteractionEnabled = false
}
print("bookingId is: \(valueStart.bookingId!)")
}
}

cell in UICollectionView returning nil when trying to change UITextField in that cell from the controller

I have a UICollectionViewController with a datePicker. When the date is changed, it calls this function:
var cell: InfoSection?
#objc func didChangeDate(sender: UIDatePicker) {
let myDateFormatter: DateFormatter = DateFormatter()
myDateFormatter.dateFormat = "MM/dd/yyyy hh:mm"
let mySelectedDate: String = myDateFormatter.string(from: sender.date)
cell?.dateTextField.text! = mySelectedDate as String
print("mySelected Date is: ", mySelectedDate as String)
print("The content of dateTextField is: ", cell?.dateTextField.text!)
}
InfoSection is my cell that contains the textField.
cell is showing up as nil at this line:
cell?.dateTextField.text! = mySelectedDate as String
I'm sure there's a fairly obvious solution I'm missing here. I've tried force unwrapping it - it crashes. I've tried setting the variable cell to a value of = InfoSection() - it prints the date in the "context of dateTextField" statement, but doesn't change the textField.
And some SO answers said to change the data in a cell through cellForItemAt indexPath which makes sense, but I don't know how to call cell?.dateTextField.text! = mySelectedDate as String in cellForItemAt whenever func didChangeDate is called.
Any help would be amazing! And if you need any other info let me know, thanks!
Your should store your selected date as variable and reload your collectionView like this way:
var mySelectedDate: String?
#objc func didChangeDate(sender: UIDatePicker) {
let myDateFormatter: DateFormatter = DateFormatter()
myDateFormatter.dateFormat = "MM/dd/yyyy hh:mm"
mySelectedDate = myDateFormatter.string(from: sender.date)
collectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CellIdentifier", for: indexPath) as! InfoSection
cell.dateTextField.text = mySelectedDate
return cell
}

How to trigger refresh in Supplementary view of UICollectionView

We are using UICollectionView to draw a calendar. The supplementary view is used for the date at the top of a column that represents a day in the calendar. Each calendar is a section in the UICollectionView. We want the current day highlighted. We have that working by
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
var view: UICollectionReusableView?
if kind == WeeklyCollectionElementKindDayColumnHeader {
let dayColumnHeader: WeeklyDayColumnHeader? = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: WeeklyDayColumnHeaderReuseIdentifier, for: indexPath) as? WeeklyDayColumnHeader
let day: Date? = collectionViewCalendarLayout?.dateForDayColumnHeader(at: indexPath)
let currentDay: Date? = currentTimeComponents(for: self.collectionView!, layout: collectionViewCalendarLayout!)
let startOfDay: Date? = Calendar.current.startOfDay(for: day!)
let startOfCurrentDay: Date? = Calendar.current.startOfDay(for: currentDay!)
dayColumnHeader?.day = day
dayColumnHeader?.isCurrentDay = startOfDay == startOfCurrentDay
view = dayColumnHeader
}
else if kind == WeeklyCollectionElementKindTimeRowHeader {
let timeRowHeader: WeeklyTimeRowHeader? = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: WeeklyTimeRowHeaderReuseIdentifier, for: indexPath) as? WeeklyTimeRowHeader
timeRowHeader?.time = collectionViewCalendarLayout?.dateForTimeRowHeader(at: indexPath)
view = timeRowHeader
}
return view!
}
which with this
class WeeklyDayColumnHeader: UICollectionReusableView {
var day: Date? {
didSet {
var dateFormatter: DateFormatter?
if dateFormatter == nil {
dateFormatter = DateFormatter()
dateFormatter?.dateFormat = "E d"
}
self.title!.text = dateFormatter?.string(from: day!)
setNeedsLayout()
}
}
var isCurrentDay: Bool = false {
didSet {
if isCurrentDay {
title?.textColor = UIColor.white
title?.font = UIFont.boldSystemFont(ofSize: CGFloat(16.0))
titleBackground?.backgroundColor = UIColor(red:0.99, green:0.22, blue:0.21, alpha:1.0)
}
else {
title?.font = UIFont.systemFont(ofSize: CGFloat(16.0))
title?.textColor = UIColor.black
titleBackground?.backgroundColor = UIColor.clear
}
}
}
set the background we want the first time I come into this view. But if I have this view open and the date changes, how do I update the header? Where should I move the logic that sets the date, and how do I "invalidate" or whatever I need to do?
Use the UIApplicationSignificantTimeChangeNotification in order to notify you of time changes.
Use the NotificationCenter to implement this. Something like this:
NotificationCenter.defaultCenter().addObserver(self, selector: "dayChanged:", name: UIApplicationSignificantTimeChangeNotification, object: nil)
Then you need a function to handle the change:
func dayChanged(notification: NSNotification){
// trigger the changes you need here
}

Which UICollectionView function should be used to update UILabels within a cell?

I want to update a UILabel within a UICollectionViewCell every second, which UICollectionView function should I be using for this?
The UILabel is coded in this way.
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
cell.dayCountLabel.text = dayCount(Globals.datesArray[indexPath.item])
}
And receives data in this way.
func dayCount (dayCount: String) -> String{
let day = dayCount
let date2 = NSDate()
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd MMMM yyyy hh:mm a"
let date1: NSDate = dateFormatter.dateFromString(day)!
let diffDateComponents = NSCalendar.currentCalendar().components([NSCalendarUnit.Day], fromDate: date1, toDate: date2, options: NSCalendarOptions.init(rawValue: 0))
let difference = String("\(abs(diffDateComponents.day))")
return difference
}
Sorry for the rookie question.
In case that you have prepared data source text to display in UILabel, call reloadData function:
yourCollectionView.reloadData()
Otherwise, you will get the old text value.
Update
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("reuseId", forIndexPath: indexPath) as! UICollectionViewCell
//update cell subviews here
return cell
}
In your case you should create and return UICollectionViewCell custom subclass, where you implemented dayCountLabel, don't know your custom class name...

Resources