2

I understood from this link that you can customise the cell of the JSQMessagesViewController library by overriding this method:

override func collectionView(collectionView: UICollectionView,  cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
 //Configure your cell here
return //yourCustomCell
}

Is there a possibility to get a sample code to understand how to implement the actual customisation including the subclass of the JSQMessagesCollectionViewCell?

As an example, I would like to add a label included at the bottom of the message bubble showing the time the message has been sent.

Thank you.

EDIT

I have created a custom cell class as follow:

class MyCustomCell: JSQMessagesCollectionViewCell {

    var textLabel: UILabel

    override init(frame: CGRect) {

        self.textLabel = UILabel(frame:  CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height/3))
        super.init(frame: frame)

        self.textLabel.font = UIFont.systemFontOfSize(UIFont.smallSystemFontSize())
        self.textLabel.textAlignment = .Center
        contentView.addSubview(self.textLabel)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

The custom cell is made programmatically without any xib file.

So in my JSQMessagesViewController, I have to declare it as follow:

override func viewDidLoad() {

    super.viewDidLoad()

    self.collectionView!.registerClass(MyCustomCell.self, forCellWithReuseIdentifier: "MyCustomCell")
}

And then, I'm able to override the cellForItemAtIndexPath method as follow:

override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

    let cell = collectionView.dequeueReusableCellWithReuseIdentifier("MyCustomCell", forIndexPath: indexPath) as! MyCustomCell
    return cell
}

The issue is that I cannot see the messages and previous settings anymore.

What am I doing wrong?

sbkl
  • 2,231
  • 2
  • 22
  • 28
  • Anyone could help me to get to the right direction? How MyCustomCell can keep all the behaviour and properties of the parent? Seems I have an issue with the init of the super class... – sbkl Jun 14 '16 at 13:52

4 Answers4

6

This is the way I managed to make it:

1- Create two sub-classes:

  • JSQMessagesCollectionViewCellOutgoing

    import UIKit
    import JSQMessagesViewController
    
    class messageViewOutgoing: JSQMessagesCollectionViewCellOutgoing {
    
        @IBOutlet weak var timeLabel: UILabel!
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)        
        }
    }
    
  • JSQMessagesCollectionViewCellIncoming

    import UIKit
    import JSQMessagesViewController
    
    class messageViewIncoming: JSQMessagesCollectionViewCellIncoming {
    
        @IBOutlet weak var timeLabel: UILabel!
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)        
        }
    }
    

2- Create two xib files with names related to the two subclasses above. For each file, add the custom class related in the File's owner Placeholder.

3- Copy/paste the xib templates of each related classes from the JSQMessagesViewController library stored in the Resources folder and add your custom label into it.

4- Link the custom labels to your new subclasses above

5- Override the following function

override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

    let message = self.messages[indexPath.item]

    if message.senderId == self.senderId {

        let cell = super.collectionView(collectionView, cellForItemAtIndexPath: indexPath) as! messageViewOutgoing

        cell.timeLabel.text = localHourFormatter.stringFromDate(message.date)

        return cell

    } else {

        let cell = super.collectionView(collectionView, cellForItemAtIndexPath: indexPath) as! messageViewIncoming

        cell.timeLabel.text = localHourFormatter.stringFromDate(message.date)

        return cell
    }
}

Now the label is displayed in the bubble.

Still some work to do to adapt the size of the bubble for a proper display but this is not the purpose of this question.

Let me know if any comment/question.

sbkl
  • 2,231
  • 2
  • 22
  • 28
  • 3
    Make all what you described here, but still get crash in cellForRowAtIndexPath "Could not cast value of type 'JSQMessagesCollectionViewCellOutgoing' (0x10b5f3538) to 'myApp.OutgoingMessageCell' (0x108cf9690)." Any ideas? – Alexey Kuznetsov Sep 02 '16 at 10:09
  • fatal error: use of unimplemented initializer 'init(frame:)' for class – Pablo Ruan Jul 03 '17 at 21:16
  • Hi guys sorry for not responding. Difficult to help with the feedback you give. I gave up on this library and moved to react native for mobile development anyway. I'll try to find the project where I made it work and share it on github. Keep you posted. – sbkl Jul 04 '17 at 02:00
  • Please follow this link, if you guys still stuck with the above error.. https://github.com/jessesquires/JSQMessagesViewController/issues/1809 – Nithin Michael Nov 04 '18 at 08:25
  • I am getting error in the line cell = super.collectionView(collectionView, cellForItemAt: indexPath) as! messageViewOutgoing . Error is Could not cast value of type 'JSQMessagesCollectionViewCellOutgoing' to 'messageViewOutgoing' . hat's wrong with my code – Vinod Apr 16 '19 at 10:17
0

Go to xcode make a new file then choose Cocoa Touch class and in subclass list choose

UICollectionViewCell and put your custom cell name like

customCellUICollectionViewCell.swift

After that go Mainstoryboard and drag a new collection cell to your view

Select your cell and in the right side menu in xcode choose

Show the identity inspector

and in Custom class type your custom class name

customCellUICollectionViewCell.swift

last thing in your collection view

override func collectionView(collectionView: UICollectionView,  cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
 let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! customCellUICollectionViewCell
return cell
}
Muhammed
  • 584
  • 1
  • 11
  • 24
  • I cannot drag a new collection cell. The whole collectionView is created by the library. – sbkl Jun 13 '16 at 14:13
0

I believe that you are just not setting the text of you custom cell. I would also guard for safety

override func collectionView(collectionView: UICollectionView,  cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

  guard let cell = collectionView.dequeueReusableCellWithReuseIdentifier("MyCustomCell", forIndexPath: indexPath) as? MyCustomCell else {
    print("Could not get my custom cell")
    return UICollectionViewCell()
  }

  let message = messages[indexPath.row] // or what ever your messages are called

  let cell.mainLabel.text = message.text

  return cell
}
Dan Leonard
  • 3,325
  • 1
  • 20
  • 32
0

I got error: Can't cast from messageViewOutgoing to JSQMessagesCollectionViewCellIncoming @sbkl. Did you get this error, because we can't cast from parent type to child type?

jacks8x
  • 31
  • 4