iOS_UITextView _ 链接地址在应用程序内跳转 _ 占位符 _ 改变选中文本的属性

  • 说明:

    • 本文将介绍UITextView的三种效果.
    • 本文会使用一些NSAttributedString的属性.
    • 所以, 建议在阅读本篇博文之前, 先阅读 iOS_NSAttributedString 的21种属性详细介绍(图文混排)
    • 本文所展示的效果只是给大家提供个思路, 一定会有不完美的地方, 同时也希望大家根据自己的需求灵活运用.
  • 此文章由 @春雨 编写. 经 @Scott,@黑子 审核. 若转载此文章,请注明出处和作者

链接地址在应用程序内跳转

核心API

Class: UITextView


/** UITextView的编辑状态, 默认YES. */
@property(nonatomic, getter=isEditable) BOOL editable

/** */
@property(nonatomic) UIDataDetectorTypes dataDetectorTypes

/** 字典内存储链接文本的属性. */
@property(nonatomic, copy) NSDictionary *linkTextAttributes


/** 询问代理人, 是否可以跳转到指定的链接地址. */
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange

功能实现

我们在UITextView里面点击链接地址时, 它是跳到浏览器里面的. 如果我们不想跳到浏览器, 想在自己的程序内部跳转显示, 该怎么做呢?

思路

UITextView有一个代理方法是用来链接跳转动作是否执行的. 返回值是BOOL类型, 默认是YES.
* 当我们返回NO时, 它就不会跳转了.
* 在这个代理方法内, 我们执行其他的操作, 让链接地址的内容在程序内显示.

Code :

#import "ViewController.h"
#import "WebViewController.h"

/** 签订协议 */
@interface ViewController ()<UITextViewDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    [self layoutTextView];

    /** 这个属性是UIViewController的属性, 当有Navicontroller的时候, 会自动向下调整UIScrollView及其子类的坐标位置, 默认为YES, 开启状态. */
    /** 如果为YES, TextView里的内容会自动向下移动位置. 可以自己测试一下. */
    self.automaticallyAdjustsScrollViewInsets = NO;

}

- (void)layoutTextView {

    /** 第一种链接界面: 地址链接. */

    /** 创建UITextView的对象. 在这里我们并不需要textContainer, 设置成nil即可. */
    UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(30, 100, 300, 150) textContainer:nil];

    textView.text = @"http://blog.csdn.net/sponge_cmz?viewmode=contents";
    textView.font = [UIFont systemFontOfSize:20];
    textView.layer.borderColor = [UIColor blackColor].CGColor;
    textView.layer.borderWidth = 1;

    /** 设置代理人, 我们要实现的效果, 需要用到代理方法. 在上面签订UITextViewDelegate协议. */
    textView.delegate = self;

    /** 链接地址能够跳转, textView的编辑状态必须为NO, 否则与普通文本无异. */
    textView.editable = NO;

    /** 设置自动检测类型为链接网址. */
    textView.dataDetectorTypes = UIDataDetectorTypeLink;

    /** 设置链接文字的属性. */
    textView.linkTextAttributes = @{NSForegroundColorAttributeName: [UIColor orangeColor]};

    [self.view addSubview:textView];


    /** 第二种连接界面: 文字链接 */
    UITextView *otherTextView = [[UITextView alloc] initWithFrame:CGRectMake(30, 350, 300, 150) textContainer:nil];

    /** font属性是设置text的字体, 但是它对attributedText的字体不起作用. */
// otherTextView.font = [UIFont systemFontOfSize:20];

    otherTextView.layer.borderColor = [UIColor blackColor].CGColor;
    otherTextView.layer.borderWidth = 1;
    otherTextView.delegate = self;
    otherTextView.editable = NO;

    /** 详细内容请见博文说明中提到的另外一篇博客. */
    NSAttributedString *linkAttribute = [[NSAttributedString alloc] initWithString:@"百度" attributes:@{NSLinkAttributeName: [NSURL URLWithString:@"http://www.baidu.com"], NSFontAttributeName:[UIFont systemFontOfSize:25]}];

    otherTextView.attributedText = linkAttribute;

    [self.view addSubview:otherTextView];



}

