2
0

WFCUFaceBoard.m 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. //
  2. // FaceBoard.m
  3. //
  4. // Created by blue on 12-9-26.
  5. // Copyright (c) 2012年 blue. All rights reserved.
  6. // Email - 360511404@qq.com
  7. // http://github.com/bluemood
  8. #import "WFCUFaceBoard.h"
  9. #import "WFCUStickerItem.h"
  10. #import "YLImageView.h"
  11. #import "YLGIFImage.h"
  12. #import "WFCUFaceButton.h"
  13. #import "WFCUConfigManager.h"
  14. #import "WFCUImage.h"
  15. #import "WFCUUtilities.h"
  16. #define FACE_COUNT_ROW 4
  17. #define FACE_COUNT_CLU 7
  18. #define FACE_COUNT_PAGE ( FACE_COUNT_ROW * FACE_COUNT_CLU - 1)
  19. #define FACE_ICON_SIZE 44
  20. #define STICKER_COUNT_ROW 2
  21. #define STICKER_COUNT_CLU 4
  22. #define STICKER_COUNT_PAGE ( STICKER_COUNT_ROW * STICKER_COUNT_CLU)
  23. #define STICKER_ICON_SIZE 80
  24. @interface WFCUFaceBoard() <UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UIScrollViewDelegate>
  25. @property(nonatomic, strong) NSArray *faceEmojiArray;
  26. @property(nonatomic,strong)UIView *tabbarView;
  27. @property(nonatomic,strong) UIButton *sendBtn;
  28. @property(nonatomic, strong)UIPageControl *facePageControl;
  29. @property(nonatomic, strong)UICollectionView *collectionView;
  30. @property(nonatomic, strong)UICollectionView *tabView;
  31. @property(nonatomic, strong)NSMutableDictionary<NSString *, WFCUStickerItem *> *stickers;
  32. @property(nonatomic, assign)int selectedTableRow;
  33. @end
  34. #define EMOJ_TAB_HEIGHT 42
  35. #define EMOJ_FACE_VIEW_HEIGHT 190
  36. #define EMOJ_PAGE_CONTROL_HEIGHT 20
  37. #define EMOJ_AREA_HEIGHT (EMOJ_TAB_HEIGHT + EMOJ_FACE_VIEW_HEIGHT + EMOJ_PAGE_CONTROL_HEIGHT)
  38. @implementation WFCUFaceBoard{
  39. int width;
  40. int location;
  41. }
  42. @synthesize delegate;
  43. + (NSString *)getStickerCachePath {
  44. NSArray * LibraryPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
  45. return [[LibraryPaths objectAtIndex:0] stringByAppendingFormat:@"/Caches/Patch/"];
  46. }
  47. + (NSString *)getStickerBundleName {
  48. NSString * bundleName = @"Stickers.bundle";
  49. return bundleName;
  50. }
  51. + (void)load {
  52. [WFCUFaceBoard initStickers];
  53. }
  54. + (void)initStickers {
  55. NSString * bundleName = [WFCUFaceBoard getStickerBundleName];
  56. NSError * err = nil;
  57. NSFileManager * defaultManager = [NSFileManager defaultManager];
  58. NSString * cacheBundleDir = [WFCUFaceBoard getStickerCachePath];
  59. NSLog(@"缓存资源目录: %@", cacheBundleDir);
  60. if (![defaultManager fileExistsAtPath:cacheBundleDir]) {
  61. [defaultManager createDirectoryAtPath:cacheBundleDir withIntermediateDirectories:YES attributes:nil error: &err];
  62. if(err){
  63. NSLog(@"初始化目录出错:%@", err);
  64. return;
  65. }
  66. }
  67. NSString * defaultBundlePath = [[NSBundle bundleForClass:[self class]].resourcePath stringByAppendingPathComponent: bundleName];
  68. NSString * cacheBundlePath = [cacheBundleDir stringByAppendingPathComponent:bundleName];
  69. if (![defaultManager fileExistsAtPath:cacheBundlePath]) {
  70. [defaultManager copyItemAtPath: defaultBundlePath toPath:cacheBundlePath error: &err];
  71. if(err){
  72. NSLog(@"复制初始资源文件出错:%@", err);
  73. }
  74. }
  75. }
  76. - (void)loadStickers {
  77. self.stickers = [[NSMutableDictionary alloc] init];
  78. NSString *stickerPath = [[WFCUFaceBoard getStickerCachePath] stringByAppendingPathComponent:[WFCUFaceBoard getStickerBundleName]];
  79. NSError * err = nil;
  80. NSFileManager * defaultManager = [NSFileManager defaultManager];
  81. NSArray *paths = [defaultManager contentsOfDirectoryAtPath:stickerPath error:&err];
  82. if (err != nil) {
  83. NSLog(@"error:%@", err);
  84. return;
  85. }
  86. for (NSString *file in paths) {
  87. BOOL isDir = false;
  88. NSString *absfile = [stickerPath stringByAppendingPathComponent:file];
  89. if ([defaultManager fileExistsAtPath:absfile isDirectory:&isDir]) {
  90. if (!isDir) {
  91. WFCUStickerItem *item = [[WFCUStickerItem alloc] init];
  92. item.key = file;
  93. item.tabIcon = absfile;
  94. item.stickerPaths = [[NSMutableArray alloc] init];
  95. NSString *name = [[file lastPathComponent] stringByDeletingPathExtension];
  96. NSString *stickerSubPath = [stickerPath stringByAppendingPathComponent:name];
  97. if ([defaultManager fileExistsAtPath:stickerSubPath isDirectory:&isDir]) {
  98. if (isDir) {
  99. NSArray *paths = [defaultManager contentsOfDirectoryAtPath:stickerSubPath error:&err];
  100. if (err != nil) {
  101. NSLog(@"error:%@", err);
  102. return;
  103. }
  104. for (NSString *p in paths) {
  105. NSString *stickerabsfile = [stickerSubPath stringByAppendingPathComponent:p];
  106. if ([defaultManager fileExistsAtPath:stickerabsfile isDirectory:&isDir]) {
  107. if (!isDir) {
  108. [item.stickerPaths addObject:stickerabsfile];
  109. }
  110. }
  111. }
  112. }
  113. }
  114. self.stickers[item.key] = item;
  115. } else {
  116. NSLog(@"is dir %@", absfile);
  117. }
  118. }
  119. }
  120. }
  121. - (id)init {
  122. width = [UIScreen mainScreen].bounds.size.width;
  123. self = [super initWithFrame:CGRectMake(0, 0, width, EMOJ_AREA_HEIGHT + [WFCUUtilities wf_safeDistanceBottom])];
  124. [self loadStickers];
  125. if (self) {
  126. self.backgroundColor = [WFCUConfigManager globalManager].backgroudColor;
  127. NSString *resourcePath = [[NSBundle bundleForClass:[self class]] resourcePath];
  128. NSString *bundlePath = [resourcePath stringByAppendingPathComponent:@"Emoj.plist"];
  129. self.faceEmojiArray = [[NSArray alloc]initWithContentsOfFile:bundlePath];
  130. [self addSubview:self.collectionView];
  131. //添加PageControl
  132. [self addSubview:self.facePageControl];
  133. _tabbarView = [[UIView alloc] initWithFrame:CGRectMake(0, self.frame.size.height - EMOJ_TAB_HEIGHT - [WFCUUtilities wf_safeDistanceBottom], self.frame.size.width, EMOJ_TAB_HEIGHT)];
  134. [self addSubview:_tabbarView];
  135. _sendBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  136. _sendBtn.tag = 333;
  137. _sendBtn.titleLabel.font = [UIFont systemFontOfSize:14.0f];
  138. _sendBtn.frame = CGRectMake(self.frame.size.width - 52,5,52, 37);
  139. [_sendBtn setTitle:WFCString(@"Send") forState:UIControlStateNormal];
  140. [_sendBtn setTitleColor:[WFCUConfigManager globalManager].textColor forState:UIControlStateNormal];
  141. self.sendBtn.layer.borderWidth = 0.5f;
  142. self.sendBtn.layer.borderColor = HEXCOLOR(0xdbdbdd).CGColor;
  143. [_sendBtn addTarget:self action:@selector(sendBtnHandle:) forControlEvents:UIControlEventTouchUpInside];
  144. [_tabbarView addSubview:_sendBtn];
  145. [_tabbarView addSubview:self.tabView];
  146. [_collectionView reloadData];
  147. [self.tabView setAllowsMultipleSelection:NO];
  148. self.tabView.allowsSelection = YES;
  149. self.selectedTableRow = 0;
  150. }
  151. return self;
  152. }
  153. - (void)setSelectedTableRow:(int)selectedTableRow {
  154. _selectedTableRow = selectedTableRow;
  155. [self.tabView reloadData];
  156. }
  157. - (UICollectionView *)tabView {
  158. if (!_tabView) {
  159. UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
  160. layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
  161. _tabView = [[UICollectionView alloc] initWithFrame:CGRectMake(0,5,self.frame.size.width - 52, 37) collectionViewLayout:layout];
  162. _tabView.delegate = self;
  163. _tabView.dataSource = self;
  164. _tabView.backgroundColor = [WFCUConfigManager globalManager].backgroudColor;
  165. _tabView.showsHorizontalScrollIndicator = NO;
  166. _tabView.userInteractionEnabled = YES;
  167. [_tabView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellId"];
  168. }
  169. return _tabView;
  170. }
  171. - (UICollectionView *)collectionView {
  172. if (!_collectionView) {
  173. UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
  174. layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
  175. layout.sectionInset = UIEdgeInsetsMake(0, 0, 0, 10);
  176. CGRect frame = self.bounds;
  177. frame.size.height = EMOJ_FACE_VIEW_HEIGHT;
  178. _collectionView = [[UICollectionView alloc] initWithFrame:frame collectionViewLayout:layout];
  179. _collectionView.delegate = self;
  180. _collectionView.dataSource = self;
  181. _collectionView.decelerationRate = 90;
  182. _collectionView.backgroundColor = [WFCUConfigManager globalManager].backgroudColor;
  183. _collectionView.showsHorizontalScrollIndicator = NO;
  184. [_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellId"];
  185. }
  186. return _collectionView;
  187. }
  188. - (UIPageControl *)facePageControl {
  189. if (!_facePageControl) {
  190. _facePageControl = [[UIPageControl alloc]initWithFrame:CGRectMake(width/2-100, EMOJ_FACE_VIEW_HEIGHT, 200, EMOJ_PAGE_CONTROL_HEIGHT)];
  191. [_facePageControl addTarget:self
  192. action:@selector(pageChange:)
  193. forControlEvents:UIControlEventValueChanged];
  194. _facePageControl.pageIndicatorTintColor = [UIColor grayColor];
  195. _facePageControl.currentPageIndicatorTintColor = [UIColor blackColor];
  196. _facePageControl.numberOfPages = [self getPagesCount:0];
  197. [self.tabView selectItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] animated:YES scrollPosition:UICollectionViewScrollPositionNone];
  198. [self.tabView reloadItemsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:0]]];
  199. _facePageControl.currentPage = 0;
  200. if (@available(iOS 14.0, *)) {
  201. _facePageControl.backgroundStyle = UIPageControlBackgroundStyleProminent;
  202. _facePageControl.allowsContinuousInteraction = YES;
  203. }
  204. }
  205. return _facePageControl;
  206. }
  207. - (void)sendBtnHandle:(id)sender {
  208. if ([self.delegate respondsToSelector:@selector(didTouchSendEmoj)]) {
  209. [self.delegate didTouchSendEmoj];
  210. }
  211. }
  212. - (int)pagesOfIndexPath:(NSIndexPath *)item {
  213. int pages = 0;
  214. for (int i = 0; i < item.section; i++) {
  215. pages += [self collectionView:self.collectionView numberOfItemsInSection:i];
  216. }
  217. pages += item.row;
  218. return pages;
  219. }
  220. - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
  221. if (scrollView == self.collectionView) {
  222. NSArray<NSIndexPath *> *items = [_collectionView indexPathsForVisibleItems];
  223. if (items.count == 2) {
  224. int pages0 = [self pagesOfIndexPath:items[0]];
  225. int pages1 = [self pagesOfIndexPath:items[1]];
  226. UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
  227. CGFloat offset0 = pages0 * (self.collectionView.bounds.size.width + layout.minimumLineSpacing);
  228. CGFloat offset1 = pages1 * (self.collectionView.bounds.size.width + layout.minimumInteritemSpacing);
  229. NSIndexPath *selectedOne;
  230. if (ABS(offset0-targetContentOffset->x) > ABS(offset1 - targetContentOffset->x)) {
  231. targetContentOffset->x = offset1;
  232. selectedOne = items[1];
  233. } else {
  234. targetContentOffset->x = offset0;
  235. selectedOne = items[0];
  236. }
  237. if (items[1].section != items[0].section) {
  238. self.facePageControl.numberOfPages = [self getPagesCount:selectedOne.section];
  239. self.selectedTableRow = selectedOne.section;
  240. }
  241. [self.facePageControl setCurrentPage:selectedOne.row];
  242. [self.facePageControl updateCurrentPageDisplay];
  243. } else if(items.count == 1) {
  244. int pages0 = [self pagesOfIndexPath:items[0]];
  245. UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
  246. CGFloat offset0 = pages0 * (self.collectionView.bounds.size.width + layout.minimumLineSpacing);
  247. targetContentOffset->x = offset0;
  248. }
  249. }
  250. }
  251. - (void)pageChange:(id)sender {
  252. }
  253. - (void)faceButton:(id)sender {
  254. int i = (int)((WFCUFaceButton*)sender).buttonIndex;
  255. if ([delegate respondsToSelector:@selector(didTouchEmoj:)]) {
  256. [delegate didTouchEmoj:self.faceEmojiArray[i]];
  257. }
  258. }
  259. - (void)backFace{
  260. if ([delegate respondsToSelector:@selector(didTouchBackEmoj)]) {
  261. [delegate didTouchBackEmoj];
  262. }
  263. }
  264. - (NSInteger)getPagesCount:(NSInteger)section {
  265. if (section == 0) {
  266. int FACE_COUNT_ALL = (int)self.faceEmojiArray.count;
  267. int pages;
  268. if (FACE_COUNT_ALL > 0) {
  269. pages = (FACE_COUNT_ALL - 1)/(FACE_COUNT_ROW * FACE_COUNT_CLU -1) + 1;
  270. } else {
  271. pages = 0;
  272. }
  273. return pages;
  274. } else {
  275. return (self.stickers[[self.stickers.allKeys objectAtIndex:(section - 1)]].stickerPaths.count - 1) / STICKER_COUNT_PAGE + 1;
  276. }
  277. }
  278. - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
  279. if (collectionView == self.collectionView) {
  280. if (self.disableSticker) {
  281. return 1;
  282. }
  283. return self.stickers.allKeys.count + 1;
  284. } else {
  285. return 1;
  286. }
  287. }
  288. - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
  289. if (collectionView == self.tabView) {
  290. NSIndexPath *minOne = [NSIndexPath indexPathForRow:0 inSection:indexPath.row];
  291. self.facePageControl.numberOfPages = [self getPagesCount:minOne.section];
  292. self.facePageControl.currentPage = 0;
  293. [_collectionView scrollToItemAtIndexPath:minOne atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
  294. self.selectedTableRow = indexPath.row;
  295. }
  296. }
  297. - (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath {
  298. }
  299. - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
  300. if (collectionView == self.collectionView) {
  301. return [self getPagesCount:section];
  302. } else {
  303. if (self.disableSticker) {
  304. return 1;
  305. }
  306. return self.stickers.allKeys.count + 1;
  307. }
  308. }
  309. - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
  310. if (collectionView == self.collectionView) {
  311. return self.collectionView.bounds.size;
  312. } else {
  313. return CGSizeMake(45, 37);
  314. }
  315. }
  316. - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
  317. UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellId" forIndexPath:indexPath];
  318. for (UIView *subView in [cell subviews]) {
  319. [subView removeFromSuperview];
  320. }
  321. if (collectionView == self.collectionView) {
  322. if (indexPath.section == 0) {
  323. int startPos = (int)indexPath.row * FACE_COUNT_PAGE;
  324. int endPos = (int)MIN(self.faceEmojiArray.count, startPos + FACE_COUNT_PAGE);
  325. for (int i = startPos; i <= endPos; i++) {
  326. int cli = (i - startPos)/FACE_COUNT_CLU;
  327. int col = (i - startPos)%FACE_COUNT_CLU;
  328. CGFloat x = col * width/7;
  329. CGFloat y = cli * FACE_ICON_SIZE + 8;
  330. if ((cli == FACE_COUNT_ROW -1 && col == FACE_COUNT_CLU - 1) || i == self.faceEmojiArray.count) {
  331. UIButton *back = [UIButton buttonWithType:UIButtonTypeCustom];
  332. [back setImage:[WFCUImage imageNamed:@"del_emoji_normal"] forState:UIControlStateNormal];
  333. [back setImage:[WFCUImage imageNamed:@"del_emoji_select"] forState:UIControlStateSelected];
  334. [back addTarget:self action:@selector(backFace) forControlEvents:UIControlEventTouchUpInside];
  335. if (i == self.faceEmojiArray.count) {
  336. x = (FACE_COUNT_CLU - 1) * width/7;
  337. y = (FACE_COUNT_ROW - 1) * FACE_ICON_SIZE + 8;
  338. }
  339. back.frame = CGRectMake( x, y, width/7, FACE_ICON_SIZE);
  340. [cell addSubview:back];
  341. } else {
  342. WFCUFaceButton *faceButton = [WFCUFaceButton buttonWithType:UIButtonTypeCustom];
  343. faceButton.buttonIndex = i;
  344. [faceButton addTarget:self
  345. action:@selector(faceButton:)
  346. forControlEvents:UIControlEventTouchUpInside];
  347. faceButton.frame = CGRectMake( x, y, width/7, FACE_ICON_SIZE);
  348. [faceButton setTitle:self.faceEmojiArray[i]
  349. forState:UIControlStateNormal];
  350. [cell addSubview:faceButton];
  351. }
  352. }
  353. } else {
  354. NSArray *paths = self.stickers[self.stickers.allKeys[indexPath.section - 1]].stickerPaths;
  355. int startPos = (int)indexPath.row * STICKER_COUNT_PAGE;
  356. int endPos = (int)MIN(paths.count, startPos + STICKER_COUNT_PAGE);
  357. for (int i = startPos; i < endPos; i++) {
  358. int cli = (i - startPos)/STICKER_COUNT_CLU;
  359. int col = (i - startPos)%STICKER_COUNT_CLU;
  360. CGFloat x = col * width/STICKER_COUNT_CLU;
  361. CGFloat y = cli * STICKER_ICON_SIZE + 8;
  362. UIImageView *imageView;
  363. if ([[paths[i] pathExtension] isEqualToString:@"gif"]) {
  364. imageView = [[YLImageView alloc] initWithFrame:CGRectMake( x + 10, y, width/STICKER_COUNT_CLU - 20, STICKER_ICON_SIZE)];
  365. imageView.image = [YLGIFImage imageWithContentsOfFile:paths[i]];
  366. } else {
  367. imageView = [[UIImageView alloc] initWithFrame:CGRectMake( x + 10, y, width/STICKER_COUNT_CLU - 20, STICKER_ICON_SIZE)];
  368. imageView.image = [UIImage imageWithContentsOfFile:paths[i]];
  369. }
  370. [imageView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTapSticker:)]];
  371. imageView.userInteractionEnabled = YES;
  372. long tag = indexPath.section;
  373. tag <<= 16;
  374. tag += i;
  375. imageView.tag = tag;
  376. [cell addSubview:imageView];
  377. }
  378. }
  379. } else {
  380. UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake(11, 7, 23, 23)];
  381. if (indexPath.row == self.selectedTableRow) {
  382. cell.backgroundColor = HEXCOLOR(0xa8a8a8);;
  383. } else {
  384. cell.backgroundColor = [WFCUConfigManager globalManager].backgroudColor;
  385. }
  386. if (indexPath.row == 0) {
  387. iv.image = [WFCUImage imageNamed:@"emoji_btn_normal"];
  388. } else {
  389. iv.image = [UIImage imageWithContentsOfFile:self.stickers[self.stickers.allKeys[indexPath.row - 1]].tabIcon];
  390. }
  391. [cell addSubview:iv];
  392. }
  393. return cell;
  394. }
  395. - (void)onTapSticker:(UITapGestureRecognizer *)sender {
  396. UIView *view = sender.view;
  397. long tag = view.tag;
  398. long i = tag & 0xFFFF;
  399. long section = tag >> 16;
  400. NSString *selectSticker = self.stickers[self.stickers.allKeys[section - 1]].stickerPaths[i];
  401. if ([self.delegate respondsToSelector:@selector(didSelectedSticker:)]) {
  402. [self.delegate didSelectedSticker:selectSticker];
  403. }
  404. }
  405. @end