iOS开发 - 第05篇 - 项目 - 12 - 图文混排

1、首页微博文字处理

对于之前微博项目中首页:微博文字中的用户名、话题、链接等文字需要高亮显示,表情字符串需要显示对应表情。

思路:

1>之前微博中的文字使用NSString,要达到不同文字的高亮显示,需要使用NSAttributedString

2>微博模型中增加一个属性,代表属性字符串

/** string     微博信息内容*/

@property(nonatomic, copy) NSString *text;

/** string     微博信息内容 -- 带有属性的(特殊文字会高亮显示\显示表情)*/

@property(nonatomic, copy) NSAttributedString *attributedText;

3> 重写text的setter方法,只要外面传进来text,就在里面算出带属性的文字attributedText

4>在HWStatusCell的setStatusFrame:方法中

self.contentLabel.attributedText = status.attributedText;

关键:利用text算出attributedText!!!

2、正则表达式

正则表达式作用:

1.判断字符串是否符合某个特定规则

* 判断某个字符串是否为QQ号码\电话号码\邮箱

2.截取字符串中符合某个特定规则的内容

* 截取@"#呵呵呵#[偷笑]5345http://foo.com/blah_blah #解放军# 58937985"的所有话题\表情\链接

关于正则表达式的规则用法可参考:点击打开链接

1> 正则表达式的基本使用:

    /**
     使用正则表达式的步骤:
     1.创建一个正则表达式对象:定义规则

     2.利用正则表达式对象 来测试 相应的字符串
     */

    // Pattern : 样式\规则
    // NSString *pattern = @"ab7";
    // [] : 找到内部的某一个字符即可
    // NSString *pattern = @"[0123456789]";
    // NSString *pattern = @"[0-9]";
    // NSString *pattern = @"[a-zA-Z0-9]";
    // NSString *pattern = @"[0-9][0-9]";
    // NSString *pattern = @"\\d\\d\\d";
    // NSString *pattern = @"\\d{2,4}";
    // ? + *
    // ? : 0个或者1个
    // + : 至少1个
    // * : 0个或者多个

    NSString *username = @"6gjkhdjkhgkjh7";

    // 1.创建正则表达式
    NSString *pattern = @"^\\d.*\\d$";
    NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:pattern options:0 error:nil];

    // 2.测试字符串
    NSArray *results = [regex matchesInString:username options:0 range:NSMakeRange(0, username.length)];

    NSLog(@"%zd", results.count);

2> 利用正则表达式找出微博文字中的关键字

    NSString *str = @"#呵呵呵#[偷笑] http://foo.com/blah_blah #解放军#//http://foo.com/blah_blah
            @Ring花椰菜:就#范德萨发生的#舍不得打[test] 就惯#急急急#着他吧[挖鼻屎]//@崔西狮:小拳头举起又放下了
            说点啥好呢…… //@toto97:@崔西狮 蹦米咋不揍他#哈哈哈# http://foo.com/blah_blah";

    // 创建规则
    // 表情的规则
    NSString *emotionPattern = @"\\[[0-9a-zA-Z\\u4e00-\\u9fa5]+\\]";

    // @的规则
    NSString *atPattern = @"@[0-9a-zA-Z\\u4e00-\\u9fa5]+";

    // #话题#的规则
    NSString *topicPattern = @"#[0-9a-zA-Z\\u4e00-\\u9fa5]+#";

    // url链接的规则
    NSString *urlPattern = @"\\b(([\\w-]+://?|www[.])[^\\s()<>]+(?:\\([\\w\\d]+\\)|([^[:punct:]\\s]|/)))";

    // | 匹配多个条件,相当于or\或
    NSString *pattern = [NSString stringWithFormat:@"%@|%@|%@|%@", emotionPattern, atPattern, topicPattern, urlPattern];

    // 1.创建正则表达式
    NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:pattern options:0 error:nil];
    // 2.测试字符串
    NSArray *results = [regex matchesInString:str options:0 range:NSMakeRange(0, str.length)];

    // 3.遍历结果
    for (NSTextCheckingResult *result in results) {
        NSLog(@"%@ %@", NSStringFromRange(result.range), [str substringWithRange:result.range]);
    }

3> 使用第三方框架RegexKitLite

注1:该框架为非ARC,使用-fno-objc-arc

注2:添加libicucor.dylib

