Search code examples
iosswiftmessagingjsqmessagesviewcontroller

iOS: How to customise JSQMessagesCollectionview?


I want to customise the JSQMessagesCollectionView. I want to add some padding in bottom view so that scroll view starts from some bottom margin.

I need this because my view is overlapping. Here the screenshot:

enter image description here

The second thing I want to customise the time stamp. I want to add a functionality just like Facebook. Here is the scenario:

  1. Show date and time. For messages sent in under a minute, use "Just Now" instead of the actual timestamp.
  2. For messages sent on the same day, use Today, time. For example: Today, 4:47 PM.
  3. For messages sent yesterday, use Yesterday, Time. For example: Yesterday, 5:01 AM.
  4. For everything else, use standard format: Date, Time. For example: April 12, 2017, 4:01 PM.

I want to customise the timestamp label and I want to add the "just now" text there. is it possible?

Can I change the time place in view? I want to show the time stamp below the bubble?

Thanks in advance. Please help if you can?


Solution

  • To show time stamp below the bubble you can use cellBottomLabel label of Cell in cellForItemAt indexPath method

    cell1.cellBottomLabel.text = "just now"

    You will aslo need to provide height for that label as following

    override func collectionView(_ collectionView: JSQMessagesCollectionView!, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout!, heightForCellBottomLabelAt indexPath: IndexPath!) -> CGFloat {
        return 20.0
    }
    

    Further to customize time stamp you can always use date formatter extension. in my case i have used following.(https://gist.github.com/minorbug/468790060810e0d29545)

    extension DateFormatter {
    /**
     Formats a date as the time since that date (e.g., “Last week, yesterday, etc.”).
    
     - Parameter from: The date to process.
     - Parameter numericDates: Determines if we should return a numeric variant, e.g. "1 month ago" vs. "Last month".
    
     - Returns: A string with formatted `date`.
     */
    
    func timeAgoSinceDate(_ date:Date, numericDates:Bool = false) -> String {
        let calendar = NSCalendar.current
        let unitFlags: Set<Calendar.Component> = [.minute, .hour, .day, .weekOfYear, .month, .year, .second]
        let now = Date()
        let earliest = now < date ? now : date
        let latest = (earliest == now) ? date : now
        let components = calendar.dateComponents(unitFlags, from: earliest,  to: latest)
    
        if (components.year! >= 2) {
            return "\(components.year!) years ago"
        } else if (components.year! >= 1){
            if (numericDates){
                return "1 year ago"
            } else {
                return "Last year"
            }
        } else if (components.month! >= 2) {
            return "\(components.month!) months ago"
        } else if (components.month! >= 1){
            if (numericDates){
                return "1 month ago"
            } else {
                return "Last month"
            }
        } else if (components.weekOfYear! >= 2) {
            return "\(components.weekOfYear!) weeks ago"
        } else if (components.weekOfYear! >= 1){
            if (numericDates){
                return "1 week ago"
            } else {
                return "Last week"
            }
        } else if (components.day! >= 2) {
            return "\(components.day!) days ago"
        } else if (components.day! >= 1){
            if (numericDates){
                return "1 day ago"
            } else {
                return "Yesterday"
            }
        } else if (components.hour! >= 2) {
            return "\(components.hour!) hours ago"
        } else if (components.hour! >= 1){
            if (numericDates){
                return "1 hour ago"
            } else {
                return "An hour ago"
            }
        } else if (components.minute! >= 2) {
            return "\(components.minute!) minutes ago"
        } else if (components.minute! >= 1){
            if (numericDates){
                return "1 minute ago"
            } else {
                return "A minute ago"
            }
        } else if (components.second! >= 3) {
            return "\(components.second!) seconds ago"
        } else {
            return "Just now"
        }
    
    }  }
    

    to use this

    let formatter = DateFormatter()
            formatter.dateFormat = "Your Format"
            formatter.timeZone = NSTimeZone(abbreviation: "UTC") as TimeZone! // time zone if needed 
            let messageUTCDate = formatter.date(from: "your date in string")
            return formatter.timeAgoSinceDate(messageUTCDate!)
    

    or you can use other date format like answered here Getting the difference between two NSDates in (months/days/hours/minutes/seconds)

    Finally, for button you can show them in top bar if you want.

    Hope it helps