How to dynamically size UITableView in Objective-C? - objective-c

I'm just starting with iOS development and I was trying to achieve something that doesn't seem to work so far for me...
Here's the situation:
I have a nib file in which I have placed a UITableView, and just underneath a UIToolbar. That works just fine, the scaling is fine if I try different screensizes etc... So I was happy.
But here's the problem:
If the toolbar should be visible or not is a choice that a user can make somewhere in the application. However when the users selects to not see the toolbar I just call the method setHidden on the toolbar and pass it 'YES'.
The toolbar is now gone when I try this but the UITableView is not strechted to the bottom of the screen which gives me quite an ugly result.
So here's finally the question:
How can I automatically let the view stretch to the bottom when hiding toolbar? I guess I will have to do it in code (and not just some configuration option somewhere) but as I'm coming from Android this is somewhat strange for me.

Your best option will probably be to resize the tableview frame as you show/hide the tool bar.
CGRect frame = myTableView.frame;
frame.size.height += toolbar.frame.height;
myTableView.frame = frame;

Because you're using Auto-Layout, you'd want to create a height constraint for the UITableView and link it with your view controller via an IBOutlet. Then, to modify the height of the UITableView, simply do:
_tableViewHeightConstraint.constant += toolbar.frame.height;
You can even animate this with:
[UIView animateWithDuration:0.25 animations:^{
_tableViewHeightConstraint.constant += toolbar.frame.height;
}];
Note that you might need to call [_tableView layoutIfNeeded] after changing the height constraint.

Related

Unable to resize a UIView

