sbkl
sbkl

Reputation: 2321

Swift - JSQMessagesViewController - cell custom

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?

Upvotes: 2

Views: 3948

Answers (4)

jacks8x
jacks8x

Reputation: 31

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?

Upvotes: 0

sbkl
sbkl

Reputation: 2321

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.

Upvotes: 6

Dan Leonard
Dan Leonard

Reputation: 3395

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
}

Upvotes: 0

Muhammed
Muhammed

Reputation: 586

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
}

Upvotes: 0

Related Questions