问题一
开发过程中,经常会遇到动态计算行高的问题,
- ( CGRect )boundingRectWithSize:( CGSize )size options:( NSStringDrawingOptions )options attributes:( nullable NSDictionary < NSString *, id > *)attributes context:( nullable NSStringDrawingContext *)context NS_AVAILABLE ( 10 _11, 7 _0);
是苹果推荐的计算方法,显然会遇到段落格式问题,例如行间距、缩进等格式设置需求,attributes传进来的字典中,包含我们设置的字体及格式,其中NSParagraphStyleAttributeName是设置段落风格,NSFontAttributeName是设置字体。
ok,具体来看一下NSParagraphStyleAttributeName的功能。
[objc] view plaincopy print?
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc ] init ]; paragraphStyle.lineSpacing = 1 0 ; paragraphStyle.firstLineHeadIndent = 2 0 .0f ; paragraphStyle.alignment = NSTextAlignmentJustified; paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail; paragraphStyle.headIndent = 2 0 ; paragraphStyle.tailIndent = 2 0 ; paragraphStyle.minimumLineHeight = 1 0 ; paragraphStyle.maximumLineHeight = 2 0 ; paragraphStyle.paragraphSpacing = 1 5 ; paragraphStyle.paragraphSpacingBefore = 2 2 .0f ; paragraphStyle.baseWritingDirection = NSWritingDirectionLeftToRight; paragraphStyle.lineHeightMultiple = 1 5 ; paragraphStyle.hyphenationFactor = 1 ;
好了,现在就可以很轻松的计算某一段落高度,例如:
[objc] view plaincopy print?
_descAtt = [[NSMutableAttributedString alloc ] initWithString :_model .desc ]; UIFont *descFont = [UIFont PingFangSC_Regular_WithSize : 1 2 ]; NSMutableParagraphStyle *descStyle = [[NSMutableParagraphStyle alloc ]init]; [descStyle setLineSpacing : 1 ]; CGSize descSize = [_model.desc boundingRectWithSize :CGSizeMake(w, MAXFLOAT) options :NSStringDrawingUsesLineFragmentOrigin attributes :@{NSFontAttributeName:descFont, NSParagraphStyleAttributeName :descStyle} context :nil ] .size ;
另外,再介绍几个富文本处理的属性:
[objc] view plaincopy print?
——————————————————————————————————————————————————————————————————
问题二
一、设置textView的行间距
1.如果只是静态显示textView的内容为设置的行间距,执行如下代码:
// textview 改变字体的行间距 NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; paragraphStyle.lineSpacing = 10;// 字体的行间距 NSDictionary *attributes = @{ NSFontAttributeName:[UIFont systemFontOfSize:15], NSParagraphStyleAttributeName:paragraphStyle }; textView.attributedText = [[NSAttributedString alloc] initWithString:@"输入你的内容" attributes:attributes];2.如果是想在输入内容的时候就按照设置的行间距进行动态改变,那就需要将上面代码放到textView的delegate方法里-(void)textViewDidChange:(UITextView *)textView{// textview 改变字体的行间距NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];paragraphStyle.lineSpacing = 20;// 字体的行间距NSDictionary *attributes = @{NSFontAttributeName:[UIFont systemFontOfSize:15],NSParagraphStyleAttributeName:paragraphStyle};textView.attributedText = [[NSAttributedString alloc] initWithString:textView.text attributes:attributes];}一、设置textView的placeholderUITextView上如何加上类似于UITextField的placeholder呢,其实在UITextView上加上一个UILabel或者UITextView,如果用UILable的话,会出现一个问题就是当placeholder的文字过长导致换行的时候就会出现问题,而用UITextView则可以有效避免此问题。- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{ if (![text isEqualToString:@""]){_placeholderLabel.hidden = YES;}if ([text isEqualToString:@""] && range.location == 0 && range.length == 1){_placeholderLabel.hidden = NO;}return YES;}说明如下:(1) _placeholderLabel 是加在UITextView后面的UITextView,_placeholderLabel要保证和真正的输入框的设置一样,字体设置成浅灰色,然后[_placeholderLabel setEditable:NO];真正的输入框要设置背景色透明,保证能看到底部的_placeholderLabel。(2) [text isEqualToString:@""] 表示输入的是退格键(3) range.location == 0 && range.length == 1 表示输入的是第一个字符————————————————————————————————————————————————————————————————————
问题三
UITextView富文本、插入图片
直接看代码
_textView 是定义的成员变量
[objc] view plaincopy
_textView = [[UITextView alloc ]init]; _textView.font = [UIFont systemFontOfSize : 1 3 ]; _textView.backgroundColor = [UIColor lightGrayColor ]; _textView.text = [NSString stringWithFormat : @"settttttttttt :%@" , self .countStr ]; _textView.frame = CGRectMake( 2 0 , 1 0 0 , 2 0 0 , 1 3 0 ); _textView.delegate = self ; [self .view addSubview :_textView]; 通过代理方法 得到选中文字的起始位置和长度 通过定义成员变量的方式保存起来 代码如下
[objc] view plaincopy
- ( void )textViewDidChangeSelection:( UITextView *)textView { _loc = (int )textView .selectedRange .location ; _len = (int )textView .selectedRange .length ; } 富文本 让选中的字体加粗或者改变颜色都可以 代码中是点击按钮触发字体选中改变方法
[objc] view plaincopy
- ( void )btnClick{ if (_len) { NSMutableAttributedString *AttributedStr = [[NSMutableAttributedString alloc ]initWithString:_textView .text ]; [AttributedStr addAttribute :NSFontAttributeName value :[UIFont boldSystemFontOfSize : 1 5 .0 ] range :NSMakeRange(_loc, _len)]; _textView.attributedText = AttributedStr; } } 图片插入 代码中也是通过按钮触发方法 点击按钮 复制一张图片到光标位置
[objc] view plaincopy
- ( void )copyBtnClick{ NSMutableAttributedString *string = [[NSMutableAttributedString alloc ] initWithAttributedString :_textView .attributedText ]; NSTextAttachment *textAttachment = [[NSTextAttachment alloc ] initWithData :nil ofType :nil ] ; textAttachment.image = [UIImage imageNamed : @"111" ]; NSAttributedString *textAttachmentString = [NSAttributedString attributedStringWithAttachment :textAttachment] ; [string insertAttributedString :textAttachmentString atIndex :_textView .selectedRange .location ]; _textView.attributedText = string; } ————————————————————————————————————————
问题四
继承UITextView
1.定制选中文字的菜单
首先新建一个类,继承自UITextView,假设类名为MyTextView,关键代码如下:
[objc] view plaincopy
- (BOOL )canBecameFirstResponder { return YES ; } - (BOOL )canPerformAction:( SEL )action withSender :( id )sender { if (action == @selector ( copy :)) { return NO ; } else if (action == @selector (selectAll:)) { return NO ; } return NO ; } 以上第一个方法用来确保我们选中文字后的菜单可以弹出,第二个方法用来关闭菜单中所有系统的菜单项,如copy, select, select all等。
然后使用UIMenuController定制菜单:
[objc] view plaincopy
UIMenuItem *selectItem = [[UIMenuItem alloc ] initWithTitle : @"选择文字" action : @selector (callSelectText:)]; UIMenuItem *cancelItem = [[UIMenuItem alloc ] initWithTitle : @"取消选中" action : @selector (cancelSelection:)]; [UIMenuController sharedMenuController ] .menuItems = @[selectItem, cancelItem ]; 注意必须实现两个MenuItem的响应方法才能显示出菜单:
[objc] view plaincopy
#pragma mark - Menu Item Actions - (void )callSelectText:( id )sender { self .currentSelection_ = self .myTextView .selectedRange ; self .selectOptionView .hidden = NO ; [self .location_inputTextField becomeFirstResponder ]; } - (void )cancelSelection:( id )sender { self .myTextView .selectedRange = NSRangeZero; }
最终效果如下:
之前的项目没有要求定制菜单项的图像,直接看SDK的内容的话貌似也没有Image之类的属性或方法,所以深层次定制菜单项的内容不得而知了。
2.通过代码选中一段文字
这个很简单,直接改变UITextView的selectedRange属性的值就可以了:
[objc] view plaincopy
@property ( nonatomic ) NSRange selectedRange; 例如我们点击选择文字后弹出一个文字选择的输入视图,这个我用一个XIB文件定制:
小心了,将xib中的UI组件和View Controller中的Outlet连接时,在代码中要先从xib文件中加载视图,才能使用其中的UI组件,例如:
[objc] view plaincopy
NSArray *nibViews = [[NSBundle mainBundle ] loadNibNamed : @"SelectOptionView" owner : self options :nil ]; self .selectOptionView = nibViews[ 0 ]; self .selectOptionView .center = CGPointMake( self .view .center .x , self .view .bounds .size .height / 3 ); self .selectOptionView .hidden = YES ; [self .view addSubview : self .selectOptionView ]; self .location_inputTextField .delegate = self ; self .length_inputTextField .delegate = self ; 如果将
self . location_inputTextField. delegate = self ;
self . length_inputTextField. delegate = self ;
这两行代码置于loadNibNamed方法之前,那么两个文本输入框的delegate将为空(因为他们本身都是空,还没有加载)。
选择文字的Action代码为:
[objc] view plaincopy
#pragma mark - Select View Actions - (IBAction)selectText:(id )sender { NSInteger loc = self .location_inputTextField .text .integerValue ; NSInteger len = self .length_inputTextField .text .integerValue ; NSUInteger textLength = self .myTextView .text .length ; if (loc < 0 || len < 0 || loc > textLength || len > textLength) { UIAlertView *alerView = [[UIAlertView alloc ] initWithTitle : @"错误" message : @"输入出错,输入的数不能小于0和大于文本长度" delegate :nil cancelButtonTitle : @"确定" otherButtonTitles :nil , nil nil ]; [alerView show ]; return ; } self .currentSelection_ = NSMakeRange(loc, len); [self finishSelectingText ]; } - (IBAction)cancelSelectText:(id )sender { [self finishSelectingText ]; } - (void )finishSelectingText { [self .location_inputTextField resignFirstResponder ]; [self .length_inputTextField resignFirstResponder ]; self .selectOptionView .hidden = YES ; [self .myTextView becomeFirstResponder ]; self .myTextView .selectedRange = self .currentSelection_ ; } 没错,只要一句self . myTextView. selectedRange = self . currentSelection_;就可以了。
另外,我们可以在UITextView的以下方法中监听到某段文字被选中:
[objc] view plaincopy
#pragma mark - UITextView Delegate - (void )textViewDidChangeSelection:( UITextView *)textView { NSLog(@"Selection changed" ); NSLog(@"loc = %d" , self .myTextView .selectedRange .location ); NSLog(@"len = %d" , self .myTextView .selectedRange .length ); } 运行结果:
控制台输出如下:
[plain] view plaincopy
2014-02-16 23:33:56.197 MyTextView[4890:70b] Selection changed 2014-02-16 23:33:56.198 MyTextView[4890:70b] loc = 507 2014-02-16 23:33:56.198 MyTextView[4890:70b] len = 0 2014-02-16 23:33:56.334 MyTextView[4890:70b] Selection changed 2014-02-16 23:33:56.335 MyTextView[4890:70b] loc = 507 2014-02-16 23:33:56.335 MyTextView[4890:70b] len = 5 2014-02-16 23:34:05.291 MyTextView[4890:70b] Selection changed 2014-02-16 23:34:05.292 MyTextView[4890:70b] loc = 10 2014-02-16 23:34:05.292 MyTextView[4890:70b] len = 100 3.让键盘主动出现
为了让用户更省心,我们可以在一个带输入框的视图出现时就让键盘弹出来,而不用用户再点一下输入框了。方法很简单,就一行代码:
[objc] view plaincopy
[ self .location_inputTextField becomeFirstResponder ]; 4.两个输入框按return时仿回车功能
有多个输入框,在一个输入框中按了return,然后好像在网站输入框中按了回车,直接跳到下一个输入框,这个也非常简单,就是resignFirstResponder和becomeFirstResponder方法结合使用而已,在UITextField的委托方法中实现:
[objc] view plaincopy
#pragma mark - UITextField Delegate - (BOOL )textFieldShouldReturn:( UITextField *)textField { if ([ self .location_inputTextField isFirstResponder ]) { [self .location_inputTextField resignFirstResponder ]; [self .length_inputTextField becomeFirstResponder ]; } else if ([ self .length_inputTextField isFirstResponder ]) { [self .length_inputTextField resignFirstResponder ]; } return YES ; }
Demo已经上传,有兴趣的可以下载看看:点此进入下载页
总结
以上是生活随笔 为你收集整理的iOS 富文本风格NSMutableParagraphStyle、定制UITextView插入图片和定制复制 的全部内容,希望文章能够帮你解决所遇到的问题。
如果觉得生活随笔 网站内容还不错,欢迎将生活随笔 推荐给好友。