NSString *str = @"#呵呵呵#[偷笑] http://foo.com/blah_blah #解放军#//http://foo.com/blah_blah
            @Ring花椰菜:就#范德萨发生的#舍不得打[test] 就惯#急急急#着他吧[挖鼻屎]//@崔西狮:小拳头举起又放下了
            说点啥好呢…… //@toto97:@崔西狮 蹦米咋不揍他#哈哈哈# http://foo.com/blah_blah";

// 表情的规则
NSString *emotionPattern = @"\\[[0-9a-zA-Z\\u4e00-\\u9fa5]+\\]";
// @的规则
NSString *atPattern = @"@[0-9a-zA-Z\\u4e00-\\u9fa5]+";
// #话题#的规则
NSString *topicPattern = @"#[0-9a-zA-Z\\u4e00-\\u9fa5]+#";
// url链接的规则
NSString *urlPattern = @"\\b(([\\w-]+://?|www[.])[^\\s()<>]+(?:\\([\\w\\d]+\\)|([^[:punct:]\\s]|/)))";
NSString *pattern = [NSString stringWithFormat:@"%@|%@|%@|%@", emotionPattern, atPattern, topicPattern, urlPattern];
// NSArray *cmps = [str componentsMatchedByRegex:pattern];

// 遍历所有的匹配结果
[str enumerateStringsMatchedByRegex:pattern usingBlock:^(NSInteger captureCount, NSString *const
        __unsafe_unretained *capturedStrings, const NSRange *capturedRanges, volatile BOOL *const stop) {
    NSLog(@"%@ %@", *capturedStrings, NSStringFromRange(*capturedRanges));
}];

// 以正则表达式为分隔符,找出所有非关键字
[str enumerateStringsSeparatedByRegex:pattern usingBlock:^(NSInteger captureCount, NSString *const
        __unsafe_unretained *capturedStrings, const NSRange *capturedRanges, volatile BOOL *const stop) {
    NSLog(@"%@ %@", *capturedStrings, NSStringFromRange(*capturedRanges));
}];

3、微博文字图文混排

3.1 关键字高亮显示

1>重写HWStatus中text的setter方法

2>转发微博文字处理

注:转发微博是由转发微博用户名和转发微博位子组成,用户名也要处理

微博模型添加转发微博文字属性

/** 被转发的原微博信息字段,当该微博为转发微博时返回 */

@property(nonatomic, strong) HWStatus *retweeted_status;

/** 被转发的原微博信息内容 -- 带有属性的(特殊文字会高亮显示\显示表情)*/

@property(nonatomic, copy) NSAttributedString *retweetedAttributedText;

重写HWStatus中retweeted_status的setter方法,算出retweetedAttributedText

3.2 文字中的表情

注意点:

注1:对于attributedText的字体设置,不能直接使用label.font来设置,这样无效,必须使用addAttribute:

[attributedTextaddAttribute:NSFontAttributeName value:font range:…];

注2:不能使用insertAttributeString: atIndex:或者replaceAttributeString:两个方法,因为一旦前面的文字替换成表情,[微笑]有四个字符,微笑表情只有一个字符会导致后面的index都变掉,不能正确插入或者替换!!!

注3:将微博打散,文字和表情分别取出来,再进行拼接!!!

注4:每一个打散碎片文字都有一个文字和一个范围,添加一个HWTextPart模型,将微博文字遍历后存放到模型数组中

注5:对数组中的模型进行排序,再进行拼接,设置表情、文字、关键字等

注6:根据表情文字找到对应的表情图片,使用之前的HWEmotionTool,添加寻找方法

1> HWTextPart

#import <Foundation/Foundation.h>

@interface HWTextPart : NSObject
/** 这段文字的内容 */
@property (nonatomic, copy) NSString *text;
/** 这段文字的范围 */
@property (nonatomic, assign) NSRange range;
/** 是否为特殊文字 */
@property (nonatomic, assign, getter = isSpecical) BOOL special;
/** 是否为表情 */
@property (nonatomic, assign, getter = isEmotion) BOOL emotion;
@end

2> HWEmotionTool

#import <Foundation/Foundation.h>
@class HWEmotion;

@interface HWEmotionTool : NSObject
+ (void)addRecentEmotion:(HWEmotion *)emotion;
+ (NSArray *)recentEmotions;
+ (NSArray *)defaultEmotions;
+ (NSArray *)lxhEmotions;
+ (NSArray *)emojiEmotions;

