Large Text Being Cut Off in UITextView That is Inside UIScrollView - iphone

I'm having a serious problem that I just can't seem to fix and it's driving me insane for the last two days. I have searched far and wide and I can't find a solution, even though I have tried many.
I have a UITextView inside a UIScrollView. I am able to dynamically resize the UITextView inside the scrollview to display the text. But when the UITextView contains very large text it gets cut off when I scroll almost to the end. However, the UIScrollView's frame is still being sized correctly.
I read these posts: this this and many similar ones.
The UIScrollview and UITextview are both created in the xib using AutoLayout.
Here is my current code and a screenshot as you can see the blank spot in the screenshot should be filled with text. please help.
- (void)viewDidAppear:(BOOL)animated
{
CGRect frame = self.longDescField.frame;
frame.size.height = self.longDescField.contentSize.height;
self.longDescField.frame = frame;
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width, self.longDescField.contentSize.height + 200);
self.scrollView.scrollEnabled = YES;
[self.scrollView flashScrollIndicators];
}

This issue has existed since iOS 7 and is still present in iOS 12.
However, I wasn't able to keep the normal scrolling behaviour by setting scrollEnabled = NO before the resize, as #igz recommended. Instead I switched scrolling on and off after the resize
// Resize text view here
textView.scrollEnabled = NO;
textView.scrollEnabled = YES;
This forced the cut off text to render correctly.

Thanks everyone for your help. This is ultimately what ended up working for me in iOS7.
I had to disable auto layout for this particular xib.
Then did the following:
[textView setScrollEnabled:YES];
[textView setText:text];
[textView sizeToFit];
[textView setScrollEnabled:NO];

For me the solution was to put sizeToFit after customizing the textView
[self.yourTextView sizeToFit];
This should be the last thing you do when manipulating the textview, should not be before you populate the content text.

This issue can be fixed by setting the contiguous layout property to false.
textView.layoutManager.allowsNonContiguousLayout = false
Although the documentation says that the default value is false, it is actually set to true for a UITextView.

Definitely iOS7. I had this same problem applying to all UITextViews that were resized, both xib and code generated. I found the textContainer.size needed adjusting after UITextView frame was changed.
I created this category code to adjust the textContainer.size but it also seems to need adjusting after setting the text value as well, so I have to call adjustAfterFrameChange after any text changes if they are not followed by setting the frame size.
This code makes the assumption that UITextView is not doing anything with setFrame: itself so take out setFrame: and call adjustAfterFrameChange manually if you want to avoid that risk
Edit: changed
self.textContainer.size = self.frame.size; // fix for cut off text
to
self.textContainer.size = self.contentSize; // fix for cut off text
#interface UITextView(Extras)
- (void)adjustAfterFrameChange;
#end
#implementation UITextView(Extras)
- (void)adjustAfterFrameChange {
#if defined(__IPHONE_7_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_0
if ([self respondsToSelector:#selector(textContainer)])
self.textContainer.size = self.contentSize; // fix for cut off text
#endif
}
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
[self adjustAfterFrameChange];
}
#end

Try this
[self.textView setContentInset:UIEdgeInsetsMake(-8.0, 0, -8.0, 0)];
It work for the cut off text display in the UITextView.

I had a similar issue, wherein long text was getting cut off after a resize of the text view.
Turning off scrollingEnabled before the resize seemed to fix it. Sure seems like an IOS 7 bug.

We had the same problem, except the left half or right half of the UITextView was getting cut off. Happened on both iOS 7 and iOS 6, on a variety of phones. Calling:
myTextView.scrollEnabled = NO;
in viewWillAppear worked around the problem.

Just try this.
In IOS 8 and Xcode 6.3,
textview.scrollEnabled=YES;
[self.textview setContentInset:UIEdgeInsetsMake(-10.0, 0, -5.0, 0)];

We had an issue like this with the rollout of iOS7. When we called setText which added a new line (or lines) to our UITextView, the textview wasn't using the correct new height for its redrawing. The setNeedsDisplay, setNeedsLayout, redrawing layers, redrawing the entire view, etc all didn't work. Finally we forced a loss and gain of focus:
[textView resignFirstResponder];
[textView becomeFirstResponder];
This forced the height recalculation and correct redraw. Thankfully it does not cause the keyboard to pop out and in, but it's worth regression testing that on any iOS versions your app supports.

This happens all the way, from in Interface Builder too.
When text view selected, in Utilities Inspector uncheck the option Shows Vertical Indicator. The cropped text appears now.

None of these answers worked for me.
I was fooling with the storyboard and somehow it's working now. It still looks wrong in the storyboard but on the device it's now displaying fine.
I did various things, including toggling many of the options for the textfield.
I think what fixed it for me was making the view larger, building, and making it the right size again.
My apologies for a vague uncertain answer, but maybe it helps. This project was originally written for iOS 5, and the text view may not have been messed with much since then.

I have the same Problem for a textview (without a scrollview). Solved this (Xcode 7.3.1, iOS 9.3) just by unchecking "Scrolling Enabled" in the Attributes Inspector.

I may be wrong but I do not understand your problem thoroughly but what is the use of using a UIScrollView since with the UITextView class implements the behavior for a scrollable, multiline text region ?
You should discard the UIScrollView.

I am facing the same situation. I have to disable the UITextView's scrolling and doing that causes the last line is cliped. Here is my solution:
//In the UITextView subClass, override "gestureRecognizerShouldBegin" and let the scrolling of UITextView remain on.
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && gestureRecognizer.view == self){
return NO;
}
return [super gestureRecognizerShouldBegin:gestureRecognizer];
}