/** 当点击链接时, 是否要跳转到浏览器. 默认返回YES. 想要实现在应用程序内部跳转, 只需要返回NO即可. */
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange {


    /** 跳转到WebViewController的WebView上. */

    WebViewController *webContro = [[WebViewController alloc] init];

    UIWebView *web = [[UIWebView alloc] initWithFrame:[UIScreen mainScreen].bounds];

    /** URL参数就是我们点击的链接地址. */
    [web loadRequest:[NSURLRequest requestWithURL:URL]];

    web.scalesPageToFit = YES;
    [webContro.view addSubview:web];

    [self.navigationController pushViewController:webContro animated:YES];

    /** 返回NO, 不跳转到浏览器. */
    return NO;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

占位符

核心API

Class : UITextView


/** 告诉代理人, 用户已经改变指定textView里面的text或者attributes. */
- (void)textViewDidChange:(UITextView *)textView

功能实现

我们在使用UITextView的时候发现, UITextView没有像UITextField一样的占位符. 如果我们想要在UITextView里面实现占位符的效果, 该怎么办呢?

思路:

我们想要实现和UITextField一样的占位符效果, 那么我们就先看看UITextField是怎么实现的.

  • 通过观察UITextField的图层, 我们发现, 占位符在一个单独的UILabel上.
  • 我们让UITextField处于编辑状态, 再来看图层, 会发现在占位符label的上面又多了两层视图.
  • 我们输入文字之后再看图层, 会发现占位符的lable没有了.
  • 由此, 我们可以推测, 这个占位符label, 再输入之后, 就被隐藏了.
  • 我们再来看UITextView的图层, 会发现它也有两个图层, 一个是UITextView, 一个是UITextContainerView. (还有两个滑条, 是UIImageView, 但是和我们实现的效果无关.)
  • 那我们也可以仿照UITextField, 把一个label放到UITextContainerView的下面, 输入时就隐藏.

注: UITextView和UITextField 我是使用StoryBoard创建的, 所以在代码中没有创建的代码.

Code:

#import "ViewController.h"

/** 签订协议. */
@interface ViewController ()<UITextViewDelegate>

@property (weak, nonatomic) IBOutlet UITextView *textView;
@property (nonatomic, strong) UILabel *label_Placeholder; /**< 用来显示占位符的label. */

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    _textView.layer.borderColor = [UIColor blackColor].CGColor;
    _textView.layer.borderWidth = 2;

    /** 签订代理人, 实现效果需要用到代理方法. */
    _textView.delegate = self;

    /** 创建占位符label. */
    self.label_Placeholder = [[UILabel alloc] initWithFrame:CGRectMake(5, 0, 200, 40)]; /**< 坐标要根据实际情况做出调整. */

    /** 使用属性文本. 详情请查看博文说明中提到的另一篇博客. */
    _label_Placeholder.attributedText = [[NSAttributedString alloc] initWithString:@"Hello World!" attributes:@{NSFontAttributeName: _textView.font, NSForegroundColorAttributeName: [UIColor grayColor]}];

    /** 我们之前说过了, textView上有UITextContainerView 和 两个UIImageView 子视图, 我们把label_Placeholder放到UITextContainerView的下面, 也就是textView的第一个子视图. */
    [_textView insertSubview:_label_Placeholder atIndex:0];

    /** 可以打印textView的子视图看一下. */
    NSLog(@"%@", [_textView subviews]);

}

/** 当textView里面的内容发生改变时, 调用这个代理方法. */
- (void)textViewDidChange:(UITextView *)textView
{
    /** 判断条件是多次尝试的结果. 大家按照自己的想法, 尝试着写判断条件, 会更加理解为什么这么写了! */
    if (_textView.text.length != 0 && _label_Placeholder.hidden == NO) {

        _label_Placeholder.hidden = YES;

    } else if (_textView.text.length == 0) {

        _label_Placeholder.hidden = NO;

    }

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

注: 还有四个关于编辑状态的代理方法, 可以调用它们, 看看它们都是在那些时刻被执行. 可以自己尝试别的方法实现占位符效果.


- (BOOL)textViewShouldBeginEditing:(UITextView *)textView - (void)textViewDidBeginEditing:(UITextView *)textView - (BOOL)textViewShouldEndEditing:(UITextView *)textView - (void)textViewDidEndEditing:(UITextView *)textView 

改变选中文本的属性

核心API

Class : UITextViews


/** 用户输入新的文本属性时, 会被存储在这个字典属性里. */
@property(nonatomic, copy) NSDictionary *typingAttributes

/** */
@property(nonatomic, readonly, retain) NSTextStorage *textStorage

/** 被选中的范围. */
@property(nonatomic) NSRange selectedRange

功能实现

我们在看小说或文档时, 可以对一些重点内容进行标注, 例如, 加下划线, 改变颜色之类的. 那么UITextView里的内容, 我们是如何进行标注的呢?

思路

首先获取到被选中的文本, 之后改变这段文本的属性设置.

Code

#import "ViewController.h"

@interface ViewController ()

@property (weak, nonatomic) IBOutlet UITextView *textView;

@property (nonatomic, strong) NSDictionary *oldAttributes; /** 用来接收textView文本的初始属性设置. */



@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    /** 我们在textView的文本还未做出任何改变的时候, 将原始属性设置保存起来, 便于以后恢复. */

    /** * 初始化oldAttributes. * typingAttributes : 在用户没有输入新的文本属性时, 里面会有一些默认的文本属性. */
    self.oldAttributes = [NSDictionary dictionaryWithDictionary:[_textView typingAttributes]];

    /** 打印看一下里面存储的内容. */
    NSLog(@"old: %@", _oldAttributes);

}