/**
 *  通过表情描述找到对应的表情
 *
 *  @param chs 表情描述
 */
+ (HWEmotion *)emotionWithChs:(NSString *)chs;

@end
// 最近表情的存储路径
#define HWRecentEmotionsPath [[NSSearchPathForDirectoriesInDomains
    (NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"emotions.archive"]

#import "HWEmotionTool.h"
#import "HWEmotion.h"
#import "MJExtension.h"

@implementation HWEmotionTool

static NSMutableArray *_recentEmotions;

+ (void)initialize
{
    _recentEmotions = [NSKeyedUnarchiver unarchiveObjectWithFile:HWRecentEmotionsPath];
    if (_recentEmotions == nil) {
        _recentEmotions = [NSMutableArray array];
    }
}

+ (HWEmotion *)emotionWithChs:(NSString *)chs
{
    NSArray *defaults = [self defaultEmotions];
    for (HWEmotion *emotion in defaults) {
        if ([emotion.chs isEqualToString:chs]) return emotion;
    }

    NSArray *lxhs = [self lxhEmotions];
    for (HWEmotion *emotion in lxhs) {
        if ([emotion.chs isEqualToString:chs]) return emotion;
    }

    return nil;
}

+ (void)addRecentEmotion:(HWEmotion *)emotion
{
    // 删除重复的表情
    [_recentEmotions removeObject:emotion];

    // 将表情放到数组的最前面
    [_recentEmotions insertObject:emotion atIndex:0];

    // 将所有的表情数据写入沙盒
    [NSKeyedArchiver archiveRootObject:_recentEmotions toFile:HWRecentEmotionsPath];
}

/**
 *  返回装着HWEmotion模型的数组
 */
+ (NSArray *)recentEmotions
{
    return _recentEmotions;
}

static NSArray *_emojiEmotions, *_defaultEmotions, *_lxhEmotions;
+ (NSArray *)emojiEmotions
{
    if (!_emojiEmotions) {
        NSString *path = [[NSBundle mainBundle] pathForResource:@"EmotionIcons/emoji/info.plist" ofType:nil];
        _emojiEmotions = [HWEmotion objectArrayWithKeyValuesArray:[NSArray arrayWithContentsOfFile:path]];
    }
    return _emojiEmotions;
}

+ (NSArray *)defaultEmotions
{
    if (!_defaultEmotions) {
        NSString *path = [[NSBundle mainBundle] pathForResource:@"EmotionIcons/default/info.plist" ofType:nil];
        _defaultEmotions = [HWEmotion objectArrayWithKeyValuesArray:[NSArray arrayWithContentsOfFile:path]];
    }
    return _defaultEmotions;
}

+ (NSArray *)lxhEmotions
{
    if (!_lxhEmotions) {
        NSString *path = [[NSBundle mainBundle] pathForResource:@"EmotionIcons/lxh/info.plist" ofType:nil];
        _lxhEmotions = [HWEmotion objectArrayWithKeyValuesArray:[NSArray arrayWithContentsOfFile:path]];
    }
    return _lxhEmotions;
}
@end

3> HWStatus

#import "HWStatus.h"
#import "MJExtension.h"
#import "HWPhoto.h"
#import "HWUser.h"
#import "HWTextPart.h"
#import "RegexKitLite.h"
#import "HWEmotion.h"
#import "HWEmotionTool.h"

@implementation HWStatus
- (NSDictionary *)objectClassInArray
{
    return @{@"pic_urls" : [HWPhoto class]};
}

/**
 *  普通文字 --> 属性文字
 *
 *  @param text 普通文字
 *
 *  @return 属性文字
 */
