前沿
最近公司也在搞一個群聊功能贪绘,再看到產(chǎn)品設計后就想到了肯定是要仿照微信進行群成員頭像拼接的方式了徘键。說時遲那時快练对,兩三下就搞定了哈!為了方便各位碼友吹害,特將源碼獻上螟凭。不用客氣。
先來一張示例圖
7人群聊.jpg
言歸正傳
1它呀、使用場景
一般情況都是在cell上面進行展示螺男,如果頻繁的進行圖片拼接操作肯定非常耗性能,因此肯定要進行性能優(yōu)化纵穿。
2下隧、使用邏輯
各位明白人肯定想到用緩存的,類似于微信再不存在點擊群聊詳情的時候我們沒有必要去重新生成新的群聊拼接圖片谓媒。我這邊采用了兩張方式獲取緩存的拼接圖片淆院。
/**
類似于微信:如果不點擊圖片詳情則不會主動更新群圖片
*/
- (NSData*)avatarDataWithGroupId:(NSString*)groupId headImgUrls:(NSString*)imgUrls;
/**
在非詳情時,根據(jù)群id獲取頭像
*/
- (NSData*)avatarDataWithGroupId:(NSString*)groupId;
實現(xiàn)方法 僅供參考
- (NSData*)avatarDataWithGroupId:(NSString*)groupId headImgUrls:(NSString*)imgUrls
{
if(groupId == nil || imgUrls.length == 0)return nil;
[_db open];
NSData* resultData = nil;
// 根據(jù)請求參數(shù)查詢數(shù)據(jù)
FMResultSet *resultSet = nil;
resultSet = [_db executeQuery:@"SELECT * FROM IM_GROUP_AVATAR_Table WHERE groupid = ? AND imgurls = ? ;",groupId,imgUrls];
// 遍歷查詢結(jié)果
while (resultSet.next) {
NSData *value = [resultSet objectForColumn:@"avatar"];
if(value){
resultData = value;
break;
}
}
[_db close];
if(resultData == nil){///這種情況下找不到對應的圖片句惯,則說明群聊的圖片集合更新了
[self deleteGroupAvatarDataWithGroupId:groupId];
return nil;
}
return resultData;
}
- (NSData*)avatarDataWithGroupId:(NSString*)groupId
{
if(groupId == nil)return nil;
[_db open];
NSData* resultData = nil;
// 根據(jù)請求參數(shù)查詢數(shù)據(jù)
FMResultSet *resultSet = nil;
resultSet = [_db executeQuery:@"SELECT * FROM IM_GROUP_AVATAR_Table WHERE groupid = ?;",groupId];
// 遍歷查詢結(jié)果
while (resultSet.next) {
NSData *value = [resultSet objectForColumn:@"avatar"];
if(value){
resultData = value;
break;
}
}
[_db close];
if(resultData == nil){
return nil;
}
return resultData;
}
///當通過groupid和imageurls尋找頭像無法找到時土辩,則說明頭像更改了支救,則先將數(shù)據(jù)庫中的無效群頭像刪除
- (void)deleteGroupAvatarDataWithGroupId:(NSString*)groupId
{
[_db open];
BOOL isFlag = [_db executeUpdate:@"DELETE FROM IM_GROUP_AVATAR_Table WHERE groupid = ? ;",groupId];
[_db close];
if(isFlag){
KFLog(@"已刪除無效的群頭像");
}
}
圖片的拼接
我這里的圖片加載方式是大家都用的SDWebImage,相信你不會陌生拷淘!
這里就直接貼上拼接的源碼搂妻,
///給一個寬度和高度一致的大圖片,用來顯示畫布的大小
static const CGFloat nomalViewWidth = 200;
@implementation BDCreatGroupAvatar
+ (void)createGroupAvatar:(NSArray *)group completeBlock:(void (^)(NSData *groupAvatar))completeBlock {
__block NSInteger loadCount = 0;
NSInteger avatarCount = group.count > 9 ? 9 : group.count;
CGFloat width = 0;//先默認寬帶
CGFloat space = 2;//圖片的間距
CGFloat x = 0;
CGFloat y = 0;
if(avatarCount == 1){
width = nomalViewWidth-2*3;
}else if (avatarCount >= 2 && avatarCount <= 4){
width = (nomalViewWidth-3*space)*0.5;
}else{
width = 1.0*(nomalViewWidth-4*space)/3;
}
NSMutableArray *resultDataArray = [NSMutableArray arrayWithCapacity:group.count];
NSMutableArray *resultFrameArray = [NSMutableArray arrayWithCapacity:group.count];
for (int i = 0; i<group.count; i++) {
NSString *avatarUrl = group[I];
if(avatarCount == 1){
x = 3;
y = 3;
}else if (avatarCount == 2){
x = (i*width)+space;
y = (nomalViewWidth-width)*0.5;
}else if (avatarCount == 3){
if(i == 0){
x = (nomalViewWidth-width)*0.5;
y = space;
}else if (i == 1){
x = space;
y = width+2*space;
}else{
x = width+2*space;
y = width+2*space;
}
}else if (avatarCount == 4){
NSInteger maxLinePerCount = 2;
x = (i%maxLinePerCount) * (width+space)+space;
y = (i/maxLinePerCount) * (width+space)+space;
}else if (avatarCount == 5){
if(i == 0){
x = (nomalViewWidth*0.5)-(space*0.5)-width;
y = (nomalViewWidth-2*width-space)*0.5;
}else if (i == 1){
x = (nomalViewWidth*0.5)+(space*0.5);
y = (nomalViewWidth-2*width-space)*0.5;
}else{
x = (i-2)*(width+space)+space;
y = (nomalViewWidth-2*width-space)*0.5+width+space;
}
}else if (avatarCount == 6){
NSInteger maxLinePerCount = 3;
CGFloat ySpace = (nomalViewWidth-2*width-space)*0.5;
x = (i%maxLinePerCount) * (width+space)+space;
y = (i/maxLinePerCount) * (width+space)+ySpace;
}else{
NSInteger maxLinePerCount = 3;
x = (i%maxLinePerCount) * (width+space)+space;
y = (i/maxLinePerCount) * (width+space)+space;
}
CGRect imageFrame = CGRectMake(x, y, width, width);
NSValue *frameValue = [NSValue valueWithCGRect:imageFrame];
[resultFrameArray addObject:frameValue];
[[SDWebImageManager sharedManager] loadImageWithURL:[NSURL URLWithString:avatarUrl] options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
loadCount ++ ;
UIImage *loadImage = nil;
if(image == nil){
loadImage = BD_PLACE_HEAD_IMAGE;
}else{
loadImage = image;
}
///將壓縮后的圖片進行暫存
NSData *resultData = [loadImage compressQualityWithMaxLength:1024*1024*0.5];
[resultDataArray addObject:resultData];
if (loadCount == avatarCount) { //圖片全部下載完成
CGSize contentSize = CGSizeMake(nomalViewWidth, nomalViewWidth);
//1.創(chuàng)建上下文尺寸
UIGraphicsBeginImageContextWithOptions(contentSize, true, 0.0);
CGContextRef ref = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(ref, 1.0*239/255, 1.0*239/255, 1.0*239/255, 1);
CGContextFillRect(ref, CGRectMake(0, 0, nomalViewWidth, nomalViewWidth));
for (int i = 0; i<resultDataArray.count; i++) {
NSData *imageData = resultDataArray[I];
NSValue *frameValue = resultFrameArray[I];
CGRect imageViewFrame = frameValue.CGRectValue;
UIImage *image = [[UIImage alloc]initWithData:imageData];
[image drawInRect:imageViewFrame];
}
UIImage *resultImg = UIGraphicsGetImageFromCurrentImageContext();//從當前上下文中獲得最終圖片
UIGraphicsEndImageContext();//關閉上下文
NSData *thetData = [resultImg compressQualityWithMaxLength:1024*1024*0.5];
dispatch_async(dispatch_get_main_queue(), ^{
if (completeBlock) {
completeBlock(thetData);
}
});
}
}];
}
}
代碼簡單說明:
1辕棚、設置畫布背景色
CGContextRef ref = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(ref, 1.0*239/255, 1.0*239/255, 1.0*239/255, 1);
CGContextFillRect(ref, CGRectMake(0, 0, nomalViewWidth, nomalViewWidth));
2欲主、以上針對1至6張圖片時,是一個個判斷的逝嚎,如果各位有好的點子可以回復告知一下哈扁瓢!
3、resultDataArray和resultFrameArray里面的元素沒有確保按位置匹配补君,這個一般應該不會要求吧引几,如果有要求的話,可以使用信號量挽铁,每次加載一張圖片完成后再加載第二張伟桅,這樣順序就不會亂了。
以上代碼有點長叽掘,但是呢已經(jīng)將整個流程代碼貼上了楣铁,不喜歡可以噴我哈,我只是想分享一下更扁,如果喜歡就點個贊吧盖腕!