TestsTested | ✗ |
LangLanguage | Obj-CObjective C |
License | MIT |
ReleasedLast Release | Jan 2018 |
Maintained by Scott Kensell.
MXRMessenger is a customizable chat library meant to provide a smooth-scrolling, responsive experience. I felt the need to write it because
That said, if you have never worked with Texture, you are probably better off choosing one of the more mature libraries linked above. This library is also hardly tested and used by only 1 app so far in production, so use at your own risk.
The MXRMessengerViewController
is like a baby version of the SlackTextViewController and can be included on its own with pod 'MXRMessenger/ViewController'
. It features
The other subspec pod 'MXRMessenger/MessageCell'
provides Facebook-style bubbles and a friendly factory. Main features:
And since we are dependent on Texture, you get 60 fps smoothness for free.
MXRMessenger is available through CocoaPods.
For the full chat library, add pod 'MXRMessenger'
to your Podfile.
For just the ViewController add pod 'MXRMessenger/ViewController'
.
For just the Facebook-style bubbles add pod 'MXRMessenger/MessageCell'
.
Where necessary, add
#import <MXRMessenger/MXRMessenger.h>
Subclass MXRMessengerViewController
. Then, the easiest way to instantiate message cells is with the provided MXRMessageCellFactory
. So create a strong property:
@property (nonatomic, strong) MXRMessageCellFactory* cellFactory;
Most customizations happen at init. You can copy-paste the following code and just remove or customize whatever you want. And then implement the delegate or datasource methods the compiler complains about.
- (instancetype)init {
MXRMessengerInputToolbar* toolbar = [[MXRMessengerInputToolbar alloc] initWithFont:[UIFont systemFontOfSize:16.0f] placeholder:@"Type a message" tintColor:[UIColor mxr_fbMessengerBlue]];
self = [super initWithToolbar:toolbar];
if (self) {
// add extra buttons to toolbar
MXRMessengerIconButtonNode* addPhotosBarButtonButtonNode = [MXRMessengerIconButtonNode buttonWithIcon:[[MXRMessengerPlusIconNode alloc] init] matchingToolbar:self.toolbar];
[addPhotosBarButtonButtonNode addTarget:self action:@selector(tapAddPhotos:) forControlEvents:ASControlNodeEventTouchUpInside];
self.toolbar.leftButtonsNode = addPhotosBarButtonButtonNode;
[self.toolbar.defaultSendButton addTarget:self action:@selector(tapSend:) forControlEvents:ASControlNodeEventTouchUpInside];
// delegate must be self for interactive keyboard, datasource can be whatever
self.node.tableNode.delegate = self;
self.node.tableNode.dataSource = self;
[self customizeCellFactory];
}
return self
}
- (void)customizeCellFactory {
MXRMessageCellLayoutConfiguration* layoutConfigForMe = [MXRMessageCellLayoutConfiguration rightToLeft];
MXRMessageCellLayoutConfiguration* layoutConfigForOthers = [MXRMessageCellLayoutConfiguration leftToRight];
MXRMessageAvatarConfiguration* avatarConfigForMe = nil;
MXRMessageAvatarConfiguration* avatarConfigForOthers = [[MXRMessageAvatarConfiguration alloc] init];
MXRMessageTextConfiguration* textConfigForMe = [[MXRMessageTextConfiguration alloc] initWithFont:nil textColor:[UIColor whiteColor] backgroundColor:[UIColor mxr_fbMessengerBlue]];
MXRMessageTextConfiguration* textConfigForOthers = [[MXRMessageTextConfiguration alloc] initWithFont:nil textColor:[UIColor blackColor] backgroundColor:[UIColor mxr_bubbleLightGrayColor]];
CGFloat maxCornerRadius = textConfigForMe.maxCornerRadius;
MXRMessageImageConfiguration* imageConfig = [[MXRMessageImageConfiguration alloc] init];
imageConfig.maxCornerRadius = maxCornerRadius;
MXRMessageMediaCollectionConfiguration* mediaCollectionConfig = [[MXRMessageMediaCollectionConfiguration alloc] init];
mediaCollectionConfig.maxCornerRadius = maxCornerRadius;
textConfigForMe.menuItemTypes |= MXRMessageMenuItemTypeDelete;
textConfigForOthers.menuItemTypes |= MXRMessageMenuItemTypeDelete;
imageConfig.menuItemTypes |= MXRMessageMenuItemTypeDelete;
imageConfig.showsUIMenuControllerOnLongTap = YES;
CGFloat s = [UIScreen mainScreen].scale;
imageConfig.borderWidth = s > 0 ? (1.0f/s) : 0.5f;
MXRMessageCellConfiguration* cellConfigForMe = [[MXRMessageCellConfiguration alloc] initWithLayoutConfig:layoutConfigForMe avatarConfig:avatarConfigForMe textConfig:textConfigForMe imageConfig:imageConfig mediaCollectionConfig:mediaCollectionConfig];
MXRMessageCellConfiguration* cellConfigForOthers = [[MXRMessageCellConfiguration alloc] initWithLayoutConfig:layoutConfigForOthers avatarConfig:avatarConfigForOthers textConfig:textConfigForOthers imageConfig:imageConfig mediaCollectionConfig:mediaCollectionConfig];
self.cellFactory = [[MXRMessageCellFactory alloc] initWithCellConfigForMe:cellConfigForMe cellConfigForOthers:cellConfigForOthers];
self.cellFactory.dataSource = self;
self.cellFactory.contentNodeDelegate = self;
self.cellFactory.mediaCollectionDelegate = self;
}
To create the message cells, you can implement the ASTableDataSource
method like so
- (ASCellNodeBlock)tableNode:(ASTableNode *)tableNode nodeBlockForRowAtIndexPath:(NSIndexPath *)indexPath {
Message* message = self.messages[indexPath.row];
if (message.media.count > 1) {
return [self.cellFactory cellNodeBlockWithMedia:message.media tableNode:tableNode row:indexPath.row];
} else if (message.media.count == 1) {
MessageMedium* medium = message.media.firstObject;
return [self.cellFactory cellNodeBlockWithImageURL:medium.photoURL showsPlayButton:(medium.videoURL != nil) tableNode:tableNode row:indexPath.row];
} else {
return [self.cellFactory cellNodeBlockWithText:message.text tableNode:tableNode row:indexPath.row];
}
}
and to send a new message or update the table with new/old messages there is just one method on the cellFactory
:
- (void)updateTableNode:(ASTableNode*)tableNode animated:(BOOL)animated withInsertions:(NSArray<NSIndexPath*>*)insertions deletions:(NSArray<NSIndexPath*>*)deletions reloads:(NSArray<NSIndexPath*>*)reloads completion:(void(^)(BOOL))completion;
There are a few key assumptions to keep in mind:
cellFactory
(e.g. when the user taps the cell).MXRMessageCellFactoryDataSource
methods for the current indexPath as well as its neighbors. That means you should keep those methods quick - ideally they are just dictionary lookups.For more details, it's probably best to check the example project.
To run the example project, clone the repo, and run pod install
from the Example directory which has a Podfile
. Then open the *.xcworkspace
file and build.
Texture 2.X and iOS 8+.
There are no tests at present. Keep PRs very small please.
Scott Kensell, [email protected]
MXRMessenger is available under the MIT license. See the LICENSE file for more info.