- (NSAttributedString *)attributedTextWithText:(NSString *)text
{
    NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] init];

    // 表情的规则
    NSString *emotionPattern = @"\\[[0-9a-zA-Z\\u4e00-\\u9fa5]+\\]";
    // @的规则
    NSString *atPattern = @"@[0-9a-zA-Z\\u4e00-\\u9fa5-_]+";
    // #话题#的规则
    NSString *topicPattern = @"#[0-9a-zA-Z\\u4e00-\\u9fa5]+#";
    // url链接的规则
    NSString *urlPattern = @"\\b(([\\w-]+://?|www[.])[^\\s()<>]+(?:\\([\\w\\d]+\\)|([^[:punct:]\\s]|/)))";
    NSString *pattern = [NSString stringWithFormat:@"%@|%@|%@|%@", emotionPattern, atPattern, topicPattern, urlPattern];

    // 遍历所有的特殊字符串
    NSMutableArray *parts = [NSMutableArray array];
    [text enumerateStringsMatchedByRegex:pattern usingBlock:^(NSInteger captureCount, NSString *const
                __unsafe_unretained *capturedStrings, const NSRange *capturedRanges, volatile BOOL *const stop) {
        if ((*capturedRanges).length == 0) return;

        HWTextPart *part = [[HWTextPart alloc] init];
        part.special = YES;
        part.text = *capturedStrings;
        part.emotion = [part.text hasPrefix:@"["] && [part.text hasSuffix:@"]"];
        part.range = *capturedRanges;
        [parts addObject:part];
    }];
    // 遍历所有的非特殊字符
    [text enumerateStringsSeparatedByRegex:pattern usingBlock:^(NSInteger captureCount, NSString *const
                __unsafe_unretained *capturedStrings, const NSRange *capturedRanges, volatile BOOL *const stop) {
        if ((*capturedRanges).length == 0) return;

        HWTextPart *part = [[HWTextPart alloc] init];
        part.text = *capturedStrings;
        part.range = *capturedRanges;
        [parts addObject:part];
    }];

    // 排序
    // 系统是按照从小 -> 大的顺序排列对象
    [parts sortUsingComparator:^NSComparisonResult(HWTextPart *part1, HWTextPart *part2) {
        // NSOrderedAscending = -1L, NSOrderedSame, NSOrderedDescending
        // 返回NSOrderedSame:两个一样大
        // NSOrderedAscending(升序):part2>part1
        // NSOrderedDescending(降序):part1>part2
        if (part1.range.location > part2.range.location) {
            // part1>part2
            // part1放后面, part2放前面
            return NSOrderedDescending;
        }
        // part1<part2
        // part1放前面, part2放后面
        return NSOrderedAscending;
    }];

    UIFont *font = [UIFont systemFontOfSize:15];
    // 按顺序拼接每一段文字
    for (HWTextPart *part in parts) {
        // 等会需要拼接的子串
        NSAttributedString *substr = nil;
        if (part.isEmotion) { // 表情
            NSTextAttachment *attch = [[NSTextAttachment alloc] init];
            NSString *name = [HWEmotionTool emotionWithChs:part.text].png;
            if (name) { // 能找到对应的图片
                attch.image = [UIImage imageNamed:name];
                attch.bounds = CGRectMake(0, -3, font.lineHeight, font.lineHeight);
                substr = [NSAttributedString attributedStringWithAttachment:attch];
            } else { // 表情图片不存在
                substr = [[NSAttributedString alloc] initWithString:part.text];
            }
        } else if (part.special) { // 非表情的特殊文字
           substr = [[NSAttributedString alloc] initWithString:part.text
                        attributes:@{ NSForegroundColorAttributeName : [UIColor redColor] }];
        } else { // 非特殊文字
            substr = [[NSAttributedString alloc] initWithString:part.text];
        }
        [attributedText appendAttributedString:substr];
    }

    // 一定要设置字体,保证计算出来的尺寸是正确的
    [attributedText addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, attributedText.length)];

    return attributedText;
}

- (void)setText:(NSString *)text
{
    _text = [text copy];

    // 利用text生成attributedText
    self.attributedText = [self attributedTextWithText:text];
}

- (void)setRetweeted_status:(HWStatus *)retweeted_status
{
    _retweeted_status = retweeted_status;

     NSString *retweetContent = [NSString stringWithFormat:@"@%@ : %@", retweeted_status.user.name, retweeted_status.text];
    self.retweetedAttributedText = [self attributedTextWithText:retweetContent];
}

4、监听点击

4.1 自定义HWStatusTextView

实现:对关键字点击实现高亮显示

关键:首先判断手指是否在关键字上,其次算出关键字的范围,最后设置高亮背景!!!

注1:利用UILabel不能根据文字找出文字对应的尺寸范围,利用UITextView可以实现,自定义HWStatusTextView!

注2:textView默认会有内边距,需要取消

注3:

self.editable = NO;

self.textContainerInset =UIEdgeInsetsMake(0, -5, 0, -5);

//
禁止滚动,让文字完全显示出来

self.scrollEnabled = NO;

4.2 HWStatusTextView点击

注1:找出关键字在textView的范围,可以使用textView的selectedRange属性,再通过selectionRectsForRange:方法!!!

