UITextView contentOffset is set
i deleted the controller in the storyboard and rebuilt it and it just works now..
UITextView contentOffset changes between viewDidLoad and viewDidAppear
My guess is that when auto layout is applied, the content offset is mangled. This happens right before -layoutSubviews
is performed.
So to fix this issue, I could recommend two solutions.
- Subclass
UITextView
and setcontentOffset
in-layoutSubviews
. - Add
-viewDidLayoutSubviews
to your view controller and setcontentOffset
for any text views there.
Both of these are kind of hacky workarounds, but are better hacky workarounds than -viewDidAppear:
or dispatch_async()
.
NOTE: Take care to ensure you only adjust the contentOffset
in -layoutSubviews
or -viewDidLayoutSubviews
when appropriate.
UITextView contentOffset on iOS 7
Ok, based on my research and other answers, the problem was the UITextView
's content height and not the scrolling to a specific offset. Here is a solution that works the way it should work for iOS 7:
First, you need to recreate the UITextView
like this:
NSString *reqSysVer = @"7.0";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
BOOL osVersionSupported = ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending);
if (osVersionSupported) {
NSLog(@"reset chatoutput");
CGRect outputFrame = self.chatOutput.frame;
[chatOutput removeFromSuperview];
[chatOutput release];
chatOutput = nil;
NSTextStorage* textStorage = [[NSTextStorage alloc] init];
NSLayoutManager* layoutManager = [NSLayoutManager new];
[textStorage addLayoutManager:layoutManager];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:self.view.bounds.size];
[layoutManager addTextContainer:textContainer];
chatOutput = [[UITextView alloc] initWithFrame: outputFrame
textContainer: textContainer];
// if using ARC, remove these 3 lines
[textContainer release];
[layoutManager release];
[textStorage release];
[self.view addSubview: chatOutput];
}
Then, use this method to get the UITextView
content height:
- (CGFloat)textViewHeightForAttributedText:(NSAttributedString*)text andWidth:(CGFloat)width
{
UITextView *calculationView = [[UITextView alloc] init];
[calculationView setAttributedText:text];
CGSize size = [calculationView sizeThatFits:CGSizeMake(width, FLT_MAX)];
NSLog(@"size: %f", size.height) ;
return size.height;
}
Now you can set the content offset:
CGPoint bottomOffset;
bottomOffset = CGPointMake(0, [self textViewHeightForAttributedText: self.chatOutput.attributedText andWidth: self.chatOutput.frame.size.width] - self.chatOutput.frame.size.height);
[self.chatOutput setContentOffset:bottomOffset animated:YES];
UPDATE
I've read this in the Apple Documentation for NSAttributedString
:
"The default font for NSAttributedString objects is Helvetica 12-point, which may differ from the default system font for the platform."
In conclusion, if you use different fonts of different sizes, you have to set those to the NSAttributeString
instance as well. Otherwise, the returned height won't correspond to your expectations. You may want to use something like this:
NSDictionary *attrsDictionary = [NSDictionary dictionaryWithObject: [UIFont systemFontOfSize: 18.0] //or any other font or size
forKey: NSFontAttributeName];
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString: currentPost.postMessageText attributes: attrsDictionary];
frame.size.height = [self textViewHeightForAttributedText: attributedString andWidth: 280.0];
[attributedString release];
UITextView content offset changes after setting frame
Setting textView.scrollable = NO
lets me resize the text view without any strange offsets, that's the only way I've been able to figure out. And I guess it's not too much of a limitation for common scenarios, if you want the text view to be scrollable you probably don't need to resize it on the fly since the user can scroll around as the content changes.
UITextView starts at Bottom or Middle of the text
That did the trick for me!
Objective C:
[self.textView scrollRangeToVisible:NSMakeRange(0, 0)];
Swift:
self.textView.scrollRangeToVisible(NSMakeRange(0, 0))
Swift 2 (Alternate Solution)
Add this override method to your ViewController
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
textView.setContentOffset(CGPointZero, animated: false)
}
Swift 3 & 4 (syntax edit)
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
textView.contentOffset = .zero
}
Add constraints to UITextView change contentOffset
In layoutSubviews if UIView and in viewDidLayoutSubview ad the below line:
[textview setContentOffset:CGPointMake(0,0)];
This worked for me.
Related Topics
Swift Cannot Convert The Expression's Type 'Void' to Type 'string!'
Different UIfont Sizes for Different iOS Devices in Swift
Is The for Loop Condition Evaluated Each Loop in Swift
Type 'Int' Does Not Conform to Protocol 'Booleantype'
iOS App Extension - Action - Custom Data
Uitableview Only Displays One Section
Trying to Access Error Code in Alamofire
Swift: Urlsession.Shared.Datatask Says Status Code 304 = 200
Dynamic Dispatching Protocol Extension Doesn't Work Multiple Targets
Swift Wkwebview: Can't Find Variable Error When Calling Method
How to Add Two Generic Values in Swift
Is There Any Reasonable Way to Access The Contents of a Characterset
Position of Mouse Click Relative to Scene, Not Window
How to Unwrap Optional<Optional<T>> in Swift 1.2
How to Get The Coordinates of The Point on a Line That Has The Smallest Distance from Another Point