美文网首页
iOS TextView长按时自定义菜单(仿微信),实现换行功能

iOS TextView长按时自定义菜单(仿微信),实现换行功能

作者: 倒着游的鱼 | 来源:发表于2023-04-23 14:18 被阅读0次

.h 类

@interface XJCustomTextView : UITextView
/**
 占位文字
 */
@property (nonatomic, copy) NSString *placeholder;
/**
 占位文字的颜色
 */
@property (nonatomic, strong) UIColor *placeholderColor;
/**
 占位符的文字位置
 */
@property(nonatomic,assign)CGPoint placePoint;
/**
 最大字数
 */
@property (nonatomic, assign)NSInteger maxLength;
/**
 文字改变的回调(只是赋值的回调,编辑的改变不回调 有KVO监听)
 */
@property(nonatomic,copy)void (^textDidChangeHandlerBlock)(XJCustomTextView *textView);
/**
 触发到最大字数的回调
 */
@property(nonatomic,copy)void (^textLengthDidMaxHandlerBlock)(XJCustomTextView *textView);

@end

.m类

@interface XJCustomTextView()
#pragma mark - Data Perproty
@property (nonatomic, assign) BOOL isNameTextFieldEnbable;
@end

@implementation XJCustomTextView

#pragma mark - life Cycle
-(instancetype)initWithCoder:(NSCoder *)aDecoder{
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self initilize];
    }
    return self;
}

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self initilize];
    }
    return self;
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [self removeObserver:self forKeyPath:@"text"];
}

- (void)drawRect:(CGRect)rect{
    if (self.hasText) return;
    // 文字属性
    NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
    attrs[NSFontAttributeName] = self.font;
    attrs[NSForegroundColorAttributeName] = self.placeholderColor?self.placeholderColor:[UIColor grayColor];
    // 画文字
    CGFloat x = self.placePoint.x;
    CGFloat w = rect.size.width - 2 * x;
    CGFloat y = self.placePoint.y;
    CGFloat h = rect.size.height - 2 * y;
    CGRect placeholderRect = CGRectMake(x, y, w, h);
    [self.placeholder drawInRect:placeholderRect withAttributes:attrs];
}

#pragma mark - NSNotification
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
    //返回删除键
    if ([text isEqualToString:@"\n"]) {
        //切换下一个
        return NO;
    }
    if ([text isEqualToString:@""]) {
        return YES;
    }else{
        return _isNameTextFieldEnbable;
    }
}

#pragma mark - Notification
/**
 * 监听文字改变
 */
- (void)textDidChange:(NSNotification *)notification {
    self.isNameTextFieldEnbable = YES;
    UITextInputMode *mode = (UITextInputMode *)[UITextInputMode activeInputModes][0];
    NSString *lang = mode.primaryLanguage;
    //汉字
    if ([lang isEqualToString:@"zh-Hans"]) {
        UITextRange *selectedRange = [self markedTextRange];
        UITextPosition *position = [self positionFromPosition:selectedRange.start offset:0];
        if (!position) {
            if (self.text.length > self.maxLength) {
                self.text = [self.text substringToIndex:self.maxLength];
                self.isNameTextFieldEnbable = NO;
                !self.textLengthDidMaxHandlerBlock?:self.textLengthDidMaxHandlerBlock(self);
            }
        }
    }
    //非汉字状态
    else{
        if (self.text.length > self.maxLength) {
            self.text = [self.text substringToIndex:self.maxLength];
            self.isNameTextFieldEnbable = NO;
            !self.textLengthDidMaxHandlerBlock?:self.textLengthDidMaxHandlerBlock(self);
        }
    }
    // 重绘(重新调用)
    [self setNeedsDisplay];
}

#pragma mark - private
-(void)initilize{
    if (@available(iOS 11.0, *)) {
        self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
    }
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange:) name:UITextViewTextDidChangeNotification object:self];
    self.placePoint = CGPointMake(5, 0);
    [self addObserver:self forKeyPath:@"text" options:NSKeyValueObservingOptionNew context:nil];
    
    //设置菜单 长按时自定义菜单,实现换行功能
    UIMenuItem *menuItem = [[UIMenuItem alloc]initWithTitle:@"换行" action:@selector(selfMenu:)];
    UIMenuController *menuController = [UIMenuController sharedMenuController];
    [menuController setMenuItems:[NSArray arrayWithObject:menuItem]];
    [menuController setMenuVisible:NO];
}

-(BOOL)canPerformAction:(SEL)action withSender:(id)sender{
    
    if (action == @selector(selfMenu:)) {
        
        return YES;
        
    }else if(action ==@selector(copy:) ||action ==@selector(selectAll:)|| action ==@selector(cut:)|| action ==@selector(select:)){
        
        BOOL isAppear = [super canPerformAction:action withSender:sender];
        
        return isAppear;
    }
   if (self.text.length) { //处理无文字 而用户需粘贴不出现菜单问题
        return NO;
    }else {
        return YES;
    }
}

-(void)selfMenu:(id)sender{
    self.text = [self.text stringByAppendingString:@"\n"];
    //为了让kvo 监听的textviewb内容变化 能撑起contentSize,默认只是对self.text赋值self.scrollEnabled = NO;
    self.scrollEnabled = YES;
    //如果输入的文字超出最大行数,清零的时候需要将contentSizeOffset置空,可以让绘制的placeholde位置能正确显示
    if (self.text.length == 0) {
        [self setContentOffset:CGPointZero];
    }
    [self setNeedsDisplay];
    
}
#pragma mark -KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    if (object == self && [keyPath isEqualToString:@"text"]) {
        !self.textDidChangeHandlerBlock?:self.textDidChangeHandlerBlock(self);
    }
}

#pragma mark - getter & setter
- (void)setPlaceholder:(NSString *)placeholder {
    _placeholder = [placeholder copy];
    [self setNeedsDisplay];
}

- (void)setPlaceholderColor:(UIColor *)placeholderColor {
    _placeholderColor = placeholderColor;
    [self setNeedsDisplay];
}

- (void)setText:(NSString *)text {
    [super setText:text];
    //为了让kvo 监听的textviewb内容变化 能撑起contentSize,默认只是对self.text赋值self.scrollEnabled = NO;
    self.scrollEnabled = YES;
    //如果输入的文字超出最大行数,清零的时候需要将contentSizeOffset置空,可以让绘制的placeholde位置能正确显示
    if (text.length == 0) {
        [self setContentOffset:CGPointZero];
    }
    [self setNeedsDisplay];
}

- (void)setFont:(UIFont *)font {
    [super setFont:font];
    [self setNeedsDisplay];
}

-(void)setPlacePoint:(CGPoint)placePoint{
    _placePoint = placePoint;
    [self setNeedsDisplay];
}

@end

相关文章

网友评论

      本文标题:iOS TextView长按时自定义菜单(仿微信),实现换行功能

      本文链接:https://www.haomeiwen.com/subject/xdfyjdtx.html