注2:找出关键字的range,自定义HWSpecial模型

#import <Foundation/Foundation.h>

@interface HWSpecial : NSObject
/** 这段特殊文字的内容 */
@property (nonatomic, copy) NSString *text;
/** 这段特殊文字的范围 */
@property (nonatomic, assign) NSRange range;
@end

注3:在HWStatus中拼接字符串时,计算每个字符串中的特殊文字,将HWSpecial模型数组绑定到attributedText中,就可以在textView中根据Key取出特殊字符串!!!

UIFont *font = [UIFont systemFontOfSize:15];
NSMutableArray *specials = [NSMutableArray array];
// 按顺序拼接每一段文字
for (HWTextPart *part in parts) {
    // 等会需要拼接的子串
    NSAttributedString *substr = nil;
    if (part.isEmotion) { // 表情
        NSTextAttachment *attch = [[NSTextAttachment alloc] init];
        NSString *name = [HWEmotionTool emotionWithChs:part.text].png;
        if (name) { // 能找到对应的图片
            attch.image = [UIImage imageNamed:name];
            attch.bounds = CGRectMake(0, -3, font.lineHeight, font.lineHeight);
            substr = [NSAttributedString attributedStringWithAttachment:attch];
        } else { // 表情图片不存在
            substr = [[NSAttributedString alloc] initWithString:part.text];
        }
    } else if (part.special) { // 非表情的特殊文字
       substr = [[NSAttributedString alloc] initWithString:part.text attributes:@{
                                                                          NSForegroundColorAttributeName : [UIColor redColor]
                                                                          }];

        // 创建特殊对象
        HWSpecial *s = [[HWSpecial alloc] init];
        s.text = part.text;
        NSUInteger loc = attributedText.length;
        NSUInteger len = part.text.length;
        s.range = NSMakeRange(loc, len);
        [specials addObject:s];
    } else { // 非特殊文字
        substr = [[NSAttributedString alloc] initWithString:part.text];
    }
    [attributedText appendAttributedString:substr];
}

// 一定要设置字体,保证计算出来的尺寸是正确的
[attributedText addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, attributedText.length)];
[attributedText addAttribute:@"specials" value:specials range:NSMakeRange(0, 1)];

注4:HWStatusTextView中处理如下:

#import "HWStatusTextView.h"
#import "HWSpecial.h"

#define HWStatusTextViewCoverTag 999

@implementation HWStatusTextView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor clearColor];
        self.editable = NO;
        self.textContainerInset = UIEdgeInsetsMake(0, -5, 0, -5);
        // 禁止滚动, 让文字完全显示出来
        self.scrollEnabled = NO;
    }
    return self;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 触摸对象
    UITouch *touch = [touches anyObject];

    // 触摸点
    CGPoint point = [touch locationInView:self];

    NSArray *specials = [self.attributedText attribute:@"specials" atIndex:0 effectiveRange:NULL];
    BOOL contains = NO;

    for (HWSpecial *special in specials) {
        self.selectedRange = special.range;
        // self.selectedRange --影响--> self.selectedTextRange
        // 获得选中范围的矩形框
        NSArray *rects = [self selectionRectsForRange:self.selectedTextRange];
        // 清空选中范围
        self.selectedRange = NSMakeRange(0, 0);

        for (UITextSelectionRect *selectionRect in rects) {
            CGRect rect = selectionRect.rect;
            if (rect.size.width == 0 || rect.size.height == 0) continue;

            if (CGRectContainsPoint(rect, point)) { // 点中了某个特殊字符串
                contains = YES;
                break;
            }
        }

        if (contains) {
            for (UITextSelectionRect *selectionRect in rects) {
                CGRect rect = selectionRect.rect;
                if (rect.size.width == 0 || rect.size.height == 0) continue;

                UIView *cover = [[UIView alloc] init];
                cover.backgroundColor = [UIColor greenColor];
                cover.frame = rect;
                cover.tag = HWStatusTextViewCoverTag;
                cover.layer.cornerRadius = 5;
                [self insertSubview:cover atIndex:0];
            }

            break;
        }
    }
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self touchesCancelled:touches withEvent:event];
    });
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 去掉特殊字符串后面的高亮背景
    for (UIView *child in self.subviews) {
        if (child.tag == HWStatusTextViewCoverTag) [child removeFromSuperview];
    }
}
@end

5、代码重构