In Swift I fixed this issue by simply setting the textContainerInset of my UITextView:
textView.textContainerInset = UIEdgeInsets(top: 0.0, left: 0.0,
bottom: 50.0, right: 0.0)

This worked for me:
textView.scrollEnabled = NO;
//resize here
textView.scrollEnabled=YES;

Related

How to insert UIImageView in UITextView in the same way that iphone default message (SMS) app uses to insert multimedia content in the UITextView

I want to insert UIImageView in UITextView of Toolbar having send and camera button in the same way as iPhone default SMS app do.
You would be better off using a UIScrollView and managing UITextViews and UIImageViews in it. UITextView doesn't support adding image inline with text. In fact, it doesn't really support anything other than multiline text.
Per your comment below, there are three things I can think of to get the image as part of the text entry box:
They're not using a UITextView, but instead some custom view. That sort of thing is difficult to replicate.
They are overlaying a UIImageView over the UITextView as a subview and setting the contentInset of the UITextView so there is no overlap.
They are using a separate UIView to contain both the UITextView and UIImageView as subviews and simply arrange those subviews as needed.
Both 2 & 3 are very similar (just slightly different approaches) and probably your best approach. Personally, I think 3 is probably the best, since it give you the most control over the position of both views, but 2 should also work fine.
I agree with Aaron. Based on what I have seen, I believe the native SMS app is actually a UITableView with highly modified TableCells. The TableCells are then composite views that contain the UITextView and UIImageView as Aaron suggested.
It might be a little more work up front, but I think you will find the customization of defining your own UITableCell with the above elements will be quite useful and fall in line with the overall iOS paradigm. Things work a lot better when you work with the native paradigms than against / around them.
Cheers
I have one suggetion that try to make html file with image and text as per your requirements and load that html file into webview.
Here you can also back some particular text Bold etc.
I think nice look then textfield.
To make webview just look like simple scroll view just put this method in your code
don't forgot to write this
webView.opaque = NO;,
[self hideGradientBackground:webView]; and
- (void) hideGradientBackground:(UIView*)theView
{
for (UIView * subview in theView.subviews)
{
subview.backgroundColor = [UIColor clearColor];
if ([subview isKindOfClass:[UIImageView class]])
subview.hidden = YES;
[self hideGradientBackground:subview];
}
}
I hope this may help you.
You can implement it using UITextViewDelegate and ContentInset.
- (void)viewDidLoad
{
self.textView.delegate = self;
[self.textView addSubview:self.addedView];
[self.textView setContentInset:UIEdgeInsetsMake(0, 0, CGRectGetHeight(self.addedView.frame), 0)];
}
- (void)textViewDidChange:(UITextView *)textView
{
NSLog(#"%#",NSStringFromCGSize(textView.contentSize));
__weak typeof(self) wself = self;
[UIView animateWithDuration:0.5f animations:^{
[wself.addedView setFrame:CGRectMake(0, textView.contentSize.height + 10, CGRectGetWidth(wself.addedView.frame), CGRectGetHeight(wself.addedView.frame))];
}];
}

How to make Autoresize property work in Xcode 4.3?

I recently updated to Xcode 4.3 and it disabled my UILabels' autoshrink property. I rechecked the boxes in IB and rebuilt the project but it is still cutting off the text. Any suggestions? Is this a known bug? Is there a way to fix this programatically.
I'm seeing the same thing. You can work around it programmatically (I do it in viewDidLoad):
myLabel.adjustsFontSizeToFitWidth = YES;
I had the same problem. Here's the fix, I added it to a utility method, since I have over 100 xibs in my project, and a bunch of them needed fixing. Works great.
Add this to Utility.m:
// UIView+viewRecursion.h
#interface UIView (viewRecursion)
- (NSMutableArray*) allSubViews;
#end
// UIView+viewRecursion.m
#implementation UIView (viewRecursion)
- (NSMutableArray*)allSubViews
{
NSMutableArray *arr=[[NSMutableArray alloc] init];
[arr addObject:self];
for (UIView *subview in self.subviews)
{
[arr addObjectsFromArray:(NSArray*)[subview allSubViews]];
}
return arr;
}
#end
And this:
+(void)fixLabels:(UIView *)theView{
for(UIView *v in [theView allSubViews])
{
if([v isKindOfClass:[UILabel class]])
{
if( !((UILabel*)v).adjustsFontSizeToFitWidth ){
((UILabel*)v).adjustsFontSizeToFitWidth=YES;
// NSLog(#"fixed %#", theView);
}
}
}
}
And then call fixLabels from viewDidLoad for any view that has UILabels that are not auto shrinking:
[Utility fixLabels:self.view];
I have the exact opposite problem! I updated to Xcode 4.3, and now it auto shrinks the text in my tableview cells when I want them to truncate them with the ellipses. I went through the storyboard and modified all of the options that might have to do with that, but it refuses to do what I want. So frustrating.
Edited...
Try and re-create what Xcode was doing to me since it's the reverse of what's happening to you. Highlight the prototype cell you have for your tableview in the storyboard and click on the "Title" and "Subtitle" words. You can find the AutoShrinking property within the attributes inspector, and I suppose you can fix your issue by unchecking this box and rebuilding your app. Very strange how the Xcode upgrade would cause this. It also caused my app to behave a bit strangely (i.e. crashing unexpectedly while running in the simulator), but a few clean and rebuilds solved this. Hopefully you are able to fix this, since I know it was just as frustrating for me!
It just did the same thing to me. All the autoshrink are turned off. Putting back a font size and turning auto shrink on didn't actually work.
I had to fix it programmatically as JLundell suggested.
Xcode 4.3 doesn't respecting the Interface Builder Settings for adjustsFontSizeToFitWidth property.
You can fix it by setting the property value programmatically as JLundell suggested.
myLabel.adjustsFontSizeToFitWidth = YES;
It has been fixed up in 4.3.1

UIScrollView scrollRectToVisible isn't doing anything

I'm not really sure why this isn't working, hopefully you can help me find the missing piece. I have a UIScrollView with paging enabled. I'm using it for side-scrolling through a tutorial. I have a button that when tapped should scroll the user back to the beginning of the tutorial. I originally tried using the scroll view's frame as the rect to scroll to because that CGRect should represent the first page. I've tried a couple of different CGRects to no avail though.
- (IBAction) touchedButtonReturnToBeginning:(id)sender {
// I've tried several CGRect's, none of which cause the UIScrollView to move.
// CGRect beginning = self.containerScrollView.frame
// CGRect beginning = self.containerScrollView.bounds;
CGRect beginning = CGRectMake(0, 44, 1, 1);
[self.containerScrollView scrollRectToVisible:beginning animated:YES];
}
I have verified that self.containerScrollView is hooked up in my xib as well as the touchedButtonReturnToBeginning action is connected to my button. I've used my debugger to step through this method, so I have verified that it is getting called. All of the variables are appropriately set, but when I call scrollRectToVisible the scroll view just doesn't do anything.
Any ideas?
I don't know why that wouldn't work, but have you tried [self.containerScrollView setContentOffset:CGPointZero animated:YES]?
To make scrollRectToVisible works check your self.containerScrollView.contentSize. It should be big enough :)