I'm using xcode 4.5 (incase that makes any difference) along with a Storyboard and I'm trying to do something seemingly very simple without any luck. In my storyboard view I have placed a UIView component as you can see in the image here http://www.shopow.co.uk/assets/storyboard-view.png where the green section is the UIView which has a height of 100
In the viewDidLoad method I've added the following code
NSLog(#"View Height: %f", self.testView.bounds.size.height);
CGRect viewFrame = self.testView.frame;
CGSize newSize = CGSizeMake(viewFrame.size.width, 300);
viewFrame.size = newSize;
self.testView.frame = viewFrame;
NSLog(#"View Height: %f", self.testView.bounds.size.height);
From what I've read about resizing stuff I'd assume the green section to resize to be 300 high however this doesn't happen although the output in the log window shows the following
2012-10-19 13:05:28.015 TableTest[54318:c07] View Height: 460.000000
2012-10-19 13:05:28.016 TableTest[54318:c07] View Height: 300.000000
Notice the initial height being 460 rather than 100 which may mean something!
iOS simulator shows this http://www.shopow.co.uk/assets/simulator-view.png
I must be overlooking something obvious as far as I can tell this is not working as expected. Any guidance would be greatly appreciated.
I'm not sure if it will fix your problem, but you should really do your view resizing in viewWillAppear rather than viewDidLoad.
viewDidLoad literally means what it says, 'the view has loaded'. However, at this point your nib may not have set up the view as you would expect.
As a test, try logging the following in both viewDidLoad and viewWillAppear
NSLog(#"frame: %#", NSStringFromCGRect(self.view.frame));
You should see that in both methods you get different results. The viewWillAppear method is more likely to be correct as the view has been set up and is ready to be presented.
I personally don't use Interface Builder all that much as it causes more headaches than I can deal with but perhaps your auto-resizing masks or elastic constraints are set which is affecting the dimensions of your view?
Like #CaptainRedmuff said, you're calling it in the wrong method. viewDidLoad is called after the view is loaded, which means the frame has already been set. The method you're looking for is loadView, as viewWillAppear:animated and viewDidAppear:animated are being called after viewDidLoad.
OP wasn't really clear how he solved it. In case anyone else is having this problem.
If your view is showing the same layout as what you see in your storyboard despite the fact that you are programmatically resizing/changing its property in some way, this is because auto-layout is causing havoc.
Just select the view that you want to programmatically change and go to File Inspector in the Attributes pane. Deselect the checkbox next to Use Auto layout. Run again and you'll see your problem magically disappear.

iOS PopOver - only from bar button item or round rect?

Im building an iPad app which has a tableview embeded within a UIview (odd, i know). In the UITableview there is data loaded in via a PLIST. I want to allow a user to "select" a row and it would show a "popover" (uiview) containing a textfield allowing them to edit that field.
However, looking through the code i see there are only two ways to fire the function:
presentPopoverFromBarButtonItem
presentPopoverFromRect
IS this true, can you only fire that function from either a round rect or a bar button item? I have a feeling i can be done, however searching has not turned up any answers.
Yes you can only present a popover from a bar button item or from a rect in a view.
From the official doc:
Presenting and Dismissing the Popover
– presentPopoverFromRect:inView:permittedArrowDirections:animated:
– presentPopoverFromBarButtonItem:permittedArrowDirections:animated:
– dismissPopoverAnimated:
Those are the only two ways to present a subclass of UIPopoverController. It is not clear in your question as to why "presentPopoverFromRect" wouldn't work.
I understand that "presentPopoverFromBarButtonItem" is a bit limiting but "presentPopoverFromRect" lets you do whatever you want. It allows you to position a popover relative to a view where the "rect" provides a way to offset the popover relative to the view's frame.
Try:
CGRect popoverRectFromCell = CGRectMake(tappedCell.frame.size.width / 2, tappedCell.frame.size.height / 2, 1, 1);
[cellPopover presentPopoverFromRect:popoverRectFromCell
inView:tappedCell
permittedArrowDirections:UIPopoverArrowDirectionUp
animated:YES];
Of course you can tweak the "popoverRectFromCell" to achieve desired results.
However, I am not sure this is really a use-case for a UIPopoverController. Might be easier to just make a custom view and use that for text input when the user taps a cell.

Change layer of images

Is there a way to change the "layer" that UIImageView objects are drawn in? Whenever I add an image view to a view controller it defaults to drawing the most recently added one on top of all the others. So if I decide to add a "background" image it is now a "foreground" image and blocks everything else.
There isn't anything in the IB options or in the UIImageView class reference and I haven't been able to find anything here on SO. It's been a problem for a while and it's weird that I haven't seen anything about it before... I think it might just be my semantics coming from a delphi background.
Anyway, does anyone know about this issue / ICANHAZTEHCODEZ to fix it? Or is this just like the UIScrollView problem and poorly supported by the development environment.
This happens when I try to use the editor to arrange the subviews.
You can bring a SubView to Front or Send it background programmatically using
[self.view bringSubviewToFront:yourImageView];
and
[self.view sendSubviewToBack:yourImageView];
when self.view must be the superview of your imageView
In IB, select a UIControl and from top menu bar select Editor->arrage->send to front or back
When you use UIView's addSubview: method, it will add it to the top of the view stack resulting in what you are seeing.
There are numerous other UIView methods you can use to determine the order of subviews. E.g.:
- (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview;
- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index;
- (void)sendSubviewToBack:(UIView *)view;
- (void)bringSubviewToFront:(UIView *)view;

Using a patternimage for a View inside an NSScrollView

I have a quite big problem, I am really not able to solve myself.
The result should look like this:
This image was made with photoshop and is part of the interface I try to build.
In the middle you see something, that should be a list of projects, you should be able to scroll, if it the list is bigger then the view.
So I am making a scrollview like this: (for some reason I cannot do this in the interface builder and want this to work programmatically)
NSScrollView *projectsListView = [[NSScrollView alloc] initWithFrame:NSMakeRect(15, 2, 801, 588)];
[projectsListView setHasVerticalScroller:YES];
Then I create the content view and set a pattern image as backgroundcolor:
NSClipView *contentView = [[NSClipView alloc] initWithFrame:NSMakeRect(0, 0,
[projectsListView frame].size.width, [projectsListView frame].size.height+(98*2))];
[contentView setBackgroundColor:[NSColor colorWithPatternImage:[NSImage imageNamed:#"BoxLineBackground"]]];
[contentView setDrawsBackground:YES];
Then set the view as document view:
[projectsListView setDocumentView:contentView];
Should work, right?
However the content view gets clipped and looks like this while scrolling:
I tried this to fix it, but it does nothing:
[[projectsListView documentView] setCopiesOnScroll:NO];
I also tried this, but it causes the contentview not to scroll at all.
The image stays the same, but I can move the scroller normally.
[[projectsListView contentView] setCopiesOnScroll:NO];
If I try to set the contentview with setContentView: instead of using setDocumentView:
it may work, but the scroller is gone, so it is also not working correctly.
I would really like to use the patternimage method, because I cannot tell how long the list will be. It depends on the user.
An additional problem then would be to get the whole thing rounded, but that does not matter that much. I tried to use a transparent border image and to overlay the NSScrollView with it using an NSImageView, but again this causes corruption, because it clips and moves the overlaying parts of the image view together with the content of the scrollview.
Anyone having an idea, how to achieve this?
Thanks
Rather than re-inventing the wheel, this interface should be implemented with a view-based NSTableView. The table cell UI could then be created in Interface Builder and you could control the background of the cells using the various NSTableView delegate methods. NSTableView will handle redraws upon scrolling correctly.
To handle the pattern color, just make the background of your cell a custom subclass of NSTableCellView and implement your pattern drawing code.
Regardless of all this, the problem you are having is due to an NSScrollView drawing optimisation. You can turn this off by calling [[yourScrollView contentView] setCopiesOnScroll:NO] on your NSScrollView instance. You can also set this in Interface Builder, just un-check the Copies on Scroll checkbox.
I fixed the problem by setting the Background Color on the NSScrollView instead on the NSClipView.
I though the background would be static in that case and I need to set it for the content view for that reason, but it works pretty well and does scroll together with the content view.
And thanks for Rob Keniger's answer. I will probably try this out.

Cause UIScrollView zoomToRect: to only display a portion

I have a UIScrollView subclass that contains a UIImageView. When the user double taps on the zone I want to zoom to that CGRect (calculated from CGPoint) and "hide" the rest of the UIImageView. The final effect is similar in Mavel.app and The Walking Dead.app when you are reading a comic.
Until now I got:
-(void)presentRect:(CGRect)rect {
self.bounds = originalFrame; //1
[UIView beginAnimations:#"navigateToPos" context:nil];
[self zoomToRect:rect animated:NO];
self.bounds = rect;
[UIView commitAnimations];
}
This works, but "zoomToRect" needs the whole bounds of the UIScrollView and when I restart it (line 1), it gives an undesired effect.
I am stuck with this. I don't know if I need a new approach or need to use another property of UIScrollView.
Any help is appreciated. Thanks.
I downloaded this apps to see it. I'm almost sure they didn't even use uiscrollview. The way the pages moves make me think about that. And uiscrollview should be used only when you really need it, because it have a lot issues when you're customizing. (tiled content, zooming and others problems).
Slide to a next page only 50px aprox., the page goes to the next, in uiscrollview it didn't happen because it works diff.
As I said before, probably it's made using 4 bars (as you correct me) or it can be done with a view wrapping the uiimage and working as a mask. You only need calculate the size of the zoom square and move it to center, and resize the wrapper view to fit this new size. The substitute for the uiscrollview for pages can be a simple image gallery, but where is images you put this "comic-view".
I've solved using other properies from UIScrollView simulating the desired effect.