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

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...

Related

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
}

Access Parent tableViewCell from Child CollectionViewCell

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

Adding Multiple Countdown Timers to UICollectionView

My goal is to have a unique (hh:mm:ss) countdown timer for each populated uicollectionviewcell within a uicollectionview.
Below is the (abbreviated) code I've been able to compile, but am stuck on getting it to really work in any capacity...any guidance would be appreciated.
class VC: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var timer = Timer()
var secondsRemaining: Int?
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! ExampleCollectionViewCell
let expirationDate = Calendar.current.date(byAdding: .hour, value: 24, to: startDate)
secondsRemaining = expirationDate?.seconds(from: startDate)
timer = Timer(timeInterval: 1, target: self, selector: #selector(countdown), userInfo: nil, repeats: true)
return cell
}
#objc func countdown() {
secondsRemaining = secondsRemaining! - 1
if secondsRemaining == 0 {
print("CELL TIME HAS EXPIRED!")
timer.invalidate()
} else {
let hours = secondsRemaining! / 3600
let minutes = (secondsRemaining! % 3600) / 60
let seconds = (secondsRemaining! % 3600) % 60
let countdownLabelString = String(format: "%02d:%02d:%02d", hours, minutes, seconds)
//i need to take this countdownLabelString and set it to the
//countdownLabel.text that is an element of each cell. i tried
//doing all of this in the cell subclass, but no luck...
}
}
}
Collection view cells are not made to update constantly. If you want them to update, you have to tell them to update.
If you want each cell to show a different amount of time remaining, you need a data model that saves a separate expirationDate for each indexPath you display. If your collection view is a simple one-dimensional list of items, like a table view, then you could just use a 1-dimensional array. If your collection view shows a grid of cells you might need a 2 dimensional array of model objects.
Each time you add an item to your data model, include an expirationDate value. (The Date when that item expires.)
Then have your timer call the collection view's reloadData method each time it fires.
In your collectionView(collectionView:cellForItemAt:) method, use the indexPath to figure out which item in your data model you are displaying. Look up the expirationDate for that indexPath, calculate the time remaining from now until your expiration date, and display that information in the cell. (Use the Calendar method dateComponents(_:from:to:) to calculate the number of hours, minutes, and seconds between now and your expiration date.)
EDIT
DO NOT decrement a counter every time your timer fires. Do math on the difference between your expiration date and the current date using dateComponents(_:from:to:)
EDIT #2:
A sample collection view controller that does something like what you want is below:
import UIKit
private let reuseIdentifier = "aCell"
class DatesCollectionVC: UICollectionViewController {
weak var timer: Timer?
var dates: [Date] = []
lazy var componentsFormatter: DateComponentsFormatter = {
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute, .second]
return formatter
}()
override func viewDidLoad() {
super.viewDidLoad()
for _ in 1...100 {
let interval = Double(arc4random_uniform( 10000)) + 120
dates.append(Date().addingTimeInterval(interval))
}
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
self.collectionView?.reloadData()
}
}
// MARK: - UICollectionViewDataSource
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dates.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as? MyCell else {
return UICollectionViewCell()
}
let now = Date()
let expireDate = dates[indexPath.row]
guard expireDate > now else {
cell.intervalLabel.text = "00"
return cell
}
let desiredComponents: Set<Calendar.Component> = [.hour, .minute, .second]
let components = Calendar.current.dateComponents(desiredComponents, from: now, to: expireDate)
cell.intervalLabel.text = self.componentsFormatter.string(from: components)
return cell
}
}
The code above looks like this:

How to update a UILabel without refreshing the main view?

I am trying to use the collection view delegate to update a UILabel on the main view. However, once the label updates, it updates the whole view which means it goes back to the start of the screen - before an animation. Is it possible to only update the monthLabel and not everything?
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell2 = CollectionView.dequeueReusableCellWithReuseIdentifier("CollectionCell", forIndexPath: indexPath) as! BookingDateCollectionCellClass
let later = getDate(indexPath.row + 5).day
print(later)
let date: String = String(later)
print(date)
cell2.dateLabel.text = date
let day = getDateData(indexPath.row + 5).dayOfWeek()
print(day)
cell2.dayLabel.text = dayShortFromNumber(day!)
self.monthlabel.text = monthFromNumber(getDate(indexPath.row + 5).month)
return cell2
}
This is the screen before the start animation:
This is the screen after the start animation:

find uitableviewcell which is swiped / in editing mode

I've added a UITableView into my app. This tableview includes cells, which shows a few custom editing buttons if they're swiped to the left (via this function: editActionsForRowAtIndexPath). I'd like to find out which UITableViewCell is swiped to the left or shows up the custom editing options and set a default text as a detailText label into this cell.
For further explanation:
I have a few UITableViewCells. The user swipes one of these cells. Now the cell is in the editing mode and shows the editing option, which I've added (named "Date"). The user press this button/option (Date). Now a datePicker is poping up. The user chose a date. This date is written in a label. This dateLabel should be transmitted into the detailTextLabel of the cell which was swiped. The problem is that I don't know how to transmit the label with the date to the detailTextLabel of the cell which was swiped.
I hope someone can help me. I am coding with Swift.
This is my code for the custom options if the UITableViewCell is swiped to the left:
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {
let editingCell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
let date = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Date", handler: { (action, indexPath) -> Void in
self.showSideBar(true)
self.delegate?.sideBarWillOpen?()
self.isEditingStyle = true
})
date.backgroundColor = UIColor(red: 0.204, green:0.667, blue:0.863, alpha: 1.0);
return [date];
}
date picker:
func datePickerChanged(datePicker:UIDatePicker) {
var dateFormatter = NSDateFormatter()
dateFormatter.dateStyle = NSDateFormatterStyle.ShortStyle
dateFormatter.timeStyle = NSDateFormatterStyle.ShortStyle
var strDate = dateFormatter.stringFromDate(datePicker.date)
dateLabel.text = strDate
}
adding date into detailTextLabel:
lastEditedCell?.detailTextLabel?.text = dateLabel
You can keep track of the lastEditedCell in tableView(tableView:, editActionsForRowAtIndexPath indexPath:) function
var lastEditedCell:UITableViewCell? // property of the class
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {
let editingCell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
lastEditedCell = editingCell
//Your Code
}
After you set the date from picker view, you can set in the callback function.
lastEditedCell?.detailTextLabel.text = date

Resources