OC开发记录3——UITextView和NSNotification

首先,在之前的开发中,我获取一个控件底部最下面的坐标是采用这样的方式(以label为例)

label.frame.origin.y + label.frame.size.height

后来,在翻阅前人的代码的时候,发现了一个更简便的方法

CGRectGetMaxY(label.frame)

两者的使用方法是相当的,都是获取控件的底部坐标(当然,这个坐标是相对于该控件所在的父控件的)

下面是本次的正文,直接针对技术点展开

目录

1.什么?你的UITextView没有placeholder?

1.1 用UILabel和delegate实现placeholder

1.2 防止在拼音输入时,TextView直接获取拼音字符

1.3 调整TextView的行高

1.4 设置UITextView自动换行

2.数据变化了?快使用NSNotification告诉所有控件吧!

2.1 NSNotification的一个生活例子

2.2 通过NSNotification实现对数据的实时刷新


1.什么?你的UITextView没有placeholder?

1.1 用UILabel和delegate实现placeholder

我们都知道处理用户输入的控件有两个,分别为UITextField和UITextView,其中UITextField可以通过NSAttributedString和attributedPlaceholder来直接设置placeholder(当然也可以直接用placeholder)举例:

NSAttributedString *attStr = [[NSAttributedString alloc] initWithString:@"请输入用户名" attributes: @{NSForegroundColorAttributeName:HEXRGBACOLOR(0x000000, 0.3), NSFontAttributeName:textField.font}];
textField.attributedPlaceholder = attrString2;

ps:这里的HEXRGBACOLOR是一个宏定义

#define HEXRGBACOLOR(hex,a)     [UIColor colorWithRed:((float)((hex & 0xFF0000) >> 16))/255.0 green:((float)((hex & 0xFF00) >> 8))/255.0 blue:((float)(hex & 0xFF))/255.0 alpha:a]

ps2:textField就是目标控件

而UITextView是没有placeholder相关属性的,我的解决方法是,定义一个label,把label添加到textView中作为子控件。然后实现UITextView的delegate——textViewDidChange,当textView中的文字发生改变时会调用该方法。部分代码如下:

// 备注文本输入区
_remarkTV = [[UITextView alloc] initWithFrame:CGRectMake(16, CGRectGetMaxY(remarkLabel.frame) + 10.5, MRFullScreenWidth - 32, 120)];
_remarkTV.font = [UIFont systemFontOfSize:16];
_remarkTV.textColor = HEXRGBCOLOR(0x1D2129);
_remarkTV.delegate = self;
_remarkTV.layoutManager.delegate = self;
// 把键盘的回车键当成“完成“使用
_remarkTV.returnKeyType = UIReturnKeyDone;
[contentView addSubview:_remarkTV];

// 默认提示信息(由于UITextView不支持默认文本,因此自定义一个label)
_placeholder = [[UILabel alloc] initWithFrame:CGRectMake(0, 10.5, 200, 16)];
_placeholder.font = [UIFont systemFontOfSize:16];
_placeholder.textColor = HEXRGBCOLOR(0xBCBCBC);
_placeholder.backgroundColor = [UIColor clearColor];
_placeholder.text = @"(选填)请输入备注";
[_remarkTV addSubview:_placeholder];
// 当文字发生改变时
- (void)textViewDidChange:(UITextView *)textView
{
    // 先隐藏备注
    _placeholder.hidden = YES;
    // 防止拼音输入时,文本直接获取拼音(在拼音输入时,不继续执行textViewDidChange方法)
    UITextRange *selectedRange = [textView markedTextRange];
    NSString *newText = [textView textInRange:selectedRange];
    if (newText.length > 0)
    {
        return;
    }

    // 无输入文字
    if (_remarkTV.text.length == 0)
    {
        _placeholder.hidden = NO;
    }
    // 有输入文字
    else
    {
        _placeholder.hidden = YES;
    }
}

1.2 防止在拼音输入时,TextView直接获取拼音字符

还有一个小知识点,单独拿出来说。就是在使用拼音时,如何拦截该代理方法。例如我们限定字符长度为10,那么在拼音输入时,如果不做该处理,当拼音(英文字符)+已输入的字符长度超过10时,会直接停下,导致用户的输入无法完成。有了这个方法,我们可以做一些更复杂的操作。例如在本次的需求中,要求实时监控字符数。这样我可以定义一个字符数label,然后在上面的代码的else分支中对这个字符数label的text进行修改即可。

// 防止拼音输入时,文本直接获取拼音(在拼音输入时,不继续执行textViewDidChange方法)
UITextRange *selectedRange = [textView markedTextRange];
NSString *newText = [textView textInRange:selectedRange];

1.3 调整TextView的行高

一个delegate方法就能实现:

// 行高
- (CGFloat)layoutManager:(NSLayoutManager *)layoutManager lineSpacingAfterGlyphAtIndex:(NSUInteger)glyphIndex withProposedLineFragmentRect:(CGRect)rect
{
    return 行高;
}

1.4 设置UITextView自动换行

一个delegate方法加一些 魔法 就能实现:

// 换行
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    if ([text isEqualToString:@"\n"])
    {
        [self.view endEditing:YES];
        return NO;
    }
    return YES;
}

贴两张效果图吧,具体的实现细节就忽略了,主要的技术点就在上面。

     

2.数据变化了?快使用NSNotification告诉所有控件吧!

2.1 NSNotification的一个生活例子

