UITableView as ScrollView Between Navigation and Tab Bars - ios

I have a table view laid out between a navigation bar and a tab bar and want to achieve scrolling only for the table view section (so in other words, in my iOS Simulator, I would want the two bars to always be seen, and I should be able to scroll my table view between them).
Having tried out various suggestions from SO posts, afraid am still getting something wrong. Can you advise please how do I fix this issue - I've been struggling with it for the last 1 day!
In the table view controller's viewDidLoad, I use the following code. Earlier, I also tried initializing a scroll view separately but understand that table view is a sub-class of scroll view, so ditched that path...
- (void)viewDidLoad
{
[super viewDidLoad];
// To remove extra separators from the table view to prevent blank rows from showing.
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
// ***** Scroll view implementation *****
[[self tableView] setFrame:CGRectMake(0, self.navigationController.navigationBar.frame.size.height, self.view.frame.size.width, self.view.frame.size.height - self.navigationController.navigationBar.frame.size.height - self.tabBarController.tabBar.frame.size.height)];
[[self tableView] setContentSize:CGSizeMake(self.view.frame.size.width, 2000)];
[self setEdgesForExtendedLayout:UIRectEdgeNone];
self.automaticallyAdjustsScrollViewInsets = YES;
}
In fact, to test this further, I have created a scroll view in a separate tab (in this tabbarcontroller app) where I only have a navigation bar and a tab bar so far (no table view). Its viewDidLoad looks like this - somehow, no luck there as well... the scroll bar starts from the top of the screen (rather than from the bottom of the navigation bar) and goes till the bottom of the screen (rather than till the top of the tab bar). So clearly I'm doing something conceptually wrong here... appreciate if you can help out please!!! The numbers put in here are experimental to test this out but I've ensured that the content size is larger than the scroll view frame...
- (void)viewDidLoad
{
[super viewDidLoad];
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 100, self.view.frame.size.width, 300)];
[scrollView setContentSize:CGSizeMake(self.view.frame.size.width, 1500)];
[self.view addSubview:scrollView];
[self setEdgesForExtendedLayout:UIRectEdgeNone];
self.automaticallyAdjustsScrollViewInsets = NO;
[scrollView setScrollEnabled:YES];
}
Finally, when I debug my app in the simulator, what is odd is that for the table view tab, the scroll bar does appear momentarily to start from below the navigation bar. But as soon as I touch the track pad to scroll, it disappears and a more prominent scroll bar appears and starts from the top of screen to the bottom of the screen as I mention initially above!

I think I found the underlying error in my ways. More than an implementation bug, it was me missing out on a very basic issue...
In summary, the iOS Simulator would typically always have higher resolution / number of pixels than the computer screen, and no matter what, the simulator would always outsize the computer screen unless manually resized. So the scroll bar would usually be always present. This SO post helped me understand it.
On the other hand, the UIScrollView was automatically already implemented in my table view, given that UITableView is a subclass of UIScrollView - I didnt have to do anything. I was scrolling the simulator with a 'light' double-touch, which was taking me to the scroll bar due to the issue mentioned above. If I 'hard-clicked' and then scrolled, then voila! The required UIScrollView did work properly as expected! This is probably what misled me to mention these statements in the question...!
Finally, when I debug my app in the simulator, what is odd is that for the table view tab, the scroll bar does appear momentarily to start from below the navigation bar. But as soon as I touch the track pad to scroll, it disappears and a more prominent scroll bar appears and starts from the top of screen to the bottom of the screen as I mention initially above!

Related

Why does UIWebView Not Scroll?

