小说绘上架版本
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// CXCustomTextView.h
|
||||
// CXTextView_Example
|
||||
//
|
||||
// Created by caixiang on 2019/5/6.
|
||||
// Copyright © 2019年 616704162@qq.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface CXCustomTextView : 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)(CXCustomTextView *textView);
|
||||
/**
|
||||
触发到最大字数的回调
|
||||
*/
|
||||
@property(nonatomic,copy)void (^textLengthDidMaxHandlerBlock)(CXCustomTextView *textView);
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,168 @@
|
||||
//
|
||||
// CXCustomTextView.m
|
||||
// CXTextView_Example
|
||||
//
|
||||
// Created by caixiang on 2019/5/6.
|
||||
// Copyright © 2019年 616704162@qq.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CXCustomTextView.h"
|
||||
#import "TFKeyboardManager.h"
|
||||
|
||||
@interface CXCustomTextView()
|
||||
#pragma mark - Data Perproty
|
||||
@property (nonatomic, assign) BOOL isNameTextFieldEnbable;
|
||||
@end
|
||||
|
||||
@implementation CXCustomTextView
|
||||
|
||||
#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.returnKeyType = UIReturnKeySend;
|
||||
self.placePoint = CGPointMake(5, 0);
|
||||
[self addObserver:self forKeyPath:@"text" options:NSKeyValueObservingOptionNew context:nil];
|
||||
|
||||
UIToolbar *toolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 40)];
|
||||
toolBar.barStyle = UIBarStyleDefault;
|
||||
|
||||
UIBarButtonItem *flexibleSpaceItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
|
||||
|
||||
UIBarButtonItem *doneItem = [[UIBarButtonItem alloc] initWithTitle:TFLocalizedString(@"完成") style:UIBarButtonItemStyleDone target:self action:@selector(hideKeyboard)];
|
||||
|
||||
[toolBar setItems:@[flexibleSpaceItem, doneItem]];
|
||||
|
||||
self.inputAccessoryView = toolBar;
|
||||
}
|
||||
|
||||
- (void)hideKeyboard
|
||||
{
|
||||
[TFKeyboardManager hideKeyboard];
|
||||
}
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,94 @@
|
||||
//
|
||||
// CXTextView.h
|
||||
// CXTextView_Example
|
||||
//
|
||||
// Created by caixiang on 2019/5/6.
|
||||
// Copyright © 2019年 616704162@qq.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
@class CXCustomTextView;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface CXTextView : UIView
|
||||
|
||||
/**
|
||||
真实的textView
|
||||
*/
|
||||
@property (nonatomic, strong) CXCustomTextView *textView;
|
||||
/**
|
||||
竖直方向上下间距 默认为8
|
||||
*/
|
||||
@property (nonatomic, assign)CGFloat v_margin;
|
||||
/**
|
||||
水平方向上下间距 默认为0
|
||||
*/
|
||||
@property(nonatomic,assign)CGFloat h_margin;
|
||||
/**
|
||||
初始需要展示的行数 默认为1
|
||||
*/
|
||||
@property(nonatomic,assign)NSInteger initiLine;
|
||||
/**
|
||||
最大行数 默认为无穷大
|
||||
*/
|
||||
@property(nonatomic,assign)NSInteger maxLine;
|
||||
/**
|
||||
占位文字
|
||||
*/
|
||||
@property(nonatomic,strong)NSString *placeholder;
|
||||
/**
|
||||
占位文字的颜色
|
||||
*/
|
||||
@property (nonatomic, strong) UIColor *placeholderColor;
|
||||
/**
|
||||
最大字数
|
||||
*/
|
||||
@property (nonatomic, assign)NSInteger maxLength;
|
||||
/**
|
||||
默认为17
|
||||
*/
|
||||
@property(nonatomic,strong)UIFont *font;
|
||||
/**
|
||||
置占位符的位置,竖直方向设置v_margin即可 CGPointMake(5, 0);//占位文字的起始位置
|
||||
*/
|
||||
@property(nonatomic,assign)CGPoint placePoint;
|
||||
/**
|
||||
文字
|
||||
*/
|
||||
@property (copy, nonatomic) NSString *text;
|
||||
/**
|
||||
文字颜色
|
||||
*/
|
||||
@property (strong, nonatomic) UIColor *textColor;
|
||||
/**
|
||||
高度变化回调
|
||||
*/
|
||||
@property(nonatomic,copy)void (^textHeightChangeBlock)(CGFloat height);
|
||||
/**
|
||||
开始编辑回调
|
||||
*/
|
||||
@property(nonatomic,copy)void (^textViewDidBeginEditingBlock)(UITextView *textView);
|
||||
/**
|
||||
结束编辑回调
|
||||
*/
|
||||
@property(nonatomic,copy)void (^textViewDidEndEditingBlock)(UITextView *textView);
|
||||
/**
|
||||
最大值回调
|
||||
*/
|
||||
@property(nonatomic,copy)void (^textLengthDidMaxHandlerBlock)(UITextView *textView);
|
||||
/**
|
||||
文字变动改变回调
|
||||
*/
|
||||
@property(nonatomic,copy)void (^textDidChangeHandlerBlock)(UITextView *textView);
|
||||
|
||||
/**
|
||||
发送按钮
|
||||
*/
|
||||
@property (nonatomic, copy) void(^returnHandlerBlock)(void);
|
||||
|
||||
- (void)textViewBecomeFirstResponder;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,205 @@
|
||||
//
|
||||
// CXTextView.m
|
||||
// CXTextView_Example
|
||||
//
|
||||
// Created by caixiang on 2019/5/6.
|
||||
// Copyright © 2019年 616704162@qq.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import "CXTextView.h"
|
||||
#import "CXCustomTextView.h"
|
||||
|
||||
@interface CXTextView()<UITextViewDelegate>
|
||||
@end
|
||||
|
||||
@implementation CXTextView
|
||||
|
||||
@synthesize text = _text;
|
||||
|
||||
#pragma mark - life Cycle
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
|
||||
self = [super initWithCoder: aDecoder];
|
||||
if (self) {
|
||||
[self initilize];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self initilize];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews{
|
||||
[super layoutSubviews];
|
||||
self.textView.width = self.frame.size.width - 2 *self.h_margin;
|
||||
}
|
||||
|
||||
#pragma mark - UITextViewDelegate
|
||||
-(void)textViewDidChange:(UITextView *)textView{
|
||||
!self.textDidChangeHandlerBlock?:self.textDidChangeHandlerBlock(textView);
|
||||
[self updateTextViewHeight];
|
||||
!self.textHeightChangeBlock?:self.textHeightChangeBlock(self.height);
|
||||
[textView scrollRangeToVisible:NSMakeRange(textView.selectedRange.location, 1)];
|
||||
}
|
||||
|
||||
- (void)textViewDidBeginEditing:(UITextView *)textView {
|
||||
!self.textViewDidBeginEditingBlock?:self.textViewDidBeginEditingBlock(textView);
|
||||
}
|
||||
|
||||
- (void)textViewDidEndEditing:(UITextView *)textView {
|
||||
!self.textViewDidEndEditingBlock?:self.textViewDidEndEditingBlock(textView);
|
||||
}
|
||||
|
||||
- (BOOL)textView:(YYTextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
|
||||
{
|
||||
if ([text isEqualToString:@"\n"]){
|
||||
NSString *sendMessage = [textView.text stringByReplacingOccurrencesOfString:@" " withString:@""];
|
||||
if (sendMessage.length > 0) {
|
||||
if (self.returnHandlerBlock) {
|
||||
self.returnHandlerBlock();
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)updateTextViewHeight {
|
||||
CGFloat contentSizeH = ceilf(self.textView.contentSize.height);
|
||||
//内容高度
|
||||
if (self.textView.text.length == 0) {
|
||||
contentSizeH = ceilf(self.font.lineHeight * self.initiLine);
|
||||
}
|
||||
//最大高度
|
||||
CGFloat maxHeight = ceilf(self.font.lineHeight * self.maxLine);
|
||||
//初始高度
|
||||
CGFloat initiTextViewHeight = ceilf(self.initiLine *self.font.lineHeight);
|
||||
if (contentSizeH <= maxHeight) {
|
||||
if (contentSizeH <= initiTextViewHeight) {
|
||||
self.textView.height = ceilf(initiTextViewHeight);
|
||||
}else{
|
||||
self.textView.height = ceilf(contentSizeH);
|
||||
}
|
||||
}else{
|
||||
self.textView.height = ceilf(maxHeight);
|
||||
}
|
||||
self.height = self.textView.height + 2 * self.v_margin;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - private
|
||||
//初始化
|
||||
- (void)initilize{
|
||||
self.h_margin = 0;
|
||||
self.v_margin = 8;
|
||||
self.initiLine = 1;
|
||||
self.maxLine = CGFLOAT_MAX;
|
||||
self.maxLength = CGFLOAT_MAX;
|
||||
self.font = [UIFont systemFontOfSize:16];
|
||||
[self addSubview:self.textView];
|
||||
}
|
||||
|
||||
- (void)updateTextViewFrame{
|
||||
self.textView.frame = CGRectMake(self.h_margin, self.v_margin, self.frame.size.width - 2 *self.h_margin, ceilf(self.initiLine *self.font.lineHeight));
|
||||
self.height = self.v_margin *2 + ceilf(self.initiLine *self.font.lineHeight);
|
||||
}
|
||||
|
||||
- (void)textViewBecomeFirstResponder
|
||||
{
|
||||
[self.textView becomeFirstResponder];
|
||||
}
|
||||
|
||||
#pragma mark - getter & setter
|
||||
- (void)setMaxLine:(NSInteger)maxLine{
|
||||
_maxLine = maxLine;
|
||||
}
|
||||
|
||||
- (void)setH_margin:(CGFloat)h_margin{
|
||||
_h_margin = h_margin;
|
||||
[self updateTextViewFrame];
|
||||
}
|
||||
|
||||
- (void)setV_margin:(CGFloat)v_margin{
|
||||
_v_margin = v_margin;
|
||||
[self updateTextViewFrame];
|
||||
}
|
||||
|
||||
- (void)setInitiLine:(NSInteger)initiLine{
|
||||
_initiLine = initiLine;
|
||||
[self updateTextViewFrame];
|
||||
}
|
||||
|
||||
- (void)setFont:(UIFont *)font{
|
||||
_font = font;
|
||||
self.textView.font = font;
|
||||
[self updateTextViewFrame];
|
||||
}
|
||||
|
||||
- (void)setPlaceholderColor:(UIColor *)placeholderColor {
|
||||
_placeholderColor = placeholderColor;
|
||||
self.textView.placeholderColor = placeholderColor;
|
||||
}
|
||||
|
||||
- (void)setTextColor:(UIColor *)textColor {
|
||||
_textColor = textColor;
|
||||
self.textView.textColor = textColor;
|
||||
}
|
||||
|
||||
- (void)setPlaceholder:(NSString *)placeholder{
|
||||
_placeholder = placeholder;
|
||||
self.textView.placeholder = placeholder;
|
||||
}
|
||||
|
||||
- (void)setPlacePoint:(CGPoint)placePoint{
|
||||
_placePoint = placePoint;
|
||||
self.textView.placePoint = placePoint;
|
||||
}
|
||||
|
||||
-(void)setMaxLength:(NSInteger)maxLength {
|
||||
_maxLength = maxLength;
|
||||
self.textView.maxLength = maxLength;
|
||||
}
|
||||
|
||||
- (void)setText:(NSString *)text {
|
||||
_text = [text copy];
|
||||
self.textView.text = text;
|
||||
}
|
||||
|
||||
- (NSString *)text {
|
||||
return self.textView.text;
|
||||
}
|
||||
|
||||
- (CXCustomTextView *)textView{
|
||||
if (!_textView) {
|
||||
_textView = [[CXCustomTextView alloc] initWithFrame:CGRectMake(self.h_margin, self.v_margin, self.frame.size.width - 2 *self.h_margin, self.initiLine *self.font.lineHeight)];
|
||||
_textView.textContainerInset = UIEdgeInsetsZero;
|
||||
_textView.delegate = self;
|
||||
_textView.backgroundColor = [UIColor whiteColor];
|
||||
_textView.textColor = [UIColor blackColor];
|
||||
_textView.placeholder = TFLocalizedString(@"请输入");
|
||||
__weak __typeof(self)weakSelf = self;
|
||||
_textView.textLengthDidMaxHandlerBlock = ^(CXCustomTextView *textView) {
|
||||
__strong __typeof(weakSelf)sSelf = weakSelf;
|
||||
!sSelf.textLengthDidMaxHandlerBlock?:sSelf.textLengthDidMaxHandlerBlock(textView);
|
||||
};
|
||||
_textView.textDidChangeHandlerBlock = ^(CXCustomTextView *textView) {
|
||||
__strong __typeof(weakSelf)sSelf = weakSelf;
|
||||
!sSelf.textDidChangeHandlerBlock?:sSelf.textDidChangeHandlerBlock(textView);
|
||||
[sSelf updateTextViewHeight];
|
||||
if (textView.text.length > 0) {
|
||||
!sSelf.textHeightChangeBlock?:sSelf.textHeightChangeBlock(sSelf.height);
|
||||
} else {
|
||||
!sSelf.textHeightChangeBlock?:sSelf.textHeightChangeBlock(self.v_margin *2 + ceilf(self.initiLine *self.font.lineHeight));
|
||||
}
|
||||
};
|
||||
}
|
||||
return _textView;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// CXTextViewHelper.h
|
||||
// CXTextView
|
||||
//
|
||||
// Created by caixiang on 2019/5/7.
|
||||
// Copyright © 2019年 616704162@qq.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#ifndef CXTextViewHelper_h
|
||||
#define CXTextViewHelper_h
|
||||
//#import "UIView+CXPostion.h"
|
||||
#import "CXTextView.h"
|
||||
#import "CXCustomTextView.h"
|
||||
|
||||
UIKIT_STATIC_INLINE UIEdgeInsets cx_viewSafeArea(UIView *view) {
|
||||
|
||||
#ifdef __IPHONE_11_0
|
||||
if (@available(iOS 11.0, *)) {
|
||||
return view.safeAreaInsets;
|
||||
}
|
||||
#endif
|
||||
return UIEdgeInsetsZero;
|
||||
}
|
||||
|
||||
UIKIT_STATIC_INLINE UIColor *CXRGBA(NSInteger r,NSInteger g,NSInteger b,CGFloat a) {
|
||||
return [UIColor colorWithRed:(float)r/255.0f green:(float)g/255.0f blue:(float)b/255.0f alpha:a];
|
||||
}
|
||||
|
||||
UIKIT_STATIC_INLINE UIColor *CXRGB(NSInteger r,NSInteger g,NSInteger b) {
|
||||
return CXRGBA(r,g,b,1.0f);
|
||||
}
|
||||
|
||||
UIKIT_STATIC_INLINE UIColor *CXUIColorFromRGBA(uint32_t rgbValue, CGFloat a) {
|
||||
return [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0f
|
||||
green:((float)((rgbValue & 0xFF00) >> 8))/255.0f
|
||||
blue:((float)(rgbValue & 0xFF))/255.0f
|
||||
alpha:a];
|
||||
}
|
||||
|
||||
UIKIT_STATIC_INLINE UIColor *CXUIColorFromRGB(uint32_t rgbValue) {
|
||||
return CXUIColorFromRGBA(rgbValue,1.0f);
|
||||
}
|
||||
|
||||
#endif /* CXTextViewHelper_h */
|
||||
Reference in New Issue
Block a user