You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
233 lines
10 KiB
233 lines
10 KiB
1 year ago
|
//
|
||
|
// 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
|