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> 利用正則表達式找出微博文字中的keyword

    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));
}]; // 以正則表達式为分隔符,找出全部非keyword
[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 keyword高亮显示

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:对数组中的模型进行排序,再进行拼接,设置表情、文字、keyword等

注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

实现:对keyword点击实现高亮显示

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

!!

注1:利用UILabel不能依据文字找出文字相应的尺寸范围。利用UITextView能够实现,自己定义HWStatusTextView。

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

注3:

self.editable = NO;

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

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

self.scrollEnabled = NO;

4.2 HWStatusTextView点击

注1:找出keyword在textView的范围。能够使用textView的selectedRange属性。再通过selectionRectsForRange:方法!!!

注2:找出keyword的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的事件处理,再点击keyword的时候交给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;
}

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

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

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

  2. IOS总结_实现UIButton的图文混排(二)

    非常久没有写博客了,之前写过一篇关于UIButton图文混排的,可是有点复杂,今天来一个比較简单地.相信大家回用得着 UIButton *button=[[UIButton alloc, , )]; ...

  3. iOS开发——图层OC篇&Quartz 2D各种绘制实例

    Quartz 2D各种绘制实例 首先说一下,本篇文章只是介绍怎么使用Quartz 2D绘制一些常用的图像效果,关于Quartz和其他相关技术请查看笔者之前写的完整版(Quartz 2D详解) 一:画线 ...

  4. iOS开发——实战OC篇&环境搭建之Xib(玩转UINavigationController与UITabBarController)

    iOS开发——实战OC篇&环境搭建之Xib(玩转UINavigationController与UITabBarController)   前面我们介绍了StoryBoard这个新技术,和纯技术 ...

  5. iOS开发——实战OC篇&环境搭建之纯代码(玩转UINavigationController与UITabBarController)

    iOS开发——实战OC篇&环境搭建之纯代码(玩转UINavigationController与UITabBarController)   这里我们就直接上实例: 一:新建一个项目singleV ...

  6. IOS开发数据存储篇—IOS中的几种数据存储方式

    IOS开发数据存储篇—IOS中的几种数据存储方式 发表于2016/4/5 21:02:09  421人阅读 分类: 数据存储 在项目开发当中,我们经常会对一些数据进行本地缓存处理.离线缓存的数据一般都 ...

  7. 在iOS开发中,给项目添加新的.framework

    首先需要了解一下iOS中静态库和动态库.framework的概念 静态库与动态库的区别 首先来看什么是库,库(Library)说白了就是一段编译好的二进制代码,加上头文件就可以供别人使用. 什么时候我 ...

  8. ios开发--图文混排(富文本)

    最近准备接一个编辑类的app,所以就查了下相关的功能,并自己试验了下: /** iOS 6之前:CoreText,纯C语言,极其蛋疼 iOS 6开始:NSAttributedString,简单易用 i ...

  9. iOS开发——UI进阶篇(八)pickerView简单使用,通过storyboard加载控制器,注册界面,通过xib创建控制器,控制器的view创建,导航控制器的基本使用

    一.pickerView简单使用 1.UIPickerViewDataSource 这两个方法必须实现 // 返回有多少列 - (NSInteger)numberOfComponentsInPicke ...

随机推荐

  1. sersync+rsync作实时同事

    http://liubao0312.blog.51cto.com/2213529/1677586 配置搞定,参照上面的文章,用时搞一搞就OK. 注意IPTABLES的配置及环境变量 最简陋配置: rs ...

  2. 新建Maven工程

    这个如果不勾选那个Create a simple project也可以,但是创建完成后还需要修改工程的packaging为pom.还有如果不勾选,就选择maven-archetype-quicksta ...

  3. 51nod 1091 线段的重叠【贪心/区间覆盖类】

    1091 线段的重叠 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题  收藏  关注 X轴上有N条线段,每条线段包括1个起点和终点.线段的重叠是这样来算的,[10 2 ...

  4. Manacher【p4555】 [国家集训队]最长双回文串

    题目描述 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为abc,逆序为cba,不相同). 输入长度为 n 的串 S ,求 S 的最长双回文子串 T ,即可 ...

  5. 九. 常用类库、向量与哈希2.Object类

    Object 类位于 java.lang 包中,是所有 Java 类的祖先,Java 中的每个类都由它扩展而来. 定义Java类时如果没有显示的指明父类,那么就默认继承了 Object 类.例如: p ...

  6. Android Developer -- Bluetooth篇 开发实例之二 连接设备

    连接设备 In order to create a connection between your application on two devices, you must implement bot ...

  7. Creating and Flashing UBIFS with MTD Utils

    转:http://wiki.atlas-embedded.com/index.php?title=Creating_and_Flashing_UBIFS_with_MTD_Utils Contents ...

  8. 【mybatis】in查询+判断list查询条件是否进行in查询

    mybatis中的in查询: 并且判断in查询的list是否为null或者list有值才进行In查询 <select id="find" parameterType=&quo ...

  9. wireshark问题现象分析

    讲的非常透彻:建议学习 wireshark问题现象分析1:参考博客1 https://blog.csdn.net/u012398362/article/details/52276067 wiresha ...

  10. 【Hadoop】如何形象描述大数据生态?

    作者:千岁大王链接:https://www.zhihu.com/question/27974418/answer/39845635来源:知乎著作权归作者所有,转载请联系作者获得授权. Google内部 ...