123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 |
- //
- // YOUPAINIMGrowingTextView.m
- // NIMKit
- //
- // Created by chris on 16/3/27.
- // Copyright © 2016年 Netease. All rights reserved.
- //
- #import "YOUPAINIMGrowingTextView.h"
- #import "YOUPAINIMGrowingInternalTextView.h"
- @interface YOUPAINIMGrowingTextView()<UITextViewDelegate>
- @property (nonatomic,strong) YOUPAINIMGrowingInternalTextView *textView;
- @property (nonatomic,assign) CGFloat maxHeight;
- @property (nonatomic,assign) CGFloat minHeight;
- @property (nonatomic,assign) CGRect previousFrame;
- @end
- @implementation YOUPAINIMGrowingTextView
- #pragma mark - Override
- - (instancetype)initWithFrame:(CGRect)frame
- {
- self = [super initWithFrame:frame];
- if (self) {
- CGRect rect = CGRectMake(0, 0, frame.size.width, frame.size.height);
- YOUPAINIMGrowingInternalTextView *textView = [[YOUPAINIMGrowingInternalTextView alloc] initWithFrame:rect];
- textView.tintColor = LZ7C69FEColor;
- self.textView = textView;
- self.previousFrame = frame;
- [self setup];
- }
- return self;
- }
- - (instancetype)initWithCoder:(NSCoder *)aDecoder
- {
- self = [super initWithCoder:aDecoder];
- if (self) {
- YOUPAINIMGrowingInternalTextView *textView = [[YOUPAINIMGrowingInternalTextView alloc] initWithFrame:CGRectZero];
- self.textView = textView;
- self.previousFrame = CGRectZero;
- [self setup];
- }
- return self;
- }
- - (void)layoutSubviews
- {
- [super layoutSubviews];
- if (self.previousFrame.size.width != self.bounds.size.width) {
- self.previousFrame = self.frame;
- [self fitToScrollView];
- }
- }
- - (CGSize)intrinsicContentSize
- {
- return [self measureFrame:self.measureTextViewSize].size;
- }
- #pragma mark - UIResponder
- - (UIView *)inputView
- {
- return self.textView.inputView;
- }
- - (void)setInputView:(UIView *)inputView
- {
- self.textView.inputView = inputView;
- }
- - (BOOL)isFirstResponder
- {
- return self.textView.isFirstResponder;
- }
- - (BOOL)becomeFirstResponder
- {
- return [self.textView becomeFirstResponder];
- }
- - (BOOL)resignFirstResponder
- {
- [super resignFirstResponder];
- return [self.textView resignFirstResponder];
- }
- #pragma mark - Set
- - (void)setMinNumberOfLines:(NSInteger)minNumberOfLines
- {
- if (minNumberOfLines <= 0) {
- self.minHeight = 0;
- return;
- }
- self.minHeight = [self simulateHeight:minNumberOfLines];
- _minNumberOfLines = minNumberOfLines;
- }
- - (void)setMaxNumberOfLines:(NSInteger)maxNumberOfLines
- {
- if (maxNumberOfLines <= 0) {
- self.maxHeight = 0;
- return;
- }
- self.maxHeight = [self simulateHeight:maxNumberOfLines];
- _maxNumberOfLines = maxNumberOfLines;
- }
- #pragma mark - Private
- - (void)setup
- {
- self.textView.delegate = self;
- self.textView.scrollEnabled = NO;
- self.textView.font = [UIFont systemFontOfSize:16];
- self.textView.backgroundColor = [UIColor clearColor];
- [self addSubview:self.textView];
- self.minHeight = self.frame.size.height;
- self.maxNumberOfLines = 3;
- }
- - (CGFloat)simulateHeight:(NSInteger)line
- {
- NSString *saveText = self.textView.text;
- NSMutableString *newText = [NSMutableString stringWithString:@"-"];
-
- self.textView.delegate = nil;
- self.textView.hidden = YES;
-
- for (NSInteger index=0; index<line; index++) {
- [newText appendString:@"\n|W|"];
- }
-
- self.textView.text = newText;
-
- CGFloat textViewMargin = 16;
- CGFloat height = self.measureTextViewSize.height - (textViewMargin + self.textView.contentInset.top + self.textView.contentInset.bottom);
- self.textView.text = saveText;
- self.textView.hidden = NO;
- self.textView.delegate = self;
-
- return height;
- }
- - (void)fitToScrollView{
- BOOL scrollToBottom = self.contentOffset.y == self.contentSize.height - self.frame.size.height;
- CGSize actualTextViewSize = [self measureTextViewSize];
- CGRect oldScrollViewFrame = self.frame;
-
- CGRect frame = self.bounds;
- frame.origin = CGPointZero;
- frame.size.height = actualTextViewSize.height;
- self.textView.frame = frame;
- self.contentSize = frame.size;
-
- CGRect newScrollViewFrame = [self measureFrame:actualTextViewSize];
-
- if(oldScrollViewFrame.size.height != newScrollViewFrame.size.height && newScrollViewFrame.size.height <= self.maxHeight) {
- [self flashScrollIndicators];
- if ([self.textViewDelegate respondsToSelector:@selector(youpaifwillChangeHeight:)]) {
- [self.textViewDelegate youpaifwillChangeHeight:newScrollViewFrame.size.height];
- }
- }
- self.frame = newScrollViewFrame;
-
- if(scrollToBottom) {
- [self scrollToBottom];
- }
-
- if (oldScrollViewFrame.size.height != newScrollViewFrame.size.height && [self.textViewDelegate respondsToSelector:@selector(youpaifdidChangeHeight:)]) {
- [self.textViewDelegate youpaifdidChangeHeight:newScrollViewFrame.size.height];
- }
-
- [self invalidateIntrinsicContentSize];
- }
- - (CGSize)measureTextViewSize
- {
- return [self.textView sizeThatFits:CGSizeMake(self.bounds.size.width, CGFLOAT_MAX)];
- }
- - (CGRect)measureFrame:(CGSize)contentSize
- {
- CGSize selfSize;
- if (contentSize.height < self.minHeight || !self.textView.hasText) {
- selfSize = CGSizeMake(contentSize.width, self.minHeight);
- } else if (self.maxHeight > 0 && contentSize.height > self.maxHeight) {
- selfSize = CGSizeMake(contentSize.width, self.maxHeight);
- } else {
- selfSize = contentSize;
- }
- CGRect frame = self.frame;
- frame.size.height = selfSize.height;
- return frame;
- }
- - (void)scrollToBottom{
- CGPoint offset = self.contentOffset;
- self.contentOffset = CGPointMake(offset.x, self.contentSize.height - self.frame.size.height);
- }
- #pragma mark - UITextViewDelegate
- - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
- {
- if ([self.textViewDelegate respondsToSelector:@selector(youpaifshouldChangeTextInRange:replacementText:)]) {
- return [self.textViewDelegate youpaifshouldChangeTextInRange:range replacementText:text];
- }
- return YES;
- }
- - (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction{
- if ([self.textViewDelegate respondsToSelector:@selector(youpaifshouldInteractWithURL:inRange:)]) {
- return [self.textViewDelegate youpaifshouldInteractWithURL:URL inRange:characterRange];
- }
- return YES;
- }
- - (BOOL)textView:(UITextView *)textView shouldInteractWithTextAttachment:(nonnull NSTextAttachment *)textAttachment inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction{
- if ([self.textViewDelegate respondsToSelector:@selector(youpaifshouldInteractWithTextAttachment:inRange:)]) {
- return [self.textViewDelegate youpaifshouldInteractWithTextAttachment:textAttachment inRange:characterRange];
- }
- return YES;
- }
- - (void)textViewDidBeginEditing:(UITextView *)textView
- {
- if ([self.textViewDelegate respondsToSelector:@selector(textViewDidBeginEditing:)]) {
- [self.textViewDelegate textViewDidBeginEditing:self];
- }
- }
- - (void)textViewDidChangeSelection:(UITextView *)textView
- {
- if ([self.textViewDelegate respondsToSelector:@selector(textViewDidChangeSelection:)]) {
- [self.textViewDelegate textViewDidChangeSelection:self];
- }
- }
- - (void)textViewDidEndEditing:(UITextView *)textView
- {
- if ([self.textViewDelegate respondsToSelector:@selector(textViewDidEndEditing:)]) {
- [self.textViewDelegate textViewDidEndEditing:self];
- }
- }
- - (BOOL)textViewShouldBeginEditing:(UITextView *)textView
- {
- if ([self.textViewDelegate respondsToSelector:@selector(textViewShouldBeginEditing:)]) {
- return [self.textViewDelegate textViewShouldBeginEditing:self];
- }
- return YES;
- }
- - (BOOL)textViewShouldEndEditing:(UITextView *)textView
- {
- if ([self.textViewDelegate respondsToSelector:@selector(textViewShouldEndEditing:)]) {
- return [self.textViewDelegate textViewShouldEndEditing:self];
- }
- return YES;
- }
- - (void)textViewDidChange:(UITextView *)textView
- {
- if ([self.textViewDelegate respondsToSelector:@selector(textViewDidChange:)]) {
- [self.textViewDelegate textViewDidChange:self];
- }
- [self fitToScrollView];
- }
- @end
- @implementation YOUPAINIMGrowingTextView(TextView)
- - (NSAttributedString *)placeholderAttributedText
- {
- return self.textView.placeholderAttributedText;
- }
- - (void)setPlaceholderAttributedText:(NSAttributedString *)placeholderAttributedText
- {
- [self.textView setPlaceholderAttributedText:placeholderAttributedText];
- }
- // MARK: TextView
- - (NSString *)text
- {
- return self.textView.text;
- }
- - (void)setText:(NSString *)text
- {
- self.textView.text = text;
- [self fitToScrollView];
- }
- - (UIFont *)font
- {
- return self.textView.font;
- }
- - (void)setFont:(UIFont *)font
- {
- self.textView.font = font;
- }
- - (UIColor *)textColor
- {
- return self.textView.textColor;
- }
- - (void)setTextColor:(UIColor *)textColor
- {
- self.textView.textColor = textColor;
- }
- - (NSTextAlignment)textAlignment
- {
- return self.textView.textAlignment;
- }
- - (void)setTextAlignment:(NSTextAlignment)textAlignment
- {
- self.textView.textAlignment = textAlignment;
- }
- - (NSRange)selectedRange
- {
- return self.textView.selectedRange;
- }
- - (void)setSelectedRange:(NSRange)selectedRange
- {
- self.textView.selectedRange = selectedRange;
- }
- - (UIDataDetectorTypes)dataDetectorTypes
- {
- return self.textView.dataDetectorTypes;
- }
- - (void)setDataDetectorTypes:(UIDataDetectorTypes)dataDetectorTypes
- {
- self.textView.dataDetectorTypes = dataDetectorTypes;
- }
- - (BOOL)editable
- {
- return self.textView.editable;
- }
- - (void)setEditable:(BOOL)editable
- {
- self.textView.editable = editable;
- }
- - (BOOL)selectable
- {
- return self.textView.selectable;
- }
- - (void)setSelectable:(BOOL)selectable
- {
- self.textView.selectable = selectable;
- }
- - (BOOL)allowsEditingTextAttributes
- {
- return self.allowsEditingTextAttributes;
- }
- - (void)setAllowsEditingTextAttributes:(BOOL)allowsEditingTextAttributes
- {
- self.textView.allowsEditingTextAttributes = allowsEditingTextAttributes;
- }
- - (NSAttributedString *)attributedText
- {
- return self.textView.attributedText;
- }
- - (void)setAttributedText:(NSAttributedString *)attributedText
- {
- self.textView.attributedText = attributedText;
- [self fitToScrollView];
- }
- - (void)scrollRangeToVisible:(NSRange)range
- {
- [self.textView scrollRangeToVisible:range];
- }
- - (UIView *)textViewInputAccessoryView
- {
- return self.textView.inputAccessoryView;
- }
- - (void)setTextViewInputAccessoryView:(UIView *)textViewInputAccessoryView
- {
- self.textView.inputAccessoryView = textViewInputAccessoryView;
- }
- - (BOOL)clearsOnInsertion
- {
- return self.textView.clearsOnInsertion;
- }
- - (void)setClearsOnInsertion:(BOOL)clearsOnInsertion
- {
- self.textView.clearsOnInsertion = clearsOnInsertion;
- }
- - (NSTextContainer *)textContainer
- {
- return self.textView.textContainer;
- }
- - (UIEdgeInsets)textContainerInset
- {
- return self.textView.textContainerInset;
- }
- - (void)setTextContainerInset:(UIEdgeInsets)textContainerInset
- {
- self.textView.textContainerInset = textContainerInset;
- }
- - (NSLayoutManager *)layoutManger
- {
- return self.textView.layoutManager;
- }
- - (NSTextStorage *)textStorage
- {
- return self.textView.textStorage;
- }
- - (NSDictionary<NSString *,id> *)linkTextAttributes
- {
- return self.textView.linkTextAttributes;
- }
- - (void)setLinkTextAttributes:(NSDictionary<NSString *,id> *)linkTextAttributes
- {
- self.textView.linkTextAttributes = linkTextAttributes;
- }
- - (void)setReturnKeyType:(UIReturnKeyType)returnKeyType
- {
- [self.textView setReturnKeyType:returnKeyType];
- }
- - (UIReturnKeyType)returnKeyType
- {
- return self.textView.returnKeyType;
- }
- @end
|