JSQMessagesViewController – Messages UI

On the app I’m currently working on I’ve got a messaging portion.

Originally I implemented a basic TableView with a TextField to add a message.

Then I searched for Messages UI frameworks and came across JSQMessagesViewController

There’s a Sample project you can look into – JSQMessagesDemo.

It comes as a Cocoapod:

I’m using 7.3.4.


Create a new Xcode project.

Open terminal at that folder

pod init

add

pod 'JSQMessagesViewController'

then

pod install

Open the Xcode ‘#App.xcworkspace’

Create a View Controller that inherits

: JSQMessagesViewController<UIActionSheetDelegate, JSQMessagesComposerTextViewPasteDelegate>
#import <JSQMessagesViewController/JSQMessagesViewController.h>
#import "DemoData.h"
@class MessageViewController;
@protocol MessageViewControllerDelegate <NSObject>
- (void)didDismissMessagesViewController:(MessageViewController *)vc;
@end

Add some properties and methods

@property (weak, nonatomic) id<MessageViewControllerDelegate> delegateModal;
@property (strong, nonatomic) DemoData *data;
- (void)receiveMessagePressed:(UIBarButtonItem *)sender;
- (void)closePressed:(UIBarButtonItem *)sender;

I didn’t bother with any of the settings so commented these checks out.


I couldn’t find the Accessory Button Delegate to add to my View Controller.

#import "JSQMessagesViewAccessoryButtonDelegate.h"
<JSQMessagesViewAccessoryButtonDelegate>

For testing create a new class for your demo data.

DemoData.h

@interface DemoData : NSObject
@property (strong, nonatomic) NSMutableArray *messages;
@property (strong, nonatomic) NSDictionary *users;
@property (strong, nonatomic) JSQMessagesBubbleImage *outgoingBubbleImageData;
@property (strong, nonatomic) JSQMessagesBubbleImage *incomingBubbleImageData;
@end


DemoData.m

Create some test Users.

- (instancetype)init
{
    self = [super init];
    if (self) {  
        [self loadFakeMessages];
        self.users = @{ @"1" : @"Alex",
                        @"2" : @"Sam",
                        @"3" : @"Kev",
                        @"4" : @"Ray" };
        JSQMessagesBubbleImageFactory *bubbleFactory = [[JSQMessagesBubbleImageFactory alloc] init];       
        self.outgoingBubbleImageData = [bubbleFactory outgoingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleLightGrayColor]];
        self.incomingBubbleImageData = [bubbleFactory incomingMessagesBubbleImageWithColor:[UIColor jsq_messageBubbleGreenColor]];
    }
    return self;
}

Create the Fake Messages

- (void)loadFakeMessages { ... }

We can use this back in our MessageViewController.m

#pragma mark - View lifecycle
  • viewDidLoad
  • viewWillAppear
  • viewDidAppear

Since I’m not using Avatars add this to viewDidLoad

self.collectionView.collectionViewLayout.incomingAvatarViewSize = CGSizeZero; self.collectionView.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero;

Also return nil in ‘avatarImageDataForItemAtIndexPath’

- (id<JSQMessageAvatarImageDataSource>)collectionView:(JSQMessagesCollectionView *)collectionView avatarImageDataForItemAtIndexPath:(NSIndexPath *)indexPath {
    ...
    return nil;
}

Implement these other methods.

#pragma mark - Custom menu actions for cells
#pragma mark - Actions
#pragma mark - JSQMessagesViewController method overrides
#pragma mark - JSQMessages CollectionView DataSource

Choose a user here

  • senderId
  • senderId
#pragma mark - UICollectionView DataSource
#pragma mark - UICollectionView Delegate
#pragma mark - Custom menu items
#pragma mark - JSQMessages collection view flow layout delegate
#pragma mark - Adjusting cell label heights
#pragma mark - Responding to collection view tap events
#pragma mark - JSQMessagesComposerTextViewPasteDelegate methods
#pragma mark - JSQMessagesViewAccessoryDelegate methods

Changing some settings

I didn’t want the Add Attachments button.

viewDidLoad

self.inputToolbar.contentView.leftBarButtonItem = nil;

Now just to swap out the messages to my XMPP Server…

Advertisements

XMPPFramework

XMPPFramework

Create an Xcode project.

Open terminal at that folder location.

pod init
pod 'XMPPFramework', :git => "https://github.com/robbiehanson/XMPPFramework.git", :branch => 'master'
@import XMPPFramework;

Getting Started

Tutorials

Had issues setting up Ejabbered on the mac.

I’m using an OpenFire server I setup so used that instead, with a couple of clients connected to there instead.

Clients

Stack Overflow


Setting the Server

set the server url

set the port


Delivery Receipts

Read Receipts


Group Chat

MapKit

So I’ve been learning MapKit this week.

It’s been a fun new framework to look into.

Create an Annotation so you can have custom properties.

@interface Annotation : NSObject<MKAnnotation>

Add a category to it so you have a way of telling what it is.

This could be an enum.

In the Delegate method

- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation

You can use the category to set up some properties like a button and the pin colour.

I’m wondering if the “reuseIdentifier” should be unique here too?

You’ve added a button, now how to call it?

