Search code examples
iosuicollectionviewuicollectionviewlayoutjsqmessagesviewcontroller

Setting minimum width for some bubbles


I was wondering which was the correct approach to setting a minimum width for some bubbles. I've tried overriding the applyLayoutAttributes: in my custom cell, but I need access to my datasource to know which cell should have a minimum width. I've been tinkering with messageBubbleLeftRightMargin in cellForItemAtIndexPath: but with no results. Any pointers would be great

EDIT

My Message model (which conforms to ) has a flag which tells me if the bubble needs to have a minimum width

In my custom cell, I can override the custom layout, but I don't have access to the datasource, hence I have no access to that flag

-(void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes{
            JSQMessagesCollectionViewLayoutAttributes *customAttributes = (JSQMessagesCollectionViewLayoutAttributes *)layoutAttributes;

    // I need access to my <JSQMessageData> for the condition
            if (condition) {
                if(customAttributes.messageBubbleContainerViewWidth <175){
                    customAttributes.messageBubbleContainerViewWidth = 175;
                }
            }

            [super applyLayoutAttributes:customAttributes];
}

I also tried in my JSQMessagesViewController subclass to access the leftright constraint, but to no avail

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
    /**
     *  Override point for customizing cells
     */
    JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];

    BLMessage *message = [self.visibleMessagesArray objectAtIndex:indexPath.item];

    JSQMessagesCollectionViewLayoutAttributes *customAttributes = [JSQMessagesCollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

    if(message.isEphemeral){
      //random number to see if it had an effect
      self.collectionView.collectionViewLayout.messageBubbleLeftRightMargin = 200;

       //I also tried modifying the customAttributes
       //customAttributes.messageBubbleContainerViewWidth = 175;

    }
    return cell;
}

I'm kind of new to the UICollectionViewFlowLayout and such, I may be missing some core concepts


Solution

  • Ok, so I found out what was wrong. I wasn't applying the new layout to the cell, so my cellForItemAtIndexPath ended up like:

    -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
        /**
         *  Override point for customizing cells
         */
        JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView cellForItemAtIndexPath:indexPath];
    
        BLMessage *message = [self.visibleMessagesArray objectAtIndex:indexPath.item];
    
        JSQMessagesCollectionViewLayoutAttributes *customAttributes = (JSQMessagesCollectionViewLayoutAttributes *)[self.collectionView layoutAttributesForItemAtIndexPath:indexPath];
    
        if(message.isEphemeral){
           //I also tried modifying the customAttributes
           customAttributes.messageBubbleContainerViewWidth = 175;
           [cell applyLayoutAttributes: customAttributes];
    
        }
        return cell;
    }
    

    -------------EDIT------------

    My answer before had some side effects, it's not recommended to call applyLayoutAttributes: inside your collectionView:cellForItemAtIndexPath:.

    The proper way to do this, is to subclass JSQMessagesCollectionViewFlowLayout

    CustomCollectionViewFlowLayout.h

    #import "JSQMessagesCollectionViewFlowLayout.h"
    
    @interface CustomCollectionViewFlowLayout : JSQMessagesCollectionViewFlowLayout
    @property (strong, nonatomic) UIImageView *incomingBubbleMask;
    @end
    

    CustomCollectionViewFlowLayout.m

    #import "CustomCollectionViewFlowLayout.h"
    #import "JSQMessage.h"
    
    #import "JSQMessagesCollectionView.h"
    #import "JSQMessagesCollectionViewCell.h"
    
    #import "JSQMessagesCollectionViewLayoutAttributes.h"
    #import "JSQMessagesCollectionViewFlowLayoutInvalidationContext.h"
    
    #import "UIImage+JSQMessages.h"
    
    @implementation CustomCollectionViewFlowLayout
    + (Class)layoutAttributesClass
    {
        return [JSQMessagesCollectionViewLayoutAttributes class];
    }
    
    - (CGSize)messageBubbleSizeForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        CGSize superSize = [super messageBubbleSizeForItemAtIndexPath:indexPath];
    
        JSQMessage *currentMessage = (JSQMessage *)[self.collectionView.dataSource collectionView:self.collectionView messageDataForItemAtIndexPath:indexPath];
    
        /*********** Setting size **************/
        //check if outgoing, you can import your Session Manager to check your user identifier
        if ([currentMessage.senderId isEqualToString:@"me") {
            superSize = CGSizeMake(175, superSize.height);
        }
        //do whatever other checks and setup your width/height accordingly
    
        return superSize;
    }
    
    @end
    

    Don't forget to set your custom layout in your JSQMessagesViewController subclass, #import "CustomCollectionViewFlowLayout.h" and in your viewDidLoad add: self.collectionView.collectionViewLayout = [[CustomCollectionViewFlowLayout alloc] init];