| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545 |
- //
- // WBStatusComposeEmoticonView.m
- // YYKitExample
- //
- // Created by ibireme on 15/9/6.
- // Copyright (C) 2015 ibireme. All rights reserved.
- //
- #import "WBEmoticonInputView.h"
- #import "WBStatusHelper.h"
- #import "WBModel.h"
- #import "YYKit.h"
- #define kViewHeight 216
- #define kToolbarHeight 37
- #define kOneEmoticonHeight 50
- #define kOnePageCount 20
- @interface WBEmoticonCell : UICollectionViewCell
- @property (nonatomic, strong) WBEmoticon *emoticon;
- @property (nonatomic, assign) BOOL isDelete;
- @property (nonatomic, strong) UIImageView *imageView;
- @end
- @implementation WBEmoticonCell
- - (instancetype)initWithFrame:(CGRect)frame {
- self = [super initWithFrame:frame];
- _imageView = [UIImageView new];
- _imageView.size = CGSizeMake(32, 32);
- _imageView.contentMode = UIViewContentModeScaleAspectFit;
- [self.contentView addSubview:_imageView];
- return self;
- }
- - (void)setEmoticon:(WBEmoticon *)emoticon {
- if (_emoticon == emoticon) return;
- _emoticon = emoticon;
- [self updateContent];
- }
- - (void)setIsDelete:(BOOL)isDelete {
- if (_isDelete == isDelete) return;
- _isDelete = isDelete;
- [self updateContent];
- }
- - (void)layoutSubviews {
- [super layoutSubviews];
- [self updateLayout];
- }
- - (void)updateContent {
- [_imageView cancelCurrentImageRequest];
- _imageView.image = nil;
-
- if (_isDelete) {
- _imageView.image = [WBStatusHelper imageNamed:@"compose_emotion_delete"];
- } else if (_emoticon) {
- if (_emoticon.type == WBEmoticonTypeEmoji) {
- NSNumber *num = [NSNumber numberWithString:_emoticon.code];
- NSString *str = [NSString stringWithUTF32Char:num.unsignedIntValue];
- if (str) {
- UIImage *img = [UIImage imageWithEmoji:str size:_imageView.width];
- _imageView.image = img;
- }
- } else if (_emoticon.group.groupID && _emoticon.png){
- NSString *pngPath = [[WBStatusHelper emoticonBundle] pathForScaledResource:_emoticon.png ofType:nil inDirectory:_emoticon.group.groupID];
- if (!pngPath) {
- NSString *addBundlePath = [[WBStatusHelper emoticonBundle].bundlePath stringByAppendingPathComponent:@"additional"];
- NSBundle *addBundle = [NSBundle bundleWithPath:addBundlePath];
- pngPath = [addBundle pathForScaledResource:_emoticon.png ofType:nil inDirectory:_emoticon.group.groupID];
- }
- if (pngPath) {
- [_imageView setImageWithURL:[NSURL fileURLWithPath:pngPath] options:YYWebImageOptionIgnoreDiskCache];
- }
- }
- }
- }
- - (void)updateLayout {
- _imageView.center = CGPointMake(self.width / 2, self.height / 2);
- }
- @end
- @protocol WBEmoticonScrollViewDelegate <UICollectionViewDelegate>
- - (void)emoticonScrollViewDidTapCell:(WBEmoticonCell *)cell;
- @end
- @interface WBEmoticonScrollView : UICollectionView
- @end
- @implementation WBEmoticonScrollView {
- NSTimeInterval *_touchBeganTime;
- BOOL _touchMoved;
- UIImageView *_magnifier;
- UIImageView *_magnifierContent;
- __weak WBEmoticonCell *_currentMagnifierCell;
- NSTimer *_backspaceTimer;
- }
- - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout {
- self = [super initWithFrame:frame collectionViewLayout:layout];
- self.backgroundColor = [UIColor clearColor];
- self.backgroundView = [UIView new];
- self.pagingEnabled = YES;
- self.showsHorizontalScrollIndicator = NO;
- self.clipsToBounds = NO;
- self.canCancelContentTouches = NO;
- self.multipleTouchEnabled = NO;
- _magnifier = [[UIImageView alloc] initWithImage:[WBStatusHelper imageNamed:@"emoticon_keyboard_magnifier"]];
- _magnifierContent = [UIImageView new];
- _magnifierContent.size = CGSizeMake(40, 40);
- _magnifierContent.centerX = _magnifier.width / 2;
- [_magnifier addSubview:_magnifierContent];
- _magnifier.hidden = YES;
- [self addSubview:_magnifier];
- return self;
- }
- - (void)dealloc {
- [self endBackspaceTimer];
- }
- - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
- _touchMoved = NO;
- WBEmoticonCell *cell = [self cellForTouches:touches];
- _currentMagnifierCell = cell;
- [self showMagnifierForCell:_currentMagnifierCell];
-
- if (cell.imageView.image && !cell.isDelete) {
- [[UIDevice currentDevice] playInputClick];
- }
-
- if (cell.isDelete) {
- [self endBackspaceTimer];
- [self performSelector:@selector(startBackspaceTimer) afterDelay:0.5];
- }
- }
- - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
- _touchMoved = YES;
- if (_currentMagnifierCell && _currentMagnifierCell.isDelete) return;
-
- WBEmoticonCell *cell = [self cellForTouches:touches];
- if (cell != _currentMagnifierCell) {
- if (!_currentMagnifierCell.isDelete && !cell.isDelete) {
- _currentMagnifierCell = cell;
- }
- [self showMagnifierForCell:cell];
- }
- }
- - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
- WBEmoticonCell *cell = [self cellForTouches:touches];
- if ((!_currentMagnifierCell.isDelete && cell.emoticon) || (!_touchMoved && cell.isDelete)) {
- if ([self.delegate respondsToSelector:@selector(emoticonScrollViewDidTapCell:)]) {
- [((id<WBEmoticonScrollViewDelegate>) self.delegate) emoticonScrollViewDidTapCell:cell];
- }
- }
- [self hideMagnifier];
- [self endBackspaceTimer];
- }
- - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
- [self hideMagnifier];
- [self endBackspaceTimer];
- }
- - (WBEmoticonCell *)cellForTouches:(NSSet<UITouch *> *)touches {
- UITouch *touch = touches.anyObject;
- CGPoint point = [touch locationInView:self];
- NSIndexPath *indexPath = [self indexPathForItemAtPoint:point];
- if (indexPath) {
- WBEmoticonCell *cell = (id)[self cellForItemAtIndexPath:indexPath];
- return cell;
- }
- return nil;
- }
- - (void)showMagnifierForCell:(WBEmoticonCell *)cell {
- if (cell.isDelete || !cell.imageView.image) {
- [self hideMagnifier];
- return;
- }
- CGRect rect = [cell convertRect:cell.bounds toView:self];
- _magnifier.centerX = CGRectGetMidX(rect);
- _magnifier.bottom = CGRectGetMaxY(rect) - 9;
- _magnifier.hidden = NO;
-
- _magnifierContent.image = cell.imageView.image;
- _magnifierContent.top = 20;
-
- [_magnifierContent.layer removeAllAnimations];
- NSTimeInterval dur = 0.1;
- [UIView animateWithDuration:dur delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
- _magnifierContent.top = 3;
- } completion:^(BOOL finished) {
- [UIView animateWithDuration:dur delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
- _magnifierContent.top = 6;
- } completion:^(BOOL finished) {
- [UIView animateWithDuration:dur delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
- _magnifierContent.top = 5;
- } completion:^(BOOL finished) {
- }];
- }];
- }];
- }
- - (void)hideMagnifier {
- _magnifier.hidden = YES;
- }
- - (void)startBackspaceTimer {
- [self endBackspaceTimer];
- @weakify(self);
- _backspaceTimer = [NSTimer timerWithTimeInterval:0.1 block:^(NSTimer *timer) {
- @strongify(self);
- if (!self) return;
- WBEmoticonCell *cell = self->_currentMagnifierCell;
- if (cell.isDelete) {
- if ([self.delegate respondsToSelector:@selector(emoticonScrollViewDidTapCell:)]) {
- [[UIDevice currentDevice] playInputClick];
- [((id<WBEmoticonScrollViewDelegate>) self.delegate) emoticonScrollViewDidTapCell:cell];
- }
- }
- } repeats:YES];
- [[NSRunLoop mainRunLoop] addTimer:_backspaceTimer forMode:NSRunLoopCommonModes];
- }
- - (void)endBackspaceTimer {
- [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(startBackspaceTimer) object:nil];
- [_backspaceTimer invalidate];
- _backspaceTimer = nil;
- }
- @end
- @interface WBEmoticonInputView () <UICollectionViewDelegate, UICollectionViewDataSource, UIInputViewAudioFeedback,WBEmoticonScrollViewDelegate>
- @property (nonatomic, strong) NSArray<UIButton *> *toolbarButtons;
- @property (nonatomic, strong) UICollectionView *collectionView;
- @property (nonatomic, strong) UIView *pageControl;
- @property (nonatomic, strong) NSArray<WBEmoticonGroup *> *emoticonGroups;
- @property (nonatomic, strong) NSArray<NSNumber *> *emoticonGroupPageIndexs;
- @property (nonatomic, strong) NSArray<NSNumber *> *emoticonGroupPageCounts;
- @property (nonatomic, assign) NSInteger emoticonGroupTotalPageCount;
- @property (nonatomic, assign) NSInteger currentPageIndex;
- @end
- @implementation WBEmoticonInputView
- + (instancetype)sharedView {
- static WBEmoticonInputView *v;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- v = [self new];
- });
- return v;
- }
- - (instancetype)init {
- self = [super init];
- self.frame = CGRectMake(0, 0, kScreenWidth, kViewHeight);
- self.backgroundColor = UIColorHex(f9f9f9);
- [self _initGroups];
- [self _initTopLine];
- [self _initCollectionView];
- [self _initToolbar];
-
- _currentPageIndex = NSNotFound;
- [self _toolbarBtnDidTapped:_toolbarButtons.firstObject];
-
- return self;
- }
- - (void)_initGroups {
- _emoticonGroups = [WBStatusHelper emoticonGroups];
- NSMutableArray *indexs = [NSMutableArray new];
- NSUInteger index = 0;
- for (WBEmoticonGroup *group in _emoticonGroups) {
- [indexs addObject:@(index)];
- NSUInteger count = ceil(group.emoticons.count / (float)kOnePageCount);
- if (count == 0) count = 1;
- index += count;
- }
- _emoticonGroupPageIndexs = indexs;
-
- NSMutableArray *pageCounts = [NSMutableArray new];
- _emoticonGroupTotalPageCount = 0;
- for (WBEmoticonGroup *group in _emoticonGroups) {
- NSUInteger pageCount = ceil(group.emoticons.count / (float)kOnePageCount);
- if (pageCount == 0) pageCount = 1;
- [pageCounts addObject:@(pageCount)];
- _emoticonGroupTotalPageCount += pageCount;
- }
- _emoticonGroupPageCounts = pageCounts;
- }
- - (void)_initTopLine {
- UIView *line = [UIView new];
- line.width = self.width;
- line.height = CGFloatFromPixel(1);
- line.backgroundColor = UIColorHex(bfbfbf);
- line.autoresizingMask = UIViewAutoresizingFlexibleWidth;
- [self addSubview:line];
- }
- - (void)_initCollectionView {
- CGFloat itemWidth = (kScreenWidth - 10 * 2) / 7.0;
- itemWidth = CGFloatPixelRound(itemWidth);
- CGFloat padding = (kScreenWidth - 7 * itemWidth) / 2.0;
- CGFloat paddingLeft = CGFloatPixelRound(padding);
- CGFloat paddingRight = kScreenWidth - paddingLeft - itemWidth * 7;
-
- UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new];
- layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
- layout.itemSize = CGSizeMake(itemWidth, kOneEmoticonHeight);
- layout.minimumLineSpacing = 0;
- layout.minimumInteritemSpacing = 0;
- layout.sectionInset = UIEdgeInsetsMake(0, paddingLeft, 0, paddingRight);
-
- _collectionView = [[WBEmoticonScrollView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, kOneEmoticonHeight * 3) collectionViewLayout:layout];
- [_collectionView registerClass:[WBEmoticonCell class] forCellWithReuseIdentifier:@"cell"];
- _collectionView.delegate = self;
- _collectionView.dataSource = self;
- _collectionView.top = 5;
- [self addSubview:_collectionView];
-
- _pageControl = [UIView new];
- _pageControl.size = CGSizeMake(kScreenWidth, 20);
- _pageControl.top = _collectionView.bottom - 5;
- _pageControl.userInteractionEnabled = NO;
- [self addSubview:_pageControl];
- }
- - (void)_initToolbar {
- UIView *toolbar = [UIView new];
- toolbar.size = CGSizeMake(kScreenWidth, kToolbarHeight);
-
- UIImageView *bg = [[UIImageView alloc] initWithImage:[WBStatusHelper imageNamed:@"compose_emotion_table_right_normal"]];
- bg.size = toolbar.size;
- [toolbar addSubview:bg];
-
- UIScrollView *scroll = [UIScrollView new];
- scroll.showsHorizontalScrollIndicator = NO;
- scroll.alwaysBounceHorizontal = YES;
- scroll.size = toolbar.size;
- scroll.contentSize = toolbar.size;
- [toolbar addSubview:scroll];
-
- NSMutableArray *btns = [NSMutableArray new];
- UIButton *btn;
- for (NSUInteger i = 0; i < _emoticonGroups.count; i++) {
- WBEmoticonGroup *group = _emoticonGroups[i];
- btn = [self _createToolbarButton];
- [btn setTitle:group.nameCN forState:UIControlStateNormal];
- btn.left = kScreenWidth / (float)_emoticonGroups.count * i;
- btn.tag = i;
- [scroll addSubview:btn];
- [btns addObject:btn];
- }
-
- toolbar.bottom = self.height;
- [self addSubview:toolbar];
- _toolbarButtons = btns;
- }
- - (UIButton *)_createToolbarButton {
- UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
- btn.exclusiveTouch = YES;
- btn.size = CGSizeMake(kScreenWidth / _emoticonGroups.count, kToolbarHeight);
- btn.titleLabel.font = [UIFont systemFontOfSize:14];
- [btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
- [btn setTitleColor:UIColorHex(5D5C5A) forState:UIControlStateSelected];
-
- UIImage *img;
- img = [WBStatusHelper imageNamed:@"compose_emotion_table_left_normal"];
- img = [img resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, img.size.width - 1) resizingMode:UIImageResizingModeStretch];
- [btn setBackgroundImage:img forState:UIControlStateNormal];
-
- img = [WBStatusHelper imageNamed:@"compose_emotion_table_left_selected"];
- img = [img resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, img.size.width - 1) resizingMode:UIImageResizingModeStretch];
- [btn setBackgroundImage:img forState:UIControlStateSelected];
-
- [btn addTarget:self action:@selector(_toolbarBtnDidTapped:) forControlEvents:UIControlEventTouchUpInside];
- return btn;
- }
- - (void)_toolbarBtnDidTapped:(UIButton *)btn {
- NSInteger groupIndex = btn.tag;
- NSInteger page = ((NSNumber *)_emoticonGroupPageIndexs[groupIndex]).integerValue;
- CGRect rect = CGRectMake(page * _collectionView.width, 0, _collectionView.width, _collectionView.height);
- [_collectionView scrollRectToVisible:rect animated:NO];
- [self scrollViewDidScroll:_collectionView];
- }
- - (WBEmoticon *)_emoticonForIndexPath:(NSIndexPath *)indexPath {
- NSUInteger section = indexPath.section;
- for (NSInteger i = _emoticonGroupPageIndexs.count - 1; i >= 0; i--) {
- NSNumber *pageIndex = _emoticonGroupPageIndexs[i];
- if (section >= pageIndex.unsignedIntegerValue) {
- WBEmoticonGroup *group = _emoticonGroups[i];
- NSUInteger page = section - pageIndex.unsignedIntegerValue;
- NSUInteger index = page * kOnePageCount + indexPath.row;
-
- // transpose line/row
- NSUInteger ip = index / kOnePageCount;
- NSUInteger ii = index % kOnePageCount;
- NSUInteger reIndex = (ii % 3) * 7 + (ii / 3);
- index = reIndex + ip * kOnePageCount;
-
- if (index < group.emoticons.count) {
- return group.emoticons[index];
- } else {
- return nil;
- }
- }
- }
- return nil;
- }
- #pragma mark WBEmoticonScrollViewDelegate
- - (void)emoticonScrollViewDidTapCell:(WBEmoticonCell *)cell {
- if (!cell) return;
- if (cell.isDelete) {
- if ([self.delegate respondsToSelector:@selector(emoticonInputDidTapBackspace)]) {
- [[UIDevice currentDevice] playInputClick];
- [self.delegate emoticonInputDidTapBackspace];
- }
- } else if (cell.emoticon) {
- NSString *text = nil;
- switch (cell.emoticon.type) {
- case WBEmoticonTypeImage: {
- text = cell.emoticon.chs;
- } break;
- case WBEmoticonTypeEmoji: {
- NSNumber *num = [NSNumber numberWithString:cell.emoticon.code];
- text = [NSString stringWithUTF32Char:num.unsignedIntValue];
- } break;
- default:break;
- }
- if (text && [self.delegate respondsToSelector:@selector(emoticonInputDidTapText:)]) {
- [self.delegate emoticonInputDidTapText:text];
- }
- }
- }
- #pragma mark UICollectionViewDelegate
- - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
- NSInteger page = round(scrollView.contentOffset.x / scrollView.width);
- if (page < 0) page = 0;
- else if (page >= _emoticonGroupTotalPageCount) page = _emoticonGroupTotalPageCount - 1;
- if (page == _currentPageIndex) return;
- _currentPageIndex = page;
- NSInteger curGroupIndex = 0, curGroupPageIndex = 0, curGroupPageCount = 0;
- for (NSInteger i = _emoticonGroupPageIndexs.count - 1; i >= 0; i--) {
- NSNumber *pageIndex = _emoticonGroupPageIndexs[i];
- if (page >= pageIndex.unsignedIntegerValue) {
- curGroupIndex = i;
- curGroupPageIndex = ((NSNumber *)_emoticonGroupPageIndexs[i]).integerValue;
- curGroupPageCount = ((NSNumber *)_emoticonGroupPageCounts[i]).integerValue;
- break;
- }
- }
- [_pageControl.layer removeAllSublayers];
- CGFloat padding = 5, width = 6, height = 2;
- CGFloat pageControlWidth = (width + 2 * padding) * curGroupPageCount;
- for (NSInteger i = 0; i < curGroupPageCount; i++) {
- CALayer *layer = [CALayer layer];
- layer.size = CGSizeMake(width, height);
- layer.cornerRadius = 1;
- if (page - curGroupPageIndex == i) {
- layer.backgroundColor = UIColorHex(fd8225).CGColor;
- } else {
- layer.backgroundColor = UIColorHex(dedede).CGColor;
- }
- layer.centerY = _pageControl.height / 2;
- layer.left = (_pageControl.width - pageControlWidth) / 2 + i * (width + 2 * padding) + padding;
- [_pageControl.layer addSublayer:layer];
- }
- [_toolbarButtons enumerateObjectsUsingBlock:^(UIButton *btn, NSUInteger idx, BOOL *stop) {
- btn.selected = (idx == curGroupIndex);
- }];
- }
- - (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath {
- return NO;
- }
- - (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath {
- return NO;
- }
- #pragma mark UICollectionViewDataSource
- - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
- return _emoticonGroupTotalPageCount;
- }
- - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
- return kOnePageCount + 1;
- }
- - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
-
- WBEmoticonCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
- if (indexPath.row == kOnePageCount) {
- cell.isDelete = YES;
- cell.emoticon = nil;
- } else {
- cell.isDelete = NO;
- cell.emoticon = [self _emoticonForIndexPath:indexPath];
- }
- return cell;
- }
- #pragma mark - UIInputViewAudioFeedback
- - (BOOL)enableInputClicksWhenVisible {
- return YES;
- }
- @end
|