- 紅色區(qū)域是
TMSStickerView
- 藍(lán)色區(qū)域是
UIcollectionViewCell
点晴,每個cell的model依據(jù)屏幕尺寸已經(jīng)預(yù)先處理成TMSEmoji
,通過該model中的emojis屬性悯周,來顯示當(dāng)前cell所需要展示的所有數(shù)據(jù) - 綠色區(qū)域是cell上的自定義view(
TMSEmojiItem
)粒督,長按預(yù)覽的手勢添加于該視圖上
@interface TMSEmoji : NSObject
@property (assign, nonatomic) TMSEmojiType type;
@property (strong, nonatomic) NSString *title;
@property (strong, nonatomic) NSArray *emojis;
@end
開發(fā)中遇到的問題:
1. 系統(tǒng)emoji表情頁與自定義表情頁交替時,底部滑塊的隱藏與顯示
2. 手指從自定義表情頁拖拽到emoji表情頁禽翼,在不松手的情況下屠橄,又拖回自定義表情頁時,底部滑塊的隱藏與顯示
處理方案:
何時對滑塊做顯隱動畫捐康?
既然是交替時的特殊處理仇矾,首先在- (void)scrollViewDidScroll:(UIScrollView *)scrollView
方法中依據(jù)collectionview當(dāng)前偏移量從dataSource中取出當(dāng)前展示的模型,以及下一個模型解总。獲得兩個模型后贮匕,首先判斷兩個表情模型(TMSEmoji
)的類型是否相同,如果不同花枫,則需要對滑塊添加顯隱的動畫刻盐。對滑塊是做顯示動畫還是隱藏動畫?
當(dāng)collectionview的contentOffset.x逐漸變大時劳翰,此時需要對滑塊做顯示動畫敦锌;反之對其做隱藏動畫。這里需要辨別出collectionview的滑動方向是左滑還是滑佳簸。
并且針對于上述問題2中的情形乙墙,需要在- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
方法中對于當(dāng)前顯示的item根據(jù)類型判斷來控制滑塊動畫是否執(zhí)行。
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// if (self.lastContentOffsetX < scrollView.contentOffset.x) {
// NSLog(@"向左滾動");
// }else{
// NSLog(@"向右滾動");
// }
CGFloat fIdx = (scrollView.contentOffset.x + SCREEN_WIDTH * 0.2) / SCREEN_WIDTH;
NSInteger index = (NSInteger)fIdx;
if (index >= self.dataSource.count) {
return;
}
TMSEmoji *emojiModel = self.dataSource[index];
[self.toolBar setCurrentSelectedTooItemWithEmojiString:emojiModel.title];
if (index+1 >= self.dataSource.count) {
if (emojiModel.type == TMSEmojiTypeCustom) {
[self.emojiSlider setValue:(scrollView.contentOffset.x / SCREEN_WIDTH - self.customEmojiStartIndex) animated:YES];
}
return;
}
TMSEmoji *nextEmoji = self.dataSource[index+1];
if (emojiModel.type == nextEmoji.type) {
if (emojiModel.type == TMSEmojiTypeCustom) {
[self.emojiSlider setValue:(scrollView.contentOffset.x / SCREEN_WIDTH - self.customEmojiStartIndex) animated:YES];
}
return;
}
if (nextEmoji.type == TMSEmojiTypeCustom) {
if (self.isAnimationing) {
return;
}
// 左滑 消失
/*
右滑 顯示
1.在custom上右滑
2.從people上右滑
*/
if (self.lastContentOffsetX > scrollView.contentOffset.x) { // 右滑
if (self.emojiSlider.alpha != 0) {
[self sliderAnimationWithState:NO];
}
} else {
if (scrollView.contentOffset.x >= (self.customEmojiStartIndex - 0.3) * SCREEN_WIDTH) {
if (self.emojiSlider.alpha != 1) {
self.emojiSlider.alpha = 1;
[self sliderAnimationWithState:YES];
}
}
}
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
if (self.hideCustomEmoji || self.emojiSlider.hidden) {
return;
}
NSInteger index = scrollView.contentOffset.x / SCREEN_WIDTH;
TMSEmoji *emoji = self.dataSource[index];
if (emoji.type == TMSEmojiTypeCustom) {
self.customSelectedIndex = index - self.customEmojiStartIndex > 0 ? index - self.customEmojiStartIndex : 0;
if (self.emojiSlider.alpha == 0) {
if (self.isAnimationing) {
return;
}
self.emojiSlider.alpha = 1;
[self sliderAnimationWithState:YES];
}
} else {
self.normalSelectedIndex = index;
if (self.emojiSlider.alpha == 1) {
[self sliderAnimationWithState:NO];
}
}
}
3. 按分類瀏覽過的表情生均,當(dāng)點擊底部分類按鈕時听想,跳轉(zhuǎn)到之前瀏覽過的頁面(僅支持鍵盤類型為包含自定義表情的類型)
處理方案:
聲明兩個屬性:customSelectedIndex(自定義表情用戶最后停留的index)和normalSelectedIndex(系統(tǒng)emoji表情用戶最后停留的index)。在- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
方法中記錄這兩個值马胧,當(dāng)點擊底部分類進行跳轉(zhuǎn)時汉买,遍歷整個collectionview的dataSource,依據(jù)用戶當(dāng)前所點擊的分類找到屬于該分類的第一個model所處的index佩脊,在index基礎(chǔ)上加上customSelectedIndex或者normalSelectedIndex蛙粘,使用- (void)collectionView的scrollToItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated
方法進行跳轉(zhuǎn)
[weakSelf.dataSource enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
TMSEmoji *emoji = weakSelf.dataSource[idx];
if (emoji.type == emojiType) { // 找到屬于該分類表情的第一頁所屬的index
if (emojiType == TMSEmojiTypeCustom) {
idx = idx + weakSelf.customSelectedIndex;
} else {
if (!weakSelf.hideCustomEmoji) {
idx = weakSelf.normalSelectedIndex;
}
}
[weakSelf.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:idx inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
weakSelf.emojiSlider.alpha = emojiType == TMSEmojiTypeCustom ? 1 : 0;
[weakSelf.emojiSlider setValue:weakSelf.customSelectedIndex animated:YES];
*stop = YES;
}
}];
4. 當(dāng)調(diào)出表情鍵盤時垫卤,單擊輸入框重新調(diào)出系統(tǒng)鍵盤。
處理方案:
當(dāng)展示出表情鍵盤時出牧,對textView添加tap手勢穴肘,在tap手勢的action中重新調(diào)出系統(tǒng)鍵盤,并且移除tap手勢
if (sender.selected) { // 顯示表情鍵盤
self.stickerView.sendActionBlock = ^(id emoji) {
NSLog(@"發(fā)送emoji表情");
};
[self.stickerView setTextView:self.textView];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.textView addGestureRecognizer:self.textViewTap];
});
} else {
self.textView.inputView = nil;
[self.textView removeGestureRecognizer:self.textViewTap];
}
5. 表情的長按預(yù)覽功能
處理方案:
參考于PPStickerKeyboard的實現(xiàn)思路崔列,在TMSEmojItem上添加UILongPressGestureRecognizer梢褐,依據(jù)手勢recognizer.state的三種狀態(tài)(UIGestureRecognizerStateBegan, UIGestureRecognizerStateChanged, UIGestureRecognizerStateEnded)來控制標(biāo)簽預(yù)覽層的顯示與隱藏
自定義表情預(yù)覽層的邊框通過drawRect方法實現(xiàn),考慮到drawRect對性能的影響赵讯,也可以使用CAShapeLayer來替換drawRect方法盈咳。