/**
 * 获取特殊字符串rect数组
 */
- (void)setupSpecialRects
{
    NSArray *specials = [self.attributedText attribute:@"specials" atIndex:0 effectiveRange:NULL];
    for (HWSpecial *special in specials) {
        self.selectedRange = special.range;
        // self.selectedRange --影响--> self.selectedTextRange
        // 获得选中范围的矩形框
        NSArray *selectionRects = [self selectionRectsForRange:self.selectedTextRange];
        // 清空选中范围
        self.selectedRange = NSMakeRange(0, 0);

        NSMutableArray *rects = [NSMutableArray array];
        for (UITextSelectionRect *selectionRect in selectionRects) {
            CGRect rect = selectionRect.rect;
            if (rect.size.width == 0 || rect.size.height == 0) continue;

            // 添加rect
            [rects addObject:[NSValue valueWithCGRect:rect]];
        }
        special.rects = rects;
    }
}

/**
 * 找出被触摸的特殊字符串
 */
- (HWSpecial *)touchingSpecialWithPoint:(CGPoint)point
{
    NSArray *specials = [self.attributedText attribute:@"specials" atIndex:0 effectiveRange:NULL];
    for (HWSpecial *special in specials) {
        for (NSValue *rectValue in special.rects) {
            if (CGRectContainsPoint(rectValue.CGRectValue, point)) { // 点中了某个特殊字符串
                return special;
            }
        }
    }
    return nil;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 触摸对象
    UITouch *touch = [touches anyObject];

    // 触摸点
    CGPoint point = [touch locationInView:self];

    // 初始化矩形框
    [self setupSpecialRects];

    // 根据触摸点获得被触摸的特殊字符串
    HWSpecial *special = [self touchingSpecialWithPoint:point];

    // 在被触摸的特殊字符串后面显示一段高亮的背景
    for (NSValue *rectValue in special.rects) {
        // 在被触摸的特殊字符串后面显示一段高亮的背景
        UIView *cover = [[UIView alloc] init];
        cover.backgroundColor = [UIColor greenColor];
        cover.frame = rectValue.CGRectValue;
        cover.tag = HWStatusTextViewCoverTag;
        cover.layer.cornerRadius = 5;
        [self insertSubview:cover atIndex:0];
    }
}

6、事件处理

注:上述做法,textView拦截了所有的触摸事件,即点击了textView,事件不会交给cell去处理,实际应用中,点击cell,还需要跳转微博详情,即交给cell去处理cell点击事件,因此需要修改textView的事件处理,再点击关键字的时候交给textView处理,其余情况下交给cell去处理!!!

触摸事件的处理

1.判断触摸点在谁身上:调用所有UI控件的-(BOOL)pointInside:(CGPoint)point
withEvent:(UIEvent *)event

2.pointInside返回YES的控件就是触摸点所在的UI控件

3.由触摸点所在的UI控件选出处理事件的UI控件:调用-
(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event

//- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
//{
//    return [super hitTest:point withEvent:event];
//}

/**
 * 告诉系统:触摸点point是否在这个UI控件身上
 */
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    // 初始化矩形框
    [self setupSpecialRects];

    // 根据触摸点获得被触摸的特殊字符串
    HWSpecial *special = [self touchingSpecialWithPoint:point];

    return special : YES ? NO;
}
时间: 2025-01-15 01:26:43

iOS开发 - 第05篇 - 项目 - 12 - 图文混排的相关文章

iOS开发 - 第05篇 - 项目 - 10 - 发微博

1.点击表情 1.1 表情放大界面 1.2 实现思路 1>监听表情按钮点击 2>同一时间只能显示一个放大镜,创建一个即可,不用重复创建 3>放大镜应该作为一个整体HWEmotionPopView,而且比较简单,用XIB来实现即可,提供类方法 4>在HWEmotionPageView中懒加载HWEmotionPopView 注1:HWEmotionPopView添加位置问题,若添加在HWEmotionPageView上面,则会被上面工具台挡住,因此,应该添加到最上面的窗口UIWind

iOS开发日记21-7.0之后的图文混排

