I met a really strange problem while using UITextView, I try to use "GrowStyle" of UITextView, wire up the frame with contentSize, turn off the .scrollEnabled, Build & Run: but when click the bottom of the screen, the keyboard showing up, the UITextView moves up a short distance, and its Top lines disappear, here is the code:
- (void)viewDidLoad {
[super viewDidLoad];
//Turn off the scrollEnabled.
UITextView *growStyleText.scrollEnabled = NO;
//Wire the growStyleText's contentSize to its frame, let it grow.
CGRect selfHack = growStyleText.frame;
selfHack.size = growStyleText.contentSize;
growStyleText.frame = selfHack;
//Make a UIScrollView
UIScrollView *scroll.contentSize = selfHack.size;
scroll.clipsToBounds = NO;
[self.view insertSubview:scroll atIndex:1];
//Add the TextView on the ScrollView, make it scrollable.
[scroll addSubview:growStyleText];
}
After click the last line, Keyboard shows up, then the Top line Disappears! I thought about for all day long, anybody seen this? how can I make Top line moves up instead of disappear? hard question for me, guess there may be simple answers, thank you, very much.
I don't know what you are trying to do, but, since UITextView is a subclass of UIScrollView, why do you need to create it as a subview of a UIScrollView?
Then, in my experience, you can't get the contentSize of a UIScrollView before you add it to a view.
I found this answer very useful
How do I size a UITextView to its content?
Hope it helps.
Related
My UIScrollView is a ~4500px horizontal view that the user needs to scroll horizontally through to view the content.
I have set it up as follows:
- (void)viewDidLoad
{
[super viewDidLoad];
sview.frame = CGRectMake(0, 0, 568, 320);
sview.contentSize = CGSizeMake(4500, 320);
[sview setScrollEnabled:YES];
}
Yet the scroll view does nothing. Is there something obvious I missed? i've tried literally every tutorial on the web.
I got similar issue. I did following modifications and the scrollView started scrolling for me:
Select to check the 'Bounce Horizontally' property for UIScrollView
in xib.
Move the code following code to viewDidAppear instead of
viewDidLoad:
-(void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
sview.frame = CGRectMake(0, 0, 568, 320);
sview.contentSize = CGSizeMake(4500, 320);
[sview setScrollEnabled:YES];
}
I think this should help you.
I've explained it here, but there are so many answers to this problem that suggests turning off Auto Layout. That fixes the problem but that's not really the correct solution. Here's my answer:
Turning Auto Layout works, but that's not the solution. If you really need Auto Layout, then use it, if you don't need it, turn it off. But that is not the correct fix for this solution.
UIScrollView works differently with other views in Auto Layout. Here is Apple's release note on Auto Layout, I've copied the interesting bit:
Here are some notes regarding Auto Layout support for UIScrollView:
In general, Auto Layout considers the top, left, bottom, and right edges of a view to be the visible edges. That is, if you pin a view to
the left edge of its superview, you’re really pinning it to the
minimum x-value of the superview’s bounds. Changing the bounds origin
of the superview does not change the position of the view.
The UIScrollView class scrolls its content by changing the origin of its bounds. To make this work with Auto Layout, the top, left, bottom,
and right edges within a scroll view now mean the edges of its content
view.
The constraints on the subviews of the scroll view must result in a size to fill, which is then interpreted as the content size of the
scroll view. (This should not be confused with the
intrinsicContentSize method used for Auto Layout.) To size the scroll
view’s frame with Auto Layout, constraints must either be explicit
regarding the width and height of the scroll view, or the edges of the
scroll view must be tied to views outside of its subtree.
Note that you can make a subview of the scroll view appear to float (not scroll) over the other scrolling content by creating constraints
between the view and a view outside the scroll view’s subtree, such as
the scroll view’s superview.
Apple then goes on to show example of how to correctly use UIScrollView with Auto Layout.
As a general rule, one of the easiest fix is to create a constraint between the element to the bottom of the UIScrollView. So in the element that you want to be at the bottom of the UIScrollView, create this bottom space constraint:
Once again, if you do not want to use Auto Layout, then turn it off. You can then set the contentSize the usual way. But what you should understand is that this is an intended behaviour of Auto Layout.
First of all you have to add some content to UIScrollSiew as subview for scrolling,without content on UIScrollView how can you scroll?. Here is what i did,just add UIImageView to UIScrollView as subview of size same as size of UIScrollView...
In viewDidLoad method try the following code..
-(void)viewDidLoad
{
UIScrollView *scroll=[[UIScrollView alloc] init];
scroll.frame=CGRectMake(0, 0, 320, 460);
UIImageView *imageView=[[UIImageView alloc] init];
imageView.frame=CGRectMake(0, 0, 320,460);
imageView.image=[UIImage imageNamed:#"chiranjeevi.jpeg"];
scroll.contentSize = CGSizeMake(4500, 460);
[scroll setScrollEnabled:YES];
[scroll addSubview:imageView];
[self.view addSubview:scroll];
}
I tested this code it works well.I hope this code will be helpful to you..
I assume you are adding UISrollingView in your Xib file. This will work for you.
sview.delegate = self;
sview.backgroundColor=[UIColor clearColor];
[sview setCanCancelContentTouches:NO];
sview.indicatorStyle = UIScrollViewIndicatorStyleWhite;
sview.clipsToBounds = YES;
sview.scrollEnabled = YES;
sview.contentSize = CGSizeMake(320,570);
CGPoint topOffset = CGPointMake(0,0);
[sview setContentOffset:topOffset animated:YES];
Also, make sure to give IBOutlet connection in your Xib file.
I also faced the same issue.I added the scroll view in xib.I also added some subviews to this scroll view. The scroll view would stop scrolling after I added the subviews. The solution for this problem was in the xib for the view in file inspector Use Autolayout was checked. I unchecked it and the scroll view scrolled after adding the subviews.
The solution was uncheking the Use Autolayout in file inspector in xib.
I'm fairly new to programming, and I have looked for an answer for a very long time. There are some posts about it, but nothing has solved my problem. I have a UIScrollView view that I get from the nib, everything is ok with this, the content length is good and scrolling works, but it just scrolls on the left side, if I try to scroll on the right side it doesn't scroll..
Here is the code,
- (void)viewDidLoad {
[super viewDidLoad];
NSString *descriptionString = _currentBook.description;
CGSize stringSize = [descriptionString sizeWithFont:[UIFont boldSystemFontOfSize:16] constrainedToSize:CGSizeMake(387, 9999) lineBreakMode:UILineBreakModeWordWrap];
_authorLabel.text = _currentBook.author;
_titleLabel.text = _currentBook.title;
_descriptionLabel.text = [NSString stringWithFormat:#"Description: %#",_currentBook.description];
[(UIScrollView *)self.view setContentSize:CGSizeMake(387, stringSize.height +50)];
}
Thanks in advance!
Its hard to understand the problem since we cant see your nib file, but its better practice to put the scrollView on top the view of the view controller, and connect it to an IBOutlet in your view controller.
In order to find the problem I would get rid of the textfields for testing purposes (I think the constrained 9999 might be a problem but I am not sure) and then print and post the frame of the scrollView and the Content size in runtime.I am betting that you will see some issue with the frame of the uiscrollview.
Thanks,
Ok, after copy-pasting and running some tests, I found out the problem.
The problem is in the wording of the question, your problem is not that the "scroll doesn't work on the right side" (As in: you move your finger up and down on the right side of the screen without triggering a scroll), the problem is that the contents, the label itself is going out of bounds, outside of the visible area of the scrollView, and the right-handed side is not visible.
First of all, you should note that the iphone resolution is 320x480 (640x960 for Retina), so you actually have to work with a smaller width (using 387 width will make it go out of bounds).
Second, take in account the x position of the label itself is also affecting the amount of visible text. With this in mind, a more generic code would be:
- (void)viewDidLoad
{
[super viewDidLoad];
// This number represents the total width of the label that will fit centered in
// the scrollView area.
CGFloat visibleWidth = self.view.frame.width - descriptionLabel.frame.origin.x*2;
// Use the number above to get a more accurate size for the string.
NSString *descriptionString = _currentBook.description;
CGSize stringSize = [descriptionString sizeWithFont:[UIFont boldSystemFontOfSize:16] constrainedToSize:CGSizeMake(visibleWidth, 9999) lineBreakMode:UILineBreakModeWordWrap];
// Fill data (why so many underscores?)
_authorLabel.text = _currentBook.author;
_titleLabel.text = _currentBook.title;
_descriptionLabel.text = [NSString stringWithFormat:#"Description: %#", _currentBook.description];
// Also, why didn't you resize the description label? I'm assuming that you forgot this.
// (Make sure that the descriptionLabel number of lines is 0)
CGRect frame = descriptionLabel.frame;
descriptionLabel.frame.size = stringSize;
// Now set the content size, since you're using the scrollView as the main view of the viewController,
// I'll asume that it's using the whole screen, so I'm gonna use the whole width
// of the screen (that's what UIScreen is for).
[(UIScrollView *)self.view setContentSize:CGSizeMake([UIScreen mainScreen].bounds.size.width, stringSize.height +50)];
}
Finally i've found my problem, I've added a uiview programmatically as a subview to some view and then to this View i've added my scroll view as a subview.. And then it would only scroll in the area of my UIView. It was nonsense to do it like this, still a lack of knowledge..
Thank you all for trying to help!
I have seen this question being addressed several times here at SO, e.g Problem with UIScrollView Content Offset, but I´m still not able to solve it.
My iphone app is basically a tab bar controller with navigation bar. I have a tableview controller made programmatically and a DetailViewController that slides in when I tap a cell in my tableview controller.
The DetailViewController is made in IB and has the following hierarchy:
top view => UIScrollView => UIView => UIImage and a UITextField.
My goal is to be able to scroll the image and text field and this works well. The problem is that my UIScrollView always gets positioned at the bottom instead at the top.
After recommendations her at SO, I have made my UIScrollView same size as the top view and instead made the UIView with the max height (1500) of my variable contents.
In ViewDidLoad I set the contentSize for the UIScrollView (as this is not accessible from IB):
- (void)viewDidLoad {
[scrollView setContentSize:CGSizeMake(320, 1500)];
[scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
NSLog(#"viewDidLoad: contentOffset y: %f",[scrollView contentOffset].y);
}
Specifically setting the contentOffset, I would expect my scrollView to always end up at the top. Instead it always go to the bottom. It looks to me that there is some autoscrolling beyond my control taking place after this method.
My read back of the contentOffset looks OK. It looks to me that there may be some timing related issues as the scrolling result may vary whether animation is YES or NO.
A ugly workaround I have found is by using this delegate method:
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrView {
NSLog(#"Prog. scrolling ended");
[scrollView setContentOffset:CGPointMake(0, 0) animated:YES];
}
This brings my scrollview to top, but makes it bounce down and up like a yo-yo
Another clue might be that although my instance variables for the IBOutlet are set before I push the view controller, the first time comes up with empty image and textfield:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (!detailViewController) {
detailViewController = [[DayDetailViewController alloc] init];
}
// Pass dictionary for the selected event to next controller
NSDictionary *dict = [eventsDay objectAtIndex:[indexPath row]];
// This method sets values for the image and textfield outlets
[detailViewController setEventDictionary:dict];
// Push it onto the top of the navigation controller´s stack.
[[self navigationController] pushViewController:detailViewController animated:NO];
}
If I set animation to YES, and switch the order of the IBOutlet setting and pushViewController, I can avoid the emptiness upon initialization. Why?
Any help with these matters are highly appreciated, as this is really driving me nuts!
Inspired of Ponchotg´s description of a programmatically approach, I decided to skip interface builder. The result was in some way disappointing: The same problem, with the scrollview ending up in unpredictable positions (mostly at bottom), persisted.
However, I noticed that the scroll offset error was much smaller. I think this is related to the now dynamic (and generally smaller) value of ContentOffset. After some blind experimenting I ended up setting
[textView setScrollEnabled:YES];
This was previously set to NO, as the UITextView is placed inside the scrollview, which should take care of the scrolling. (In my initial question, I have erroneously said it was a UITextField, that was wrong)
With this change my problem disappeared, I was simply not able to get into the situation with scrollview appearing at bottom anymore in the simulator! (At my 3G device I have seen a slight offset appear very seldom, but this is easily fixed with scrollViewDidEndScrollingAnimation delegate described previously ).
I consider this as solved now, but would appreciate if anyone understand why this little detail messes up things?
OK! i have a question before i can give a correct answer.
Why are you using a UIView inside the Scrollview?
You can always only put your UIImageView and UITextField inside the UIScrollView without the UIView
and set the contentSize dynamically depending on the size of the text.
to give you an example how i do it:
int contSize = 0;
imageView.frame = CGRectMake(10, 0, 300, 190);
imageView.image = [UIImage imageNamed:#"yourimage"];
contSize = 190 //or add extra space if you dont want your image and your text to be so close
[textField setScrollEnabled:NO];
textField.font = [UIFont systemFontOfSize:15];
textField.textColor = [UIColor grayColor];
textField.text = #"YOUR TEXT";
[textField setEditable:NO];
textField.frame = CGRectMake(5, contSize, 310, 34);
CGRect frameText = textField.frame;
frameText.size.height = textField.contentSize.height;
textField.frame = frameText;
contSize += (textField.contentSize.height);
[scrollView setScrollEnabled:YES];
[scrolView setContentSize:CGSizeMake(320, contSize)];
In the above example I first create an int to keep track of the ysize of my view then Give settings and the image to my UIImageView and add that number to my int then i give settings and text to my UITextField and then i calculate the size of my text depending on how long is my text and the size of my font, then add that to my int and finally assign the contentSize of my ScrollView to match my int.
That way the size of your scrollview will always match your view, and the scrollView will always be at top.
But if you don't want to do all this, you can allways just:
[scrollView setContentOffset:CGPointMake(0, 0) animated:NO];
at the end of the code where you set your image and your text, and the NOto avoid the bouncing.
Hope this helps.
EDIT - I've worked out what I was originally doing wrong. I was changing the size of the UIScrollView, instead of the pattern subview. I have fixed that, but amended my question with the new problem this has thrown up.
I am making a notes section in my app with a lined-paper effect. The lines are on a separate UIScrollView which responds to scrollViewDidScroll: so the lines and text always move together. My lines are set up like this in viewWillAppear:
CGRect noteLinesRect = CGRectMake(self.view.bounds.origin.x,
self.view.bounds.origin.y,
self.view.bounds.size.width,
noteTextView.contentSize.height+self.view.bounds.size.height);
UIScrollView *anoteXLinesView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
self.noteXLinesView = anoteXLinesView;
[anoteXLinesView release];
LinePatternView *linesPattern = [[LinePatternView alloc] initWithFrame:noteLinesRect];
self.linesPatternView = linesPattern; [linesPattern release];
[self.noteXLinesView addSubview:self.linesPatternView];
[linesPattern release];
CGPoint newOffset = CGPointMake(self.noteTextView.contentOffset.x, noteTextView.contentOffset.y - NOTE_LINES_OFFSET);
self.noteXLinesView.contentOffset = newOffset;
[self.view insertSubview:self.noteXLinesView atIndex:0];
This works fine when the user first looks at a stored note - all the text is nicely underlined. But when they write more text, eventually they get to the bottom of the lines I created in viewWillAppear and are writing on 'blank paper'. So I need my lined-paper pattern to dynamically get bigger and smaller so it is always a bit bigger than the contentSize of my textView. I am trying to do that like this:
-(void)textViewDidChange:(UITextView *)textView
{
self.linesPatternView.frame = CGRectMake( self.linesPatternView.frame.origin.x, //-self.noteTextView.contentOffset.y+NOTE_LINES_OFFSET,
self.linesPatternView.frame.origin.y,
self.linesPatternView.frame.size.width,
noteTextView.contentSize.height+self.view.bounds.size.height );
}
The problem is, although the lined-paper pattern does increase in size, it doesn't add new lines at the bottom. Instead, the pattern stretches out and gets bigger as the view gets bigger. What am I doing wrong?
One of the solutions is to make 3 views, each containing the lines of the size of your scrollview frame on screen. You position the three one underneath the other in the scrollview and monitor the scrollview through its delegate.
When scrolling down you check:
As soon as the topmost one goes offscreen for more than Y pixels you remove it from the scrollview and insert it underneath the bottom one.
When scrolling up you check:
As soon as the bottommost one goes offscreen for more than Y pixels you remove it from the scrollview and insert it above the top one.
Is there a reason you’re not simply using a tiled pattern as your background view’s backgroundColor? UIColor’s +colorWithPatternImage: will let you set a background that’ll tile indefinitely and won’t stretch as your view resizes. If part of the background has to be different—like the top of your paper, for instance—you can just place an image view containing that at the top of your background view.
Fixed! In addition to the changes outlined in my edit to the question above, I just needed to call [self.linesPatternView setNeedsDisplay]; after the resize.
I have a UIScrollView that shows vertical data, but where the horizontal component is no wider than the screen of the iPhone. The problem is that the user is still able to drag horizontally, and basically expose blank sections of the UI. I have tried setting:
scrollView.alwaysBounceHorizontal = NO;
scrollView.directionalLockEnabled = YES;
Which helps a little, but still doesn't stop the user from being able to drag horizontally. Surely there is a way to fix this easily?
scrollView.bounces = NO;
Worked for me.
That's strange, because whenever I create a scroll view with frame and content size within the bounds of the screen on either dimension, the scroll view does not scroll (or bounce) in that direction.
// Should scroll vertically but not horizontally
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
scrollView.contentSize = CGSizeMake(320, 1000);
Are you sure the frame fits completely within the screen and contentSize's width is not greater than the scroll view's width?
The checkbox for bounce vertically in storyboard-scrollview can simply help...
That works for me in Swift:
scrollView.alwaysBounceHorizontal = false
scrollView.bounces = false
Try setting scrollView.bounces to NO and scrollView.alwaysBounceVertical to YES.
Whether or not a view scrolls (and bounces) horizontally depends on three things:
The content size
The left and right content insets
The width of the scroll view -
If the scroll view can fit the content size plus the insets then it doesn't scroll or bounce.
Avoid horizontal bouncing like so:
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width - scrollView.contentInset.left - scrollView.contentInset.right, height);
I am adding this answer because the previous ones did not take contentInset into account.
Make sure the UIScrollView's contentSize is not wider than the UIScrollView itself. In my own apps this was enough to avoid horizontal scrolling, except in cases where I got really crazy swiping in random directions (e.g., starting a scroll while the view was still decelerating).
If anyone developing for OS X is looking here, as of OS X 10.7, the solution is to set the horizontalScrollElasticity property to false/NO on the scroll view, like this:
Swift:
scrollView.horizontalScrollElasticity = false
Objective-C:
scrollView.horizontalScrollElasticity = NO
Something to keep in mind: You know there's nothing extra to see horizontally, but will your users know that? You may want a little horizontal bounce, even if there's no extra content to show horizontally. This let's the user know that their attempts to scroll horizontally are not being ignored, there's just nothing there for them to see. But, yeah, often you really don't want the bounce.
My version for webViews, a common solution:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[webView.scrollView setContentSize: CGSizeMake(webView.frame.size.width, webView.scrollView.contentSize.height)];
}
You can disable horizontal bounces like this:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.x < 0) {
scrollView.contentOffset = CGPointMake(0, scrollView.contentOffset.y);
} else if (scrollView.contentOffset.x > scrollView.contentSize.width) {
scrollView.contentOffset = CGPointMake(scrollView.contentSize.width, scrollView.contentOffset.y);
}
}
It resets the contentOffset.x manually and won't affect the vertical bounces. It works...
In my case, i just need to set this line:
collectionView.bounces = false