Hello: I'm building an app that supports iOS 6 and higher. I have a few UITextViews throughout the app, and I noticed that on iOS 6, the text views are able to be scrolled horizontally. On iOS 7, they can only be scrolled vertically. Is there a way to restrict scrolling so that it will only scroll vertically?
I've checked out some other similar questions, but I don't want to add a UILabel to a UIScrollView.
Any help is much appreciated!
EDIT
When using the following two lines (per the answers suggested), this still doesn't work when setting content insets. Anyone know how to fix this?
Attempt to disable scroll:
tView.contentSize = CGSizeMake(tView.frame.size.width, tView.contentSize.height);
tView.showsHorizontalScrollIndicator = FALSE;
Insets:
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
tView.contentInset = UIEdgeInsetsMake(kTextViewInsets, kTextViewInsets, kTextViewInsets, kTextViewInsets);
} else {
tView.textContainerInset = UIEdgeInsetsMake(kTextViewInsets, kTextViewInsets, kTextViewInsets, kTextViewInsets);
}
I would subclass UITextView and override setContentOffset:
- (void)setContentOffset:(CGPoint)contentOffset
{
super.contentOffset = CGPointMake(0.0, // Ignore the passed offset. Could also use self.contentOffset.x
contentOffset.y);
}
Try this -
mytextView.contentSize = CGSizeMake(mytextView.frame.size.width,HEIGHT_YOU_WANT);
mytextView.showsHorizontalScrollIndicator = NO;
ALso take a look at SO Question may it help you.
Related
I am building an iOS Today widget, and while testing for iOS 10, I see a "Show More" / "Show Less" button on the top right of the widget header. How can I remove this button? I am using Objective-C.
In iOS 10, as far as I know, the show more option is new and we cannot remove it, but we can modify it as needed.
The following code will allow you to automatically size the Today widget. Just change the table or collection view or whatever you used in your project.
static CGFloat padding = 25.0;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
// This will remove extra separators from tableview
self.articleTableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
// Add the iOS 10 Show More ability
[self.extensionContext setWidgetLargestAvailableDisplayMode:NCWidgetDisplayModeExpanded];
}
- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize {
if (activeDisplayMode == NCWidgetDisplayModeCompact){
// Changed to compact mode
self.preferredContentSize = maxSize;
}
else{
// Changed to expanded mode
self.preferredContentSize = CGSizeMake(self.articleTableView.contentSize.width, self.articleTableView.contentSize.height + padding);
}
}
In viewDidLoad you can set the largest available display mode.
[self.extensionContext setWidgetLargestAvailableDisplayMode:NCWidgetDisplayModeCompact];
This will remove the Show More/Less button, but it may not be what you want. The maximum allowed size for the compact view is fairly small.
You can implement:
-(void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize
to update your preferredContentSize. The maxSize parameter will be the maximum allowed size for the activeDisplayMode.
-[NCWidgetProviding widgetActiveDisplayModeDidChange:withMaximumSize:]
Is probably what you're looking for, I would reference this
Sadly you cannot hide it and should conform to the
widgetActiveDisplayModeDidChange:withMaximumSize:
widgets that doesn't show this control were not build for iOS10
I know the original post mentions using objective-c
but in the event anyone needs the swift answer, here it is
override func viewDidLoad()
{
super.viewDidLoad()
self.extensionContext?.widgetLargestAvailableDisplayMode = .compact
}
When set to compact, the app will only support compact mode i.e. show less/show show buttons/functionality will be gone.
here's some documentation for more info
Placing this line of code inside the widgetActiveDisplayModeDidChange delegate method solved my problem.
[self.extensionContext setWidgetLargestAvailableDisplayMode:NCWidgetDisplayModeExpanded];
If you wanna hide the show more/ show less option replace NCWidgetDisplayModeExpanded with NCWidgetDisplayModeCompact.
- (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode
withMaximumSize:(CGSize)maxSize {
[self.extensionContext setWidgetLargestAvailableDisplayMode:NCWidgetDisplayModeExpanded];
}
I am doing a test project, and came across a problem with UITextView.
I am dynamically getting the content size of the text in the text view, and then increasing its height when needed. When the height reaches the threshold I have set, I will set scrollEnabled = YES to enable scrolling. Weird thing seems to happen as shown in the following screen shots:
Before going to new line and enabling scrolling:
After entering the next character, which will enable the scrolling:
After that, entering another character again, the text view will become normal again with scroll enabled (in fact the height remains as in the previous screen shot, I change the height according to content size, so it become the same height before enable scroll):
Anyone has came across this problem and able to solve it? If this is an iOS7 bug, any other suggestion for creating a message input text box? I wonder if previous iOS versions have this problem though.
Edited:
It seems like this problem occurs when the textview's scrollEnabled is YES and change the textview.frame.size.height, then the height will reset to the initial height (as in the height set in Interface Builder). Wonder if this will help for this problem.
The following shows the code used for editing the height of the text view (it is a method for the selector which will be called upon received UITextViewTextDidChangeNotification):
NSInteger maxInputFieldWidth = self.inputTextField.frame.size.width;
CGSize maxSize = CGSizeMake(maxInputFieldWidth, 9999);
CGSize neededSize = [self.inputTextField sizeThatFits:maxSize];
NSInteger neededHeight = neededSize.height;
if (self.inputTextField.hasText)
{
[self.inputTextField scrollRangeToVisible:NSMakeRange([self.inputTextField.text length], 0)];
if (neededHeight <= TEXTVIEW_MAX_HEIGHT_IN_USE && neededHeight != previousHeight)
{
previousHeight = neededHeight;
CGRect inputTextFieldFrame = self.inputTextField.frame;
inputTextFieldFrame.size.height = neededHeight;
inputTextFieldFrame.origin.y = TEXTVIEW_ORIGIN_Y;
self.inputTextField.frame = inputTextFieldFrame;
}
else if (neededSize.height > TEXTVIEW_MAX_HEIGHT_IN_USE)
{
if (!self.inputTextField.scrollEnabled)
{
self.inputTextField.scrollEnabled = YES;
CGRect inputTextFieldFrame = self.inputTextField.frame;
inputTextFieldFrame.size.height = TEXTVIEW_MAX_HEIGHT_IN_USE;
inputTextFieldFrame.origin.y = TEXTVIEW_ORIGIN_Y;
self.inputTextField.frame = inputTextFieldFrame;
}
else if (neededHeight != previousHeight)
{
previousHeight = neededHeight;
CGRect inputTextFieldFrame = self.inputTextField.frame;
inputTextFieldFrame.size.height = TEXTVIEW_MAX_HEIGHT_IN_USE;
inputTextFieldFrame.origin.y = TEXTVIEW_ORIGIN_Y;
self.inputTextField.frame = inputTextFieldFrame;
}
}
}
Over a year later and scrollEnabled is still causing problems. I had a similar issue where setting scrollEnabled = true (I'm using Swift) would not cause any changes.
I solved the problem by setting autolayout constraints on all sides of the textView. Then, like you detailed here, I just set textView.frame again. My guess is that this causes some internal update, which actually turns scrolling on. I'm also guessing that autolayout then forces the textView to stay at the right height, as opposed to the collapse that you're experiencing.
The brilliant Pete Steinberger has had a lot of problems with the UITextView and implemented a lot of fixes as a result.
His article can be found here with links to his code.
For a direct link to the code, it can be found here, but I recommend reading the post.
I ran into a similar issue (I'm using auto-layout) and was able to solve it with the following set up:
Adding top, leading, bottom, trailing margin constraints to my text view
Adding a greater-than-or-equal-to minimum height constraint with priority 999 (in my case this was set to 50)
Adding a less-than-or-equal-to maximum height constraint with priority 1000 (in my case this was set to 125)
Adding an equal-to height constraint with priority 1000 (set to 125) and making sure it's not installed (uncheck the 'installed' option in Interface Builder or set 'active' to NO/false on the constraint in code)
I then use the following code to determine the height of the text view and enable/disable scroll and constraints:
- (void)textViewDidChange:(UITextView *)textView {
...
CGSize size = textView.bounds.size;
CGSize newSize = [textView sizeThatFits:CGSizeMake(size.width, CGFLOAT_MAX)];
if (newSize.height >= self.textViewMaxHeightConstraint.constant
&& !textView.scrollEnabled) {
textView.scrollEnabled = YES;
self.textViewHeightConstraint.active = YES;
} else if (newSize.height < self.textViewMaxHeightConstraint.constant
&& textView.scrollEnabled) {
textView.scrollEnabled = NO;
self.textViewHeightConstraint.active = NO;
}
...
}
Using sizeThatFits: to determine the desired size of the text view, I either set scroll enabled or disabled. If it's enabled, I set the height constraint to active to force the text view to stay at the desired height.
In previous versions of iOS, my UITextView will scroll to the bottom using
[displayText scrollRangeToVisible:NSMakeRange(0,[displayText.text length])];
or
CGFloat topCorrect = displayText.contentSize.height -[displayText bounds].size.height;
topCorrect = (topCorrect<0.0?0.0:topCorrect);
displayText.contentOffset = (CGPoint){.x=0, .y=topCorrect};
But the former will now have the weird effect of starting at the top of a long length of text and animating the scroll to the bottom each time I append text to the view. Is there a way to pop down to the bottom of the text when I add text?
textView.scrollEnabled = NO;
[textView scrollRangeToVisible:NSMakeRange(textView.text.length - 1,0)];
textView.scrollEnabled = YES;
This really works for me in iOS 7.1.2.
For future travelers, building off of #mikeho's post, I found something that worked wonders for me, but is a bit simpler.
1) Be sure your UITextView's contentInsets are properly set & your textView is already firstResponder() before doing this.
2) After my the insets are ready to go, and the cursor is active, I call the following function:
private func scrollToCursorPosition() {
let caret = textView.caretRectForPosition(textView.selectedTextRange!.start)
let keyboardTopBorder = textView.bounds.size.height - keyboardHeight!
// Remember, the y-scale starts in the upper-left hand corner at "0", then gets
// larger as you go down the screen from top-to-bottom. Therefore, the caret.origin.y
// being larger than keyboardTopBorder indicates that the caret sits below the
// keyboardTopBorder, and the textView needs to scroll to the position.
if caret.origin.y > keyboardTopBorder {
textView.scrollRectToVisible(caret, animated: true)
}
}
I believe this is a bug in iOS 7. Toggling scrollEnabled on the UITextView seems to fix it:
[displayText scrollRangeToVisible:NSMakeRange(0,[displayText.text length])];
displayText.scrollEnabled = NO;
displayText.scrollEnabled = YES;
I think your parameters are reversed in NSMakeRange. Location is the first one, then how many you want to select (length).
NSMakeRange(0,[displayText.text length])
...would create a selection starting with the 0th (first?) character and going the entire length of the string. To scroll to the bottom you probably just want to select a single character at the end.
This is working for me in iOS SDK 7.1 with Xcdoe 5.1.1.
[textView scrollRangeToVisible:NSMakeRange(textView.text.length - 1,0)];
textView.scrollEnabled = NO;
textView.scrollEnabled = YES;
I do this as I add text programmatically, and the text views stays at the bottom like Terminal or command line output.
The best way is to set the bounds for the UITextView. It does not trigger scrolling and has an immediate effect of repositioning what is visible. You can do this by finding the location of the caret and then repositioning:
- (void)userInsertingNewText {
UITextView *textView;
// find out where the caret is located
CGRect caret = [textView caretRectForPosition:textView.selectedTextRange.start];
// there are insets that offset the text, so make sure we use that to determine the actual text height
UIEdgeInsets textInsets = textView.textContainerInset;
CGFloat textViewHeight = textView.frame.size.height - textInsets.top - textInsets.bottom;
// only set the offset if the caret is out of view
if (textViewHeight < caret.origin.y) {
[self repositionScrollView:textView newOffset:CGPointMake(0, caret.origin.y - textViewHeight)];
}
}
/**
This method allows for changing of the content offset for a UIScrollView without triggering the scrollViewDidScroll: delegate method.
*/
- (void)repositionScrollView:(UIScrollView *)scrollView newOffset:(CGPoint)offset {
CGRect scrollBounds = scrollView.bounds;
scrollBounds.origin = offset;
scrollView.bounds = scrollBounds;
}
I have two views one is textView and below it is a scrollview, in my application the textView should toggle expand when touch it.I set the "Top Space to: Text View" for scrollView in IB.But When I expand the textView it seems not work.
here is the toggle expand code.
- (void)onTextViewClicked:(id)sender
{
CGRect targetFrame = _descTextView.frame;
if (_isTextViewExpand) {
targetFrame.size.height = _descTextViewNormalHeight;
_descTextView.frame = targetFrame;
_isTextViewExpand = NO;
[_contentScrollView setContentSize:CGSizeMake(320.f, kContentScrollViewDefaultHeight)];
}
else {
targetFrame.size.height = _descTextViewExpandHeight;
_descTextView.frame = targetFrame;
_isTextViewExpand = YES;
[_contentScrollView setContentSize:CGSizeMake(320.f, kContentScrollViewDefaultHeight + ( _descTextViewExpandHeight - _descTextViewNormalHeight ))];
}
}
You need a different approach entirely. With Auto Layout, you should never call -setFrame:. If you want the views to grow you should add a constraint or edit one of the existing constraints and then call either -setNeedsUpdateConstraints or -layoutIfNeeded.
Or just turn off Auto Layout.
I am new to iOS development and I am developing an application which will show and web page in UIWebView. I want to get rid of the default zoom-in and zoom-out functionality of the webview.
This is in the Apple Documentation:
#property(nonatomic) BOOL scalesPageToFit
Discussion
If YES, the webpage is scaled to fit and the user can zoom in and zoom out. If NO, user zooming is disabled. The default value is NO.
Interface Builder Approach:
Make sure that the "Scale pages to fit" tick box in the right-side column of the interface builder when you click on your webview is un-ticked. It's right at the top.
You're also going to need to un-tick the box that says "Multiple Touch" around half way down. That will disable pinching to zoom.
Code Approach:
You can also do it programmatically with this code:
webView.scalesPageToFit = NO;
You're also going to want to add:
webView.multipleTouchEnabled = NO;
That will disable the ability to pinch and zoom, since it disables the ability to use multiple fingers in an action, and pinching requires two, obviously!
set the UIWebView property scalesPageToFit to NO, will disable the user zooming
myWebView.scalesPageToFit = NO;
One simply needs to do:
myWebView.scalesPageToFit = NO;
and also disable the pesky pinch to zoom:
webView.multipleTouchEnabled = NO;
For me the ideal solution was, surprinsingly, in the html side only. Just add this in <head>:
<meta name="viewport" content="user-scalable=0" />
I don't recommend to use webView.scalesPageToFit = false because it brings issues like making everything 4x bigger. I also did not use initial-scale=1.0, maximum-scale=1.0 nor minmum-scale=1.0
UIScrollView *scrollView = [webView.subviews objectAtIndex:0];
scrollView.delegate = self;//self must be UIScrollViewDelegate
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return nil;
}
try this ... It works..
Disable bouncesZoom of the scrollView will solve your problem. Give it a try!
webView.scrollView.bouncesZoom = false
When inheriting from UIWebView you can implement. (Works from iOS 5, lower not sure)
- (UIView *) viewForZoomingInScrollView:(UIScrollView *) scrollView
{
return nil;
}
Try this:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return nil;
}
Swift Solution
Simply set the value mentioned above to false: webView.scalesPageToFit = false
To add to the answers, this will work:
webView.scrollView.multipleTouchEnabled = NO;
i am also struggle at first when i use webview scroll event after that i fond the below code for disable the scroll in webview and this also remove the multitouch gestures function in that particular webview.
[[[theWebView subviews] lastObject] setScrollEnabled:NO];
here theWebView is the name of my UIWebView..
use this code in webViewDidFinishLoad function ,,, its really helpful to me,..