今天博主有一个图文混排的需求,遇到了一些困难点,在此和大家分享,希望能够共同进步. iOS7.0以前,图文混排主要有两种方法:1.WebView+js  2.coreText iOS7.0之后,苹果提供了新的封装,让图文混排更加的简便,也就是第三种方法:3.TextKit 今天就和大家详细的分享一下这三种图文混排的方法 1.webview+js的方法其实很简单,下面贴出代码,各位自行研究 去除webView滚动时,上下的白边. - (void)clearWebViewBackground:(UI

iOS开发 - 第05篇 - 项目 - 11 - const &amp; git &amp; 项目重构

1.发微博键盘最近标签页完善 问题: 1>表情出现重复 2>其他标签页转换到最近标签也没有及时出现最新使用表情 1.1 表情实时刷新 方法一:切换到最近标签页,刷新最新使用表情 注:需要在listView中表情数组的setter方法中先移除之前的控件,并在最后[selfsetNeedsLayout]; 方法二:上述方法只能在其他标签页切换到最近标签页的时候刷新表情,若在最近页需要点击表情按钮立即刷新,需要监听表情按钮点击的通知 1.2 表情重复问题 在表情工具类,存储表情的时候增加判断,删除重

iOS开发 - 第05篇 - 项目 - 01 - 搭建框架

实现:仿新浪微博 1.项目配置 1> 取消横竖屏 2> 设置图标和启动图片 3> 删除MainStoryboard,全部代码创建 2.添加TabBarController 2.1 创建窗口 1>在didFinishLaunchingWithOptions方法中,创建窗口,设置根控制器,显示窗口 2> 添加TabBarController的子控制器 3>抽取重复代码 注:上述方法限制每次创建的都是UIViewController,实际使用中,需要设置不同的控制器作为Tab

iOS开发 - 第05篇 - 项目 - 02 - 导航栏

1.Debug下NSLog 2.Xcode图片拉伸 直接选中图片,在右侧属性中设置即可,避免代码拉伸. 3.添加搜索框 在发现控制器的导航栏中添加一个搜索框. 3.1 通过UISearchBar 系统自带的UISearchBar并不好用,不能改变其高度. 3.2 通过UITextField 3.3 自定义搜索框 注:由于上述创建搜索框控件在其他地方也有可能用得上,因此最好将其抽取出来,自定义一个搜索框控件 4.弹出下拉菜单 4.1 界面 4.2 设置导航栏的titleView 注1:设置UIBu

iOS开发 - 第05篇 - 项目 - 04 - OAuth授权 &amp; 首页

1.存储帐号信息 1.1 基本实现 由于一旦授权成功,新浪返回的accessToken是同一个值(针对同一个第三方应用,同一个账号),为避免每次都重新登录,应该讲accessToken存储起来. 实现:先检测沙盒里面是否存在accessToken,若无,则意味从来没有登陆过,加载登录界面,一旦成功登录,就将获得的accessToken存进沙盒,下次进来就不需要再进行登录,直接从沙盒中取出accessToken,进入首页,获取用户数据. 1>在发送请求,成功获取accessToken方法后,将返回

iOS开发 - 第05篇 - 项目 - 05 - 首页

1.下拉刷新 1.1 进入首页自动刷新 1.2 显示最新微博数量 注:弹出的UILabel应该添加到导航控制器的View上,而不应该添加到tableView上,否则会更随tableView一起滚动!!! 在发送请求成功后,调用下面方法(注意动画): 2.添加上拉刷新控件 1> 自定义HWLoadMoreFooter(XIB) 1. UILabel利用autoLayout填充View 2.添加转圈控件,勾选动画 2>提供类方法加载XIB控件 3> 添加到tableView的tableFoo

iOS开发 - 第05篇 - 项目 - 03 - 版本新特性 &amp; OAuth授权

1.版本新特性 1.1 界面 程序第一次启动的时候会弹出新特性界面,之后启动不会出现. 1.2 实现思路 1> 新建一个HWNewfeatureViewController(继承自UIViewController) 2> 先将其设置为整个程序的根控制器,用于演示 3> 使用UIScrollView 4>添加UIPageControl 5> 设置UIScrollView代理,监听滚动,设置UIPageControl 2.控制器切换 2.1 一个View中显示其他控制器的View

IOS开发UI篇--一个支持图文混排的ActionSheet

一.简单介绍 UIActionSheet是IOS提供给我们开发人员的底部弹出菜单控件.一般用于菜单选择.操作确认.删除确认等功能.IOS官方提供的下面方式对UIActionView进行实例化: - (instancetype)initWithTitle:(NSString *)title delegate:(id<UIActionSheetDelegate>)delegate cancelButtonTitle:(NSString *)cancelButtonTitle destructive