So i'm adding UIView with UIScrollView in it to another view by pressing segment tool:
UIView.h
#interface gettingELORolesViewController : UIViewController{
UIViewController *currentController;
NSMutableArray *viewControllers;
}
- (IBAction)SegmentToggle:(UISegmentedControl *)sender;
#property (strong, nonatomic) IBOutlet UIView *containerView;
UIView.m
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Storyboard_iPhone"
bundle:nil];
firstView *FirstView = [sb instantiateViewControllerWithIdentifier:#"firstOne"];
secondView *SecondView = [sb instantiateViewControllerWithIdentifier:#"secondOne"];
viewControllers = [NSMutableArray arrayWithObjects:FirstView,SecondView,nil];
currentController = FirstView;
[containerView addSubview:FirstView.view];//containerView = self.view
and then depends on what segment is chosen, it shows different view:
- (IBAction)SegmentToggle:(UISegmentedControl *)sender {
UIViewController *selectedView=nil;
if (sender.selectedSegmentIndex==0) {
selectedView= [viewControllers objectAtIndex:0]; // retrieve object at index 0 from viewControllers array
}
else if(sender.selectedSegmentIndex==1){
selectedView= [viewControllers objectAtIndex:1]; // retrieve object at index 1 from viewControllers array
}
[currentController.view removeFromSuperview]; // remove Current displaying view from superView
currentController=selectedView; // make selected View to be the current View
[containerView addSubview:selectedView.view]; // Add newly selected view on container View
}
secondView is tableViewController and everything is working great when i choose second segment. When i choose first one it shows up but scroll doesn't work and i don't know why.
firstView.m viewDidLoad method looks like this:
-(void)viewDidLoad{
[super viewDidLoad];
mainScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
[mainScrollView setContentSize:CGSizeMake(320, 600)];
[mainScrollView setScrollEnabled:YES];
}
Paging is enabled in storyBoard. And it hooked up with .h file of firstView.
Please tell me what am i doing wrong.
When you call -SegmentToggle:,
you create a local variable called selectedView
you assign a view controller to selectedView depending on what segment is selected
the method ends, selectedView goes out of scope
In short, you're not doing anything. You should, at least, replace a view in the current view hierarchy with the view of the selected controller (and maybe stash a reference to the selected controller in an instance variable for later lookup?)
But taking a step back, it looks like you're trying to create a view controller that manages other view controllers. There are now very specific rules around that as of iOS 5. Please watch the WWDC 2011 video called "Implementing UIViewController Containment" for more information and examples.
Related
I have a UIView designed in XIB file. Basically with a navigation bar and a button to close the UIVIew. I want to show this UIView in several UIViewControllers across the app.
Below is the code I have imp[emnted so far.However the UIView doesn't show up.
My ViewControllers are designed in storyboard however I needed a simple UIView that is why I created a new custom subclass of UIView alongwith a xib file of the same name.The File's Owner is also set to custom subclass. What else is required here?
#interface BottomSlidingView : UIView //this is my UIView
{
}
#implementation BottomSlidingView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setUserInteractionEnabled:YES];
NSLog(#"Bottom View Loaded"); //I get this log entry but the view doesn't showup.
}
return self;
}
- (BOOL)loadMyNibFile {
if (![[NSBundle mainBundle] loadNibNamed:#"BottomSlidingView" owner:self options:nil]) {
return NO;
}
return YES;
}
And this is how I call the custom UIView in my UIViewController.
-(void)shareButton:(UIBarButtonItem *)button
{
NSLog(#"share button clicked");
BottomSlidingView *bsv = [[BottomSlidingView alloc] initWithFrame:CGRectMake(20, 480, 280, 420)];
[bsv loadMyNibFile];
[self.view insertSubview:bsv belowSubview:self.optionsToolBar]; //this toolbar is a subview that I am adding to this view controller.
}
I see a couple problems with your approach:
Create the view instance from a nib file, rather than instantiating it with initWithFrame:. For example (if the custom view is the only root-level object in the nib file):
+ (instancetype)bottomSlidingView
{
return [[[UINib nibWithNibName:#"BottomSlidingView" bundle:nil] instantiateWithOwner:nil options:nil] lastObject];
}
Implement awakeFromNib or initWithCoder: instead of initWithFrame: (which isn't called when loading from nibs) in your UIView subclass.
In your view controller, you would use something like the following to create the view:
- (void)shareButtonPressed:(id)sender
{
BottomSlidingView *slidingView = [BottomSlidingView bottomSlidingView];
[slidingView setFrame:CGRectMake(20, 480, 280, 420)];
[[self view] insertSubview:slidingView belowSubview:[self optionsToolBar]];
}
Hope that helps.
Where ever you want to reuse a UIView of a UIViewController in another view controller you need to use this....
YourViewController * child = [[YourViewController alloc] initWithNibName:#"YourViewController" bundle:nil];//View controller of view , you want to reuse
[self.view addSubView:child.YourView]; //YourView = Name of view, you want to reuse
[self addChildViewController:child];
[child release];
After adding childViewController All IBActions will be work in child.
And after removing this view You have to remove YourViewController from parentViewController other wise there will be memory issues.......
I have page-based app. On each page I have 3 uibuttons at the top, uiscrollview with alphabet (uibuttons to sort data in uitable) at the right and uitableview at the center. How to show cell's detail view? If it is necessary to add uinavigationcontroller I can't do this. If I adds it, it disables interaction with my table, buttons and scrollview.
And another question is how to show new data in tableview and scrollview when goes to next page??
I have rootViewController class and DataViewController class.
rootViewController listing:
#interface RootViewController ()
#property (readonly, strong, nonatomic) ModelController *modelController;
#end
#implementation RootViewController
#synthesize pageViewController = _pageViewController;
#synthesize modelController = _modelController;
#synthesize navContr = _navContr;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Configure the page view controller and add it as a child view controller.
//[self presentModalViewController:navContr animated:YES];
self.pageViewController = [[[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil] autorelease];
self.pageViewController.delegate = self;
DataViewController *startingViewController = [self.modelController viewControllerAtIndex:0 storyboard:self.storyboard];
NSArray *viewControllers = [NSArray arrayWithObject:startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];
self.pageViewController.dataSource = self.modelController;
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
self.navContr = [[UINavigationController alloc] initWithRootViewController:self.pageViewController];
[self.view addSubview:self.navContr.view];
// Set the page view controller's bounds using an inset rect so that self's view is visible around the edges of the pages.
CGRect pageViewRect = self.view.bounds;
self.pageViewController.view.frame = pageViewRect;
[self.pageViewController didMoveToParentViewController:self];
// Add the page view controller's gesture recognizers to the book view controller's view so that the gestures are started more easily.
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
for (UIGestureRecognizer *recognizer in self.pageViewController.gestureRecognizers){
if ([recognizer isKindOfClass:[UITapGestureRecognizer class]]){
[recognizer setEnabled:NO];
}
}
}
After few manipulations it works but I need help to get it work fine!
So now it looks like this
Next question: how do I remove the brown space at the top???
::UPDATE::
Problem solved. It needs just to set y-axis position of UINavigationController to -20 ;)
i'm not sure if this link about creating navigation-based project may help you.. (http://iosmadesimple.blogspot.com/2012/08/navigation-based-project-doing-it.html)
From that tutorial, there's a class called SampleViewController, subclass of UIViewController. You might want to put a tableView in SampleViewController.xib file. Then in your SampleViewController.h file, add an IBOutlet UITableView* yourTable property and synthesize it. Connect it to your tableView in your .xib file. //Or you may do it programmatically
in your SampleViewController.h, make your interface header look like this.. I think you already know this...
#interface SampleViewController:UIViewController < UITableviewDelegate, UITableViewDatasource >
in your SampleViewcontroller.m, under viewDidLoad method, set the table delegate and datasource to self:
yourTableView.delegate = self;
yourTableView.datasource = self;
Afterwhich, you implement tableView delegate and datasource methods... //you already know those since you were already able to show a tableview ;)
one of these methods is the "tableview:didSelectAtIndexpath:" --> this is the part wherein you can put your code when you click one of the cells.
Let's assume you have the DetailsViewController Class, this is the class you would like to show after clicking a cell and show its details.
DetailsViewController Class must have a variable that will accept the data you would like to show. Let's say, an NSString *detailsMessage; //do the #property and #synthesize thing...
Let's go back to SampleViewController.m file, under tableview:didSelectAtIndexpath: Method:
inside that Method.. put these codes.
DetailsViewController *detailsVC = [[DetailsViewController alloc] init];
detailsVC.detailsMessage = #"The Data you want to pass.";
[self.navigationController pushViewController:detailsVC animated:YES];
I hope this helps. :(
There may be other ways but by far the easiest way is to use a navigation controller. In fact, it is built to do exactly this.
If you don't want the navigationBar then you can hide it in the viewWillAppear function.
[self.navigationController setNavigationBarHidden:YES animated:YES];
Then you can add an other UIViewController to push when the user selects a cell.
Having read your OP again I'm not sure how you are adding your navigationController.
To use a navigationController you create it and load it at start time. You then create your current viewController (the one with the buttons and table etc...) and set this as the rootViewController of the navigationController.
Then you display the navigationController.
Could you explain how you are adding your navigationController as it may help understand what is going wrong.
Thanks
::EDIT::
OK, my assumption was correct.
The way you are using the navigation controller is not how it was intended.
OK, so at the moment your AppDelegate file will have a method Application didFinishLaunching...
It will look something like this...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[OJFViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
You should change it so that it is like this...
first add a property to your appDelegate...
#property (nonatomic, strong) UINavigationController *navigationController;
Then change the didFinishLaunchingMethod to this...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[OJFViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
This will still show you MainViewController but it will now be contained within a navigationController.
Next in your MainViewController function viewWillAppearAnimated add the line...
[self.navigationController setNavigationBarHidden:YES animated:animated];
This will then hide the navigationBar at the top of the view so you still have access to your buttons.
The you need a new ViewController and xib file (for example DetailViewController).
When the user selects a table row you need to then do something like...
DetailViewController *detailView = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
//pass in details of which row was selected.
[self.navigationController pushViewController:detailView animated:YES];
This will then display your new view and new viewController. You will also need to write a way of passing the data in (set up a property on the DetailViewController).
Hope this helps.
I have a ViewController with xib,.h,.m files. Now i want to display it as a popUpView in another viewController. so I did like this...
Second *view2 = [[Second alloc] initWithNibName:#"Second" bundle:nil];
[view2.view setFrame:CGRectMake(20, 20, 280, 400)];
{self.view addSubview:view2.view];
but the problem here I am able to set frame randomly, but the viewController contains a textField and button. They are not getting added at random positions on the view like some textField comes out of the frame of view added.
After some googling i find this, but this not enough to solve my issue.
Adding a ViewConroller's View as subview programmatically
How to solve it...
It seems that you are changing the frame of the view in your view controller but not handling the repositioning of the elements inside the view. What you can do is override the layoutSubviews method in the view so that when the frame changes the text fields reposition themselves.
You will have to create an actual UIView subclass which will layout the text fields,
#interface SecondView : UIView{
}
#implementation SecondView{
- (void) layoutSubviews{
//self.frame would be to most up-to-date frame that you just set
}
}
Your UIViewController will just create the view like so,
#interface Second : UIViewController{
}
#implementation Second{
- (void) loadView{
self.view = [[[SecondView alloc] init] autorelease];
}
}
I have a View Controller that initializes a UIView as its view. That view initializes another UIView as a subview. Both UIViews communicate with the View Controller through a delegate/protocol.
Each UIView creates an instance of the ViewController and makes it equal to the delegate:
ViewController *aDelegate = [[ViewController alloc] init];
self.delegate = aDelegate;
PROBLEM: The View Controller has a variable called (int)selection that is modified by both UIViews. Both views must know how each other modified the variable, but since each has a different instance of the View Controller that communication is impossible. How would I fix this problem?
Thanks a ton
EDIT: Peter mentioned assigning the delegate at the views creation which I like, but how would I do that for the subview since it is created in the UIView and not the View Controller. PS. In reality it is a subview of a subview of a subview so can I create them all in the View Controller and then assign it as the delegate?
Tried assigning the delegate as follows but it continually crashes when I attempt to call a ViewController method from the view:
MyView *mainView = [[MyView alloc] initWithFrame:frame];
self.view = mainView;
mainView.delegate = self;
[mainView release];
The views does not need to know about each other. In your view controller you define a property for the sub view
#property (nonatomic, retain) MyView *myView;
Then you create your sub view and assign the delegate. This can be done in viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
CGRect frame = ...;
MyView *subView = [[MyView alloc] initWithFrame:frame];
self.myView = subView;
subView.delegate = self;
[self.view addSubView:subView];
[subView release];
self.view.delegate = self;
}
Then in your delegate method, which I just guessed how it could look, you can update the view controller as well as the other view.
- (void)view:(MyView *)view didUpdateSelection:(int)newSelection {
self.selection = newSelection;
if (view == self.view) {
self.myView.selection = newSelection;
}
else {
self.view.selection = newSelection;
}
}
It sounds like instead of each view allocating a separate instance of the view controller, you want to assign the instance of the view controller that created the views as the delegate of each view.
One way to approach this is to have the view controller assign itself as the view's delegate when it creates the view.
EDIT: This question is due to a big lack of understanding how Interface Builder and properties in classes works.
Why can't i just set self.mySubView = anoterhView; like one can set self.view = anotherView; ?
## .h
#interface TestController : UIViewController {
IBOutlet UIView *mySubView;
}
#property (nonatomic, retain) IBOutlet UIView *mySubView;
##.m
#implements TestController
#synthesize mySubView;
- (void)viewDidLoad {
AnotherController *anotherController = [[AnotherController alloc] initWithNibName:nil bundle:nil];
anotherView = anotherController.view;
// if i do
self.view = anotherView;
// result: replaces whole view with anotherView
// if i instead do
self.mySubView = anotherView;
// result: no change at all
// or if i instead do:
[self.mySubView addSubview:anotherView];
// result: mySubView is now displaying anotherView
}
NOTE: I'm using interfacebuilder. I'm sure everything is hooked up allright because self.view, and self.mySubView addSubview: is working allright..
To make it automatically appear on your self.view you need to overwrite your setter method, e.g.:
- (void)setMySubView:(UIView *)view {
[mySubView removeFromSuperview]; // removing previous view from self.view
[mySubView autorelease];
mySubView = [view retain];
[self.view addSubview: mySubView]; // adding new view to self.view
}
mySubview is a property which is a reference to an UIView object. So when you assign an UIView object to it, you are merely changing what mySubview is referring to and no more as in this case,
self.mySubview = anotherView;
The original UIView object that mySubview was referring to is still referred to within view's subviews property. Nothing changes.
But when you add anotherView as a subview of mySubview, anotherView belongs to the view hierarchy and is displayed on screen. So this works.
view (parent of) mySubview (parent of) anotherView
However when you assign anotherView directly to the view, You not only change the UIView object view was referring to but it also adds itself to the parentView. This is handled by UIViewController.
self.view = anotherView;
Your setCurrentView should be more or so like this,
- (void) replaceSubview:(UIView *)newView {
CGRect frame = mySubview.frame;
[mySubview removeFromSuperview];
self.mySubview = newView;
[self.view addSubview:newView];
newView.frame = frame;
}
As a response to what #beefon said. This works kind of as expected, but background-color is transparent. It doesen't respond either... buttons do not get pressed etc..
- (void)setCurrentView:(UIView *)newView {
/* 1. save current view.frame: CGRect mySubViewFrame = [mySubView frame];
2. remove and put new subview - I have wrote how to do it
3. set new frame for new view: [mySubView setFrame:mySubViewFrame]; */
CGRect currentViewFrame = [currentView frame];
[currentView removeFromSuperview];
[currentView autorelease];
currentView = [newView retain];
[self.view addSubview:currentView];
[currentView setFrame:currentViewFrame];
}
Your instance variable needs to be a property in order to use the dot. syntax, use:
#Property (nonatomic, retain) IBOutlet UIView* subview;
in the header, and use:
#synthesize subview;
in the main file.
In order to set a UIView using the dot. syntax you need to make it a property. This also allows you to set the subview's properties outside the class.