forked from mirrors/linphone-iphone
Chat: fix bubbles and input text
This commit is contained in:
parent
50f0a56a4f
commit
68e3aad07a
14 changed files with 896 additions and 873 deletions
|
|
@ -16,7 +16,7 @@
|
|||
<outlet property="composeLabel" destination="fpY-Fv-ht2" id="4L6-ik-ZAe"/>
|
||||
<outlet property="listSwipeGestureRecognizer" destination="dzw-n4-l9i" id="JVP-Vl-lIa"/>
|
||||
<outlet property="listTapGestureRecognizer" destination="tkk-Tm-A7C" id="gqU-iJ-RGm"/>
|
||||
<outlet property="messageField" destination="CPp-ts-xy0" id="wPX-Uo-vZQ"/>
|
||||
<outlet property="messageField" destination="pqa-tg-5ml" id="emj-yI-K60"/>
|
||||
<outlet property="messageView" destination="14" id="89"/>
|
||||
<outlet property="pictureButton" destination="73" id="84"/>
|
||||
<outlet property="sendButton" destination="15" id="27"/>
|
||||
|
|
@ -146,7 +146,7 @@
|
|||
</button>
|
||||
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="bci-3K-AcG" userLabel="cancelButton" customClass="UIIconButton">
|
||||
<rect key="frame" x="0.0" y="0.0" width="75" height="66"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
<accessibility key="accessibilityConfiguration" label="Cancel"/>
|
||||
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
|
||||
|
|
@ -228,18 +228,13 @@
|
|||
<action selector="onPictureClick:" destination="-1" eventType="touchUpInside" id="87"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" id="CPp-ts-xy0" userLabel="messageField">
|
||||
<view contentMode="scaleToFill" id="pqa-tg-5ml" userLabel="messageField" customClass="HPGrowingTextView">
|
||||
<rect key="frame" x="88" y="14" width="200" height="40"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<accessibility key="accessibilityConfiguration" hint="" label="Message field"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="26"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences" autocorrectionType="yes" spellCheckingType="yes" keyboardAppearance="alert" returnKeyType="send"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="-1" id="RVG-F4-M9q"/>
|
||||
</connections>
|
||||
</textView>
|
||||
<accessibility key="accessibilityConfiguration" label="Message field"/>
|
||||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="15" userLabel="sendButton">
|
||||
<rect key="frame" x="303" y="2" width="72" height="63"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@
|
|||
|
||||
}];
|
||||
// also add current entry, if not listed
|
||||
LinphoneAddress *addr = linphone_core_interpret_url([LinphoneManager getLc], filter.UTF8String);
|
||||
NSString *nsuri = filter;
|
||||
NSString *nsuri = filter.lowercaseString;
|
||||
LinphoneAddress *addr = linphone_core_interpret_url([LinphoneManager getLc], nsuri.UTF8String);
|
||||
if (addr) {
|
||||
char *uri = linphone_address_as_string(addr);
|
||||
nsuri = [NSString stringWithUTF8String:uri];
|
||||
|
|
|
|||
|
|
@ -26,11 +26,13 @@
|
|||
#import "OrderedDictionary.h"
|
||||
#import "UIRoundedImageView.h"
|
||||
#import "UIBackToCallButton.h"
|
||||
#import "Utils/HPGrowingTextView/HPGrowingTextView.h"
|
||||
|
||||
#include "linphone/linphonecore.h"
|
||||
|
||||
@interface ChatConversationView : UIViewController <UITextViewDelegate, UICompositeViewDelegate, ImagePickerDelegate,
|
||||
ChatConversationDelegate, UISearchBarDelegate> {
|
||||
@interface ChatConversationView
|
||||
: UIViewController <HPGrowingTextViewDelegate, UICompositeViewDelegate, ImagePickerDelegate,
|
||||
ChatConversationDelegate, UISearchBarDelegate> {
|
||||
LinphoneChatRoom *chatRoom;
|
||||
OrderedDictionary *imageQualities;
|
||||
BOOL scrollOnGrowingEnabled;
|
||||
|
|
@ -38,7 +40,7 @@
|
|||
}
|
||||
|
||||
@property(nonatomic, strong) IBOutlet ChatConversationTableView *tableController;
|
||||
@property(weak, nonatomic) IBOutlet UITextView *messageField;
|
||||
@property(weak, nonatomic) IBOutlet HPGrowingTextView *messageField;
|
||||
@property(weak, nonatomic) IBOutlet UIView *topBar;
|
||||
@property(nonatomic, strong) IBOutlet UIButton *sendButton;
|
||||
@property(nonatomic, strong) IBOutlet UILabel *addressLabel;
|
||||
|
|
|
|||
|
|
@ -70,6 +70,14 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
_messageField.minNumberOfLines = 1;
|
||||
_messageField.maxNumberOfLines = ([LinphoneManager runningOnIpad]) ? 10 : 3;
|
||||
_messageField.delegate = self;
|
||||
_messageField.font = [UIFont systemFontOfSize:18.0f];
|
||||
_messageField.contentInset = UIEdgeInsetsMake(0, -5, -2, -5);
|
||||
_messageField.internalTextView.scrollIndicatorInsets = UIEdgeInsetsMake(0, 0, 0, 10);
|
||||
|
||||
[_tableController setChatRoomDelegate:self];
|
||||
}
|
||||
|
||||
|
|
@ -336,6 +344,58 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
#pragma mark - UITextFieldDelegate Functions
|
||||
|
||||
- (BOOL)growingTextViewShouldBeginEditing:(HPGrowingTextView *)growingTextView {
|
||||
if (_tableController.isEditing) {
|
||||
[_tableController setEditing:NO];
|
||||
}
|
||||
[_listTapGestureRecognizer setEnabled:TRUE];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
- (BOOL)growingTextViewShouldEndEditing:(HPGrowingTextView *)growingTextView {
|
||||
[_listTapGestureRecognizer setEnabled:FALSE];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
- (void)growingTextChanged:(HPGrowingTextView *)growingTextView text:(NSString *)text {
|
||||
if ([text length] > 0 && chatRoom)
|
||||
linphone_chat_room_compose(chatRoom);
|
||||
}
|
||||
|
||||
- (void)growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height {
|
||||
int diff = height - growingTextView.bounds.size.height;
|
||||
|
||||
if (diff != 0) {
|
||||
CGRect messageRect = [_messageView frame];
|
||||
messageRect.origin.y -= diff;
|
||||
messageRect.size.height += diff;
|
||||
[_messageView setFrame:messageRect];
|
||||
|
||||
// Always stay at bottom
|
||||
if (scrollOnGrowingEnabled) {
|
||||
CGRect tableFrame = [_tableController.view frame];
|
||||
CGPoint contentPt = [_tableController.tableView contentOffset];
|
||||
contentPt.y += diff;
|
||||
if (contentPt.y + tableFrame.size.height > _tableController.tableView.contentSize.height)
|
||||
contentPt.y += diff;
|
||||
[_tableController.tableView setContentOffset:contentPt animated:FALSE];
|
||||
}
|
||||
|
||||
CGRect tableRect = [_tableController.view frame];
|
||||
tableRect.size.height -= diff;
|
||||
[_tableController.view setFrame:tableRect];
|
||||
|
||||
// if we're showing the compose message, update it position
|
||||
if (![_composeLabel isHidden]) {
|
||||
CGRect frame = [_composeLabel frame];
|
||||
frame.origin.y -= diff;
|
||||
[_composeLabel setFrame:frame];
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
#pragma mark - UITextFieldDelegate Functions
|
||||
|
||||
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
|
||||
if (_tableController.isEditing) {
|
||||
[_tableController setEditing:NO];
|
||||
|
|
@ -369,7 +429,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
[_listTapGestureRecognizer setEnabled:FALSE];
|
||||
[textView resignFirstResponder];
|
||||
}
|
||||
|
||||
*/
|
||||
/*
|
||||
- (void)growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height {
|
||||
int diff = height - growingTextView.bounds.size.height;
|
||||
|
|
@ -612,7 +672,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
animated:FALSE];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
completion:^(BOOL finished){
|
||||
}];
|
||||
|
|
|
|||
|
|
@ -23,14 +23,6 @@
|
|||
#import "ChatConversationTableView.h"
|
||||
#import "UIRoundedImageView.h"
|
||||
|
||||
static const CGFloat TEXT_MIN_HEIGHT = 0.;
|
||||
static const CGFloat TEXT_MIN_WIDTH = 150.0f;
|
||||
static const CGFloat MARGIN_WIDTH = 60;
|
||||
static const CGFloat MARGIN_HEIGHT = 19 + 16 /*this 16 is because textview add some top&bottom padding*/;
|
||||
static const CGFloat CHECK_BOX_WIDTH = 40;
|
||||
static const CGFloat IMAGE_HEIGHT = 100.0f;
|
||||
static const CGFloat IMAGE_WIDTH = 100.0f;
|
||||
|
||||
@interface UIChatBubbleTextCell : UITableViewCell
|
||||
|
||||
@property(readonly, nonatomic) LinphoneChatMessage *message;
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@
|
|||
|
||||
_backgroundColorImage.image = _bottomBarColor.image =
|
||||
[UIImage imageNamed:(outgoing ? @"color_A.png" : @"color_D.png")];
|
||||
_contactDateLabel.textColor = [UIColor colorWithPatternImage:_backgroundColorImage.image];
|
||||
|
||||
if (outgoing && state == LinphoneChatMessageStateInProgress) {
|
||||
_statusErrorImage.hidden = YES;
|
||||
|
|
@ -229,13 +230,24 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st
|
|||
{ return [text sizeWithFont:font constrainedToSize:size lineBreakMode:NSLineBreakByCharWrapping]; }
|
||||
}
|
||||
|
||||
static const CGFloat CELL_MIN_HEIGHT = 60.0f;
|
||||
static const CGFloat CELL_MIN_WIDTH = 150.0f;
|
||||
static const CGFloat CELL_MESSAGE_X_MARGIN = 72 + 10.0f;
|
||||
static const CGFloat CELL_MESSAGE_Y_MARGIN = 32;
|
||||
static const CGFloat CELL_IMAGE_HEIGHT = 100.0f;
|
||||
static const CGFloat CELL_IMAGE_WIDTH = 100.0f;
|
||||
|
||||
+ (CGSize)ViewSizeForMessage:(LinphoneChatMessage *)chat withWidth:(int)width {
|
||||
static UIFont *messageFont = nil;
|
||||
static UIFont *dateFont = nil;
|
||||
static CGSize dateViewSize;
|
||||
|
||||
int messageAvailableWidth = width - MARGIN_WIDTH - CHECK_BOX_WIDTH;
|
||||
CGSize messageSize;
|
||||
const char *url = linphone_chat_message_get_external_body_url(chat);
|
||||
NSString *messageText = [UIChatBubbleTextCell TextMessageForChat:chat];
|
||||
|
||||
UITableView *tableView = VIEW(ChatConversationView).tableController.tableView;
|
||||
if (tableView.isEditing)
|
||||
width -= 40; /*checkbox */
|
||||
|
||||
if (!messageFont) {
|
||||
UIChatBubbleTextCell *cell =
|
||||
|
|
@ -244,24 +256,37 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st
|
|||
dateFont = cell.contactDateLabel.font;
|
||||
dateViewSize = cell.contactDateLabel.frame.size;
|
||||
}
|
||||
|
||||
if (linphone_chat_message_get_file_transfer_information(chat)) {
|
||||
NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:chat];
|
||||
messageSize = (localImage != nil) ? CGSizeMake(IMAGE_WIDTH, IMAGE_HEIGHT) : CGSizeMake(50, 50);
|
||||
if (url == nil && linphone_chat_message_get_file_transfer_information(chat) == NULL) {
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
|
||||
if ([[[UIDevice currentDevice] systemVersion] doubleValue] >= 7) {
|
||||
messageSize = [messageText boundingRectWithSize:CGSizeMake(width - CELL_MESSAGE_X_MARGIN, CGFLOAT_MAX)
|
||||
options:(NSStringDrawingUsesLineFragmentOrigin |
|
||||
NSStringDrawingTruncatesLastVisibleLine |
|
||||
NSStringDrawingUsesFontLeading)
|
||||
attributes:@{
|
||||
NSFontAttributeName : messageFont
|
||||
}
|
||||
context:nil]
|
||||
.size;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
messageSize = [messageText sizeWithFont:messageFont
|
||||
constrainedToSize:CGSizeMake(width - CELL_MESSAGE_X_MARGIN, 10000.0f)
|
||||
lineBreakMode:NSLineBreakByTruncatingTail];
|
||||
}
|
||||
} else {
|
||||
NSString *text = [UIChatBubbleTextCell TextMessageForChat:chat];
|
||||
messageSize =
|
||||
[self computeBoundingBox:text size:CGSizeMake(messageAvailableWidth, CGFLOAT_MAX) font:messageFont];
|
||||
messageSize.width = MAX(TEXT_MIN_WIDTH, ceil(messageSize.width));
|
||||
messageSize.height = MAX(TEXT_MIN_HEIGHT, ceil(messageSize.height));
|
||||
NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:chat];
|
||||
messageSize = (localImage != nil) ? CGSizeMake(CELL_IMAGE_WIDTH, CELL_IMAGE_HEIGHT) : CGSizeMake(50, 50);
|
||||
}
|
||||
|
||||
CGSize dateSize = [self computeBoundingBox:[self ContactDateForChat:chat] size:dateViewSize font:dateFont];
|
||||
messageSize.width = MAX(messageSize.width, dateSize.width);
|
||||
|
||||
CGSize bubbleSize;
|
||||
bubbleSize.width = MAX(messageSize.width, dateSize.width + 20 /*error icon*/ + 5) + MARGIN_WIDTH;
|
||||
bubbleSize.height = messageSize.height + MARGIN_HEIGHT;
|
||||
messageSize.width = MAX(messageSize.width + CELL_MESSAGE_X_MARGIN, CELL_MIN_WIDTH);
|
||||
messageSize.height = MAX(messageSize.height + CELL_MESSAGE_Y_MARGIN, CELL_MIN_HEIGHT);
|
||||
|
||||
return bubbleSize;
|
||||
return messageSize;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
|
|
@ -270,9 +295,17 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st
|
|||
UITableView *tableView = VIEW(ChatConversationView).tableController.tableView;
|
||||
BOOL is_outgoing = linphone_chat_message_is_outgoing(_message);
|
||||
CGRect bubbleFrame = _bubbleView.frame;
|
||||
bubbleFrame.size = [self.class ViewSizeForMessage:_message withWidth:self.frame.size.width];
|
||||
bubbleFrame.origin.x =
|
||||
tableView.isEditing ? 0 : (is_outgoing ? self.frame.size.width - bubbleFrame.size.width : 0);
|
||||
int available_width = self.frame.size.width;
|
||||
int origin_x;
|
||||
|
||||
if (tableView.isEditing) {
|
||||
origin_x = 0;
|
||||
} else {
|
||||
origin_x = (is_outgoing ? self.frame.size.width - bubbleFrame.size.width : 0);
|
||||
}
|
||||
|
||||
bubbleFrame.size = [self.class ViewSizeForMessage:_message withWidth:available_width];
|
||||
bubbleFrame.origin.x = origin_x;
|
||||
_bubbleView.frame = bubbleFrame;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
</accessibility>
|
||||
</imageView>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="11:35 John Doe" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="GRe-ur-aSb" userLabel="contactDateLabel">
|
||||
<rect key="frame" x="48" y="0.0" width="246" height="20"/>
|
||||
<rect key="frame" x="48" y="0.0" width="246" height="14"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
<accessibility key="accessibilityConfiguration" label="Contact name"/>
|
||||
|
|
@ -56,7 +56,7 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<textView clipsSubviews="YES" contentMode="scaleToFill" scrollEnabled="NO" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" editable="NO" text="Lore ipsum..." id="CYa-If-oB4" userLabel="messageText" customClass="UITextViewNoDefine">
|
||||
<rect key="frame" x="48" y="8" width="268" height="42"/>
|
||||
<rect key="frame" x="48" y="7" width="280" height="54"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
|
|
|
|||
|
|
@ -1,657 +0,0 @@
|
|||
//
|
||||
// HPTextView.m
|
||||
//
|
||||
// Created by Hans Pinckaers on 29-06-10.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2011 Hans Pinckaers
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "HPGrowingTextView.h"
|
||||
#import "HPTextViewInternal.h"
|
||||
|
||||
@interface HPGrowingTextView(private)
|
||||
-(void)commonInitialiser;
|
||||
-(void)resizeTextView:(NSInteger)newSizeH;
|
||||
-(void)growDidStop;
|
||||
@end
|
||||
|
||||
@implementation HPGrowingTextView
|
||||
@synthesize internalTextView;
|
||||
@synthesize delegate;
|
||||
@synthesize maxHeight;
|
||||
@synthesize minHeight;
|
||||
@synthesize font;
|
||||
@synthesize textColor;
|
||||
@synthesize textAlignment;
|
||||
@synthesize selectedRange;
|
||||
@synthesize editable;
|
||||
@synthesize dataDetectorTypes;
|
||||
@synthesize animateHeightChange;
|
||||
@synthesize animationDuration;
|
||||
@synthesize returnKeyType;
|
||||
@dynamic placeholder;
|
||||
@dynamic placeholderColor;
|
||||
|
||||
// having initwithcoder allows us to use HPGrowingTextView in a Nib. -- aob, 9/2011
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder
|
||||
{
|
||||
if ((self = [super initWithCoder:aDecoder])) {
|
||||
[self commonInitialiser];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame {
|
||||
if ((self = [super initWithFrame:frame])) {
|
||||
[self commonInitialiser];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)commonInitialiser
|
||||
{
|
||||
// Initialization code
|
||||
CGRect r = self.frame;
|
||||
r.origin.y = 0;
|
||||
r.origin.x = 0;
|
||||
internalTextView = [[HPTextViewInternal alloc] initWithFrame:r];
|
||||
internalTextView.delegate = self;
|
||||
internalTextView.scrollEnabled = NO;
|
||||
internalTextView.font = [UIFont systemFontOfSize:13];
|
||||
internalTextView.contentInset = UIEdgeInsetsZero;
|
||||
internalTextView.showsHorizontalScrollIndicator = NO;
|
||||
internalTextView.text = @"-";
|
||||
[self addSubview:internalTextView];
|
||||
|
||||
minHeight = internalTextView.frame.size.height;
|
||||
minNumberOfLines = 1;
|
||||
|
||||
animateHeightChange = YES;
|
||||
animationDuration = 0.1f;
|
||||
|
||||
internalTextView.text = @"";
|
||||
|
||||
[self setMaxNumberOfLines:3];
|
||||
|
||||
[self setPlaceholderColor:[UIColor lightGrayColor]];
|
||||
internalTextView.displayPlaceHolder = YES;
|
||||
}
|
||||
|
||||
-(CGSize)sizeThatFits:(CGSize)size
|
||||
{
|
||||
if (self.text.length == 0) {
|
||||
size.height = minHeight;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
-(void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
|
||||
CGRect r = self.bounds;
|
||||
r.origin.y = 0;
|
||||
r.origin.x = contentInset.left;
|
||||
r.size.width -= contentInset.left + contentInset.right;
|
||||
|
||||
internalTextView.frame = r;
|
||||
}
|
||||
|
||||
-(void)setContentInset:(UIEdgeInsets)inset
|
||||
{
|
||||
contentInset = inset;
|
||||
|
||||
CGRect r = self.frame;
|
||||
r.origin.y = inset.top - inset.bottom;
|
||||
r.origin.x = inset.left;
|
||||
r.size.width -= inset.left + inset.right;
|
||||
|
||||
internalTextView.frame = r;
|
||||
|
||||
[self setMaxNumberOfLines:maxNumberOfLines];
|
||||
[self setMinNumberOfLines:minNumberOfLines];
|
||||
}
|
||||
|
||||
-(UIEdgeInsets)contentInset
|
||||
{
|
||||
return contentInset;
|
||||
}
|
||||
|
||||
-(void)setMaxNumberOfLines:(int)n
|
||||
{
|
||||
if(n == 0 && maxHeight > 0) return; // the user specified a maxHeight themselves.
|
||||
|
||||
// Use internalTextView for height calculations, thanks to Gwynne <http://blog.darkrainfall.org/>
|
||||
NSString *saveText = internalTextView.text, *newText = @"-";
|
||||
|
||||
internalTextView.delegate = nil;
|
||||
internalTextView.hidden = YES;
|
||||
|
||||
for (int i = 1; i < n; ++i)
|
||||
newText = [newText stringByAppendingString:@"\n|W|"];
|
||||
|
||||
internalTextView.text = newText;
|
||||
|
||||
maxHeight = [self measureHeight];
|
||||
|
||||
internalTextView.text = saveText;
|
||||
internalTextView.hidden = NO;
|
||||
internalTextView.delegate = self;
|
||||
|
||||
[self sizeToFit];
|
||||
|
||||
maxNumberOfLines = n;
|
||||
}
|
||||
|
||||
-(int)maxNumberOfLines
|
||||
{
|
||||
return maxNumberOfLines;
|
||||
}
|
||||
|
||||
- (void)setMaxHeight:(int)height
|
||||
{
|
||||
maxHeight = height;
|
||||
maxNumberOfLines = 0;
|
||||
}
|
||||
|
||||
-(void)setMinNumberOfLines:(int)m
|
||||
{
|
||||
if(m == 0 && minHeight > 0) return; // the user specified a minHeight themselves.
|
||||
|
||||
// Use internalTextView for height calculations, thanks to Gwynne <http://blog.darkrainfall.org/>
|
||||
NSString *saveText = internalTextView.text, *newText = @"-";
|
||||
|
||||
internalTextView.delegate = nil;
|
||||
internalTextView.hidden = YES;
|
||||
|
||||
for (int i = 1; i < m; ++i)
|
||||
newText = [newText stringByAppendingString:@"\n|W|"];
|
||||
|
||||
internalTextView.text = newText;
|
||||
|
||||
minHeight = [self measureHeight];
|
||||
|
||||
internalTextView.text = saveText;
|
||||
internalTextView.hidden = NO;
|
||||
internalTextView.delegate = self;
|
||||
|
||||
[self sizeToFit];
|
||||
|
||||
minNumberOfLines = m;
|
||||
}
|
||||
|
||||
-(int)minNumberOfLines
|
||||
{
|
||||
return minNumberOfLines;
|
||||
}
|
||||
|
||||
- (void)setMinHeight:(int)height
|
||||
{
|
||||
minHeight = height;
|
||||
minNumberOfLines = 0;
|
||||
}
|
||||
|
||||
- (NSString *)placeholder
|
||||
{
|
||||
return internalTextView.placeholder;
|
||||
}
|
||||
|
||||
- (void)setPlaceholder:(NSString *)placeholder
|
||||
{
|
||||
[internalTextView setPlaceholder:placeholder];
|
||||
}
|
||||
|
||||
- (UIColor *)placeholderColor
|
||||
{
|
||||
return internalTextView.placeholderColor;
|
||||
}
|
||||
|
||||
- (void)setPlaceholderColor:(UIColor *)placeholderColor
|
||||
{
|
||||
[internalTextView setPlaceholderColor:placeholderColor];
|
||||
}
|
||||
|
||||
- (void)textViewDidChange:(UITextView *)textView
|
||||
{
|
||||
[self refreshHeight];
|
||||
if( [delegate respondsToSelector:@selector(growingTextChanged:text:)])
|
||||
[delegate growingTextChanged:self text:[textView text]];
|
||||
}
|
||||
|
||||
- (void)refreshHeight
|
||||
{
|
||||
//size of content, so we can set the frame of self
|
||||
NSInteger newSizeH = [self measureHeight];
|
||||
if(newSizeH < minHeight || !internalTextView.hasText) newSizeH = minHeight; //not smalles than minHeight
|
||||
if (internalTextView.frame.size.height > maxHeight) newSizeH = maxHeight; // not taller than maxHeight
|
||||
|
||||
if (internalTextView.frame.size.height != newSizeH)
|
||||
{
|
||||
// [fixed] Pasting too much text into the view failed to fire the height change,
|
||||
// thanks to Gwynne <http://blog.darkrainfall.org/>
|
||||
|
||||
if (newSizeH > maxHeight && internalTextView.frame.size.height <= maxHeight)
|
||||
{
|
||||
newSizeH = maxHeight;
|
||||
}
|
||||
|
||||
if (newSizeH <= maxHeight)
|
||||
{
|
||||
if(animateHeightChange) {
|
||||
|
||||
if ([UIView resolveClassMethod:@selector(animateWithDuration:animations:)]) {
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
|
||||
[UIView animateWithDuration:animationDuration
|
||||
delay:0
|
||||
options:(UIViewAnimationOptionAllowUserInteraction|
|
||||
UIViewAnimationOptionBeginFromCurrentState)
|
||||
animations:^(void) {
|
||||
[self resizeTextView:newSizeH];
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
if ([delegate respondsToSelector:@selector(growingTextView:didChangeHeight:)]) {
|
||||
[delegate growingTextView:self didChangeHeight:newSizeH];
|
||||
}
|
||||
}];
|
||||
#endif
|
||||
} else {
|
||||
[UIView beginAnimations:@"" context:nil];
|
||||
[UIView setAnimationDuration:animationDuration];
|
||||
[UIView setAnimationDelegate:self];
|
||||
[UIView setAnimationDidStopSelector:@selector(growDidStop)];
|
||||
[UIView setAnimationBeginsFromCurrentState:YES];
|
||||
[self resizeTextView:newSizeH];
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
} else {
|
||||
[self resizeTextView:newSizeH];
|
||||
// [fixed] The growingTextView:didChangeHeight: delegate method was not called at all when not animating height changes.
|
||||
// thanks to Gwynne <http://blog.darkrainfall.org/>
|
||||
|
||||
if ([delegate respondsToSelector:@selector(growingTextView:didChangeHeight:)]) {
|
||||
[delegate growingTextView:self didChangeHeight:newSizeH];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if our new height is greater than the maxHeight
|
||||
// sets not set the height or move things
|
||||
// around and enable scrolling
|
||||
if (newSizeH >= maxHeight)
|
||||
{
|
||||
if(!internalTextView.scrollEnabled){
|
||||
internalTextView.scrollEnabled = YES;
|
||||
[internalTextView flashScrollIndicators];
|
||||
}
|
||||
|
||||
} else {
|
||||
internalTextView.scrollEnabled = NO;
|
||||
}
|
||||
|
||||
// scroll to caret (needed on iOS7)
|
||||
if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)])
|
||||
{
|
||||
CGRect r = [internalTextView caretRectForPosition:internalTextView.selectedTextRange.end];
|
||||
CGFloat caretY = MAX(r.origin.y - internalTextView.frame.size.height + r.size.height + 8, 0);
|
||||
if(internalTextView.contentOffset.y < caretY && r.origin.y != INFINITY)
|
||||
internalTextView.contentOffset = CGPointMake(0, MIN(caretY, internalTextView.contentSize.height));
|
||||
}
|
||||
}
|
||||
// Display (or not) the placeholder string
|
||||
|
||||
BOOL wasDisplayingPlaceholder = internalTextView.displayPlaceHolder;
|
||||
internalTextView.displayPlaceHolder = self.internalTextView.text.length == 0;
|
||||
|
||||
if (wasDisplayingPlaceholder != internalTextView.displayPlaceHolder) {
|
||||
[internalTextView setNeedsDisplay];
|
||||
}
|
||||
|
||||
// Tell the delegate that the text view changed
|
||||
|
||||
if ([delegate respondsToSelector:@selector(growingTextViewDidChange:)]) {
|
||||
[delegate growingTextViewDidChange:self];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Code from apple developer forum - @Steve Krulewitz, @Mark Marszal, @Eric Silverberg
|
||||
- (CGFloat)measureHeight
|
||||
{
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
|
||||
if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)])
|
||||
{
|
||||
CGRect frame = internalTextView.bounds;
|
||||
CGSize fudgeFactor;
|
||||
// The padding added around the text on iOS6 and iOS7 is different.
|
||||
fudgeFactor = CGSizeMake(10.0, 16.0);
|
||||
|
||||
frame.size.height -= fudgeFactor.height;
|
||||
frame.size.width -= fudgeFactor.width;
|
||||
|
||||
NSMutableAttributedString* textToMeasure;
|
||||
if(internalTextView.attributedText && internalTextView.attributedText.length > 0){
|
||||
textToMeasure = [[NSMutableAttributedString alloc] initWithAttributedString:internalTextView.attributedText];
|
||||
}
|
||||
else{
|
||||
textToMeasure = [[NSMutableAttributedString alloc] initWithString:internalTextView.text];
|
||||
[textToMeasure addAttribute:NSFontAttributeName value:internalTextView.font range:NSMakeRange(0, textToMeasure.length)];
|
||||
}
|
||||
|
||||
if ([textToMeasure.string hasSuffix:@"\n"])
|
||||
{
|
||||
[textToMeasure appendAttributedString:[[NSAttributedString alloc] initWithString:@"-" attributes:@{NSFontAttributeName: internalTextView.font}]];
|
||||
}
|
||||
|
||||
// NSAttributedString class method: boundingRectWithSize:options:context is
|
||||
// available only on ios7.0 sdk.
|
||||
CGRect size = [textToMeasure boundingRectWithSize:CGSizeMake(CGRectGetWidth(frame), MAXFLOAT)
|
||||
options:NSStringDrawingUsesLineFragmentOrigin
|
||||
context:nil];
|
||||
|
||||
return ceil(CGRectGetHeight(size) + fudgeFactor.height);
|
||||
} else {
|
||||
return self.internalTextView.contentSize.height;
|
||||
}
|
||||
#else
|
||||
return self.internalTextView.contentSize.height;
|
||||
#endif
|
||||
}
|
||||
|
||||
-(void)resizeTextView:(NSInteger)newSizeH
|
||||
{
|
||||
if ([delegate respondsToSelector:@selector(growingTextView:willChangeHeight:)]) {
|
||||
[delegate growingTextView:self willChangeHeight:newSizeH];
|
||||
}
|
||||
|
||||
CGRect internalTextViewFrame = self.frame;
|
||||
internalTextViewFrame.size.height = newSizeH; // + padding
|
||||
self.frame = internalTextViewFrame;
|
||||
|
||||
internalTextViewFrame.origin.y = contentInset.top - contentInset.bottom;
|
||||
internalTextViewFrame.origin.x = contentInset.left;
|
||||
internalTextViewFrame.size.width = internalTextView.contentSize.width;
|
||||
|
||||
if(!CGRectEqualToRect(internalTextView.frame, internalTextViewFrame)) internalTextView.frame = internalTextViewFrame;
|
||||
}
|
||||
|
||||
- (void)growDidStop
|
||||
{
|
||||
if ([delegate respondsToSelector:@selector(growingTextView:didChangeHeight:)]) {
|
||||
[delegate growingTextView:self didChangeHeight:self.frame.size.height];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
[internalTextView becomeFirstResponder];
|
||||
}
|
||||
|
||||
- (BOOL)becomeFirstResponder
|
||||
{
|
||||
[super becomeFirstResponder];
|
||||
return [self.internalTextView becomeFirstResponder];
|
||||
}
|
||||
|
||||
-(BOOL)resignFirstResponder
|
||||
{
|
||||
[super resignFirstResponder];
|
||||
return [internalTextView resignFirstResponder];
|
||||
}
|
||||
|
||||
-(BOOL)isFirstResponder
|
||||
{
|
||||
return [self.internalTextView isFirstResponder];
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark UITextView properties
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
-(void)setText:(NSString *)newText
|
||||
{
|
||||
internalTextView.text = newText;
|
||||
|
||||
// include this line to analyze the height of the textview.
|
||||
// fix from Ankit Thakur
|
||||
[self performSelector:@selector(textViewDidChange:) withObject:internalTextView];
|
||||
}
|
||||
|
||||
-(NSString*) text
|
||||
{
|
||||
return internalTextView.text;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
-(void)setFont:(UIFont *)afont
|
||||
{
|
||||
internalTextView.font= afont;
|
||||
|
||||
[self setMaxNumberOfLines:maxNumberOfLines];
|
||||
[self setMinNumberOfLines:minNumberOfLines];
|
||||
}
|
||||
|
||||
-(UIFont *)font
|
||||
{
|
||||
return internalTextView.font;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
-(void)setTextColor:(UIColor *)color
|
||||
{
|
||||
internalTextView.textColor = color;
|
||||
}
|
||||
|
||||
-(UIColor*)textColor{
|
||||
return internalTextView.textColor;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
-(void)setBackgroundColor:(UIColor *)backgroundColor
|
||||
{
|
||||
[super setBackgroundColor:backgroundColor];
|
||||
internalTextView.backgroundColor = backgroundColor;
|
||||
}
|
||||
|
||||
-(UIColor*)backgroundColor
|
||||
{
|
||||
return internalTextView.backgroundColor;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
-(void)setTextAlignment:(NSTextAlignment)aligment
|
||||
{
|
||||
internalTextView.textAlignment = aligment;
|
||||
}
|
||||
|
||||
-(NSTextAlignment)textAlignment
|
||||
{
|
||||
return internalTextView.textAlignment;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
-(void)setSelectedRange:(NSRange)range
|
||||
{
|
||||
internalTextView.selectedRange = range;
|
||||
}
|
||||
|
||||
-(NSRange)selectedRange
|
||||
{
|
||||
return internalTextView.selectedRange;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)setIsScrollable:(BOOL)isScrollable
|
||||
{
|
||||
internalTextView.scrollEnabled = isScrollable;
|
||||
}
|
||||
|
||||
- (BOOL)isScrollable
|
||||
{
|
||||
return internalTextView.scrollEnabled;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
-(void)setEditable:(BOOL)beditable
|
||||
{
|
||||
internalTextView.editable = beditable;
|
||||
}
|
||||
|
||||
-(BOOL)isEditable
|
||||
{
|
||||
return internalTextView.editable;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
-(void)setReturnKeyType:(UIReturnKeyType)keyType
|
||||
{
|
||||
internalTextView.returnKeyType = keyType;
|
||||
}
|
||||
|
||||
-(UIReturnKeyType)returnKeyType
|
||||
{
|
||||
return internalTextView.returnKeyType;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)setEnablesReturnKeyAutomatically:(BOOL)enablesReturnKeyAutomatically
|
||||
{
|
||||
internalTextView.enablesReturnKeyAutomatically = enablesReturnKeyAutomatically;
|
||||
}
|
||||
|
||||
- (BOOL)enablesReturnKeyAutomatically
|
||||
{
|
||||
return internalTextView.enablesReturnKeyAutomatically;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
-(void)setDataDetectorTypes:(UIDataDetectorTypes)datadetector
|
||||
{
|
||||
internalTextView.dataDetectorTypes = datadetector;
|
||||
}
|
||||
|
||||
-(UIDataDetectorTypes)dataDetectorTypes
|
||||
{
|
||||
return internalTextView.dataDetectorTypes;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (BOOL)hasText{
|
||||
return [internalTextView hasText];
|
||||
}
|
||||
|
||||
- (void)scrollRangeToVisible:(NSRange)range
|
||||
{
|
||||
[internalTextView scrollRangeToVisible:range];
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark -
|
||||
#pragma mark UITextViewDelegate
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
|
||||
if ([delegate respondsToSelector:@selector(growingTextViewShouldBeginEditing:)]) {
|
||||
return [delegate growingTextViewShouldBeginEditing:self];
|
||||
|
||||
} else {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
- (BOOL)textViewShouldEndEditing:(UITextView *)textView {
|
||||
if ([delegate respondsToSelector:@selector(growingTextViewShouldEndEditing:)]) {
|
||||
return [delegate growingTextViewShouldEndEditing:self];
|
||||
|
||||
} else {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
- (void)textViewDidBeginEditing:(UITextView *)textView {
|
||||
if ([delegate respondsToSelector:@selector(growingTextViewDidBeginEditing:)]) {
|
||||
[delegate growingTextViewDidBeginEditing:self];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
- (void)textViewDidEndEditing:(UITextView *)textView {
|
||||
if ([delegate respondsToSelector:@selector(growingTextViewDidEndEditing:)]) {
|
||||
[delegate growingTextViewDidEndEditing:self];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range
|
||||
replacementText:(NSString *)atext {
|
||||
|
||||
//weird 1 pixel bug when clicking backspace when textView is empty
|
||||
if(![textView hasText] && [atext isEqualToString:@""]) return NO;
|
||||
|
||||
//Added by bretdabaker: sometimes we want to handle this ourselves
|
||||
if ([delegate respondsToSelector:@selector(growingTextView:shouldChangeTextInRange:replacementText:)])
|
||||
return [delegate growingTextView:self shouldChangeTextInRange:range replacementText:atext];
|
||||
|
||||
if ([atext isEqualToString:@"\n"]) {
|
||||
if ([delegate respondsToSelector:@selector(growingTextViewShouldReturn:)]) {
|
||||
if (![delegate performSelector:@selector(growingTextViewShouldReturn:) withObject:self]) {
|
||||
return YES;
|
||||
} else {
|
||||
[textView resignFirstResponder];
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
- (void)textViewDidChangeSelection:(UITextView *)textView {
|
||||
if ([delegate respondsToSelector:@selector(growingTextViewDidChangeSelection:)]) {
|
||||
[delegate growingTextViewDidChangeSelection:self];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
//
|
||||
// HPTextViewInternal.m
|
||||
//
|
||||
// Created by Hans Pinckaers on 29-06-10.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2011 Hans Pinckaers
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "HPTextViewInternal.h"
|
||||
|
||||
|
||||
@implementation HPTextViewInternal
|
||||
|
||||
@synthesize placeholder;
|
||||
@synthesize placeholderColor;
|
||||
@synthesize displayPlaceHolder;
|
||||
|
||||
-(void)setText:(NSString *)text
|
||||
{
|
||||
BOOL originalValue = self.scrollEnabled;
|
||||
//If one of GrowingTextView's superviews is a scrollView, and self.scrollEnabled == NO,
|
||||
//setting the text programatically will cause UIKit to search upwards until it finds a scrollView with scrollEnabled==yes
|
||||
//then scroll it erratically. Setting scrollEnabled temporarily to YES prevents this.
|
||||
[self setScrollEnabled:YES];
|
||||
[super setText:text];
|
||||
[self setScrollEnabled:originalValue];
|
||||
}
|
||||
|
||||
- (void)setScrollable:(BOOL)isScrollable
|
||||
{
|
||||
[super setScrollEnabled:isScrollable];
|
||||
}
|
||||
|
||||
-(void)setContentOffset:(CGPoint)s
|
||||
{
|
||||
if(self.tracking || self.decelerating){
|
||||
//initiated by user...
|
||||
|
||||
UIEdgeInsets insets = self.contentInset;
|
||||
insets.bottom = 0;
|
||||
insets.top = 0;
|
||||
self.contentInset = insets;
|
||||
|
||||
} else {
|
||||
|
||||
float bottomOffset = (self.contentSize.height - self.frame.size.height + self.contentInset.bottom);
|
||||
if(s.y < bottomOffset && self.scrollEnabled){
|
||||
UIEdgeInsets insets = self.contentInset;
|
||||
insets.bottom = 8;
|
||||
insets.top = 0;
|
||||
self.contentInset = insets;
|
||||
}
|
||||
}
|
||||
|
||||
[super setContentOffset:s];
|
||||
}
|
||||
|
||||
-(void)setContentInset:(UIEdgeInsets)s
|
||||
{
|
||||
UIEdgeInsets insets = s;
|
||||
|
||||
if(s.bottom>8) insets.bottom = 0;
|
||||
insets.top = 0;
|
||||
|
||||
[super setContentInset:insets];
|
||||
}
|
||||
|
||||
-(void)setContentSize:(CGSize)contentSize
|
||||
{
|
||||
// is this an iOS5 bug? Need testing!
|
||||
if(self.contentSize.height > contentSize.height)
|
||||
{
|
||||
UIEdgeInsets insets = self.contentInset;
|
||||
insets.bottom = 0;
|
||||
insets.top = 0;
|
||||
self.contentInset = insets;
|
||||
}
|
||||
|
||||
[super setContentSize:contentSize];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)rect
|
||||
{
|
||||
[super drawRect:rect];
|
||||
if (displayPlaceHolder && placeholder && placeholderColor) {
|
||||
[placeholderColor set];
|
||||
[placeholder drawInRect:CGRectMake(8.0f, 8.0f, self.frame.size.width - 16.0f, self.frame.size.height - 16.0f) withFont:self.font];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -28,9 +28,10 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED < 60000
|
||||
// UITextAlignment is deprecated in iOS 6.0+, use NSTextAlignment instead.
|
||||
// Reference: https://developer.apple.com/library/ios/documentation/uikit/reference/NSString_UIKit_Additions/Reference/Reference.html
|
||||
#define NSTextAlignment UITextAlignment
|
||||
// UITextAlignment is deprecated in iOS 6.0+, use NSTextAlignment instead.
|
||||
// Reference:
|
||||
// https://developer.apple.com/library/ios/documentation/uikit/reference/NSString_UIKit_Additions/Reference/Reference.html
|
||||
#define NSTextAlignment UITextAlignment
|
||||
#endif
|
||||
|
||||
@class HPGrowingTextView;
|
||||
|
|
@ -45,9 +46,11 @@
|
|||
- (void)growingTextViewDidBeginEditing:(HPGrowingTextView *)growingTextView;
|
||||
- (void)growingTextViewDidEndEditing:(HPGrowingTextView *)growingTextView;
|
||||
|
||||
- (void)growingTextChanged:(HPGrowingTextView *)growingTextView text:(NSString*)text;
|
||||
- (void)growingTextChanged:(HPGrowingTextView *)growingTextView text:(NSString *)text;
|
||||
|
||||
- (BOOL)growingTextView:(HPGrowingTextView *)growingTextView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
|
||||
- (BOOL)growingTextView:(HPGrowingTextView *)growingTextView
|
||||
shouldChangeTextInRange:(NSRange)range
|
||||
replacementText:(NSString *)text;
|
||||
- (void)growingTextViewDidChange:(HPGrowingTextView *)growingTextView;
|
||||
|
||||
- (void)growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height;
|
||||
|
|
@ -58,57 +61,56 @@
|
|||
@end
|
||||
|
||||
@interface HPGrowingTextView : UIView <UITextViewDelegate> {
|
||||
HPTextViewInternal *internalTextView;
|
||||
|
||||
HPTextViewInternal *internalTextView;
|
||||
|
||||
int minHeight;
|
||||
int maxHeight;
|
||||
|
||||
//class properties
|
||||
|
||||
// class properties
|
||||
int maxNumberOfLines;
|
||||
int minNumberOfLines;
|
||||
|
||||
|
||||
BOOL animateHeightChange;
|
||||
NSTimeInterval animationDuration;
|
||||
|
||||
//uitextview properties
|
||||
NSObject <HPGrowingTextViewDelegate> *__unsafe_unretained delegate;
|
||||
NSTimeInterval animationDuration;
|
||||
|
||||
// uitextview properties
|
||||
NSObject<HPGrowingTextViewDelegate> *__unsafe_unretained delegate;
|
||||
NSTextAlignment textAlignment;
|
||||
NSRange selectedRange;
|
||||
BOOL editable;
|
||||
UIDataDetectorTypes dataDetectorTypes;
|
||||
UIReturnKeyType returnKeyType;
|
||||
|
||||
UIEdgeInsets contentInset;
|
||||
|
||||
UIEdgeInsets contentInset;
|
||||
}
|
||||
|
||||
//real class properties
|
||||
// real class properties
|
||||
@property int maxNumberOfLines;
|
||||
@property int minNumberOfLines;
|
||||
@property (nonatomic) int maxHeight;
|
||||
@property (nonatomic) int minHeight;
|
||||
@property(nonatomic) int maxHeight;
|
||||
@property(nonatomic) int minHeight;
|
||||
@property BOOL animateHeightChange;
|
||||
@property NSTimeInterval animationDuration;
|
||||
@property (nonatomic, strong) NSString *placeholder;
|
||||
@property (nonatomic, strong) UIColor *placeholderColor;
|
||||
@property (nonatomic, strong) UITextView *internalTextView;
|
||||
@property(nonatomic, strong) NSString *placeholder;
|
||||
@property(nonatomic, strong) UIColor *placeholderColor;
|
||||
@property(nonatomic, strong) UITextView *internalTextView;
|
||||
|
||||
|
||||
//uitextview properties
|
||||
// uitextview properties
|
||||
@property(unsafe_unretained) NSObject<HPGrowingTextViewDelegate> *delegate;
|
||||
@property(nonatomic,strong) NSString *text;
|
||||
@property(nonatomic,strong) UIFont *font;
|
||||
@property(nonatomic,strong) UIColor *textColor;
|
||||
@property(nonatomic) NSTextAlignment textAlignment; // default is NSTextAlignmentLeft
|
||||
@property(nonatomic) NSRange selectedRange; // only ranges of length 0 are supported
|
||||
@property(nonatomic,getter=isEditable) BOOL editable;
|
||||
@property(nonatomic, strong) NSString *text;
|
||||
@property(nonatomic, strong) UIFont *font;
|
||||
@property(nonatomic, strong) UIColor *textColor;
|
||||
@property(nonatomic) NSTextAlignment textAlignment; // default is NSTextAlignmentLeft
|
||||
@property(nonatomic) NSRange selectedRange; // only ranges of length 0 are supported
|
||||
@property(nonatomic, getter=isEditable) BOOL editable;
|
||||
@property(nonatomic) UIDataDetectorTypes dataDetectorTypes __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_3_0);
|
||||
@property (nonatomic) UIReturnKeyType returnKeyType;
|
||||
@property (assign) UIEdgeInsets contentInset;
|
||||
@property (nonatomic) BOOL isScrollable;
|
||||
@property(nonatomic) UIReturnKeyType returnKeyType;
|
||||
@property(assign) UIEdgeInsets contentInset;
|
||||
@property(nonatomic) BOOL isScrollable;
|
||||
@property(nonatomic) BOOL enablesReturnKeyAutomatically;
|
||||
|
||||
//uitextview methods
|
||||
//need others? use .internalTextView
|
||||
// uitextview methods
|
||||
// need others? use .internalTextView
|
||||
- (BOOL)becomeFirstResponder;
|
||||
- (BOOL)resignFirstResponder;
|
||||
- (BOOL)isFirstResponder;
|
||||
602
Classes/Utils/HPGrowingTextView/HPGrowingTextView.m
Executable file
602
Classes/Utils/HPGrowingTextView/HPGrowingTextView.m
Executable file
|
|
@ -0,0 +1,602 @@
|
|||
//
|
||||
// HPTextView.m
|
||||
//
|
||||
// Created by Hans Pinckaers on 29-06-10.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2011 Hans Pinckaers
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "HPGrowingTextView.h"
|
||||
#import "HPTextViewInternal.h"
|
||||
|
||||
@interface HPGrowingTextView (private)
|
||||
- (void)commonInitialiser;
|
||||
- (void)resizeTextView:(NSInteger)newSizeH;
|
||||
- (void)growDidStop;
|
||||
@end
|
||||
|
||||
@implementation HPGrowingTextView
|
||||
@synthesize internalTextView;
|
||||
@synthesize delegate;
|
||||
@synthesize maxHeight;
|
||||
@synthesize minHeight;
|
||||
@synthesize font;
|
||||
@synthesize textColor;
|
||||
@synthesize textAlignment;
|
||||
@synthesize selectedRange;
|
||||
@synthesize editable;
|
||||
@synthesize dataDetectorTypes;
|
||||
@synthesize animateHeightChange;
|
||||
@synthesize animationDuration;
|
||||
@synthesize returnKeyType;
|
||||
@dynamic placeholder;
|
||||
@dynamic placeholderColor;
|
||||
|
||||
// having initwithcoder allows us to use HPGrowingTextView in a Nib. -- aob, 9/2011
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder {
|
||||
if ((self = [super initWithCoder:aDecoder])) {
|
||||
[self commonInitialiser];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame {
|
||||
if ((self = [super initWithFrame:frame])) {
|
||||
[self commonInitialiser];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)commonInitialiser {
|
||||
// Initialization code
|
||||
CGRect r = self.frame;
|
||||
r.origin.y = 0;
|
||||
r.origin.x = 0;
|
||||
internalTextView = [[HPTextViewInternal alloc] initWithFrame:r];
|
||||
internalTextView.delegate = self;
|
||||
internalTextView.scrollEnabled = NO;
|
||||
internalTextView.font = [UIFont systemFontOfSize:13];
|
||||
internalTextView.contentInset = UIEdgeInsetsZero;
|
||||
internalTextView.showsHorizontalScrollIndicator = NO;
|
||||
internalTextView.text = @"-";
|
||||
[self addSubview:internalTextView];
|
||||
|
||||
minHeight = internalTextView.frame.size.height;
|
||||
minNumberOfLines = 1;
|
||||
|
||||
animateHeightChange = YES;
|
||||
animationDuration = 0.1f;
|
||||
|
||||
internalTextView.text = @"";
|
||||
|
||||
[self setMaxNumberOfLines:3];
|
||||
|
||||
[self setPlaceholderColor:[UIColor lightGrayColor]];
|
||||
internalTextView.displayPlaceHolder = YES;
|
||||
}
|
||||
|
||||
- (CGSize)sizeThatFits:(CGSize)size {
|
||||
if (self.text.length == 0) {
|
||||
size.height = minHeight;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
|
||||
CGRect r = self.bounds;
|
||||
r.origin.y = 0;
|
||||
r.origin.x = contentInset.left;
|
||||
r.size.width -= contentInset.left + contentInset.right;
|
||||
|
||||
internalTextView.frame = r;
|
||||
}
|
||||
|
||||
- (void)setContentInset:(UIEdgeInsets)inset {
|
||||
contentInset = inset;
|
||||
|
||||
CGRect r = self.frame;
|
||||
r.origin.y = inset.top - inset.bottom;
|
||||
r.origin.x = inset.left;
|
||||
r.size.width -= inset.left + inset.right;
|
||||
|
||||
internalTextView.frame = r;
|
||||
|
||||
[self setMaxNumberOfLines:maxNumberOfLines];
|
||||
[self setMinNumberOfLines:minNumberOfLines];
|
||||
}
|
||||
|
||||
- (UIEdgeInsets)contentInset {
|
||||
return contentInset;
|
||||
}
|
||||
|
||||
- (void)setMaxNumberOfLines:(int)n {
|
||||
if (n == 0 && maxHeight > 0)
|
||||
return; // the user specified a maxHeight themselves.
|
||||
|
||||
// Use internalTextView for height calculations, thanks to Gwynne <http://blog.darkrainfall.org/>
|
||||
NSString *saveText = internalTextView.text, *newText = @"-";
|
||||
|
||||
internalTextView.delegate = nil;
|
||||
internalTextView.hidden = YES;
|
||||
|
||||
for (int i = 1; i < n; ++i)
|
||||
newText = [newText stringByAppendingString:@"\n|W|"];
|
||||
|
||||
internalTextView.text = newText;
|
||||
|
||||
maxHeight = [self measureHeight];
|
||||
|
||||
internalTextView.text = saveText;
|
||||
internalTextView.hidden = NO;
|
||||
internalTextView.delegate = self;
|
||||
|
||||
[self sizeToFit];
|
||||
|
||||
maxNumberOfLines = n;
|
||||
}
|
||||
|
||||
- (int)maxNumberOfLines {
|
||||
return maxNumberOfLines;
|
||||
}
|
||||
|
||||
- (void)setMaxHeight:(int)height {
|
||||
maxHeight = height;
|
||||
maxNumberOfLines = 0;
|
||||
}
|
||||
|
||||
- (void)setMinNumberOfLines:(int)m {
|
||||
if (m == 0 && minHeight > 0)
|
||||
return; // the user specified a minHeight themselves.
|
||||
|
||||
// Use internalTextView for height calculations, thanks to Gwynne <http://blog.darkrainfall.org/>
|
||||
NSString *saveText = internalTextView.text, *newText = @"-";
|
||||
|
||||
internalTextView.delegate = nil;
|
||||
internalTextView.hidden = YES;
|
||||
|
||||
for (int i = 1; i < m; ++i)
|
||||
newText = [newText stringByAppendingString:@"\n|W|"];
|
||||
|
||||
internalTextView.text = newText;
|
||||
|
||||
minHeight = [self measureHeight];
|
||||
|
||||
internalTextView.text = saveText;
|
||||
internalTextView.hidden = NO;
|
||||
internalTextView.delegate = self;
|
||||
|
||||
[self sizeToFit];
|
||||
|
||||
minNumberOfLines = m;
|
||||
}
|
||||
|
||||
- (int)minNumberOfLines {
|
||||
return minNumberOfLines;
|
||||
}
|
||||
|
||||
- (void)setMinHeight:(int)height {
|
||||
minHeight = height;
|
||||
minNumberOfLines = 0;
|
||||
}
|
||||
|
||||
- (NSString *)placeholder {
|
||||
return internalTextView.placeholder;
|
||||
}
|
||||
|
||||
- (void)setPlaceholder:(NSString *)placeholder {
|
||||
[internalTextView setPlaceholder:placeholder];
|
||||
}
|
||||
|
||||
- (UIColor *)placeholderColor {
|
||||
return internalTextView.placeholderColor;
|
||||
}
|
||||
|
||||
- (void)setPlaceholderColor:(UIColor *)placeholderColor {
|
||||
[internalTextView setPlaceholderColor:placeholderColor];
|
||||
}
|
||||
|
||||
- (void)textViewDidChange:(UITextView *)textView {
|
||||
[self refreshHeight];
|
||||
if ([delegate respondsToSelector:@selector(growingTextChanged:text:)])
|
||||
[delegate growingTextChanged:self text:[textView text]];
|
||||
}
|
||||
|
||||
- (void)refreshHeight {
|
||||
// size of content, so we can set the frame of self
|
||||
NSInteger newSizeH = [self measureHeight];
|
||||
if (newSizeH < minHeight || !internalTextView.hasText)
|
||||
newSizeH = minHeight; // not smalles than minHeight
|
||||
if (internalTextView.frame.size.height > maxHeight)
|
||||
newSizeH = maxHeight; // not taller than maxHeight
|
||||
|
||||
if (internalTextView.frame.size.height != newSizeH) {
|
||||
// [fixed] Pasting too much text into the view failed to fire the height change,
|
||||
// thanks to Gwynne <http://blog.darkrainfall.org/>
|
||||
|
||||
if (newSizeH > maxHeight && internalTextView.frame.size.height <= maxHeight) {
|
||||
newSizeH = maxHeight;
|
||||
}
|
||||
|
||||
if (newSizeH <= maxHeight) {
|
||||
if (animateHeightChange) {
|
||||
|
||||
if ([UIView resolveClassMethod:@selector(animateWithDuration:animations:)]) {
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
|
||||
[UIView animateWithDuration:animationDuration
|
||||
delay:0
|
||||
options:(UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState)
|
||||
animations:^(void) {
|
||||
[self resizeTextView:newSizeH];
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
if ([delegate respondsToSelector:@selector(growingTextView:didChangeHeight:)]) {
|
||||
[delegate growingTextView:self didChangeHeight:newSizeH];
|
||||
}
|
||||
}];
|
||||
#endif
|
||||
} else {
|
||||
[UIView beginAnimations:@"" context:nil];
|
||||
[UIView setAnimationDuration:animationDuration];
|
||||
[UIView setAnimationDelegate:self];
|
||||
[UIView setAnimationDidStopSelector:@selector(growDidStop)];
|
||||
[UIView setAnimationBeginsFromCurrentState:YES];
|
||||
[self resizeTextView:newSizeH];
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
} else {
|
||||
[self resizeTextView:newSizeH];
|
||||
// [fixed] The growingTextView:didChangeHeight: delegate method was not called at all when not animating
|
||||
// height changes.
|
||||
// thanks to Gwynne <http://blog.darkrainfall.org/>
|
||||
|
||||
if ([delegate respondsToSelector:@selector(growingTextView:didChangeHeight:)]) {
|
||||
[delegate growingTextView:self didChangeHeight:newSizeH];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if our new height is greater than the maxHeight
|
||||
// sets not set the height or move things
|
||||
// around and enable scrolling
|
||||
if (newSizeH >= maxHeight) {
|
||||
if (!internalTextView.scrollEnabled) {
|
||||
internalTextView.scrollEnabled = YES;
|
||||
[internalTextView flashScrollIndicators];
|
||||
}
|
||||
|
||||
} else {
|
||||
internalTextView.scrollEnabled = NO;
|
||||
}
|
||||
|
||||
// scroll to caret (needed on iOS7)
|
||||
if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)]) {
|
||||
CGRect r = [internalTextView caretRectForPosition:internalTextView.selectedTextRange.end];
|
||||
CGFloat caretY = MAX(r.origin.y - internalTextView.frame.size.height + r.size.height + 8, 0);
|
||||
if (internalTextView.contentOffset.y < caretY && r.origin.y != INFINITY)
|
||||
internalTextView.contentOffset = CGPointMake(0, MIN(caretY, internalTextView.contentSize.height));
|
||||
}
|
||||
}
|
||||
// Display (or not) the placeholder string
|
||||
|
||||
BOOL wasDisplayingPlaceholder = internalTextView.displayPlaceHolder;
|
||||
internalTextView.displayPlaceHolder = self.internalTextView.text.length == 0;
|
||||
|
||||
if (wasDisplayingPlaceholder != internalTextView.displayPlaceHolder) {
|
||||
[internalTextView setNeedsDisplay];
|
||||
}
|
||||
|
||||
// Tell the delegate that the text view changed
|
||||
|
||||
if ([delegate respondsToSelector:@selector(growingTextViewDidChange:)]) {
|
||||
[delegate growingTextViewDidChange:self];
|
||||
}
|
||||
}
|
||||
|
||||
// Code from apple developer forum - @Steve Krulewitz, @Mark Marszal, @Eric Silverberg
|
||||
- (CGFloat)measureHeight {
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
|
||||
if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)]) {
|
||||
CGRect frame = internalTextView.bounds;
|
||||
CGSize fudgeFactor;
|
||||
// The padding added around the text on iOS6 and iOS7 is different.
|
||||
fudgeFactor = CGSizeMake(10.0, 16.0);
|
||||
|
||||
frame.size.height -= fudgeFactor.height;
|
||||
frame.size.width -= fudgeFactor.width;
|
||||
|
||||
NSMutableAttributedString *textToMeasure;
|
||||
if (internalTextView.attributedText && internalTextView.attributedText.length > 0) {
|
||||
textToMeasure =
|
||||
[[NSMutableAttributedString alloc] initWithAttributedString:internalTextView.attributedText];
|
||||
} else {
|
||||
textToMeasure = [[NSMutableAttributedString alloc] initWithString:internalTextView.text];
|
||||
[textToMeasure addAttribute:NSFontAttributeName
|
||||
value:internalTextView.font
|
||||
range:NSMakeRange(0, textToMeasure.length)];
|
||||
}
|
||||
|
||||
if ([textToMeasure.string hasSuffix:@"\n"]) {
|
||||
[textToMeasure appendAttributedString:[[NSAttributedString alloc]
|
||||
initWithString:@"-"
|
||||
attributes:@{NSFontAttributeName : internalTextView.font}]];
|
||||
}
|
||||
|
||||
// NSAttributedString class method: boundingRectWithSize:options:context is
|
||||
// available only on ios7.0 sdk.
|
||||
CGRect size = [textToMeasure boundingRectWithSize:CGSizeMake(CGRectGetWidth(frame), MAXFLOAT)
|
||||
options:NSStringDrawingUsesLineFragmentOrigin
|
||||
context:nil];
|
||||
|
||||
return ceil(CGRectGetHeight(size) + fudgeFactor.height);
|
||||
} else {
|
||||
return self.internalTextView.contentSize.height;
|
||||
}
|
||||
#else
|
||||
return self.internalTextView.contentSize.height;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)resizeTextView:(NSInteger)newSizeH {
|
||||
if ([delegate respondsToSelector:@selector(growingTextView:willChangeHeight:)]) {
|
||||
[delegate growingTextView:self willChangeHeight:newSizeH];
|
||||
}
|
||||
|
||||
CGRect internalTextViewFrame = self.frame;
|
||||
internalTextViewFrame.size.height = newSizeH; // + padding
|
||||
self.frame = internalTextViewFrame;
|
||||
|
||||
internalTextViewFrame.origin.y = contentInset.top - contentInset.bottom;
|
||||
internalTextViewFrame.origin.x = contentInset.left;
|
||||
internalTextViewFrame.size.width = internalTextView.contentSize.width;
|
||||
|
||||
if (!CGRectEqualToRect(internalTextView.frame, internalTextViewFrame))
|
||||
internalTextView.frame = internalTextViewFrame;
|
||||
}
|
||||
|
||||
- (void)growDidStop {
|
||||
if ([delegate respondsToSelector:@selector(growingTextView:didChangeHeight:)]) {
|
||||
[delegate growingTextView:self didChangeHeight:self.frame.size.height];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
|
||||
[internalTextView becomeFirstResponder];
|
||||
}
|
||||
|
||||
- (BOOL)becomeFirstResponder {
|
||||
[super becomeFirstResponder];
|
||||
return [self.internalTextView becomeFirstResponder];
|
||||
}
|
||||
|
||||
- (BOOL)resignFirstResponder {
|
||||
[super resignFirstResponder];
|
||||
return [internalTextView resignFirstResponder];
|
||||
}
|
||||
|
||||
- (BOOL)isFirstResponder {
|
||||
return [self.internalTextView isFirstResponder];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark UITextView properties
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)setText:(NSString *)newText {
|
||||
internalTextView.text = newText;
|
||||
|
||||
// include this line to analyze the height of the textview.
|
||||
// fix from Ankit Thakur
|
||||
[self performSelector:@selector(textViewDidChange:) withObject:internalTextView];
|
||||
}
|
||||
|
||||
- (NSString *)text {
|
||||
return internalTextView.text;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)setFont:(UIFont *)afont {
|
||||
internalTextView.font = afont;
|
||||
|
||||
[self setMaxNumberOfLines:maxNumberOfLines];
|
||||
[self setMinNumberOfLines:minNumberOfLines];
|
||||
}
|
||||
|
||||
- (UIFont *)font {
|
||||
return internalTextView.font;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)setTextColor:(UIColor *)color {
|
||||
internalTextView.textColor = color;
|
||||
}
|
||||
|
||||
- (UIColor *)textColor {
|
||||
return internalTextView.textColor;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)setBackgroundColor:(UIColor *)backgroundColor {
|
||||
[super setBackgroundColor:backgroundColor];
|
||||
internalTextView.backgroundColor = backgroundColor;
|
||||
}
|
||||
|
||||
- (UIColor *)backgroundColor {
|
||||
return internalTextView.backgroundColor;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)setTextAlignment:(NSTextAlignment)aligment {
|
||||
internalTextView.textAlignment = aligment;
|
||||
}
|
||||
|
||||
- (NSTextAlignment)textAlignment {
|
||||
return internalTextView.textAlignment;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)setSelectedRange:(NSRange)range {
|
||||
internalTextView.selectedRange = range;
|
||||
}
|
||||
|
||||
- (NSRange)selectedRange {
|
||||
return internalTextView.selectedRange;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)setIsScrollable:(BOOL)isScrollable {
|
||||
internalTextView.scrollEnabled = isScrollable;
|
||||
}
|
||||
|
||||
- (BOOL)isScrollable {
|
||||
return internalTextView.scrollEnabled;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)setEditable:(BOOL)beditable {
|
||||
internalTextView.editable = beditable;
|
||||
}
|
||||
|
||||
- (BOOL)isEditable {
|
||||
return internalTextView.editable;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)setReturnKeyType:(UIReturnKeyType)keyType {
|
||||
internalTextView.returnKeyType = keyType;
|
||||
}
|
||||
|
||||
- (UIReturnKeyType)returnKeyType {
|
||||
return internalTextView.returnKeyType;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)setEnablesReturnKeyAutomatically:(BOOL)enablesReturnKeyAutomatically {
|
||||
internalTextView.enablesReturnKeyAutomatically = enablesReturnKeyAutomatically;
|
||||
}
|
||||
|
||||
- (BOOL)enablesReturnKeyAutomatically {
|
||||
return internalTextView.enablesReturnKeyAutomatically;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (void)setDataDetectorTypes:(UIDataDetectorTypes)datadetector {
|
||||
internalTextView.dataDetectorTypes = datadetector;
|
||||
}
|
||||
|
||||
- (UIDataDetectorTypes)dataDetectorTypes {
|
||||
return internalTextView.dataDetectorTypes;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
- (BOOL)hasText {
|
||||
return [internalTextView hasText];
|
||||
}
|
||||
|
||||
- (void)scrollRangeToVisible:(NSRange)range {
|
||||
[internalTextView scrollRangeToVisible:range];
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#pragma mark -
|
||||
#pragma mark UITextViewDelegate
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
|
||||
if ([delegate respondsToSelector:@selector(growingTextViewShouldBeginEditing:)]) {
|
||||
return [delegate growingTextViewShouldBeginEditing:self];
|
||||
|
||||
} else {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
- (BOOL)textViewShouldEndEditing:(UITextView *)textView {
|
||||
if ([delegate respondsToSelector:@selector(growingTextViewShouldEndEditing:)]) {
|
||||
return [delegate growingTextViewShouldEndEditing:self];
|
||||
|
||||
} else {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
- (void)textViewDidBeginEditing:(UITextView *)textView {
|
||||
if ([delegate respondsToSelector:@selector(growingTextViewDidBeginEditing:)]) {
|
||||
[delegate growingTextViewDidBeginEditing:self];
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
- (void)textViewDidEndEditing:(UITextView *)textView {
|
||||
if ([delegate respondsToSelector:@selector(growingTextViewDidEndEditing:)]) {
|
||||
[delegate growingTextViewDidEndEditing:self];
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)atext {
|
||||
|
||||
// weird 1 pixel bug when clicking backspace when textView is empty
|
||||
if (![textView hasText] && [atext isEqualToString:@""])
|
||||
return NO;
|
||||
|
||||
// Added by bretdabaker: sometimes we want to handle this ourselves
|
||||
if ([delegate respondsToSelector:@selector(growingTextView:shouldChangeTextInRange:replacementText:)])
|
||||
return [delegate growingTextView:self shouldChangeTextInRange:range replacementText:atext];
|
||||
|
||||
if ([atext isEqualToString:@"\n"]) {
|
||||
if ([delegate respondsToSelector:@selector(growingTextViewShouldReturn:)]) {
|
||||
if (![delegate performSelector:@selector(growingTextViewShouldReturn:) withObject:self]) {
|
||||
return YES;
|
||||
} else {
|
||||
[textView resignFirstResponder];
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
- (void)textViewDidChangeSelection:(UITextView *)textView {
|
||||
if ([delegate respondsToSelector:@selector(growingTextViewDidChangeSelection:)]) {
|
||||
[delegate growingTextViewDidChangeSelection:self];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -27,11 +27,10 @@
|
|||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
|
||||
@interface HPTextViewInternal : UITextView
|
||||
|
||||
@property (nonatomic, strong) NSString *placeholder;
|
||||
@property (nonatomic, strong) UIColor *placeholderColor;
|
||||
@property (nonatomic) BOOL displayPlaceHolder;
|
||||
@property(nonatomic, strong) NSString *placeholder;
|
||||
@property(nonatomic, strong) UIColor *placeholderColor;
|
||||
@property(nonatomic) BOOL displayPlaceHolder;
|
||||
|
||||
@end
|
||||
105
Classes/Utils/HPGrowingTextView/HPTextViewInternal.m
Executable file
105
Classes/Utils/HPGrowingTextView/HPTextViewInternal.m
Executable file
|
|
@ -0,0 +1,105 @@
|
|||
//
|
||||
// HPTextViewInternal.m
|
||||
//
|
||||
// Created by Hans Pinckaers on 29-06-10.
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2011 Hans Pinckaers
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "HPTextViewInternal.h"
|
||||
|
||||
@implementation HPTextViewInternal
|
||||
|
||||
@synthesize placeholder;
|
||||
@synthesize placeholderColor;
|
||||
@synthesize displayPlaceHolder;
|
||||
|
||||
- (void)setText:(NSString *)text {
|
||||
BOOL originalValue = self.scrollEnabled;
|
||||
// If one of GrowingTextView's superviews is a scrollView, and self.scrollEnabled == NO,
|
||||
// setting the text programatically will cause UIKit to search upwards until it finds a scrollView with
|
||||
// scrollEnabled==yes
|
||||
// then scroll it erratically. Setting scrollEnabled temporarily to YES prevents this.
|
||||
[self setScrollEnabled:YES];
|
||||
[super setText:text];
|
||||
[self setScrollEnabled:originalValue];
|
||||
}
|
||||
|
||||
- (void)setScrollable:(BOOL)isScrollable {
|
||||
[super setScrollEnabled:isScrollable];
|
||||
}
|
||||
|
||||
- (void)setContentOffset:(CGPoint)s {
|
||||
if (self.tracking || self.decelerating) {
|
||||
// initiated by user...
|
||||
|
||||
UIEdgeInsets insets = self.contentInset;
|
||||
insets.bottom = 0;
|
||||
insets.top = 0;
|
||||
self.contentInset = insets;
|
||||
|
||||
} else {
|
||||
|
||||
float bottomOffset = (self.contentSize.height - self.frame.size.height + self.contentInset.bottom);
|
||||
if (s.y < bottomOffset && self.scrollEnabled) {
|
||||
UIEdgeInsets insets = self.contentInset;
|
||||
insets.bottom = 8;
|
||||
insets.top = 0;
|
||||
self.contentInset = insets;
|
||||
}
|
||||
}
|
||||
|
||||
[super setContentOffset:s];
|
||||
}
|
||||
|
||||
- (void)setContentInset:(UIEdgeInsets)s {
|
||||
UIEdgeInsets insets = s;
|
||||
|
||||
if (s.bottom > 8)
|
||||
insets.bottom = 0;
|
||||
insets.top = 0;
|
||||
|
||||
[super setContentInset:insets];
|
||||
}
|
||||
|
||||
- (void)setContentSize:(CGSize)contentSize {
|
||||
// is this an iOS5 bug? Need testing!
|
||||
if (self.contentSize.height > contentSize.height) {
|
||||
UIEdgeInsets insets = self.contentInset;
|
||||
insets.bottom = 0;
|
||||
insets.top = 0;
|
||||
self.contentInset = insets;
|
||||
}
|
||||
|
||||
[super setContentSize:contentSize];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)rect {
|
||||
[super drawRect:rect];
|
||||
if (displayPlaceHolder && placeholder && placeholderColor) {
|
||||
[placeholderColor set];
|
||||
[placeholder drawInRect:CGRectMake(8.0f, 8.0f, self.frame.size.width - 16.0f, self.frame.size.height - 16.0f)
|
||||
withFont:self.font];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -97,6 +97,8 @@
|
|||
633756391B67BAF400E21BAD /* SideMenuTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 633756381B67BAF400E21BAD /* SideMenuTableView.m */; };
|
||||
633756451B67D2B200E21BAD /* SideMenuView.m in Sources */ = {isa = PBXBuildFile; fileRef = 633756431B67D2B100E21BAD /* SideMenuView.m */; };
|
||||
633756461B67D2B200E21BAD /* SideMenuView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 633756441B67D2B100E21BAD /* SideMenuView.xib */; };
|
||||
633888451BFB2C49001D5E7B /* HPGrowingTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 633888421BFB2C49001D5E7B /* HPGrowingTextView.m */; };
|
||||
633888461BFB2C49001D5E7B /* HPTextViewInternal.m in Sources */ = {isa = PBXBuildFile; fileRef = 633888441BFB2C49001D5E7B /* HPTextViewInternal.m */; };
|
||||
6341807C1BBC103100F71761 /* ChatConversationCreateTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6341807B1BBC103100F71761 /* ChatConversationCreateTableView.m */; };
|
||||
634610061B61330300548952 /* UILabel+Boldify.m in Sources */ = {isa = PBXBuildFile; fileRef = 634610051B61330300548952 /* UILabel+Boldify.m */; };
|
||||
6346100F1B61409800548952 /* CallOutgoingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6346100E1B61409800548952 /* CallOutgoingView.m */; };
|
||||
|
|
@ -624,8 +626,6 @@
|
|||
D3ED3E871586291E006C0DE4 /* TabBarView.m in Sources */ = {isa = PBXBuildFile; fileRef = D3ED3E851586291B006C0DE4 /* TabBarView.m */; };
|
||||
D3ED3EA71587334E006C0DE4 /* HistoryListTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = D3ED3EA51587334C006C0DE4 /* HistoryListTableView.m */; };
|
||||
D3ED3EB81587392C006C0DE4 /* HistoryListView.m in Sources */ = {isa = PBXBuildFile; fileRef = D3ED3EB615873929006C0DE4 /* HistoryListView.m */; };
|
||||
D3ED40191602172200BF332B /* HPGrowingTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = D3ED40161602172200BF332B /* HPGrowingTextView.m */; };
|
||||
D3ED401B1602172200BF332B /* HPTextViewInternal.m in Sources */ = {isa = PBXBuildFile; fileRef = D3ED40181602172200BF332B /* HPTextViewInternal.m */; };
|
||||
D3F26BF115986B73005F9CAB /* CallIncomingView.m in Sources */ = {isa = PBXBuildFile; fileRef = D3F26BEF15986B71005F9CAB /* CallIncomingView.m */; };
|
||||
D3F795D615A582810077328B /* ChatConversationView.m in Sources */ = {isa = PBXBuildFile; fileRef = D3F795D415A582800077328B /* ChatConversationView.m */; };
|
||||
D3F7998115BD32370018C273 /* TPMultiLayoutViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D3F7998015BD32370018C273 /* TPMultiLayoutViewController.m */; };
|
||||
|
|
@ -907,6 +907,10 @@
|
|||
633756421B67D2B100E21BAD /* SideMenuView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SideMenuView.h; sourceTree = "<group>"; };
|
||||
633756431B67D2B100E21BAD /* SideMenuView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SideMenuView.m; sourceTree = "<group>"; };
|
||||
633756441B67D2B100E21BAD /* SideMenuView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SideMenuView.xib; sourceTree = "<group>"; };
|
||||
633888411BFB2C49001D5E7B /* HPGrowingTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HPGrowingTextView.h; sourceTree = "<group>"; };
|
||||
633888421BFB2C49001D5E7B /* HPGrowingTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HPGrowingTextView.m; sourceTree = "<group>"; };
|
||||
633888431BFB2C49001D5E7B /* HPTextViewInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HPTextViewInternal.h; sourceTree = "<group>"; };
|
||||
633888441BFB2C49001D5E7B /* HPTextViewInternal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HPTextViewInternal.m; sourceTree = "<group>"; };
|
||||
633E388219FFB0F400936D1C /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
6341807A1BBC103100F71761 /* ChatConversationCreateTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChatConversationCreateTableView.h; sourceTree = "<group>"; };
|
||||
6341807B1BBC103100F71761 /* ChatConversationCreateTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChatConversationCreateTableView.m; sourceTree = "<group>"; };
|
||||
|
|
@ -1480,10 +1484,6 @@
|
|||
D3ED3EA51587334C006C0DE4 /* HistoryListTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = HistoryListTableView.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
D3ED3EB515873928006C0DE4 /* HistoryListView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HistoryListView.h; sourceTree = "<group>"; };
|
||||
D3ED3EB615873929006C0DE4 /* HistoryListView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = HistoryListView.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
D3ED40151602172200BF332B /* HPGrowingTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HPGrowingTextView.h; sourceTree = "<group>"; };
|
||||
D3ED40161602172200BF332B /* HPGrowingTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HPGrowingTextView.m; sourceTree = "<group>"; };
|
||||
D3ED40171602172200BF332B /* HPTextViewInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HPTextViewInternal.h; sourceTree = "<group>"; };
|
||||
D3ED40181602172200BF332B /* HPTextViewInternal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HPTextViewInternal.m; sourceTree = "<group>"; };
|
||||
D3F26BEE15986B71005F9CAB /* CallIncomingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallIncomingView.h; sourceTree = "<group>"; };
|
||||
D3F26BEF15986B71005F9CAB /* CallIncomingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CallIncomingView.m; sourceTree = "<group>"; };
|
||||
D3F795D315A582800077328B /* ChatConversationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChatConversationView.h; sourceTree = "<group>"; };
|
||||
|
|
@ -2115,6 +2115,18 @@
|
|||
path = TestsLiblinphone;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
633888401BFB2C49001D5E7B /* HPGrowingTextView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
633888411BFB2C49001D5E7B /* HPGrowingTextView.h */,
|
||||
633888421BFB2C49001D5E7B /* HPGrowingTextView.m */,
|
||||
633888431BFB2C49001D5E7B /* HPTextViewInternal.h */,
|
||||
633888441BFB2C49001D5E7B /* HPTextViewInternal.m */,
|
||||
);
|
||||
name = HPGrowingTextView;
|
||||
path = Utils/HPGrowingTextView;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6354BFB41BF5EF3F00B78FFC /* images */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -2537,7 +2549,7 @@
|
|||
D32B9DFB15A2F131000B6DEC /* FastAddressBook.m */,
|
||||
6371579F1B283FE200C91677 /* FileTransferDelegate.h */,
|
||||
637157A01B283FE200C91677 /* FileTransferDelegate.m */,
|
||||
D3ED40141602172200BF332B /* GrowingTextView */,
|
||||
633888401BFB2C49001D5E7B /* HPGrowingTextView */,
|
||||
D3807FC715C2894A005BE9BC /* InAppSettingsKit */,
|
||||
D326483615887D5200930C67 /* OrderedDictionary.h */,
|
||||
D326483715887D5200930C67 /* OrderedDictionary.m */,
|
||||
|
|
@ -2668,18 +2680,6 @@
|
|||
path = Settings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D3ED40141602172200BF332B /* GrowingTextView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D3ED40151602172200BF332B /* HPGrowingTextView.h */,
|
||||
D3ED40161602172200BF332B /* HPGrowingTextView.m */,
|
||||
D3ED40171602172200BF332B /* HPTextViewInternal.h */,
|
||||
D3ED40181602172200BF332B /* HPTextViewInternal.m */,
|
||||
);
|
||||
name = GrowingTextView;
|
||||
path = Utils/GrowingTextView;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D3F7997E15BD31EC0018C273 /* TPMultiLayoutViewController */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -3415,6 +3415,7 @@
|
|||
D35497FE15875372000081D8 /* ContactsListView.m in Sources */,
|
||||
635173F91BA082A40095EB0A /* UIChatBubblePhotoCell.m in Sources */,
|
||||
D3549816158761D0000081D8 /* ContactsListTableView.m in Sources */,
|
||||
633888461BFB2C49001D5E7B /* HPTextViewInternal.m in Sources */,
|
||||
D35498211587716B000081D8 /* StatusBarView.m in Sources */,
|
||||
D3A55FBC15877E5E003FD403 /* UIContactCell.m in Sources */,
|
||||
6341807C1BBC103100F71761 /* ChatConversationCreateTableView.m in Sources */,
|
||||
|
|
@ -3432,6 +3433,7 @@
|
|||
63CD4B4F1A5AAC8C00B84282 /* DTAlertView.m in Sources */,
|
||||
D3EA53FD159850E80037DC6B /* LinphoneManager.m in Sources */,
|
||||
63B81A0E1B57DA33009604A6 /* TPKeyboardAvoidingScrollView.m in Sources */,
|
||||
633888451BFB2C49001D5E7B /* HPGrowingTextView.m in Sources */,
|
||||
6316FA6D1BE12A3E0050E441 /* UIRightImageButton.m in Sources */,
|
||||
63F1DF441BCE618E00EDED90 /* UIAddressTextField.m in Sources */,
|
||||
D3EA540D1598528B0037DC6B /* ChatsListTableView.m in Sources */,
|
||||
|
|
@ -3481,9 +3483,7 @@
|
|||
637157A11B283FE200C91677 /* FileTransferDelegate.m in Sources */,
|
||||
D378AB2A15DCDB4A0098505D /* ImagePickerView.m in Sources */,
|
||||
22405F001601C19200B92522 /* ImageView.m in Sources */,
|
||||
D3ED40191602172200BF332B /* HPGrowingTextView.m in Sources */,
|
||||
63BC49E21BA2CDFC004EC273 /* UICallPausedCell.m in Sources */,
|
||||
D3ED401B1602172200BF332B /* HPTextViewInternal.m in Sources */,
|
||||
D37EE162160377D7003608A6 /* DTActionSheet.m in Sources */,
|
||||
D306459E1611EC2A00BB571E /* UILoadingImageView.m in Sources */,
|
||||
D37E3ECD1619C27A0087659A /* CAAnimation+Blocks.m in Sources */,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue