iOS: how to change the size of the UIScrollView content? - iphone

I'm now trying to create my own Text panel (with code highlighting and so on).
In fact everything is ready except one thing - scrolling
What I've done:
created UIScrollView and inserted my own view as a subview using Interface builder.
in ViewController viewDidLoad method I've pointed initial textfield size to be the UIScrollView content size.
And when user writes too much into my text field. I call delegate (which is ViewController) to change size.
To do that I simply write
[scrollView setContentSize:newSize];
And what I get is increasing of the scroll view but not my text field - just blank lines appears. I think I need to set my view's size too but I can't figure out how...
And a second part of my question:
Every time I call [textField setNeedsDisplay] it calls drawRect: method with rectangle which is equal to the whole size of my view (which is much bigger than it's visible part). What will it look like if I try to use my view to modify file which size is more than 3 mb? How can I force it to redraw only visible part?
Thanks for your attention.

Part 1:
The scroll view's content size is not actually related to the size or position of the views it contains. If you want to change the size of the content view as well as the scroll view's content, you need to call two different methods.
CGSize newSize;
UIScrollView *scrollView;
// assume self is the content view
CGRect newFrame = (CGRect){CGPointZero,newSize}; // Assuming you want to start at the top-left corner of the scroll view. Change CGPointZero as appropriate
[scrollView setContentSize:newSize]; // Change scroll view's content size
[self setFrame:newFrame]; // Change views actual size
Part 2:
setNeedsDisplay marks the entire view as needing display. To cause it to display only the visible part, you need to use setNeedsDisplayInRect:visibleRect.
Assuming the view is at the top-left corner (its frame's origin is 0) and the scroll view does not allow zooming, the visible rect can be found using the scroll view's content offset and bounds size.
CGRect visibleRect;
visibleRect.origin = [scrollView contentOffset];
visibleRect.size = [scrollView bounds].size;
[self setNeedsDisplayInRect:visibleRect];
You could also choose to draw a part of the visible rect if only part changes.

It's simpler than you think, for example you have an UITextView called "textDesc" inside your UIScrollView, and you want to know the size of content, so next step will looks like that:
int contentHeight = textDesc.frame.size.height + textDesc.frame.origin.y;
After calculating the size of textDesc, just set it:
[scrollView setContentSize:(CGSizeMake(320, contentHeight))];
That's all, now your scrollView know the size of your text inside him, and will resize automatically, hope this helps, good luck.

Set your text field autoresizingMask property to flexible height and width:
[textField setAutoResizingMask:UIViewAutoResizingFlexibleHeight | UIViewAutoResizingFlexibleWidth];
This should expand the view automatically when you change it's parent's size (the scrollView's contentSize)
Otherwise try:
[textField setFrame:CGRectMake(0, 0, scrollView.contentSize.width, scrollView.contentSize.height)];
just after you change the scroll view's contentsize.

Related

UITableView contentInset makes table view scroll horizontally in addition to vertically

I'm creating a UITableViewController in code and pushing it on top of the navigation stack.
It's table view is intended to just show a simple list of text items.
I need to add some contentInset to my table view which I add in the init method of my UITableViewController
self.tableView.contentInset = UIEdgeInsetsMake(7.0f, 5.0f, 7.0f, 5.0f);
However, when I load the table view it seems the left and right contentInset have actually stretched the width of my table view by 10. I'm now seeing a small horizontal scrollable area. I don't want any sort of horizontal scrolling on my table view. If I remove the contentInset code, my table view behaves plainly i.e. simply provides for vertical scrolling. How I can keep just like that but with my contentInset in place? I tried reducing my contentSize.width by 10 in viewWillAppear, it had no effect.
This seems to be a duplicate but with no acceptable answer: UITableView ContentInsets scrolling content horizontally
In the mock I have marked the desired contentInset with dashed line ---
Thanks.
I ended up setting just the top and bottom insets. To achieve the left and right inset look and feel, I created custom cell as wide as the screen. But the actual cell content was restricted to a slightly narrower subview within the custom cell. Thus, there was space leftover on the left and right of the subview.
Looks like you need to do 2 things:
Add the table view to a container view and make the table view frame thinner (to add the left and right borders).
Add thecontentInset only for the top and bottom.
Maybe you should set the bounces property of the scrollView to YES.
And do not set the contentInset.
Another way that could work, is that, instead of setting the tableView frame, you can set the frame for cell's contentView , something like this,
- (void) layoutSubviews
{
[super layoutSubviews];
CGRect frame = self.contentView.frame;
frame.size.width = frame.size.width * 0.9; //90% of total width
frame.origin.x = self.center.x - (frame.size.width/2); //center the contentView
self.contentView.frame = frame;
}
The using the above, u can add any left or right or left padding u need for the cell. and all the subViews will be added to the contentView , hence no problems there.
happy coding..!

Adding buttons dynamically to a UIScrollView which changes to fit the number of buttons using Objective-C

I have an array which loads in a database depending on what button the user chooses. How can I add these buttons to a scroll view which is only as large as it needs to be to hold all the buttons? I know I can declare the size of the scroll view, but I don't want it to be too large so that it can fit a large number of buttons then have lots of empty space if a smaller array is used to create less buttons. Is there an easy way to do this?
I assume you can figure out the vertical height required to display the number of buttons to be displayed before adding them to the scrollview.
If so, at the time of adding a fresh set of buttons, or 'refreshing' the scrollview, I guess you can simply set the correct contentSize of the scrollview.
Check the UIScrollView reference for #property(nonatomic) CGSize contentSize
You can do it in two ways .
Either you can change the frame of the scrollview dynamically
myScrollView.frame = CGRectMake(x, y, newWidth, newHeight);
or you can change the contentSize of the scrollView dynamically keeping the frame constant.
myScrollView.contentSize = CGSizeMake(newWidth, newHeight);

iPhone UIScrollView how to properly zoom the view? Currently it's height is not adjusted properly

I have a UITableView within a UIScrollView. It took me quite a lot of work to make it work.
The tableView is 640x350, I use the scroll view to scroll from one end of the cell to the next.
The scroll view is 320x350.
The scroll view's content size is 640x350
I'm running into this problem:
if I set scrollView's minimum zoom scale to 0.5, the tableview's width now fills the screen, but it's height is only half the screen. I would like the tableview to show more rows when I zoom out to 0.5.
First of all I would like to understand if this is the correct behavior, or the result of my tableView's content size and frame manipulations. The tableview has all springs and struts set in interface builder and should fill the frame available. This is my first attempt at zooming in months, and I don't remember how it works with zooming.
Can someone help me understand where and what do I need to adjust?
As far as I understand, I need to put the code into scrollViewDidZoom: that will manipulate the tableView's frame and content size.
PS. I"m returning the tableview from the viewForZooming: method of UIScrollView
What you are trying to achieve is pretty hard.
Solution 1 This solution uses the exact setup you have (UITableView inside UIScrollView).
You say that when you set the zoomScale to 0.5, you want your table view to fill the scrollView vertically. At 0.5, your table view must be 640x700 in order to fill the UIScrollView as you wish. For this to happen, on scrollViewDidZoom: you must resize the frame of the table view to 640x700
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
// No matter what the zoomScale is, the tableView will be zoomed accordingly
// Only zoom the height of the table
tableView.frame = CGRectMake(0, 0, 640, 350 / zoomScale);
// Also, update the contentSize
scrollView.contentSize = CGSizeMake(640, 350 / zoomScale);
}
If you run the code above for zoomScale = 0.5 you will get a frame size of 640x700.
This only changes the frame of the table and doesn't change the heights of the cells. This means that as you zoom out, you will also see more cells in the tableview.
Solution 2 Use only UITableView
UITableView is a subclass of UIScrollView. This means it has the ability to zoom and scroll around.
Start with a UITableView with the size that you want on the screen. Then, after the content is loaded modify the contentSize and make it wider than your frame width. This should enable horizontal scrolling.
However, UITableViewCells have their frame set automatically to the width of the tableview frame. You can bypass this by using a custom UITableViewCell, with clipsToBounds=false. Inside it you will insert a UIView with the frame set to the width&height you desire and with no autoresizingMask. When the tableview will resize UITableViewCell frame, this will not affect your inner UIView.

How do you programmatically force a scroll using UIScrollView?

I have a horizontal UIScrollview set up (meaning its not one that scrolls up and down but one that only scrolls left-right) and upon the app launching, I want this scrollview to scroll itself left, then right - kind of "demonstrating" its ability to scroll - and finally then stop, letting the user then take over and control the scroll manually with their finger.
Everything works - except for this on-load left-right demo-scrolling.
I'm not using Interface Builder for any of this, I'm doing everything with code:
//(this is in viewDidLoad:)
// Create the scrollView:
UIScrollView *photosScroll = [[UIScrollView alloc] initWithFrame: CGRectMake(0, 0, 320, 200)];
[photosScroll setContentSize: CGSizeMake(1240, 200)];
// Add it as a subview to the mainView
[mainView addSubview:photosScroll];
// Set the photoScroll's delegate:
photosScroll.delegate = self;
// Create a frame to which to scroll:
CGRect frame = CGRectMake(10, 10, 80, 150);
// Scroll to that frame:
[photosScroll scrollRectToVisible: frame animated:YES];
So the scrollView loads successfully and I'm able to scroll it left and right with my finger - but it doesn't do this "auto-scroll" like I was hoping it would.
I tried calling the scrollRectToVisible before and after adding the
scrollView as a subview - didn't work.
Thinking maybe this should
happen in loadView and not in viewDidLoad? But if so, how?
Any ideas?
A couple of ways to do this:
Use scrollRectToVisible:animated: for a zero X value and then a largeish positive one, then set it back to your middle point. You can call the method after the scroll view is added as a subview (probably before too, but best be safe). You'll need to calculate what value of X is off-screen to the left using your contentSize and knowledge about how wide your various elements inside the scroll view are.
Since you're just doing a quick animation and will give the user control, this can really be a quick-and-dirty animation, so you could use setContentOffset:animated: to force the content of the scrollview to move relative to your current view position. Move the elements right for a left scroll (positive X value), then left twice as far for a right scroll (negative X value), then set the offset back to zero.
You shouldn't put either of these in viewDidLoad or loadView; put them in viewDidAppear, which is after your scrollview is actually drawn on screen. You only care about animations when the user can see them!

UIScrollView won't scroll!

In IB I have my UIView. Then I have a sub-UIView with a UIScrollView as a sub view. Then the UIScrollView has a sub-UIImageView. The UIScrollView and UIImageView are the same size. They're much bigger than the UIView of which they are subviews. I assumed this would make scrolling work. It doesn't. Is some sort of code required for scroll views to work?
You need to set UIScrollView.contentSize to match the total scrollable size, which is your subview frame size in this case.
As mentioned in the accepted answer, you must set the UIScrollView's contentSize property.
This can be done in Interface Builder.
Select the scroll view
Select the 'identity inspect' in Utilities pane on the right
Under 'User Defined Runtime Attributes' click the '+' button
Set the 'Key Path' value to 'contentSize'
Set the 'Type' value to 'Size'
Set the 'Value' value to '{width, height}' (eg: '{320, 600}')
Build and run and your scroll view will scroll.
The content inset does not affect scrolling. See What's the UIScrollView contentInset property for?
To scroll, you have to make the scrollview's frame smaller than its content, the contained image or view.
This might be obvious to most, but I spent ages wondering why my UIScrollView wouldn't scroll so I'm posting what was stopping me in case it helps anyone else:
The UIScrollView has to be of the dimensions of the visible area in which you wish it to be presented and not the size of it's contents.
Ridiculous on my behalf I know, but just in case it helps someone.
I placed all the content of my scrollview in IB. (buttons, labels, text fields, etc). The full size is 500 tall.
I then resized it to 436 tall in IB.
Then in code, I put this is viewDidLoad:
optionsScrollView.contentSize = CGSizeMake(320,500);
So that leaves 64 pixels that I can scroll. It works perfectly.
I also placed "UIScrollViewDelegate" in the <> braces of #interface for my .h file and tied the delegate outlet of the scrollview to File's owner in IB.
I could solve the scrolling problem with the following answer:
https://stackoverflow.com/a/39945124/5056173
By me the trick was:
You now need to set the height of the content UIView. You can then either specify the height of the content view (blech) or use the
height of the controls contained within by making sure the bottom
control is constrained to the bottom of the content view.
I have set the height and width of the view inside the scrollView with center vertical and horizontal alignment and that was the reason, why it did not work!
After deleting this constraints, I need to add equal width (scrollView and the view inside the scrollView) AND I set the height of the view inside the scrollView directly with the content. Which means: The last element in the view must have a bottom constraint to the view!!
The other important thing that I don't see mentioned here is that UIScrollView does not play nicely with AutoLayout. If it seems like you've done everything correctly, check if your ViewController has autolayout turned on and, if so, turn it off.
(Every time you scroll, the views are re-laid-out. Gak!)
So:
Make sure scrollview's contentSize is bigger than its frame.size
Make sure AutoLayout for the ViewController is turned off.
more, did you enable scrolling?
look at the property
#property(nonatomic, getter=isScrollEnabled) BOOL scrollEnabled
Make sure 3 things,
checking scrollView frame & contentView frame, u may find the answer
scrollView.isScrollEnabled = true
contentView of scrollView height didn't constraint with scroll view height
UIScrollView won't scroll!
reason: contentSize is same as (sub) view
should: contentSize is large than (sub) view
-> UIScrollView can scroll
how set UIScrollView contentSize?
two method:
in code
- (void)viewDidLoad {
[super viewDidLoad];
。。。
//[(UIScrollView *)self.view setContentSize:CGSizeMake(375, 1000)];
CGSize curScreenSize = UIScreen.mainScreen.bounds.size;
CGFloat scrollWidth = curScreenSize.width;
CGFloat scrollHeight = curScreenSize.height * 2;
[(UIScrollView *)self.view setContentSize:CGSizeMake(scrollWidth, scrollHeight)];
in UI (Storyboard)
Storyboard-》Identity Inspector-》User Defined Runtime Attributes-》 add new attribute:
contentSize
Type:Size
Value:{375, 1000}
Scroll view works with this:
Frame
then
contentSize
views or objects etc...
If your frame is set to your content size then it won't scroll.
So set your frame ( in IB right panel -> second last tab 'Size Inspector") to the length of your app ( in my case it is 367 as i have a navbar and a tab bar) then programatically set the contentSize to - yup you guessed it ... more than your frame so it can scroll.
Happy days!!