Swift - QQ讨论组头像的实现 (多人聊天的组合头像)
生活随笔
收集整理的這篇文章主要介紹了
Swift - QQ讨论组头像的实现 (多人聊天的组合头像)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
我們知道?QQ?里面的聯系人頭像是圓形的。當我們發起多人聊天時,會自動生成一個討論組。這個討論組的頭像圖標是由組內人員頭像自動組合生成的。比如:組內有兩個人,就用兩個人的頭像組合成討論組的頭像圖標。有三個就是用三個頭像來組成,以此類推。最多5個。
本文演示如何實現這種組合頭像的功能。
(2)GroupIcon.swift(組合頭像組件)
源碼下載:
hangge_1462.zip
原文出自: www.hangge.com ??轉載請保留原文鏈接: http://www.hangge.com/blog/cache/detail_1462.html
1,討論組頭像組件效果圖
(1)根據初始化傳入的圖片數組中圖片數量的不同(超過?5?張圖片的話也只顯示前?5?個),組件會自動設置內部圖片的尺寸和位置。 (2)為了讓顯示效果更好,多張圖片組合時不是簡單地將每張圖片裁剪成圓形。而會根據位置,向內凹陷一部分。 (3)組件默認背景是透明的,這里為了更好的演示將背景設置成灰色。2,組件代碼
(1)GroupIconCell.swift(組件內部的圓形圖標)- 初始化參數中?isClip?表示圖標是否要裁剪。
- 如果不裁剪,則生成圓形的圖標。
- 如果裁剪,則根據?degrees?角度參數,在對應的位置掏一個弧形的缺口。(其實代碼中的剪切路徑是由兩段圓弧組成。外面的大圓弧和內陷的圓弧)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | import?UIKit //組合圖標內部小圖標 class?GroupIconCell:CALayer?{ ????//使用的圖片 ????var?image:?UIImage! ????//裁剪缺口位于圓上的位置(0~360度,0為y軸向下位置,順時針旋轉) ????var?degrees:?Double! ????//是否裁剪 ????var?isClip:?Bool? ????? ????//裁剪角度的一半(30即表示裁剪角度為60度,即圓弧上裁剪部分是1/6(60/360)) ????let?clipHalfAngle:Double?= 30 ????? ????//初始化 ????init(image:?UIImage, degrees:?Double, isClip:?Bool) { ????????super.init() ????????//參數初始化 ????????self.degrees = degrees ????????self.image = image ????????self.isClip = isClip ????????//這個記得設置,否則圖片在Retina設備上顯示不準確,會模糊 ????????self.contentsScale =?UIScreen.main.scale ????} ????? ????required?init?(coder aDecoder:?NSCoder) { ????????fatalError("init(coder:) has not been implemented") ????} ????? ????//繪制內容 ????override?func?draw(in?ctx:?CGContext) { ????????super.draw(in: ctx) ????????let?bounds =?self.bounds ????????//尺寸 ????????let?size = bounds.size ????????//半徑 ????????let?radius = size.width/2 ????????//中心點位置 ????????let?center =?CGPoint(x:bounds.midX, y:bounds.midY) ????????//為方便操作,先變換坐標系 ????????var?transform =?CGAffineTransform.identity ????????transform = transform.translatedBy(x: center.x, y: center.y) ????????transform = transform.rotated(by:?CGFloat(radians(degrees:?self.degrees))) ????????transform = transform.translatedBy(x: -center.x, y: -center.y) ????????? ????????let?path =?CGMutablePath() ????????//判斷是非裁剪 ????????if?self.isClip! { ????????????//繪制大圓弧 ????????????let?angle1 = radians(degrees: (90.0-clipHalfAngle)) ????????????let?angle2 = radians(degrees: (90.0+clipHalfAngle)) ????????????path.addArc(center: center, radius: radius, ????????????????????????startAngle: angle1, endAngle: angle2, ????????????????????????clockwise:?true, transform: transform) ????????????? ????????????//繪制小圓弧(形成缺口) ????????????let?angle3 = radians(degrees: (clipHalfAngle)) ????????????let?tangent1End =?CGPoint(x:radius, ??????????????????????????????????????y:radius+(radius*sin(angle1) - ????????????????????????????????????????radius*sin(angle3)*tan(angle3))) ????????????let?tangent2End =?CGPoint(x:radius+radius*sin(angle3), ??????????????????????????????????????y:radius+radius*sin(angle1)) ????????????path.addArc(tangent1End: tangent1End, tangent2End: tangent2End, ????????????????????????radius: radius, transform: transform) ????????}?else?{ ????????????//不裁剪的話直接畫個圓 ????????????path.addEllipse(in: bounds) ????????} ????????? ????????//開始圖片處理上下文(由于輸出的圖不會進行縮放,所以縮放因子等于屏幕的scale即可) ????????UIGraphicsBeginImageContextWithOptions(self.frame.size,?false, 0) ????????let?bezierPath =?UIBezierPath(cgPath: path) ????????bezierPath.close() ????????//添加路徑裁剪 ????????bezierPath.addClip() ????????//圖片繪制 ????????self.image.draw(in:?self.bounds) ????????//獲得處理后的圖片 ????????let?maskedImage =?UIGraphicsGetImageFromCurrentImageContext()! ????????//結束上下文 ????????UIGraphicsEndImageContext() ????????? ????????//進入新狀態 ????????UIGraphicsPushContext(ctx) ????????//繪制裁剪后的圖像 ????????maskedImage.draw(in:?self.bounds) ????????//回到之前狀態 ????????UIGraphicsPopContext() ????} } //將角度轉為弧度 func?radians(degrees:?Double)->CGFloat?{ ????return?CGFloat(degrees/Double(180.0) *?M_PI) } |
(2)GroupIcon.swift(組合頭像組件)
- 組件初始化的時候會根據圖片數組里圖片數量,來調用相應的內部圖片元素創建方法。
- 每種創建方法里的行為都差不多。即計算內部圖標的尺寸,創建圖片并放置到對應的位置。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | import?UIKit //組合圖標 class?GroupIcon:UIView?{ ????//整個組合圖標的長寬尺寸(兩個相等) ????var?wh:CGFloat! ????//組合圖標內部使用的圖片 ????var?images:[UIImage]! ????? ????//初始化 ????init(wh:CGFloat, images:[UIImage]) { ????????//初始化 ????????super.init(frame:CGRect(x:0, y:0, width:wh, height:wh)) ????????self.wh = wh ????????self.images = images ????????? ????????//背景默認透明 ????????self.backgroundColor =?UIColor.clear ????????? ????????//如果傳入的圖片數組為空,就不繼續創建內部元素了 ????????if?(self.images.count <= 0) { ????????????return ????????} ????????? ????????//根據數量的不同,調用不同的創建方法 ????????switch?images.count{ ????????case?1: ????????????self.createCells1() ????????case?2: ????????????self.createCells2() ????????case?3: ????????????self.createCells3() ????????case?4: ????????????self.createCells4() ????????case?5: ????????????//如果有5個或5個以上的圖片的話,都只使用前5個圖片 ????????????fallthrough ????????default: ????????????self.createCells5() ????????????break ????????} ????} ????? ????required?init?(coder aDecoder:?NSCoder) { ????????fatalError("init(coder:) has not been implemented") ????} ????? ????//創建內部圖標元素(只有一個圖標的情況) ????func?createCells1(){ ????????//內部小圖標的直徑 ????????let?cellD =?self.wh! ????????//內部小圖標的半徑 ????????let?cellR = cellD / 2 ????????//內部每個小圖標的尺寸 ????????let?cellSize =?CGSize(width:cellD, height:cellD) ????????? ????????//第1個小圖標 ????????let?layer0 =?GroupIconCell(image:images[0], degrees:0, isClip:false) ????????let?center0 =?CGPoint(x:cellR, y:cellR) ????????layer0.frame = getRect(center: center0, size: cellSize) ????????self.layer.addSublayer(layer0) ????????layer0.setNeedsDisplay() ????} ????? ????//創建內部圖標元素(有2個圖標的情況) ????func?createCells2(){ ????????//內部小圖標的直徑 ????????let?cellD = (self.wh+self.wh-CGFloat(sqrtf(2))*self.wh) ????????//內部小圖標的半徑 ????????let?cellR = cellD / 2 ????????//內部每個小圖標的尺寸 ????????let?cellSize =?CGSize(width:cellD, height:cellD) ????????? ????????//第1個小圖標 ????????let?layer0 =?GroupIconCell(image:images[0], degrees:0, isClip:false) ????????let?center0 =?CGPoint(x:cellR, y:cellR) ????????layer0.frame = getRect(center: center0, size: cellSize) ????????self.layer.addSublayer(layer0) ????????layer0.setNeedsDisplay() ????????? ????????//第2個小圖標 ????????let?layer1 =?GroupIconCell(image:images[1], degrees:180 - 45, isClip:true) ????????let?center1 =?CGPoint(x:cellR+CGFloat(sqrtf(2))*cellD/2, ??????????????????????????????y:cellR+CGFloat(sqrtf(2))*cellD/2) ????????layer1.frame = getRect(center: center1, size: cellSize) ????????self.layer.addSublayer(layer1) ????????layer1.setNeedsDisplay() ????} ????? ????//創建內部圖標元素(有3個圖標的情況) ????func?createCells3(){ ????????//內部小圖標的直徑 ????????let?cellD =?self.wh/2 ????????//內部每個小圖標的尺寸 ????????let?cellSize =?CGSize(width:cellD, height:cellD) ????????? ????????//第1個小圖標 ????????let?layer0 =?GroupIconCell(image:images[0], degrees:30, isClip:true) ????????let?center0 =?CGPoint(x:cellD, y:cellD/2) ????????layer0.frame = getRect(center: center0, size: cellSize) ????????self.layer.addSublayer(layer0) ????????layer0.setNeedsDisplay() ????????? ????????//第2個小圖標 ????????let?layer1 =?GroupIconCell(image:images[1], degrees:270, isClip:true) ????????let?center1 =?CGPoint(x:center0.x-cellD*sin(radians(degrees: 30)), ??????????????????????????????y:cellD/2+cellD*cos(radians(degrees: 30))) ????????layer1.frame = getRect(center: center1, size: cellSize) ????????self.layer.addSublayer(layer1) ????????layer1.setNeedsDisplay() ????????? ????????//第2個小圖標 ????????let?layer2 =?GroupIconCell(image:images[2], degrees:180 - 30, isClip:true) ????????let?center2 =?CGPoint(x:center1.x+cellD, y:center1.y) ????????layer2.frame = getRect(center: center2, size: cellSize) ????????self.layer.addSublayer(layer2) ????????layer2.setNeedsDisplay() ????} ????? ????//創建內部圖標元素(有4個圖標的情況) ????func?createCells4(){ ????????//內部小圖標的直徑 ????????let?cellD =?self.wh/2 ????????//內部小圖標的半徑 ????????let?cellR = cellD / 2 ????????//內部每個小圖標的尺寸 ????????let?cellSize =?CGSize(width:cellD, height:cellD) ????????? ????????//第1個小圖標 ????????let?layer0 =?GroupIconCell(image:images[0], degrees:0, isClip:true) ????????let?center0 =?CGPoint(x:cellR, y:cellR) ????????layer0.frame = getRect(center: center0, size: cellSize) ????????self.layer.addSublayer(layer0) ????????layer0.setNeedsDisplay() ????????? ????????//第2個小圖標 ????????let?layer1 =?GroupIconCell(image:images[1], degrees:270, isClip:true) ????????let?center1 =?CGPoint(x:center0.x, y:center0.y+cellD) ????????layer1.frame = getRect(center: center1, size: cellSize) ????????self.layer.addSublayer(layer1) ????????layer1.setNeedsDisplay() ????????? ????????//第3個小圖標 ????????let?layer2 =?GroupIconCell(image:images[2], degrees:180, isClip:true) ????????let?center2 =?CGPoint(x:center1.x+cellD, y:center1.y) ????????layer2.frame = getRect(center:center2, size: cellSize) ????????self.layer.addSublayer(layer2) ????????layer2.setNeedsDisplay() ????????? ????????//第4個小圖標 ????????let?layer3 =?GroupIconCell(image:images[3], degrees:90, isClip:true) ????????let?center3 =?CGPoint(x:center2.x, y:center2.y-cellD) ????????layer3.frame = getRect(center:center3, size: cellSize) ????????self.layer.addSublayer(layer3) ????????layer3.setNeedsDisplay() ????} ????? ????//創建內部圖標元素(有5個圖標的情況) ????func?createCells5(){ ????????//內部小圖標的半徑 ????????let?cellR =?self.wh/2/(2*sin(radians(degrees: 54))+1) ????????//內部小圖標的直徑 ????????let?cellD = cellR*2 ????????//內部每個小圖標的尺寸 ????????let?cellSize =?CGSize(width:cellD, height:cellD) ????????? ????????//第1個小圖標 ????????let?layer0 =?GroupIconCell(image:images[0], degrees:54, isClip:true) ????????let?center0 =?CGPoint(x:self.wh/2, y:cellR) ????????layer0.frame = getRect(center:center0, size: cellSize) ????????self.layer.addSublayer(layer0) ????????layer0.setNeedsDisplay() ????????? ????????//第2個小圖標 ????????let?layer1 =?GroupIconCell(image:images[1], degrees:270 + 72, isClip:true) ????????let?center1 =?CGPoint(x:center0.x-cellD*sin(radians(degrees: 54)), ??????????????????????????????y:center0.y+cellD*cos(radians(degrees: 54))) ????????layer1.frame = getRect(center:center1, size: cellSize) ????????self.layer.addSublayer(layer1) ????????layer1.setNeedsDisplay() ????????? ????????//第3個小圖標 ????????let?layer2 =?GroupIconCell(image:images[2], degrees:270, isClip:true) ????????let?center2 =?CGPoint(x:center1.x+cellD*cos(radians(degrees: 72)), ??????????????????????????????y:center1.y+cellD*sin(radians(degrees: 72))) ????????layer2.frame = getRect(center:center2, size: cellSize) ????????self.layer.addSublayer(layer2) ????????layer2.setNeedsDisplay() ????????? ????????//第4個小圖標 ????????let?layer3 =?GroupIconCell(image:images[3], degrees:180 + 18, isClip:true) ????????let?center3 =?CGPoint(x:center2.x+cellD, y:center2.y) ????????layer3.frame = getRect(center:center3, size: cellSize) ????????self.layer.addSublayer(layer3) ????????layer3.setNeedsDisplay() ????????? ????????//第5個小圖標 ????????let?layer4 =?GroupIconCell(image:images[4], degrees:90 + 36, isClip:true) ????????let?center4 =?CGPoint(x:center3.x+cellD*cos(radians(degrees: 72)), ??????????????????????????????y:center3.y-cellD*sin(radians(degrees: 72))) ????????layer4.frame = getRect(center:center4, size: cellSize) ????????self.layer.addSublayer(layer4) ????????layer4.setNeedsDisplay() ????} ????? ????//通過中心點坐標和Size尺寸,返回對應的CGRect ????func?getRect(center:CGPoint, size:CGSize) ->?CGRect?{ ????????return?CGRect(x:center.x - size.width / 2, y:center.y - size.height / 2, ??????????????????????width:size.width, height:size.height) ????} } |
3,使用樣例
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | import?UIKit class?ViewController:?UIViewController?{ ????override?func?viewDidLoad() { ????????super.viewDidLoad() ????????? ????????//討論組圖標尺寸(長寬一樣) ????????let?viewWH:CGFloat?= 140 ????????//討論組圖標背景色(這里使用灰色,不設置的話則是透明的) ????????let?viewBgColor =?UIColor(red: 0, green:0, blue: 0, alpha: 0.1) ????????? ????????//只由1張圖片組成的討論組圖標 ????????let?view1 =?GroupIcon(wh: viewWH, images: [UIImage(named:"0")!]) ????????view1.center =?CGPoint(x:85, y:90) ????????view1.backgroundColor = viewBgColor ????????self.view.addSubview(view1) ????????? ????????//由2張圖片組成的討論組圖標 ????????let?view2 =?GroupIcon(wh: viewWH, images: [UIImage(named:"0")!,UIImage(named:"1")!]) ????????view2.center =?CGPoint(x:235, y:90) ????????view2.backgroundColor = viewBgColor ????????self.view.addSubview(view2) ????????? ????????//由3張圖片組成的討論組圖標 ????????let?view3 =?GroupIcon(wh: viewWH, images: [UIImage(named:"0")!,UIImage(named:"1")!, ???????????????????????????????????????????????????UIImage(named:"2")!]) ????????view3.center =?CGPoint(x:85, y:240) ????????view3.backgroundColor = viewBgColor ????????self.view.addSubview(view3) ????????? ????????//由4張圖片組成的討論組圖標 ????????let?view4 =?GroupIcon(wh: viewWH, images: [UIImage(named:"0")!,UIImage(named:"1")!, ???????????????????????????????????????????????????UIImage(named:"2")!,UIImage(named:"3")!]) ????????view4.center =?CGPoint(x:235, y:240) ????????view4.backgroundColor = viewBgColor ????????self.view.addSubview(view4) ????????//由5張圖片組成的討論組圖標 ????????let?view5 =?GroupIcon(wh: viewWH, images: [UIImage(named:"0")!,UIImage(named:"1")!, ???????????????????????????????????????????????????UIImage(named:"2")!,UIImage(named:"3")!, ???????????????????????????????????????????????????UIImage(named:"4")!]) ????????view5.center =?CGPoint(x:85, y:390) ????????view5.backgroundColor = viewBgColor ????????self.view.addSubview(view5) ????} ????override?func?didReceiveMemoryWarning() { ????????super.didReceiveMemoryWarning() ????} } |
原文出自: www.hangge.com ??轉載請保留原文鏈接: http://www.hangge.com/blog/cache/detail_1462.html
總結
以上是生活随笔為你收集整理的Swift - QQ讨论组头像的实现 (多人聊天的组合头像)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大疆推教育机器人已到第二代!机器人编程玩
- 下一篇: CentOS编译安装subversion