You could add a target and action

[rightButton addTarget:## action:## forControlEvents:UIControlEventTouchUpInside];

but instead you can use the “calloutAccessoryControlTapped” delegate method.

- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control

As this isn’t a  “MKAnnotation” like “viewForAnnotation” but an “MKAnnotationView” we need to get the annotation from the passed view.

if ([view.annotation isKindOfClass:[OotAnnotation class]]) { ... }

Then call pfs,

Then in the “prepareForSegue” you need to get the Annotation when you click on a Pin button, this can be cast from the Sender

if ([view.annotation isKindOfClass:[OotAnnotation class]]) { ... }
Annotation *annotation = (Annotation *)[(MKAnnotationView *)sender annotation];

You could then pass your custom Location details via the ViewController. (See code)

Searching for locations to add to the map:

MKLocalSearchRequest

Adding a route, need to investigate this more.

MKPolyline

All Code

Goals for 2018

Xamarin

I’d started some training last year but didn’t make any useful apps, I’d like to progress this to a production one in 2018.

.NET

I’d like to make progress in either or both of my Tracking app ideas.

599CD

Actually release it, I’ve been holding off hoping the API will be re-written, maybe I should just release, then update when it is.

Although releasing the Android at the same time would be nice.

Certs

MS: Programming in HTML5 with JavaScript and CSS3

MCSA: Web Applications

MCPS: Developing ASP.NET MVC Web Applications

Microsoft Certified Solution Developer: App Builder

Goals for 2017 – Review

599CD

  • iOS
  • Re-wrote API interaction using the Facade pattern
  • Android
  • Asked a friend to help write this

Still waiting on Rich to make a proper API.

Jam Jar

Worked with PassSlot and have a local iOS app that creates them, with images

https://alexhedley.wordpress.com/2017/05/20/jam-jar-cinema-wallet-passes/

.NET Apps

I worked a little on a GNVQ tracking app for Learning Objectives, the back end is mostly there, still working on the UI.

In general I was working on a major iOS project at work so didn’t have a massive amount of spare time, learned lots of new APIs and techniques in ObjC and iOS dev which was great.

Previous

UIBarButtonItem Image and Text

I want to add an image and text to a BarButtonItem but can’t in IB.

 

I looked into EdgeInsets but couldn’t get them to work with the image.

 

I’d also like to shrink the image

// https://stackoverflow.com/a/18853240/2895831
UIView *rightButtonView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 110, 50)];

UIImage *buttonImage = [UIImage imageNamed:@"LocationArrow"];
//UIEdgeInsets edgeInsets = UIEdgeInsetsMake(50, 50, 50, 50);
//UIImage *buttonImage = [[UIImage imageNamed:@"LocationArrow"] resizableImageWithCapInsets:edgeInsets];
//UIImage(CGImage: originalImage!.CGImage!, scale: 5, orientation: originalImage!.imageOrientation)
// https://stackoverflow.com/a/38523085/2895831
buttonImage = [UIImage imageWithCGImage:buttonImage.CGImage
 scale:4//CGImageGetHeight(buttonImage.CGImage)/2
 orientation:UIImageOrientationUp];

UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeSystem];
rightButton.backgroundColor = [UIColor clearColor];
rightButton.frame = rightButtonView.frame;
[rightButton setImage:buttonImage forState:UIControlStateNormal];
[rightButton setTitle:NSLocalizedString(@"My Location", nil) forState:UIControlStateNormal];
rightButton.tintColor = [UIColor whiteColor];
rightButton.autoresizesSubviews = YES;
rightButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin;
rightButton.semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
[rightButton addTarget:self action:@selector(myLocationAction:) forControlEvents:UIControlEventTouchUpInside];

CGFloat padding = 10.0f;
[rightButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 0, 0, padding)];
//[rightButton setContentEdgeInsets:UIEdgeInsetsMake(0, 0, 0, padding)];
//[rightButton setContentEdgeInsets:UIEdgeInsetsMake(padding, padding, padding, padding)];
//[rightButton setImageEdgeInsets:UIEdgeInsetsMake(padding, 0, padding, 0)]; //0, padding, 0, padding
//[rightButton setImageEdgeInsets:UIEdgeInsetsMake(padding, padding, padding, padding)];

[rightButtonView addSubview:rightButton];

UIBarButtonItem *rightBarButton = [[UIBarButtonItem alloc] initWithCustomView:rightButtonView];
self.navigationItem.rightBarButtonItem = rightBarButton;

 

Image

[UIImage imageWithCGImage:buttonImage.CGImage scale:4 orientation:UIImageOrientationUp];

Pick your method to scale

CGImageGetHeight(buttonImage.CGImage)/2

Or

CGImageGetWidth(...)/DESIREDWIDTH

 

IB

There is the handy

Bar Item

Image Inset

 

UIButton VerticalLayout

https://stackoverflow.com/a/22621613/2895831

I added some buttons into a UIStackView but the image overlaps the button.

I modified the contentEdgeInsets

CGFloat inset = (self.frame.size.height - totalHeight)/2;
self.contentEdgeInsets = UIEdgeInsetsMake(inset, 0.0f, inset, 0.0f);

 

 

Advertisements