Permalink
Browse files

Avatar support for standard bubbles

  • Loading branch information...
1 parent bdd0213 commit 1a85a1724680772037a000b1092fb28d9cadee25 Alex Barinov committed Oct 10, 2012
@@ -21,6 +21,9 @@
76ED208715BF09E300E186D3 /* UIBubbleTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 76ED208615BF09E300E186D3 /* UIBubbleTableView.m */; };
76ED208B15BF0BB100E186D3 /* NSBubbleData.m in Sources */ = {isa = PBXBuildFile; fileRef = 76ED208A15BF0BB100E186D3 /* NSBubbleData.m */; };
76ED209415BF29EE00E186D3 /* UIBubbleTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 76ED209315BF29EE00E186D3 /* UIBubbleTableViewCell.m */; };
+ C836D5CA1625CBA5004CB4A9 /* missingAvatar.png in Resources */ = {isa = PBXBuildFile; fileRef = C836D5C81625CBA5004CB4A9 /* missingAvatar.png */; };
+ C836D5CB1625CBA5004CB4A9 /* missingAvatar@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C836D5C91625CBA5004CB4A9 /* missingAvatar@2x.png */; };
+ C836D5CE1625D718004CB4A9 /* avatar1.png in Resources */ = {isa = PBXBuildFile; fileRef = C836D5CD1625D718004CB4A9 /* avatar1.png */; };
C83B107915DE43180067DADE /* bubbleMine.png in Resources */ = {isa = PBXBuildFile; fileRef = C83B107115DE43180067DADE /* bubbleMine.png */; };
C83B107A15DE43180067DADE /* bubbleMine@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = C83B107215DE43180067DADE /* bubbleMine@2x.png */; };
C83B107B15DE43180067DADE /* bubbleSomeone.png in Resources */ = {isa = PBXBuildFile; fileRef = C83B107315DE43180067DADE /* bubbleSomeone.png */; };
@@ -59,6 +62,9 @@
76ED208A15BF0BB100E186D3 /* NSBubbleData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSBubbleData.m; path = ../../src/NSBubbleData.m; sourceTree = "<group>"; };
76ED209215BF29EE00E186D3 /* UIBubbleTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UIBubbleTableViewCell.h; path = ../../src/UIBubbleTableViewCell.h; sourceTree = "<group>"; };
76ED209315BF29EE00E186D3 /* UIBubbleTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = UIBubbleTableViewCell.m; path = ../../src/UIBubbleTableViewCell.m; sourceTree = "<group>"; };
+ C836D5C81625CBA5004CB4A9 /* missingAvatar.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = missingAvatar.png; sourceTree = "<group>"; };
+ C836D5C91625CBA5004CB4A9 /* missingAvatar@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "missingAvatar@2x.png"; sourceTree = "<group>"; };
+ C836D5CD1625D718004CB4A9 /* avatar1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = avatar1.png; sourceTree = SOURCE_ROOT; };
C83B107115DE43180067DADE /* bubbleMine.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = bubbleMine.png; sourceTree = "<group>"; };
C83B107215DE43180067DADE /* bubbleMine@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "bubbleMine@2x.png"; sourceTree = "<group>"; };
C83B107315DE43180067DADE /* bubbleSomeone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = bubbleSomeone.png; sourceTree = "<group>"; };
@@ -130,6 +136,7 @@
76ED206915BF096C00E186D3 /* Supporting Files */ = {
isa = PBXGroup;
children = (
+ C836D5CD1625D718004CB4A9 /* avatar1.png */,
76687AFE162203AF00707588 /* halloween.jpg */,
C86D4FFD15BFEBC1003F161E /* icon_114.png */,
C86D4FFB15BFEBBF003F161E /* icon_57.png */,
@@ -166,6 +173,8 @@
C83B107215DE43180067DADE /* bubbleMine@2x.png */,
C83B107315DE43180067DADE /* bubbleSomeone.png */,
C83B107415DE43180067DADE /* bubbleSomeone@2x.png */,
+ C836D5C81625CBA5004CB4A9 /* missingAvatar.png */,
+ C836D5C91625CBA5004CB4A9 /* missingAvatar@2x.png */,
C83B107515DE43180067DADE /* typingMine.png */,
C83B107615DE43180067DADE /* typingMine@2x.png */,
C83B107715DE43180067DADE /* typingSomeone.png */,
@@ -238,6 +247,9 @@
C83B107F15DE43180067DADE /* typingSomeone.png in Resources */,
C83B108015DE43180067DADE /* typingSomeone@2x.png in Resources */,
76687AFF162203AF00707588 /* halloween.jpg in Resources */,
+ C836D5CA1625CBA5004CB4A9 /* missingAvatar.png in Resources */,
+ C836D5CB1625CBA5004CB4A9 /* missingAvatar@2x.png in Resources */,
+ C836D5CE1625D718004CB4A9 /* avatar1.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -9,8 +9,9 @@
//
//
-// Halloween image used in this example by Petr Kratochvil released into public domain
-// http://www.publicdomainpictures.net/view-image.php?image=9806&picture=halloween-autumn-theme
+// Images used in this example by Petr Kratochvil released into public domain
+// http://www.publicdomainpictures.net/view-image.php?image=9806
+// http://www.publicdomainpictures.net/view-image.php?image=1358
//
#import "ViewController.h"
@@ -23,18 +24,38 @@ @implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
+
+ NSBubbleData *heyBubble = [NSBubbleData dataWithText:@"Hey, halloween is soon" date:[NSDate dateWithTimeIntervalSinceNow:-300] type:BubbleTypeSomeoneElse];
+ heyBubble.avatar = [UIImage imageNamed:@"avatar1.png"];
- bubbleData = [[NSMutableArray alloc] initWithObjects:
- [NSBubbleData dataWithText:@"Hey, halloween is soon" date:[NSDate dateWithTimeIntervalSinceNow:-300] type:BubbleTypeSomeoneElse],
- [NSBubbleData dataWithImage:[UIImage imageNamed:@"halloween.jpg"] date:[NSDate dateWithTimeIntervalSinceNow:-290] type:BubbleTypeSomeoneElse],
- [NSBubbleData dataWithText:@"Wow.. Really cool picture out there. iPhone 5 has really nice camera, yeah?" date:[NSDate dateWithTimeIntervalSinceNow:0] type:BubbleTypeMine],
- nil];
+ NSBubbleData *photoBubble = [NSBubbleData dataWithImage:[UIImage imageNamed:@"halloween.jpg"] date:[NSDate dateWithTimeIntervalSinceNow:-290] type:BubbleTypeSomeoneElse];
+ photoBubble.avatar = [UIImage imageNamed:@"avatar1.png"];
+
+ NSBubbleData *replyBubble = [NSBubbleData dataWithText:@"Wow.. Really cool picture out there. iPhone 5 has really nice camera, yeah?" date:[NSDate dateWithTimeIntervalSinceNow:0] type:BubbleTypeMine];
+ replyBubble.avatar = nil;
+ bubbleData = [[NSMutableArray alloc] initWithObjects:heyBubble, photoBubble, replyBubble, nil];
bubbleTable.bubbleDataSource = self;
- bubbleTable.snapInterval = 130;
+ // The line below sets the snap interval in seconds. This defines how the bubbles will be grouped in time.
+ // Interval of 120 means that if the next messages comes in 2 minutes since the last message, it will be added into the same group.
+ // Groups are delimited with header which contains date and time for the first message in the group.
+
+ bubbleTable.snapInterval = 120;
+
+ // The line below enables avatar support. Avatar can be specified for each bubble with .avatar property of NSBubbleData.
+ // Avatars are enabled for the whole table at once. If particular NSBubbleData misses the avatar, a default placeholder will be set (missingAvatar.png)
+
+ bubbleTable.showAvatars = YES;
+
+ // Uncomment the line below to add "Now typing" bubble
+ // Possible values are
+ // - NSBubbleTypingTypeSomebody - shows "now typing" bubble on the left
+ // - NSBubbleTypingTypeMe - shows "now typing" bubble on the right
+ // - NSBubbleTypingTypeNone - no "now typing" bubble
+
bubbleTable.typingBubble = NSBubbleTypingTypeSomebody;
-
+
[bubbleTable reloadData];
}
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
@@ -22,6 +22,7 @@ typedef enum _NSBubbleType
@property (readonly, nonatomic) NSBubbleType type;
@property (readonly, nonatomic, strong) UIView *view;
@property (readonly, nonatomic) UIEdgeInsets insets;
+@property (nonatomic, strong) UIImage *avatar;
- (id)initWithText:(NSString *)text date:(NSDate *)date type:(NSBubbleType)type;
+ (id)dataWithText:(NSString *)text date:(NSDate *)date type:(NSBubbleType)type;
View
@@ -9,6 +9,7 @@
//
#import "NSBubbleData.h"
+#import <QuartzCore/QuartzCore.h>
@implementation NSBubbleData
@@ -18,6 +19,7 @@ @implementation NSBubbleData
@synthesize type = _type;
@synthesize view = _view;
@synthesize insets = _insets;
+@synthesize avatar = _avatar;
#pragma mark - Lifecycle
@@ -28,6 +30,9 @@ - (void)dealloc
_date = nil;
[_view release];
_view = nil;
+
+ self.avatar = nil;
+
[super dealloc];
}
#endif
@@ -91,6 +96,9 @@ - (id)initWithImage:(UIImage *)image date:(NSDate *)date type:(NSBubbleType)type
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)];
imageView.image = image;
+ imageView.layer.cornerRadius = 5.0;
+ imageView.layer.masksToBounds = YES;
+
#if !__has_feature(objc_arc)
[imageView autorelease];
View
@@ -25,5 +25,6 @@ typedef enum _NSBubbleTypingType
@property (nonatomic, assign) id<UIBubbleTableViewDataSource> bubbleDataSource;
@property (nonatomic) NSTimeInterval snapInterval;
@property (nonatomic) NSBubbleTypingType typingBubble;
+@property (nonatomic) BOOL showAvatars;
@end
View
@@ -25,6 +25,7 @@ @implementation UIBubbleTableView
@synthesize snapInterval = _snapInterval;
@synthesize bubbleSection = _bubbleSection;
@synthesize typingBubble = _typingBubble;
+@synthesize showAvatars = _showAvatars;
#pragma mark - Initializators
@@ -42,7 +43,7 @@ - (void)initializator
// UIBubbleTableView default properties
self.snapInterval = 120;
- self.typingBubble = NSBubbleTypingTypeMe;
+ self.typingBubble = NSBubbleTypingTypeNobody;
}
- (id)init
@@ -173,7 +174,7 @@ - (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath
// Now typing
if (indexPath.section >= [self.bubbleSection count])
{
- return [UIBubbleTypingTableViewCell height];
+ return MAX([UIBubbleTypingTableViewCell height], self.showAvatars ? 52 : 0);
}
// Header
@@ -183,7 +184,7 @@ - (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath
}
NSBubbleData *data = [[self.bubbleSection objectAtIndex:indexPath.section] objectAtIndex:indexPath.row - 1];
- return data.insets.top + data.view.frame.size.height + data.insets.bottom;
+ return MAX(data.insets.top + data.view.frame.size.height + data.insets.bottom, self.showAvatars ? 52 : 0);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
@@ -195,7 +196,10 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
UIBubbleTypingTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if (cell == nil) cell = [[UIBubbleTypingTableViewCell alloc] init];
+
cell.type = self.typingBubble;
+ cell.showAvatar = self.showAvatars;
+
return cell;
}
@@ -207,7 +211,9 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
NSBubbleData *data = [[self.bubbleSection objectAtIndex:indexPath.section] objectAtIndex:0];
if (cell == nil) cell = [[UIBubbleHeaderTableViewCell alloc] init];
+
cell.date = data.date;
+
return cell;
}
@@ -217,7 +223,10 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
NSBubbleData *data = [[self.bubbleSection objectAtIndex:indexPath.section] objectAtIndex:indexPath.row - 1];
if (cell == nil) cell = [[UIBubbleTableViewCell alloc] init];
+
cell.data = data;
+ cell.showAvatar = self.showAvatars;
+
return cell;
}
@@ -14,5 +14,6 @@
@interface UIBubbleTableViewCell : UITableViewCell
@property (nonatomic, strong) NSBubbleData *data;
+@property (nonatomic) BOOL showAvatar;
@end
@@ -8,13 +8,15 @@
// To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/
//
+#import <QuartzCore/QuartzCore.h>
#import "UIBubbleTableViewCell.h"
#import "NSBubbleData.h"
@interface UIBubbleTableViewCell ()
@property (nonatomic, retain) UIView *customView;
@property (nonatomic, retain) UIImageView *bubbleImage;
+@property (nonatomic, retain) UIImageView *avatarImage;
- (void) setupInternalData;
@@ -25,6 +27,7 @@ @implementation UIBubbleTableViewCell
@synthesize data = _data;
@synthesize customView = _customView;
@synthesize bubbleImage = _bubbleImage;
+@synthesize showAvatar = _showAvatar;
- (void)setFrame:(CGRect)frame
{
@@ -35,22 +38,16 @@ - (void)setFrame:(CGRect)frame
#if !__has_feature(objc_arc)
- (void) dealloc
{
- [_data release];
- _data = nil;
- [_customView release];
- _customView = nil;
+ self.data = nil;
+ self.customView = nil;
+ self.bubbleImage = nil;
[super dealloc];
}
#endif
-
- (void)setDataInternal:(NSBubbleData *)value
{
-#if !__has_feature(objc_arc)
- [value retain];
- [_data release];
-#endif
- _data = value;
+ self.data = value;
[self setupInternalData];
}
@@ -60,7 +57,7 @@ - (void) setupInternalData
if (!self.bubbleImage)
{
- self.bubbleImage = [[UIImageView alloc] init];
+ self.bubbleImage = [[[UIImageView alloc] init] autorelease];
[self addSubview:self.bubbleImage];
}
@@ -72,6 +69,29 @@ - (void) setupInternalData
CGFloat x = (type == BubbleTypeSomeoneElse) ? 0 : self.frame.size.width - width - self.data.insets.left - self.data.insets.right;
CGFloat y = 0;
+ // Adjusting the x coordinate for avatar
+ if (self.showAvatar)
+ {
+ [self.avatarImage removeFromSuperview];
+ self.avatarImage = [[[UIImageView alloc] initWithImage:(self.data.avatar ? self.data.avatar : [UIImage imageNamed:@"missingAvatar.png"])] autorelease];
+ self.avatarImage.layer.cornerRadius = 9.0;
+ self.avatarImage.layer.masksToBounds = YES;
+ self.avatarImage.layer.borderColor = [UIColor colorWithWhite:0.0 alpha:0.2].CGColor;
+ self.avatarImage.layer.borderWidth = 1.0;
+
+ CGFloat avatarX = (type == BubbleTypeSomeoneElse) ? 2 : self.frame.size.width - 52;
+ CGFloat avatarY = self.frame.size.height - 50;
+
+ self.avatarImage.frame = CGRectMake(avatarX, avatarY, 50, 50);
+ [self addSubview:self.avatarImage];
+
+ CGFloat delta = self.frame.size.height - (self.data.insets.top + self.data.insets.bottom + self.data.view.frame.size.height);
+ if (delta > 0) y = delta;
+
+ if (type == BubbleTypeSomeoneElse) x += 54;
+ if (type == BubbleTypeMine) x -= 54;
+ }
+
[self.customView removeFromSuperview];
self.customView = self.data.view;
self.customView.frame = CGRectMake(x + self.data.insets.left, y + self.data.insets.top, width, height);
@@ -15,5 +15,6 @@
+ (CGFloat)height;
@property (nonatomic) NSBubbleTypingType type;
+@property (nonatomic) BOOL showAvatar;
@end
@@ -17,7 +17,8 @@ @interface UIBubbleTypingTableViewCell ()
@implementation UIBubbleTypingTableViewCell
@synthesize type = _type;
-@synthesize typingImageView;
+@synthesize typingImageView = _typingImageView;
+@synthesize showAvatar = _showAvatar;
+ (CGFloat)height
{

0 comments on commit 1a85a17

Please sign in to comment.