我们举一个不太恰当但是比较生动的例子。妈妈要在大C放学后给他做饭,但是妈妈不知道大C的放学确切时间,做饭早了晚了都不太合适。那么这时学校引入了一个通知机制,当大C放学后,老师会告诉学校,学校会给妈妈发送一条“大C放学了”的消息,然后妈妈就可以开始做饭啦。

在这个案例中,我们把妈妈和大C都看作是一个viewController,学校看作是NSNotification。当大C的状态发生变化时,我们通知妈妈。当然,通知是一种广播形式,也就是说,假如大C有个双胞胎弟弟小C,我们同样可以让妈妈通过学校监听小C的状态。同样的,孩子通常有两个家长,我们可以让学校再多发送一条信息到爸爸那里。

有了这个例子,理解NSNotification这个通知机制应该就容易多了,它是OC中的一个非常重要的机制。我们假设在多个viewController中(爸爸妈妈)都需要监听某个对象(大C小C),一旦该对象(大C小C)发生更改,先由具体的方法(老师)post消息中心(学校),消息中心(学校)就会通知那些viewController(爸爸妈妈):“这个对象更改了!(大C小C放学了!)”。然后那些viewControlller(爸爸妈妈)就可以刷新数据(做饭)了。

2.2 通过NSNotification实现对数据的实时刷新

刚刚讲了一个通俗易懂的例子,现在拿一个落地需求来简单理解NSNotification的用法。

现在有两个界面,第一个界面是复诊计划,以table的cell形式渲染,数据通过接口获取。第二个界面是复诊确认,可以选择患者复诊的日期和添加备注。当我们在复诊确认界面点击提交后,相应的复诊计划的cell的状态也应该刷新(从未完成➡️已完成),换句话说,当我们在复诊确认界面提交数据后,后端接收到了数据,返回了正确的状态码后,我们应该重新拉取复诊计划列表,重新对cell进行渲染。那么如何在当前controller中通知其他controller呢?以下为核心代码部分。

复诊计划controller

- (void)viewDidLoad
{
// ...
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshTopicVisitPlanDetailNotified:) name:KNotificationRefreshTopicVisitPlanDetail object:nil];
// ...
}

// 刷新复诊计划数据
- (void)refreshTopicVisitPlanDetailNotified:(NSNotification *)note
{
    [self loadData:ELoadTypeRefresh];
}

ps:这里的loadData就是重新通过接口请求数据,然后对相应的array赋值,再执行tableView的reloadData方法。

复诊确认controller

// 发送请求
[MRRequestManager sendTopicVisitConfirm:_patModel.tpId
                              visitDate:_dateLabel.text
                                 remark:_remarkTV.text
                          completeBlock:^(id responseObject) {
    [self hideLoadingHUDView];
    NSMutableDictionary *dictionary = (NSMutableDictionary *)responseObject;
    NSString *code = [dictionary stringForDicKey:@"code"];
    if (![code isEqualToString:KRunCodeSuccess])
    {
        NSString *msg = [dictionary stringForDicKey:@"msg"];
        [self showWarnHUDView:msg code:code];
        return;
    }
    [self showToastHUDView:@"复诊确认成功"];
            
    [[NSNotificationCenter defaultCenter] postNotificationName:KNotificationRefreshTopicVisitPlanDetail object:nil];
            
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(KToastTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [weakSelf.navigationController popViewControllerAnimated:YES];
    });
}
                             errorBlock:^(NSError *error) {
    [self hideLoadingHUDView];
    [self showErrorHUDView:error.code];
}];

ps:方法中大多是一些提示信息,核心逻辑只有中间的NSNotification一句话,就是通知所有监听的name为KNotificationRefreshTopicVisitPlanDetail的方法,该去执行操作了。

在本案例中,当我们发送“复诊确认”请求成功后,调用了post方法,这一语句执行后,复诊计划controller中的NSNotification就会监听到由通知中心发来的消息,来去执行refreshTopicVisitPlanDetailNotified方法,也就是刷新复诊计划数据。

当然,这里的通知没有包含消息的传递,只是告诉页面去刷新数据。如果要传递一些消息,使用object来去传递消息即可。这个后面会涉及到,等到更深入的去做NSNotification后再做详解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UITextView是UIKit框架中的一个控件,可以用来显示和编辑长文本。而富文本则是指带有丰富样式的文本,可以设置文字的字体、颜色、大小、间距、行高等属性。 要在UITextView中实现富文本,首先需要创建一个NSAttributedString对象,并通过NSMutableAttributedString来设置文字的样式。NSAttributedString是不可变的,而NSMutableAttributedString可以修改和添加样式。 创建NSMutableAttributedString对象后,可以使用其方法来设置文字的样式,比如设置字体可以使用NSFontAttributeName属性,设置颜色可以使用NSForegroundColorAttributeName属性,设置字号可以使用NSFontAttributeName属性,设置段落样式可以使用NSParagraphStyleAttributeName属性等等。 设置完成后,就可以将NSMutableAttributedString对象赋值给UITextView的attributedText属性,以实现富文本的显示。 例如,我们想将某个UITextView的文字样式设置为红色、字号为20、字体为粗体,可以按如下方式设置: ``` NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@"这是富文本"]; [attributedString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0, attributedString.length)]; [attributedString addAttribute:NSFontAttributeName value:[UIFont boldSystemFontOfSize:20] range:NSMakeRange(0, attributedString.length)]; textView.attributedText = attributedString; ``` 通过上述代码,就可以在UITextView中显示带有红色、字号为20、字体为粗体的文字。 除了以上示例外,UITextView还支持更多的富文本样式设置,根据具体需求,可以设置更多的属性来实现更丰富的文本效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值