/** * textStorage : UITextView的属性, 是NSTextStorage类型. * NSTextStorage 继承于NSMutableAttributedString类, 所以可以使用父类的方法. * 关于属性设置请查看博文说明中提到的博客. */

/** * selectedRange : UITextView的属性, 是NSRange类型. * textView当前被选择的文本. */

/** 改变字体的笔画宽度. */
- (IBAction)wordWeight:(UIButton *)sender {


        [_textView.textStorage addAttribute:NSStrokeWidthAttributeName value:@5 range:_textView.selectedRange];

}

/** 给选中的文本添加黄色背景, 以及下划线. */
- (IBAction)backgroundColor:(UIButton *)sender {

    /** * 上面使用的是addAttribute: value: rang: 的方法. 它只能添加一个属性. * 如果我们要同时添加多个属性, 我们需要使用addAttributes: rang: 方法. * 这个方法的第一个参数是一个字典, 可以在字典中存储多个属性. */

    [_textView.textStorage addAttributes:@{NSBackgroundColorAttributeName: [UIColor yellowColor], NSUnderlineStyleAttributeName: @2} range:_textView.selectedRange];

    /** * 要注意 addAttributes 和 setAttributes 的区别: * addAttributes 是添加属性, 不会将之前的属性移除掉, 它们是共同存在的. * setAttributes 是设置属性, 会将之前的属性替换掉, 之前的属性将不会存在. */

// [_textView.textStorage setAttributes:@{NSBackgroundColorAttributeName: [UIColor yellowColor], NSUnderlineStyleAttributeName: @2} range:_textView.selectedRange];
}

/** 恢复到原来的文本状态. */
- (IBAction)recoverAttribute:(UIButton *)sender {

    /** 我们想要恢复之前的属性, 也就是说不再使用做出改变的属性, 所以在这里我使用的是setAttributes: rang: 方法. */
    [_textView.textStorage setAttributes:_oldAttributes range:_textView.selectedRange];

}




- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

    • 链接地址在应用程序内跳转
      • 核心API
      • 功能实现
      • 思路
        • Code
    • 占位符
      • 核心API
      • 功能实现
        • 思路
        • Code
    • 改变选中文本的属性
      • 核心API
      • 功能实现
        • 思路
        • Code
    • API官方注释

API官方注释


/**
 * @brief   A Boolean value indicating whether the receiver is editable.
 * 
 * @discussion      The default value of this property is YES.
 */
@property(nonatomic, getter=isEditable) BOOL editable


/**
 * @brief   The types of data converted to clickable URLs in the text view.
 * 
 * @discussion      You can use this property to specify the types of data (phone numbers, http links, and so on) that should be automatically converted to clickable URLs in the text view. When clicked, the text view opens the application responsible for handling the URL type and passes it the URL.
 */
@property(nonatomic) UIDataDetectorTypes dataDetectorTypes


/**
 * @brief   The attributes to apply to links.
 * 
 * @discussion      The default attributes specify blue text with a single underline and the pointing hand cursor.
 */
@property(nonatomic, copy) NSDictionary *linkTextAttributes



/** 
 * @brief  Asks the delegate if the specified text view should allow user interaction with the given URL in the given range of text.
 *
 * @param  <textView>   The text view containing the text attachment.
 *
 * @param  <URL>    The URL to be processed.
 * 
 * @param  <characterRange> The character range containing the URL.
 * 
 * @return      YES if interaction with the URL should be allowed; NO if interaction should not be allowed.
 */
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange

/** * @brief Tells the delegate that the text or attributes in the specified text view were changed by the user. * * @param <textView> The text view containing the changes. * */

- (void)textViewDidChange:(UITextView *)textView
/**
 * @brief   The attributes to apply to new text being entered by the user.
 * 
 * @discussion      This dictionary contains the attribute keys (and corresponding values) to apply to newly typed text. When the text view’s selection changes, the contents of the dictionary are cleared automatically.
 */
@property(nonatomic, copy) NSDictionary *typingAttributes

/**
 * @brief   The text storage object holding the text displayed in this text view. (read-only)
 * 
 * @discussion      This property is a convenience accessor that provides access through the text container.
 */
@property(nonatomic, readonly, retain) NSTextStorage *textStorage

/**
 * @brief   The current selection range of the receiver.
 * 
 * @discussion      In iOS 2.2 and earlier, the length of the selection range is always 0, indicating that the selection is actually an insertion point. In iOS 3.0 and later, the length of the selection range may be non-zero.
 */
@property(nonatomic) NSRange selectedRange

你可能感兴趣的:(ios,UITextView)