I've looked at numerous questions similar to this but try as I might, I cannot get a UIWebView to scroll or interact in any way. Here is the code:
- (void)loadView {
[super loadView];
...
[self.displayView loadHTMLString:entry->infoHtml baseURL:nil];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.displayView.userInteractionEnabled = YES;
self.displayView.scrollView.showsVerticalScrollIndicator = YES;
self.displayView.scrollView.scrollEnabled = YES;
[self.displayView.scrollView flashScrollIndicators];
}
The view appears, displays all the correct content, and shows the vertical scroll-bar for a second, correctly indicating the portion of the content currently displayed.
But I can't scroll it. Touching the content and moving my finger around does nothing at all. Interacting with a non-overlapping UITableView under the same parent works fine; touching entries there updates the contents of the UIWebView as it has been programmed to do.
The UIWebView was created in the Storyboard with these options:
Scales Page To Fit: unchecked (when checked, can't pinch-to-zoom, either)
Pagination: unpaginated
Mode: Aspect Fit (tried several; all un-scrollable)
UserInteractionEnabled: checked (parent views also have this checked)
The view is fully visible. I've tried making it significantly smaller than its parent and the displayed content always stops at the correct place. There is no delegate or gesture recognizers for this view.
The containing view has a UITableView and a UILabel, neither of which overlap the area of the UIWebView. I've tried changing the order of the views in the Scene on the storyboard but that also makes no difference.
I've tried removing the view from UIBuilder and creating it programmatically like so:
self.displayView = [[UIWebView alloc] initWithFrame:CGRectMake(400, 220, 400, 300)];
[self.view addSubview:self.displayView];
Same results. I tried removing all other elements from the Scene except for this single programmatically created UIWebView. Still the same results.
Elsewhere in my code, I've put a UIWebView as the #"accessoryView" of a UIAlertView and there I can scroll the content as expected.
Is there something else that needs to be done to be able to scroll a UIWebView sub-view?
2014-04-20: In fact, if I add the following lines to the bottom of my -loadView method, I get a dialog with the same HTML content as the window behind it, but I am able to scroll the dialog version. The only difference I can think of is that the dialog is modal (forced focus) while my own window with both a UITableView and UIWebView still allows interaction with the views visible behind it.
UIWebView* contents = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 250, 250)];
[contents loadHTMLString:entry->infoHtml baseURL:nil];
[alertView setValue:contents forKey:#"accessoryView"];
[alertView show];
On the other hand, if I replace the last two lines of that with [self.view addSubview:contents]; then I get the same second HTML view in the upper-left corner of the screen but that will not scroll.
I've worked it out. First, I tried adding this to -viewDidLoad in my MainController class:
UIWebView* contents = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 250, 250)];
[contents loadHTMLString:#"<html><head><title>FOO</title></head><body><p>A</p><p>B</p><p>C</p><p>D</p><p>E</p><p>F</p><p>G</p><p>H</p><p>I</p><p>J</p><p>K</p><p>L</p><p>M</p><p>N</p><p>O</p><p>P</p><p>Q</p><p>R</p><p>S</p><p>T</p><p>U</p><p>V</p><p>W</p><p>X</p><p>Y</p><p>Z</p></body></html>" baseURL:nil];
contents.backgroundColor = [UIColor redColor];
[self.view addSubview:contents];
It displays but isn't scrollable. I have a StartupController that deals with initializing the app and runs first so I added the same code there. This was scrollable! Ah-Ha!
It occurred to me that the top-level Google Map (GMSMapView) that covers the MainView might be swallowing the scroll events but passing click events. Within the scene, instead of just a single map-view, I created a top-level plain/simple/empty UIView and made the GMSMapView a full-sized child of that. Now when I add my views to that new top-level (simple) view, they are siblings rather than children of the map and get all events correctly.
As a result, my UIWebView is now scrollable. Thanks for everybody's comments and suggestions! It's been several months of on-and-off trying different things to finally figure that one out.
Please check that the web view is contained fully within the bounds of its parent view (and so on up the view hierarchy). An easy way to do this is to set some background colors. Possibly you have some constraints that aren't behaving as you expect.
Similarly, that all parent views are user-interaction-enabled.
Edit: I understand that the web view is fully visible. But that doesn't mean it is contained within the bounds of its superview. If the superview has clipsToBounds=NO (default, I believe) then any subview outside its bounds will be visible but will not receive touches.

How do I position UITableView programmatically while using iOS7's UINavigationBar?

I have a quite regular UIViewController that is a part of a UINavigationController-hierarchy, which naturally makes the view have a UINavigationBar at the top. As we all know, iOS7's navigation bars are very different from previous versions.
If I drag a UITableView into my view in Storyboard, then the 'frame' for the table view is covering the entire view (I.E [tableView setFrame:self.view.frame];). Even behind the NavigationBar.
This makes so that if I scroll, the content will be faintly visible through the bar.
Contrary to most people, I actually like this.
In my current view controller, I would like to create the UITableView programmatically and place it as a subview here. However, I am unable to achieve the same effect this way.
I have tried
UITableView *table = [[UITableView alloc] initWithFrame:self.view.frame];
[self.view addSubview: table];
This makes the 'top scrolling point' stay behind the navigation bar. Imagine a single cell in a tableView, and it's faintly visible through the top bar. If I scroll down, it pops right up behind it. That's the default 'top position'.
I have also tried
CGRect frame = CGRectMake(0, 'nav.y+nav.height', self...width, self...height-y);
UITableView *table = [[UITableView alloc] initWithFrame:frame];
[self.view addSubview: table];
to simply place the table view in the rect below the UINavigationBar, but then I won't get the scrolling transparency effect behind the bar.
I also tried the first example along with this:
[tableView setContentOffset:CGPointMake(0, 'below navbar')];
which makes it stay exactly where I want it to stay, but as soon as I touch it (scroll and release), it scrolls back up behind the navigation bar, and stays there.
What's the programmatic solution to achieve this effect? Do I have to set the offset every time I scroll too far up, or is there a simpler solution? Along with this iOS7-style, I'd imagine they would add something like [tableView setVisibleFrame:] or something..?
Add the table in storyboard like normal but make sure you have it connected to an outlet (we will call it _tableView for now).
Then in your view controller's -viewDidLoad set the top inset to be the status bar plus the navigation bar:
`self.tableView.contentInset = UIEdgeInsetsMake( (self.navigationController.navigationBar.frame.origin.y + self.navigationController.navigationBar.frame.size.height), 0, 0, 0);'
This will make sure that all of the cells will be visible but will also fill the area behind the navigation bar with white so the bar doesn't end up gray.

iOS 7 UIScrollView doesn't scroll when presented as modal view controller, works fine otherwise

I have a storyboard in which I have a view controller, (InfoViewController) in which I have an UIScrollView with some labels, uitextviews, etc. this is all created in IB, no code has been written at all. The only thing that is left for me to do is to set the content size, which I do as following:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
CGRect screenRect = [[UIScreen mainScreen] bounds];
[self.scrollView setContentSize:CGSizeMake(screenRect.size.width, 600)];
[self.scrollView setBackgroundColor:[UIColor greenColor]];
}
Whenever I make this view the entry point of my app, it works perfectly. I can see my view, the content size is set, the background color is being set to green.
Now it comes, I created another view controller, and this view controller is now my entry point of the app. I added a button in there, and on this button I did a "modal segue" to the earlier mentioned Info View Controller.
When I now run my app, I press this button, my Info View Controller shows up. The green background color is being set, but it's impossible to scroll. So the code is being executed (otherwise the background color couldn't been green, in the storyboard it's just plain white) but somehow whenever I use this "modal segue", the scroll functionality gets lost.
How can I fix this?
Try to insert a UIView into the scroll view...
Set the UIView with top, bottom, leading and trailing space to super view to 0.
Then insert everything into the UIView rather than into the ScrollView
Then modify the constraint height of the inner UIView instead of the contentsize of the scroll view, it works with iOS7

UISearchbar vanishes when in UIScrollView

I seem to be having an issue with the UISearchbar in iOS 7 vanishing in two scenarios. First the controller is fairly simple it has a nib which contains a scrollview which has in it the uisearch bar and some content. The ui search bar is at the top of the scrollview. So when I scroll the scrollview so the uisearchbar is longer visible and I exit and reneter the controller the uisearch bar is longer visible. Clicking the region makes it appear again. The uisearchbar also vanishes when I double tap it quickly. This controller worked fine is iOS 6 these issues are only happening now that I am building for ios 7
Edit
Investigating the double tap issue causing the uisearchbar to disappear. It seems that the uisearch bar when double tapped quickly is removing the uisearchbar from the view hierarchy when displaying it but never readding it back when it has been dismissed. So I can workaround that by doing
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
// workaround for bug in ios 7 were quickly double tapping uisearchbar (e.g it appears and get dismissed quickly)
// does not re add the uisearch bar to the correct view.
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0")) {
UIView *parentView = [self.scrollView.subviews objectAtIndex:0];
[parentView addSubview:self.searchDisplayController.searchBar];
}
return;
}
Have you tried doing some UI refresh stuff?
Like:
- (void)viewWillAppear:(BOOL)animated{
[self.scrollView setNeedsLayout];
}

Finding The Center of a View

I have an iphone app with 2 ViewControllers . Both screens(viewcontrollers) show a loading screen. I create the loading screen programmatically:
UIView *loadingScreen = [[UIView alloc] initWithFrame:CGRectMake(100,200,144,144)];
loadingScreen.center = CGPointMake(self.view.frame.size.width / 2.0, self.view.frame.size.height / 2.0);
//{.. Other customizations to loading screen
// ..}
[self.view addSubview:loadingScreen];
For some reason, the second viewcontroller's loadingScreen is significantly lower and it isn't centered on the screen. The first viewcontroller works perfectly and is dead center like I want.
The second viewcontroller is a UITableView and it shows the uinavigationbar, whereas the first viewcontroller doesn't show the uinavigationbar. Also, I use storyboard for my app.
I've outputted to the NSLog self.view.frame.size.height and loadingScreen.center in both instances and THEY HAVE THE SAME COORDINATES! So, not sure why it is showing up lower. Any ideas why the second loadingScreen is lower and how to fix? Thanks!
You mention that one screen displays a UINavigationBar while the other does not. When you display a navigation bar, it offsets the rest of your view - in this case by shifting it down.
There are two quick fixes. You can either adjust your center point up by the size of the UINavigationBar (65 pts - unless it's a custom UINavigationBar and you've changed its size) or you can set the "Adjust Scroll View Insets" value to false in the attributes inspector.
The latter is probably the easiest and comes most recommended. Note though, that the top of your UITableView will now be underneath the UINavigationBar.
My final note would be that if you wanted to do it programmatically than in your UITableView's delegate you can call
- (BOOL)automaticallyAdjustsScrollViewInsets
{
return NO;
}

Resources