ifish/Ifish/UMCommunity/UMCommunitySDK/UMCommunityUI/CustomView/UMComEmojiKeyBoard/UMComEmojiKeyBoardView.m

358 lines
15 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// AGEmojiKeyboardView.m
// AGEmojiKeyboard
//
// Created by Ayush on 09/05/13.
// Copyright (c) 2013 Ayush. All rights reserved.
//
#import "UMComEmojiKeyBoardView.h"
#import "UMComEmojiPageView.h"
#import "UMComResouceDefines.h"
static const CGFloat ButtonWidth = 53;
static const CGFloat ButtonHeight = 50;
#define ColumnNum 7
#define RowNum 3
static const NSUInteger DefaultRecentEmojisMaintainedCount = 50;
static NSString *const segmentRecentName = @"Recent";
NSString *const RecentUsedEmojiCharactersKey = @"RecentUsedEmojiCharactersKey";
@interface UMComEmojiKeyboardView () <UIScrollViewDelegate, AGEmojiPageViewDelegate>
@property (nonatomic) UISegmentedControl *segmentsBar;
@property (nonatomic) UIPageControl *pageControl;
@property (nonatomic) UIScrollView *emojiPagesScrollView;
@property (nonatomic) NSMutableDictionary *emojis;
@property (nonatomic) NSMutableArray *pageViews;
@property (nonatomic) NSString *category;
@end
@implementation UMComEmojiKeyboardView
- (NSDictionary *)emojis {
if (!_emojis) {
NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"UMComSDKResources.bundle/EmojisList"
ofType:@"plist"];
NSDictionary *emojis = [NSDictionary dictionaryWithContentsOfFile:plistPath];
NSString *emojiString = [emojis valueForKey:@"People"];
NSArray * emojisArray = [emojiString componentsSeparatedByString:@" "];
_emojis = [NSMutableDictionary dictionaryWithObject:emojisArray forKey:@"People"];
}
return _emojis;
}
- (NSString *)categoryNameAtIndex:(NSUInteger)index {
NSArray *categoryList = @[@"People", @"Objects", @"Nature", @"Places", @"Symbols"];
return categoryList[index];
}
- (UMComEmojiKeyboardViewCategoryImage)defaultSelectedCategory {
if ([self.dataSource respondsToSelector:@selector(defaultCategoryForEmojiKeyboardView:)]) {
return [self.dataSource defaultCategoryForEmojiKeyboardView:self];
}
return AGEmojiKeyboardViewCategoryImageFace;
}
- (NSUInteger)recentEmojisMaintainedCount {
if ([self.dataSource respondsToSelector:@selector(recentEmojisMaintainedCountForEmojiKeyboardView:)]) {
return [self.dataSource recentEmojisMaintainedCountForEmojiKeyboardView:self];
}
return DefaultRecentEmojisMaintainedCount;
}
- (NSArray *)imagesForSelectedSegments {
static NSMutableArray *array;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
array = [NSMutableArray array];
for (UMComEmojiKeyboardViewCategoryImage i = AGEmojiKeyboardViewCategoryImageFace;
i <= AGEmojiKeyboardViewCategoryImageCharacters;
++i) {
[array addObject:[self.dataSource emojiKeyboardView:self imageForSelectedCategory:i]];
}
});
return array;
}
- (NSArray *)imagesForNonSelectedSegments {
static NSMutableArray *array;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
array = [NSMutableArray array];
for (UMComEmojiKeyboardViewCategoryImage i = AGEmojiKeyboardViewCategoryImageFace;
i <= AGEmojiKeyboardViewCategoryImageCharacters;
++i) {
[array addObject:[self.dataSource emojiKeyboardView:self imageForNonSelectedCategory:i]];
}
});
return array;
}
- (instancetype)initWithFrame:(CGRect)frame dataSource:(id<AGEmojiKeyboardViewDataSource>)dataSource {
self = [super initWithFrame:frame];
if (self) {
// initialize category
self.backgroundColor = [UIColor whiteColor];
_dataSource = dataSource;
self.category = [self categoryNameAtIndex:self.defaultSelectedCategory];
self.pageControl = [[UIPageControl alloc] init];
self.pageControl.hidesForSinglePage = YES;
self.pageControl.currentPage = 0;
self.pageControl.backgroundColor = [UIColor clearColor];
CGSize pageControlSize = [self.pageControl sizeForNumberOfPages:3];
CGSize frameSize = CGSizeMake(CGRectGetWidth(self.bounds),
CGRectGetHeight(self.bounds) - pageControlSize.height);
NSUInteger numberOfPages = [self numberOfPagesForCategory:self.category
inFrameSize:frameSize];
self.pageControl.numberOfPages = numberOfPages;
// pageControlSize = [self.pageControl sizeForNumberOfPages:numberOfPages];
CGRect pageControlFrame = CGRectMake((CGRectGetWidth(self.bounds) - pageControlSize.width) / 2,
CGRectGetHeight(self.bounds) - pageControlSize.height,
pageControlSize.width,
pageControlSize.height);
self.pageControl.frame = CGRectIntegral(pageControlFrame);
[self.pageControl addTarget:self
action:@selector(pageControlTouched:)
forControlEvents:UIControlEventValueChanged];
self.pageControl.currentPageIndicatorTintColor = [UIColor darkGrayColor];
self.pageControl.pageIndicatorTintColor = [UIColor lightGrayColor];
[self addSubview:self.pageControl];
CGRect scrollViewFrame = CGRectMake(0,
CGRectGetHeight(self.segmentsBar.bounds),
CGRectGetWidth(self.bounds),
CGRectGetHeight(self.bounds) - CGRectGetHeight(self.segmentsBar.bounds) - pageControlSize.height);
self.emojiPagesScrollView = [[UIScrollView alloc] initWithFrame:scrollViewFrame];
self.emojiPagesScrollView.pagingEnabled = YES;
self.emojiPagesScrollView.showsHorizontalScrollIndicator = NO;
self.emojiPagesScrollView.showsVerticalScrollIndicator = NO;
self.emojiPagesScrollView.delegate = self;
[self addSubview:self.emojiPagesScrollView];
}
return self;
}
- (void)layoutSubviews {
CGSize pageControlSize = [self.pageControl sizeForNumberOfPages:3];
NSUInteger numberOfPages = [self numberOfPagesForCategory:self.category
inFrameSize:CGSizeMake(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) - CGRectGetHeight(self.segmentsBar.bounds) - pageControlSize.height)];
NSInteger currentPage = (self.pageControl.currentPage > numberOfPages) ? numberOfPages : self.pageControl.currentPage;
// if (currentPage > numberOfPages) it is set implicitly to max pageNumber available
self.pageControl.numberOfPages = numberOfPages;
pageControlSize = [self.pageControl sizeForNumberOfPages:numberOfPages];
CGRect pageControlFrame = CGRectMake((CGRectGetWidth(self.bounds) - pageControlSize.width) / 2,
CGRectGetHeight(self.bounds) - pageControlSize.height,
pageControlSize.width,
pageControlSize.height);
self.pageControl.frame = CGRectIntegral(pageControlFrame);
self.emojiPagesScrollView.frame = CGRectMake(0,
CGRectGetHeight(self.segmentsBar.bounds),
CGRectGetWidth(self.bounds),
CGRectGetHeight(self.bounds) - CGRectGetHeight(self.segmentsBar.bounds) - pageControlSize.height);
[self.emojiPagesScrollView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
self.emojiPagesScrollView.contentOffset = CGPointMake(CGRectGetWidth(self.emojiPagesScrollView.bounds) * currentPage, 0);
self.emojiPagesScrollView.contentSize = CGSizeMake(CGRectGetWidth(self.emojiPagesScrollView.bounds) * numberOfPages,
CGRectGetHeight(self.emojiPagesScrollView.bounds));
[self purgePageViews];
self.pageViews = [NSMutableArray array];
[self setPage:currentPage];
}
#pragma mark event handlers
- (void)setSelectedCategoryImageInSegmentControl:(UISegmentedControl *)segmentsBar
atIndex:(NSInteger)index {
for (int i=0; i < self.segmentsBar.numberOfSegments; ++i) {
[segmentsBar setImage:self.imagesForNonSelectedSegments[i] forSegmentAtIndex:i];
}
[segmentsBar setImage:self.imagesForSelectedSegments[index] forSegmentAtIndex:index];
}
- (void)categoryChangedViaSegmentsBar:(UISegmentedControl *)sender {
// recalculate number of pages for new category and recreate emoji pages
self.category = [self categoryNameAtIndex:sender.selectedSegmentIndex];
[self setSelectedCategoryImageInSegmentControl:sender
atIndex:sender.selectedSegmentIndex];
self.pageControl.currentPage = 0;
[self setNeedsLayout];
}
- (void)pageControlTouched:(UIPageControl *)sender {
CGRect bounds = self.emojiPagesScrollView.bounds;
bounds.origin.x = CGRectGetWidth(bounds) * sender.currentPage;
bounds.origin.y = 0;
// scrollViewDidScroll is called here. Page set at that time.
[self.emojiPagesScrollView scrollRectToVisible:bounds animated:YES];
}
// Track the contentOffset of the scroll view, and when it passes the mid
// point of the current views width, the views are reconfigured.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat pageWidth = CGRectGetWidth(scrollView.frame);
NSInteger newPageNumber = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
if (self.pageControl.currentPage == newPageNumber) {
return;
}
self.pageControl.currentPage = newPageNumber;
[self setPage:self.pageControl.currentPage];
}
#pragma mark change a page on scrollView
// Check if setting pageView for an index is required
- (BOOL)requireToSetPageViewForIndex:(NSUInteger)index {
if (index >= self.pageControl.numberOfPages) {
return NO;
}
for (UMComEmojiPageView *page in self.pageViews) {
if ((page.frame.origin.x / CGRectGetWidth(self.emojiPagesScrollView.bounds)) == index) {
return NO;
}
}
return YES;
}
// Create a pageView and add it to the scroll view.
- (UMComEmojiPageView *)synthesizeEmojiPageView {
CGRect pageViewFrame = CGRectMake(0,
0,
CGRectGetWidth(self.emojiPagesScrollView.bounds),
CGRectGetHeight(self.emojiPagesScrollView.bounds));
UMComEmojiPageView *pageView = [[UMComEmojiPageView alloc] initWithFrame: pageViewFrame
backSpaceButtonImage:UMComImageWithImageName(@"um_emoji_delete")
buttonSize:CGSizeMake(ButtonWidth, ButtonHeight)
rows:3
columns:7];
pageView.delegate = self;
[self.pageViews addObject:pageView];
[self.emojiPagesScrollView addSubview:pageView];
return pageView;
}
// return a pageView that can be used in the current scrollView.
// look for an available pageView in current pageView-s on scrollView.
// If all are in use i.e. are of current page or neighbours
// of current page, we create a new one
- (UMComEmojiPageView *)usableEmojiPageView {
UMComEmojiPageView *pageView = nil;
for (UMComEmojiPageView *page in self.pageViews) {
NSUInteger pageNumber = page.frame.origin.x / CGRectGetWidth(self.emojiPagesScrollView.bounds);
if (abs((int)(pageNumber - self.pageControl.currentPage)) > 1) {
pageView = page;
break;
}
}
if (!pageView) {
pageView = [self synthesizeEmojiPageView];
}
return pageView;
}
// Set emoji page view for given index.
- (void)setEmojiPageViewInScrollView:(UIScrollView *)scrollView atIndex:(NSUInteger)index {
if (![self requireToSetPageViewForIndex:index]) {
return;
}
UMComEmojiPageView *pageView = [self usableEmojiPageView];
// NSUInteger rows = [self numberOfRowsForFrameSize:scrollView.bounds.size];
// NSUInteger columns = [self numberOfColumnsForFrameSize:scrollView.bounds.size];
NSUInteger rows = RowNum;
NSUInteger columns = ColumnNum;
NSUInteger startingIndex = index * (rows * columns - 1);
NSUInteger endingIndex = (index + 1) * (rows * columns - 1);
NSMutableArray *buttonTexts = [self emojiTextsForCategory:self.category
fromIndex:startingIndex
toIndex:endingIndex];
[pageView setButtonTexts:buttonTexts];
pageView.frame = CGRectMake(index * CGRectGetWidth(scrollView.bounds),
0,
CGRectGetWidth(scrollView.bounds),
CGRectGetHeight(scrollView.bounds));
}
// Set the current page.
// sets neightbouring pages too, as they are viewable by part scrolling.
- (void)setPage:(NSInteger)page {
[self setEmojiPageViewInScrollView:self.emojiPagesScrollView atIndex:page - 1];
[self setEmojiPageViewInScrollView:self.emojiPagesScrollView atIndex:page];
[self setEmojiPageViewInScrollView:self.emojiPagesScrollView atIndex:page + 1];
}
- (void)purgePageViews {
for (UMComEmojiPageView *page in self.pageViews) {
page.delegate = nil;
}
self.pageViews = nil;
}
#pragma mark data methods
- (NSUInteger)numberOfColumnsForFrameSize:(CGSize)frameSize {
return (NSUInteger)floor(frameSize.width / ButtonWidth);
}
- (NSUInteger)numberOfRowsForFrameSize:(CGSize)frameSize {
return (NSUInteger)floor(frameSize.height / ButtonHeight);
}
- (NSArray *)emojiListForCategory:(NSString *)category {
return [self.emojis objectForKey:category];
}
// for a given frame size of scroll view, return the number of pages
// required to show all the emojis for a category
- (NSUInteger)numberOfPagesForCategory:(NSString *)category inFrameSize:(CGSize)frameSize {
if ([category isEqualToString:segmentRecentName]) {
return 1;
}
NSUInteger emojiCount = [[self emojiListForCategory:category] count];
NSUInteger numberOfRows = RowNum;
NSUInteger numberOfColumns = ColumnNum;
NSUInteger numberOfEmojisOnAPage = (numberOfRows * numberOfColumns) - 1;
NSUInteger numberOfPages = (NSUInteger)ceil((float)emojiCount / numberOfEmojisOnAPage);
return numberOfPages;
}
// return the emojis for a category, given a staring and an ending index
- (NSMutableArray *)emojiTextsForCategory:(NSString *)category
fromIndex:(NSUInteger)start
toIndex:(NSUInteger)end {
NSArray *emojis = [self emojiListForCategory:category];
end = ([emojis count] > end)? end : [emojis count];
NSIndexSet *index = [[NSIndexSet alloc] initWithIndexesInRange:NSMakeRange(start, end-start)];
return [[emojis objectsAtIndexes:index] mutableCopy];
}
#pragma mark EmojiPageViewDelegate
// add the emoji to recents
- (void)emojiPageView:(UMComEmojiPageView *)emojiPageView didUseEmoji:(NSString *)emoji {
// [self setInRecentsEmoji:emoji];
[self.delegate emojiKeyBoardView:self didUseEmoji:emoji];
}
- (void)emojiPageViewDidPressBackSpace:(UMComEmojiPageView *)emojiPageView {
[self.delegate emojiKeyBoardViewDidPressBackSpace:self];
}
@end