// // XHBubblePhotoImageView.m // MessageDisplayExample // // Created by HUAJIE-1 on 14-4-28. // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved. // #import "XHBubblePhotoImageView.h" #import "UIView+XHRemoteImage.h" #import "UIImage+Resize.h" #import "XHConfigurationHelper.h" #import "XHMacro.h" #import "CJFileUtility.h" @interface XHBubblePhotoImageView () @property dispatch_semaphore_t semaphore; /** * 消息类型 */ @property (nonatomic, assign) XHBubbleMessageType bubbleMessageType; @end @implementation XHBubblePhotoImageView - (XHBubbleMessageType)getBubbleMessageType { return self.bubbleMessageType; } - (UIActivityIndicatorView *)activityIndicatorView { if (!_activityIndicatorView) { _activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; _activityIndicatorView.hidesWhenStopped = YES; } return _activityIndicatorView; } - (void)setMessagePhoto:(UIImage *)messagePhoto { _messagePhoto = messagePhoto; [self setNeedsDisplay]; } - (void)configureMessagePhoto:(UIImage *)messagePhoto thumbnailUrl:(NSString *)thumbnailUrl originPhotoUrl:(NSString *)originPhotoUrl onBubbleMessageType:(XHBubbleMessageType)bubbleMessageType { self.bubbleMessageType = bubbleMessageType; self.messagePhoto = messagePhoto; NSLog(@"%@",self.message); if (thumbnailUrl) { WEAKSELF [self addSubview:self.activityIndicatorView]; [self.activityIndicatorView startAnimating]; NSString *placeholderImageName = [[XHConfigurationHelper appearance].messageInputViewStyle objectForKey:kXHMessageTablePlaceholderImageNameKey]; if (!placeholderImageName) { placeholderImageName = @"placeholderImage"; } self.messagePhoto = [UIImage imageNamed:placeholderImageName]; [self setImageWithURL:[NSURL URLWithString:thumbnailUrl] placeholer:nil showActivityIndicatorView:NO completionBlock:^(UIImage *image, NSURL *url, NSError *error) { if ([url.absoluteString isEqualToString:thumbnailUrl]) { if (CGRectEqualToRect(weakSelf.bounds, CGRectZero)) { if (weakSelf) { weakSelf.semaphore = dispatch_semaphore_create(0); dispatch_semaphore_wait(weakSelf.semaphore, DISPATCH_TIME_FOREVER); weakSelf.semaphore = nil; } } // if image not nil if (image) { // scale image image = [image thumbnailImage:CGRectGetWidth(weakSelf.bounds) * 2 transparentBorder:0 cornerRadius:0 interpolationQuality:1.0]; dispatch_async(dispatch_get_main_queue(), ^{ // if image not nil if (image) { // show image weakSelf.messagePhoto = image; [weakSelf.activityIndicatorView stopAnimating]; NSString *path = [CJFileUtility documentsPathSubDir:@"msg_image" andFile:[weakSelf.message id]]; [CJFileUtility writeToFile:path data:UIImageJPEGRepresentation(image ,1)]; } }); } } }]; } } - (void)setFrame:(CGRect)frame { [super setFrame:frame]; if (self.semaphore) { dispatch_semaphore_signal(self.semaphore); } _activityIndicatorView.center = CGPointMake(CGRectGetWidth(self.bounds) / 2.0, CGRectGetHeight(self.bounds) / 2.0); } - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code self.backgroundColor = [UIColor clearColor]; self.userInteractionEnabled = YES; } return self; } - (void)dealloc { _messagePhoto = nil; [self.activityIndicatorView stopAnimating]; self.activityIndicatorView = nil; } // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code rect.origin = CGPointZero; [self.messagePhoto drawInRect:rect]; CGFloat width = rect.size.width; CGFloat height = rect.size.height + 1;//莫名其妙会出现绘制底部有残留 +1像素遮盖 // 简便起见,这里把圆角半径设置为长和宽平均值的1/10 CGFloat radius = 6; CGFloat margin = kXHBubblePhotoMargin;//留出上下左右的边距 CGFloat triangleSize = 8;//三角形的边长 CGFloat triangleMarginTop = 8;//三角形距离圆角的距离 CGFloat borderOffset = 3;//阴影偏移量 UIColor *borderColor = [UIColor blackColor];//阴影的颜色 // 获取CGContext,注意UIKit里用的是一个专门的函数 CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetRGBStrokeColor(context,0,0,0,1);//画笔颜色 CGContextSetLineWidth(context, 1);//画笔宽度 // 移动到初始点 CGContextMoveToPoint(context, radius + margin, margin); // 绘制第1条线和第1个1/4圆弧 CGContextAddLineToPoint(context, width - radius - margin, margin); CGContextAddArc(context, width - radius - margin, radius + margin, radius, -0.5 * M_PI, 0.0, 0); CGContextAddLineToPoint(context, width, margin + radius); CGContextAddLineToPoint(context, width, 0); CGContextAddLineToPoint(context, radius + margin,0); // 闭合路径 CGContextClosePath(context); // 绘制第2条线和第2个1/4圆弧 CGContextMoveToPoint(context, width - margin, margin + radius); CGContextAddLineToPoint(context, width, margin + radius); CGContextAddLineToPoint(context, width, height - margin - radius); CGContextAddLineToPoint(context, width - margin, height - margin - radius); float arcSize = 3;//角度的大小 if (self.bubbleMessageType == XHBubbleMessageTypeSending) { float arcStartY = margin + radius + triangleMarginTop + triangleSize - (triangleSize - arcSize / margin * triangleSize) / 2;//圆弧起始Y值 float arcStartX = width - arcSize;//圆弧起始X值 float centerOfCycleX = width - arcSize - pow(arcSize / margin * triangleSize / 2, 2) / arcSize;//圆心的X值 float centerOfCycleY = margin + radius + triangleMarginTop + triangleSize / 2;//圆心的Y值 float radiusOfCycle = hypotf(arcSize / margin * triangleSize / 2, pow(arcSize / margin * triangleSize / 2, 2) / arcSize);//半径 float angelOfCycle = asinf(0.5 * (arcSize / margin * triangleSize) / radiusOfCycle) * 2;//角度 //绘制右边三角形 CGContextAddLineToPoint(context, width - margin , margin + radius + triangleMarginTop + triangleSize); CGContextAddLineToPoint(context, arcStartX , arcStartY); CGContextAddArc(context, centerOfCycleX, centerOfCycleY, radiusOfCycle, angelOfCycle / 2, 0.0 - angelOfCycle / 2, 1); CGContextAddLineToPoint(context, width - margin , margin + radius + triangleMarginTop); } CGContextMoveToPoint(context, width - margin, height - radius - margin); CGContextAddArc(context, width - radius - margin, height - radius - margin, radius, 0.0, 0.5 * M_PI, 0); CGContextAddLineToPoint(context, width - margin - radius, height); CGContextAddLineToPoint(context, width, height); CGContextAddLineToPoint(context, width, height - radius - margin); // 绘制第3条线和第3个1/4圆弧 CGContextMoveToPoint(context, width - margin - radius, height - margin); CGContextAddLineToPoint(context, width - margin - radius, height); CGContextAddLineToPoint(context, margin, height); CGContextAddLineToPoint(context, margin, height - margin); CGContextMoveToPoint(context, margin, height-margin); CGContextAddArc(context, radius + margin, height - radius - margin, radius, 0.5 * M_PI, M_PI, 0); CGContextAddLineToPoint(context, 0, height - margin - radius); CGContextAddLineToPoint(context, 0, height); CGContextAddLineToPoint(context, margin, height); // 绘制第4条线和第4个1/4圆弧 CGContextMoveToPoint(context, margin, height - margin - radius); CGContextAddLineToPoint(context, 0, height - margin - radius); CGContextAddLineToPoint(context, 0, radius + margin); CGContextAddLineToPoint(context, margin, radius + margin); if (!(self.bubbleMessageType == XHBubbleMessageTypeSending)) { float arcStartY = margin + radius + triangleMarginTop + (triangleSize - arcSize / margin * triangleSize) / 2;//圆弧起始Y值 float arcStartX = arcSize;//圆弧起始X值 float centerOfCycleX = arcSize + pow(arcSize / margin * triangleSize / 2, 2) / arcSize;//圆心的X值 float centerOfCycleY = margin + radius + triangleMarginTop + triangleSize / 2;//圆心的Y值 float radiusOfCycle = hypotf(arcSize / margin * triangleSize / 2, pow(arcSize / margin * triangleSize / 2, 2) / arcSize);//半径 float angelOfCycle = asinf(0.5 * (arcSize / margin * triangleSize) / radiusOfCycle) * 2;//角度 //绘制左边三角形 CGContextAddLineToPoint(context, margin , margin + radius + triangleMarginTop); CGContextAddLineToPoint(context, arcStartX , arcStartY); CGContextAddArc(context, centerOfCycleX, centerOfCycleY, radiusOfCycle, M_PI + angelOfCycle / 2, M_PI - angelOfCycle / 2, 1); CGContextAddLineToPoint(context, margin , margin + radius + triangleMarginTop + triangleSize); } CGContextMoveToPoint(context, margin, radius + margin); CGContextAddArc(context, radius + margin, margin + radius, radius, M_PI, 1.5 * M_PI, 0); CGContextAddLineToPoint(context, margin + radius, 0); CGContextAddLineToPoint(context, 0, 0); CGContextAddLineToPoint(context, 0, radius + margin); // CGContextSetShadowWithColor(context, CGSizeMake(0, 0), borderOffset, borderColor.CGColor);//阴影 CGContextSetBlendMode(context, kCGBlendModeClear); CGContextDrawPath(context, kCGPathFill); } @end