新浪微博客户端(53)-记录用户最近点击表情

设计思路:每当用户点击一个表情,就将该表情(DJEmotion)存储到沙盒,当用户切换到“最近”栏目时,从沙盒中取出用户最近点击的表情列表,进行显示。

1. 保存DJEmotion

DJEmotion.h

#import <Foundation/Foundation.h>

// 因为要保存最近使用的表情到沙盒,所以该对象须实现NSCoding协议
@interface DJEmotion : NSObject <NSCoding>

/** Emotion 中文字符 */
@property (nonatomic,copy) NSString *chs;
/** Emotion 对应图片 */
@property (nonatomic,copy) NSString *png;
/** Emoji 二进制数字 */
@property (nonatomic,copy) NSString *code;

@end

DJEmotion.m

#import "DJEmotion.h"

@implementation DJEmotion


/**
 * 此方法用于比较两个对象是否是否相等,即:==
 * 类似于java中的isEqual方法
 * 重写该方法意味着覆盖系统的比较方式
 */
- (BOOL)isEqual:(DJEmotion *)other {

    // 重写Emotion的比较方式,即:当Emotion对象中的chs或code相等时,就视这两个对象相等
    return [self.chs isEqualToString:other.chs] || [self.code isEqualToString:other.code];
    
}


// 解码
- (instancetype)initWithCoder:(NSCoder *)decoder {

    if (self = [super init]) {
        self.chs = [decoder decodeObjectForKey:@"chs"];
        self.png = [decoder decodeObjectForKey:@"png"];
        self.code = [decoder decodeObjectForKey:@"code"];
    }
    return self;
}


// 编码
- (void)encodeWithCoder:(NSCoder *)encoder {

    [encoder encodeObject:self.chs forKey:@"chs"];
    [encoder encodeObject:self.png forKey:@"png"];
    [encoder encodeObject:self.code forKey:@"code"];

}


@end

2. 将表情存储到沙盒中的工具类

DJEmotionTool.h

#import <Foundation/Foundation.h>

@class DJEmotion;
@interface DJEmotionTool : NSObject

/** 保存最近点击Emotion */
+ (void)saveRecentEmotion:(DJEmotion *)emotion;

/** 获取存储在沙盒中最近点击的Emotion集合 */
+ (NSArray *)recentEmotions;

@end

DJEmotionTool.m

#import "DJEmotionTool.h"


// 最近表情保存路径
#define DJEmotionPath [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"emotion.archiver"]

// 类似于java里面的静态成员变量
static NSMutableArray *_recentEmotions;

@implementation DJEmotionTool


/**
 * 这个方法会在第一次使用这个类的时候调一次,且只调一次
 * 类似于java中静态代码块
 */
+ (void)initialize {

    _recentEmotions = [NSKeyedUnarchiver unarchiveObjectWithFile:DJEmotionPath];
    if (_recentEmotions == nil) {
        _recentEmotions = [NSMutableArray array];
    }
}



/** 保存最近点击Emotion */
+ (void)saveRecentEmotion:(DJEmotion *)emotion {
    
    // 移除之前存储的相同Emotion
    [_recentEmotions removeObject:emotion];

    // 在数组的头部插入新的Emotion
    [_recentEmotions insertObject:emotion atIndex:0];
    
    // 保存当前数组
    [NSKeyedArchiver archiveRootObject:_recentEmotions toFile:DJEmotionPath];

}

/** 获取存储在沙盒中最近点击的Emotion集合 */
+ (NSArray *)recentEmotions {
    return _recentEmotions;
}


@end

3. 因为存储在沙盒的最近表情是实时变换的,所以不能使用懒加载,因此在点击最近按钮时,重新给最近按钮的ListView赋值:

DJEmotionKeyboard.m

#pragma mark - DJEmotionTabBar 的代理方法
- (void)emotionTabBar:(DJEmotionTabBar *)tabBar didSelectedButtonType:(DJEmotionTabBarButtonType)buttonType {

    // 1. 清空placeView中之前存在的其它View(类似于android中的ViewGroup.removeAllViews)
    [self.placeView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
    
    // 2. 切换contentView
    switch (buttonType) {
        case DJEmotionTabBarButtonTypeRecent: // 最近
            [self.placeView addSubview:self.recentEmotionView];
            // 从DJEmotionTool中获取沙盒中存储的最近使用表情,注意!此处不能使用懒加载,因为这样会导致数据无法实时更新
            self.recentEmotionView.emotions = [DJEmotionTool recentEmotions];
            break;
        case DJEmotionTabBarButtonTypeDefault: // 默认
            [self.placeView addSubview:self.defaultEmotionView];
            break;
        case DJEmotionTabBarButtonTypeEmoji: // Emoji
            [self.placeView addSubview:self.emojiEmotionView];
            break;
        case DJEmotionTabBarButtonTypeLxh: // 浪小花
            [self.placeView addSubview:self.lxhEmotionView];
            break;
        default:
            break;
    }
    
    // 3.切换完毕后通知系统重新布局,相当于再次调用layoutSubViews
    [self setNeedsLayout];
    
    
}

4. 当ListView收到传来的新数据时,清空之前的控件,进行重新布局(目的是为了让新点击的最近表情排在前面)。

DJEmotionListView.m

- (void)setEmotions:(NSArray *)emotions {

    
    _emotions = emotions;
    
    // 先清空scrollView里面已有的子控件,便于刷新
    [self.emotionScrollView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
    
    
    // emotion 总个数
    NSUInteger emotionCount = emotions.count;
    // 页码总个数
    NSUInteger pageNums = (emotionCount + DJEmotionPageSize - 1) / DJEmotionPageSize;
    
    // 更新pageControl 显示个数
    self.emotionPageControl.numberOfPages = pageNums;
    
    // 为scrollView 添加子View
    for (int i = 0; i < pageNums; i++) {
        DJEmotionPageView *pageView = [[DJEmotionPageView alloc] init];
//        pageView.backgroundColor = DJRandomColor;
        
        NSRange range;
        range.location = i * DJEmotionPageSize;
        NSUInteger leftNums = emotionCount - range.location; // 求出当前剩余Emoji个数
        if (leftNums >= DJEmotionPageSize) { // 判断当前剩余Emoji个数是否满20
            range.length = DJEmotionPageSize;
        } else { // 如果不满20,则range.length就等于剩余的个数
            range.length = leftNums;
        }
        
        NSArray *singlePageEmotions = [emotions subarrayWithRange:range];
        pageView.emotions = singlePageEmotions;
        
        [self.emotionScrollView addSubview:pageView];
    }
    
    // 数据添加完毕后,通知系统进行重新布局
    [self setNeedsLayout];
    

5. 当点击表情按钮或滑动表情按钮时,如果发出了输入通知,此时就将点击的表情按钮存储到沙盒中去。

DJEmotionPageView.m

// 发送点击广播(和android类似,区别在于android的广播是只要有上下文对象context,就可以发送)
// iOS中的通知发送和接收都是通过NSNotificationCenter完成
- (void)sendBtnClickNotification:(DJEmotionButton *)btn {

    // 存储当前Emotion表情
    [DJEmotionTool saveRecentEmotion:btn.emotion];
    
    NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    userInfo[DJEmotionDidSelctedEmotionKey] = btn.emotion;
    
    [[NSNotificationCenter defaultCenter] postNotificationName:DJEmotionDidSelectedNotification object:nil userInfo:userInfo];

}

最终效果:

 

posted @ 2016-12-05 21:42  夜行过客  阅读(432)  评论(0编辑  收藏  举报