UISwitch - change from on/off to yes/no

does anyone know of a way I can change the text label for on and off to yes and no.
I did it with
((UILabel *)[[[[[[switchControl subviews] lastObject] subviews] objectAtIndex:2] subviews] objectAtIndex:0]).text = #"Yes";
((UILabel *)[[[[[[switchControl subviews] lastObject] subviews] objectAtIndex:2] subviews] objectAtIndex:1]).text = #"No";
However, with the release of iOS 4.2, this is no longer supported (this probably wasn't recommended by Apple anyway)
My client is insisting on yes/no switches. I'd appreciate any advice!
many thanks
Hurrah! From iOS 6, it's possible to specify an image to be used for the on / off states, respectively. So, this can be used to display a YES / NO image (or whatever image representing the text you would prefer to use instead of the previously limited ON / OFF).
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"6.0"))
{
[mySwitch setOnImage: [UIImage imageNamed:#"UISwitch-Yes"]];
[mySwitch setOffImage:[UIImage imageNamed:#"UISwitch-No"]];
}
The images should be 77 px wide, 27 px high, and the text (one image for each state) should be horizontally centred within that 77 px width. I use transparent backgrounds for the text, so I can still make use of the tint for the background, which still works with this.
Of course, it would seem easier to just supply text, rather than having to use an image of text, but I'm certainly grateful for this new option, at least.
You need to implement your custom UISwitch for that. Or use one of already implemented :) (check this SO question and this post)
Vladimir answer is great, but in my humble opinion there is an even better implementation here: https://github.com/domesticcatsoftware/DCRoundSwitch.
Besides setting a custom text, it is easier to change the size and color of the UISwitch and you get a sharper result.
It is released under an MIT license. Have a look!
It turns out that you can create a custom UISwitch with the following items:
A UIScrollView
A UIButton
Two UILabels
A background image
A Boolean value
First you will need to add QuartzCore.framework to your project and #import <QuartzCore/QuartzCore.h> to your view controller.
Next add the UIScrollView to your view using Interface Builder. The ScrollView will be your custom UISwitch.
Next add the button and the two labels to your ScrollView. One label will be for "yes" the other for "no".
Add the image to the button and set its type to custom. This is the image I use:
Position the labels over the blue and white area of the image. Adjust the ScrollView so it is just big enough to show the blue part of the image and the thumb nob.
Add the following line to viewDidLoad:
self.mySwitch.layer.cornerRadius = 13.5;
mySwitch is the name of the ScrollView and 13.5 is half the height of the ScrollView. The above statement changes the ScrollView to have rounded ends like the UISwitch.
To make the custom switch active you will need to tie the buttons "Touch Up Inside" event to an IBAction. Here is the code I use in the event handler:
-(IBAction)mySwitchButton:(id)sender {
self.myValue = !self.myValue;
CGPoint scrollPoint = CGPointMake((self.myValue)? 43.0: 0, 0.0);
[mySwitch setContentOffset:scrollPoint animated:YES];
}
Where myValue is the boolean variable that contains the state of your switch and 43.0 is the number of points you will have to move the image over to put the switch in the off position.
That is all there is to it!
From iOS 6, it's possible to specify an image to be used for the UISwitch on / off states, but NOT the text.
This will lead trouble when internationalization is required because translators
have to provide an image text for each language, not text only.
Moreover, the size of the UISwitch image is fixed, limiting the text length.
Because of the above reasons, I like the JSWilson's answer: simple and flexible.
To relieve developers of the need to manually add the required controls, I coded a custom CRDScrollSwitch class that you can find at my GitHub repository:
https://github.com/corerd/CRDScrollSwitch

iPhone OS: Tap status bar to scroll to top doesn't work after remove/add back

Using this method to hide the status bar:
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:YES];
When setting "hidden" back to NO, the tap-to-scroll-to-top (in UIWebView, UITableView, whatever) doesn't work any more, and requires a restart of the app to get the functionality back.
Is this a bug (I filed a rdar anyhow) or have I missed a step? Should I perhaps expect this behavior since the statusBar "loses touch" somehow with the respective view?
You could try setting the ScrollsToTop property to true again after re-showing it:
[currentView setScrollsToTop:YES];
If that's not working, are you definitely only showing one view? If there is more than one scrolling view a scrollViewDidScrollToTop message is ignored...
In iOS 5.0 you can access the scrollview property of the UIWebView
webView.scrollView.scrollsToTop = YES;
The following fix by Alex worked for me. Thanks!
((UIScrollView *)[[webView subviews] objectAtIndex:0]).scrollsToTop = NO;
Being in a hurry this fix worked great, however given more time I might've subclassed the UIWebView and accessed the protected UIScrollView member directly.
The worry I have with Alex' method is that it assumes that UIScrollView is at index zero of the subviews (encapsulation allows private members to change). Which suggests another solution still:
for (UIView* v in [webView subviews])
{
if ([v isKindOfClass:[UIScrollView class]])
{
(UIScrollView *)v.scrollsToTop = NO;
}
}
I was having a similar problem where the scroll-to-top functionality was lost. Turns out this will only work when you have only one active view at a time (within the same scroll view). In my case I had a table view and another view which would fade in/out. Adding a removeFromSuperview at the end of the animation did the trick.
The answer was in the UIScrollView.h file comments:
/*
this is for the scroll to top gesture. by default, a single scroll visible scroll view with this flag set will get the call. if there is more than one visible with this
flag set or the delegeat method returns NO, the view isn't scrolled
*/
#property(nonatomic) BOOL scrollsToTop; // default is YES. if set, special gesture will scroll to top of view after consulting delegate
You can use the following code to have the UIWebView ignore scrollToTop without the extra UIScrollView:
((UIScrollView *)[[webView valueForKey:#"_internal"] valueForKey:#"scroller"]).scrollsToTop = NO;
I had a similar problem after playing a Youtube video within my app. scrollsToTop was still set to YES but tapping the status bar had no effect.
I finally realised that my app window was no longer the key window. After adding the following line to a UIWindow subclass (which I already had for other reasons) everything worked as it should again:
if (![self isKeyWindow]) [self makeKeyWindow];
I just ran across a similar behavior in the app I'm currently working on. In its case, if you load a YouTube video from within a UIWebView, scroll to top stops working for the rest of the application's life cycle. I kind of assume this might happen after loading the movie player as well, but haven't confirmed. That functionality has been around a lot longer and probably has fewer bugs.
When there are multiple scrollview, you can also set scrollUpToTop to NO for the others scrollview. cf:
setScrollsToTop with multiple UIScrollView classes and/or subclasses(UITableView)
I want to add my case, I add an UIWebView on an UIScrollView, as h4xxr had answered on the top:
If there is more than one scrolling view a scrollViewDidScrollToTop message is ignored
So, I get a simply way to make it work on webView: just set the scrollView·s scrollsToTop property false.
And when tap the status bar, it won`t got intercepted by the scrollView, and the webView scrolls to the top!
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.frame = self.view.bounds;
scrollView.scrollsToTop = false; //igore scrollView`s scrollsToTop
[self.view addSubview:scrollView];
UIWebView *webView = [[UIWebView alloc] init];
webView.frame = scrollView.bounds;
[scrollView addSubview:webView];