ViewController with subviews, UIScrollView not scrollable first time - iphone

Im using a UIViewController with several subviews from XIBs, (ViewController's views), they are chosen between using UISegmentedControl. One of these views are containing a UIScrollView. The problem is that the UIScrollView is not scrollable the first time this subview is added. If I choose another segment/view and then the one with the UIScrollView again, now it's scrollable.
The UIScrollView is added in IB only. This is some of the codes for the views and UISegmentedControl in MainViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
nameSubViewController = [[NameSubViewController alloc] initWithNibName:#"NameSubViewController" bundle:nil];
nameSubView = (NameSubView *)[nameSubViewController view];
priceSubViewController = [[PriceSubViewController alloc] initWithNibName:#"PriceSubViewController" bundle:nil];
priceSubView = (PriceSubView *)[priceSubViewController view];
[self.view addSubview:nameSubView];
currentView = nameSubView;
}
- (void) segmentAction:(id)sender
{
segmentedControl = sender;
if([segmentedControl selectedSegmentIndex] == 0) {
[currentView removeFromSuperview];
[self.view addSubview:nameSubView];
currentView = nil;
currentView = nameSubView;
}
if([segmentedControl selectedSegmentIndex] == 1) {
[currentView removeFromSuperview];
[self.view addSubview:priceSubView];
currentView = nil;
currentView = priceSubView;
}
In this code, let's say segment 1 (priceSubView) contains the UIScrollView. If I choose this segment, the UIScrollView does not react on the scrolling unless I choose segment 0 (nameSubView) again and re-select segment 1.
What is causing this and how to fix it?

If you need to scroll at first load.
You need to add the scrollView at firstLoad.
You are adding the scroll view after changing the segment control, that's why it's not scrolling. Check it out.
Change viewDidLoad like:
- (void)viewDidLoad
{
[super viewDidLoad];
nameSubViewController = [[NameSubViewController alloc] initWithNibName:#"NameSubViewController" bundle:nil];
nameSubView = (NameSubView *)[nameSubViewController view];
priceSubViewController = [[PriceSubViewController alloc] initWithNibName:#"PriceSubViewController" bundle:nil];
priceSubView = (PriceSubView *)[priceSubViewController view];
[self.view addSubview:priceSubView];
currentView = priceSubView;
}

Related

How to handle UITapGestureRecognizer in a subview?

I have a viewcontroller (vc1) in which I added another viewcontroller (vc2) as a subview. An UITapGestureRecognizer is triggered when you tap on a view (tappingView) contained in the subview (vc2). I would like to handle this tap inside the subview controller (vc2), and not from the first viewcontroller (vc1)... but it keeps crashing when I click on my view.
Here is the hierarchy sum up :
-vc1
--vc2
---tappingView
And here is a sample of code :
ViewController1 (viewDidLoad):
- (void)viewDidLoad
{
ViewController2 *vc2 = [[ViewController2 alloc] init];
[[self view] addSubview:[vc2 view]];
}
ViewController2 (viewDidLoad):
- (void)viewDidLoad
{
UIView *tappingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 60.0, 80.0)];
[[self view] addSubview:tappingView];
UITapGestureRecognizer *tapGestureRecognize = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureRecognizer:)];
[tappingView addGestureRecognizer:tapGestureRecognize];
}
ViewController2 (singleTapeGestureRecognizer:) :
- (void)singleTapGestureRecognizer:(id)sender {
NSLog(#"Tap gesture");
}
When I click in my view (tappingView), I keep getting a crash (BAD_ACCESS).
Anyone have an idea why ?
You shouldn't just add another view controller's view to your view -- you should make that controller a childViewController of vc1. Change the viewDidLoad in vc1 to this:
- (void)viewDidLoad {
ViewController2 *vc2 = [[ViewController2 alloc] init];
[self addChildViewController:vc2];
[vc2 didMoveToParentViewController:self];
[[self view] addSubview:[vc2 view]];
}
It's not clear why you're doing it this way in the first place. Why not present vc2 as a modal view controller instead?
In this block
- (void)viewDidLoad
{
ViewController2 *vc2 = [[ViewController2 alloc] init];
[[self view] addSubview:[vc2 view]];
}
your ViewController2 is not retained (addSubview only retains the view, not the view controller).
To fix it, declare vc2 as a strong property, instead of a variable.
self.vc2 = [[ViewController2 alloc] init];
Or better, as someone suggested, add vc2 as a child view controller.
Targets of UITapGestureRecognizer take the UIGestureRecognizer argument, not id. I.e.:
- (void)singleTapGestureRecognizer:(UIGestureRecognizer *)sender {
NSLog(#"Tap gesture");
}
Further, you're setting frames in viewDidLoad, which you should do in viewWillAppear: instead.
use below code
- (void)singleTapGestureRecognizer:(UIGestureRecognizer *)sender
instead of
- (void)singleTapGestureRecognizer:(id)sender.
As it must have UIGestureREcognizer instead of id.`

tabBarController set to nil when changing view but always in the window

I'm currently using a tableview inside a navigation controller, inside a tab bar controller. When i'm on the detail view of the table view, i want to "swipe" between Detail view, so i have implemented a UISwipeGesture with UIViewAnimations to swipe right/left.
Everything is working, but I have a little problem... When i'm on a Detail View loaded from the table view, the self.tabBarController element is here, i have my tab bar so i can add an actionsheet on it. But when i swipe, the self.tabBarController is nil now... I don't know why... Maybe because of the navigation Controller ?
Here is my code :
- (id) init
{
if (self = [super init]) {
CGRect fullScreenRect=[[UIScreen mainScreen] applicationFrame];
UIScrollView *scrollView=[[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, fullScreenRect.size.width, 367.)];
scrollView.contentSize=CGSizeMake(320,100);
scrollView.delegate = self;
self.view=scrollView;
self.myView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 367.)];
self.ButtonSizeM.tag = 0;
self.ButtonSizeP.tag = 0;
self.ContentIV = [[UIImageView alloc] init];
}
return self;
}
- (void) handleSwipeLeft {
if (!((self.ancient.tableView.indexPathForSelectedRow.section == ([self.ancient numberOfSectionsInTableView:self.ancient.tableView] - 1)) && (self.ancient.tableView.indexPathForSelectedRow.row == [self.ancient tableView:self.ancient.tableView numberOfRowsInSection:(self.ancient.tableView.indexPathForSelectedRow.section)]-1)))
{
NSIndexPath *whereToGo;
if (self.ancient.tableView.indexPathForSelectedRow.row == [self.ancient tableView:self.ancient.tableView numberOfRowsInSection:(self.ancient.tableView.indexPathForSelectedRow.section)]-1) {
whereToGo = [NSIndexPath indexPathForRow:0 inSection:(self.ancient.tableView.indexPathForSelectedRow.section)+1];
}
else {
whereToGo = [NSIndexPath indexPathForRow:(self.ancient.tableView.indexPathForSelectedRow.row)+1 inSection:self.ancient.tableView.indexPathForSelectedRow.section];
}
CCFASimpleDetail *nextView = [[CCFASimpleDetail alloc] init];
nextView = [self.ancient tableView:self.ancient.tableView prepareViewForIndexPath:whereToGo];
[nextView performSelectorOnMainThread:#selector(affichageEnPlace) withObject:nil waitUntilDone:YES];
float width = self.myView.frame.size.width;
float height = self.myView.frame.size.height;
[nextView.view setFrame:CGRectMake(width, 0.0, width, height)];
[self.view addSubview:nextView.view];
[UIView animateWithDuration:0.5f delay:0 options:UIViewAnimationCurveEaseInOut animations:^{
[nextView.view setFrame:self.view.frame];
[self.myView setFrame:CGRectMake(-width, 0.0, width, height)];
} completion:^(BOOL finished) {
[self.myView removeFromSuperview];
[self.ancient.tableView selectRowAtIndexPath:whereToGo animated:NO scrollPosition:UITableViewScrollPositionTop];
}
];
}
}
I you could help me to find my tab bar after swiping :) ?
When you add the view here:
[self.view addSubview:nextView.view];
the UINavigation controller does not know about it, and does not set the navigationBar nad tabBar properties for you.
What you can do is have the view get its superview (which will be self.view), then ask that view for the tabBarController and tabBar from that.
I just solved my problem by adding
[self.ancient.navigationController popViewControllerAnimated:NO];
[self.ancient.navigationController pushViewController:nextView animated:NO];
on the completion block !

How can I show an empty view in place of a UITableView?

I have a UITableViewController. When a certain BOOL is set, I want to show another view instead of the UITableView. How can I do this? I need to be able to bring the UITableView back also.
I implemented the following method in my Table view controller subclass to reload its background.
- (void)reloadBackground
{
if(myBool)
{
//load the view to be displayed from a nib
NSArray* nibs = [[NSBundle mainBundle] loadNibNamed:#"EmptyView" owner:self options:nil];
UIView* emptyView = [nibs objectAtIndex:0];
self.tableView.backgroundView = emptyView;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
}
else
{
self.tableView.backgroundView = nil;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
}
}
HTH,
Akshay
Instead of a UITableViewController, you can put two views inside a UIViewController:
#interface MyViewController : UIViewController <UITableViewDelegate> {
UITableView *tableView;
UIWebView *anotherView;
}
...
if (someBool) {
tableView.hidden = YES;
anotherView.hidden = NO;
} else {
tableView.hidden = NO;
anotherView.hidden = YES;
}
How about..
if(myBOOL == YES) {
ADifferentViewController * vc = (ADifferentViewController *)[[ADifferentViewController alloc]init];
[self.navigationController pushViewController:vc animated:NO];
[vc release];
}
Possibly something like:
if (myBool == YES) {
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
[self.view addSubview:myView];
}
Now to get rid of it:
[myView removeFromSuperview];
Of course there are plenty of other methods...
Even: self.view = myView;
Use a UIView instead if UITableViewController.... from .h file change
UITableViewController to UIViewController Connect view to Files owner
from xib
take UITableView in a UIView... take another UIView for a blank view
and set its background color as Tableview color
If your bool if true
then show tableview
and hide blank View else
hide tableview
show blank view

bringSubviewToFront not showing it's view

In my table view controller, I have a button that when I press, I want it to show the map view, so I just did the following. However, for some reason it's not showing up the view... why is this>
- (void)viewDidLoad {
mapViewController = mapViewController = [[MapViewController alloc] init];
[super viewDidLoad];
}
-(IBAction) toggleAction:(id) sender {
[self.view bringSubviewToFront:mapViewController.view];
self.navigationItem.backBarButtonItem = nil;
}
You need to add the view as a subview:
-(IBAction) toggleAction:(id) sender {
[self.view addSubView:mapViewController.view];
self.navigationItem.backBarButtonItem = nil;
}
Then remove it on dismissal (removeFromSuperView).

How does autosize work in iPhone SDK?

I'm trying to do the following:
alt text http://img101.imageshack.us/img101/7396/33959221.png
I need to do a lot of custom things, so I subclassed everything.
alt text http://img248.imageshack.us/img248/4201/49422483.png
I'm having issues with autoresize and positioning. For instance the UIToolBar is not at the correct position.
So here is the question:
If you don't use UITableViewController or any other Controller, that takes care of all the positioning and sizing, then you have to do it yourself.
Can someone someone tell me how this works? What do I need to understand?
---- UPDATE:
My custom goals are actually not that important as my question is actually about something else. But OK. So all "elements" like the TableView, the Toolbar and the TabBar will have custom backgrounds and use custom buttons. The TableView will be GroupedStyle and the groups can be collapsed.
My question is how do I have to structure my code especially regarding positioning and autoresizing in order to achieve what you can see in picture #1.
This is how it's structured right now:
Application Delegate:
- (void) loadView {
RootViewController *rootView = [[RootViewController alloc] init];
[window addSubview:rootView.view];
[window makeKeyAndVisible];
RootViewController:
- (void) loadView {
self.theView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
self.theView.autoresizesSubviews = YES;
self.theView.autoresizingMask = (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
self.view = self.theView;
ChildViewController *childView = [[ChildViewController alloc] init];
[self.view addSubview:childView.view];
ChildViewController:
- (void) loadView {
self.theView = [[UIView alloc] init];
self.view = self.theView;
}
- (void) viewDidLoad {
self.view.frame = [[UIScreen mainScreen] bounds];
CGRect toolbarBounds = self.theToolbar.bounds;
CGRect viewBounds = self.view.bounds;
CGRect tableViewBounds = CGRectMake(0, CGRectGetHeight(toolbarBounds), CGRectGetWidth(viewBounds), CGRectGetHeight(viewBounds) - CGRectGetHeight(toolbarBounds));
self.view.autoresizingMask = (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
self.theTableView = [[MyTableView alloc] initWithFrame:tableViewBounds
style:UITableViewStyleGrouped
parent:self];
[self.view addSubview:self.theToolbar];
[self.view addSubview:self.theTableView];
}
MyToolBar:
- (id)initWithParent:(id)theParent {
if ((self = [self init])) {
self.parent = theParent;
CGRect rectArea = CGRectMake(0, 0, CGRectGetWidth([[[self parent] view] bounds]), 44);
[self setFrame:rectArea];
self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[self loadButtons];
}
return self;
}
So this is how the positioning is structured at the moment (messy). It actually works, BUT I have a ModalView which is handled by the ChildViewController. When I have the iPad in Portrait view and I pop up the modal view and dismiss it, then everything works. But when I do the same on Landscape view it rotates the hole view... the ChildViewController by 90 degrees when dismissing the modal view. Very strange. When I load directly ChildViewController in my AppDelegate, then again everything works fine.
You're missing the UIViewAutoresizingFlexibleBottomMargin option in the autoresize mask of your toolbar, for instance.