IOS dev. Tap button, screen does not call a new view - ios

Goal: to switch views when you click the button.
What I did:
Open a single view application.
File -> New -> File -> Cocoa Touch & Objective -C. Create
PlayViewController and GMViewController, both subclass
UIViewController.
Went to mainstoryboard and from the object library, I dragged two
View Controllers, with PLayViewController and GMViewController as
their STORYBOARD IDs.
IN ViewController.h I have these codes:
.
#import <UIKit/UIKit.h>
#class PlayViewController;
#class GMViewController;
#interface ViewController : UIViewController
#property (strong, nonatomic) PlayViewController *playViewController;
#property (strong, nonatomic) GMViewController *gmViewController;
- (IBAction)toPlay:(id)sender;
- (IBAction)toGM:(id)sender;
#end
Basically, here I created two buttons. one will go to PlayView, the other to GMView.
5. In my ViewCotroller.m, I have these:
#import "ViewController.h"
#import "PLayViewController.h"
#import "GMViewController.h"
- (IBAction)toPlay:(id)sender {
UIStoryboard *storyboard =[UIStoryboard storyboardWithName:#"Main" bundle:nil];
PlayViewController *playController =[storyboard instantiateViewControllerWithIdentifier:#"PlayViewController"];
self.playViewController = playController;
[self.view removeFromSuperview];
[self.view insertSubview: self.playViewController.view atIndex:0];
}
- (IBAction)toGM:(id)sender {
//still blank, waiting to fix the play button.
}
Problem is when I click the play button the screen goes black. Please tell me what I missed. Thanks

As per your code, you are first removing self.view and then you are trying to insertSubview on self.view thats way it is not working for you so change your code with
first insret self.playViewController.view to self.view and then it remove from super view such like,
[self.view insertSubview: self.playViewController.view atIndex:0];
[self.view removeFromSuperview];
Hope that my suggestion will be work for you.

Related

How to show viewcontroller from the view?

I searched for answers like Get to UIViewController from UIView? and couple of other answers but was not successful.
My issue is that I have a button in UIView lets say class1 and when I click on that button I want to load another view class2 which is UIViewController, and as I don't get navigationController in class1 I am unable to load the class2 view.
Please help me with this.
Thanks,
In Advance.
In general UIViews should not contain any logic that triggers the flow of app. This is the job of UIViewControllers. It's just a way of making the design of your code better and more organized.
One way I often use is to use a delegate pattern in my custom UIViews. Here is s simple setup:
In your MyCustomView .h file:
#class MyCustomView;
#protocol MyCustomViewDelegate <NSObject>
#optional
- (void)myViewDidTapOnButton:(MyCustomView)myCustomView;
#end
#interface MyCustomView : UIView
#property (weak, nonatomic) id <MyCustomViewDelegate> delegate;
#end
In your MyCustomView .m file:
- (IBAction)didTapMyButton:(id)sender {
if ([self.delegate respondsToSelector:#selector(myViewDidTapOnButton:)]) {
[self.delegate myViewDidTapOnButton:self];
}
}
Then in your viewcontroller, which is presenting your view:
interface:
#interface MyViewController ()<MyCustomViewDelegate>
#property (weak, nonatomic) IBOutlet UIView *myCustomView;
and implementation:
- (void)viewDidLoad {
[super viewDidLoad];
self.myCustomView.delegate = self;
}
- (void)myViewDidTapOnButton:(MyCustomView)myCustomView {
... code for presenting viewcontroller ...
}
Note:
Even if you dont use the parameter myCustomView which is sent in this method, its a common pattern and good habit to always send the sender of the delegate as the first parameter.
This is also used a lot by Apple, e.g. in
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
Two cases :
If you are using storyboard then give your NavigationController a
storyboard id. And create an object of navigationController in your
custom UIView class.
If you have customized the app launching from AppDelegate create a
public property of your navigationController. From your UIView class create an object of appDelegate with [UIApplication sharedApplication].delegate. From this object access the navigationController property
When you have the navigationController object you can push your viewcontroller with:
[navigationController pushViewController:ViewController animated:YES];
First fill storyboard ID with "MyViewController", which is a String field that you can use to create a new ViewController based on that storyboard ViewController. And later access that view controller like this:
- (IBAction)buttonPressed:(id)sender{
MyCustomViewController *newvc = [self.storyboard instantiateViewControllerWithIdentifier:#"MyViewController"];
[self presentViewController:newvc animated:YES completion:nil];
}
When you click your button,you can do this:
YouViewController *yourViewController = [YouViewController new];
[self.view addSubView:yourViewController.view];
Hope to help you.

Pushing view controller is not working properly in ios

I am passing textfield data between two view controllers. i have two view controllers Firstviewcontroller, Secondviewcontroller. i have embed them in navigation but when i click the button on first view controller, second view controller is not showing only black screen is showing.below is my code.
First view controller.h
#import <UIKit/UIKit.h>
#import "secondViewController.h"
#interface FirstViewController : UIViewController<SecondViewControllerDelegate>
#property(nonatomic) secondViewController *secondview;
- (IBAction)btnclick:(id)sender;
#property (strong, nonatomic) IBOutlet UITextField *textfield1;
#end
First view controller.m
- (IBAction)btnclick:(id)sender {
secondViewController *SecondViewController= [[secondViewController alloc]init];
SecondViewController.data=self.textfield1.text;
[self.navigationController pushViewController:SecondViewController animated:YES];
}
- (void)dataFromController:(NSString *)data
{
[self.textfield1 setText:[NSString stringWithFormat:#"%#",data]];
}
Seconviewcontroller.h
#protocol SecondViewControllerDelegate <NSObject>
#required
- (void)dataFromController:(NSString *)data;
#end
#interface secondViewController : UIViewController
#property (nonatomic, retain) NSString *data;
#property(nonatomic,weak)id<SecondViewControllerDelegate> _delegate;
#property (strong, nonatomic) IBOutlet UITextField *textfield2;
#end
Seconviewcontroller.m
- (void)viewDidLoad {
[super viewDidLoad];
self.textfield2.text=[NSString stringWithFormat:#"%#",_data];
// Do any additional setup after loading the view.
}
whats the reason ??
You have to either use storyboard and let it intanciate the view controller for you:
[self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"]
Or you can use xib files and tell the view controller which one to load:
[[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil]
second view controller is not showing only black screen is showing
Typically, this means that the view controller has no view. Your code does not explain where secondViewController is expected to get its view from. Is there a secondViewController.xib? If there is, is it correctly configured with a view outlet? If not, what does this view controller do in order to get its view?
Note that you have done a very odd thing with capitalization: you have given your class a small letter (secondViewController), while your instance has a capital latter (SecondViewController). This is backwards and a big mistake, and you should correct it immediately. Perhaps the problem is just a capitalization problem; if you call your class secondViewController and your xib file SecondViewController, that is not a match and they won't find each other.
I see "IBOutlet" in your code, it means you created the user interface of secondviewcontroller on storyboard. I guess [[secondViewController alloc]init] does not get UI element from storyboard then the black screen is shown. You have to create instance of secondViewController by loading from storyboard file.
Basically:
you can get storyboard via storyboard file name
on storyboard, Secondviewcontroller has an storyboard id which is set in Identity Inspector and you can use it to get instance of Secondviewcontroller
You can refer this link for more detail
loading iOS viewcontroller from storyboard
Hope this can help!

Using an UIView from one UIViewController in another UIViewController?

as you can read in the title, I want to display an UIView from one UIViewController in another UIViewController.
The reason for this is, that I want to design the UIView in an extra UIViewController in the storyboard, but use it as an overlay view in my MainViewController on which the app mainly runs.
I tried the following:
In the MainViewController I created an instance of the second UIViewController and saved its view in the UIView i called overlayView.
UIViewController* rvc = [self.storyboard instantiateViewControllerWithIdentifier:#"overlayView"];
self.overlayView = rvc.view;
After that step, I thought I simply add it as a Subview, but sadly it didn't work.
[self.view addSubview:self.overlayView];
Is there anything missing or should I try something completely different ?
Thanks in advance :)
EDIT: Now theres the problem, that an Error called BAD_ACCESS occurs by pressing a button of the overlayView.
I created a ViewController, whose views alpha I regulated to a value of 0.9. On this view I added a simple button up to now. In my MainViewControllers viewDidLoad Method I used the following code to initialize the "new" ViewControllers view:
UIStoryboard* st = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
UIViewController* vc = [st instantiateViewControllerWithIdentifier:#"overlayView"];
self.overlayView = vc.view;
[self addChildViewController:vc];
self.overlayView.alpha = 0.0;
As a next step I "called" the overlayView to appear by pressing a button on the MainViewController and animated the alpha for a smooth fadeIn:
[self.view addSubview:self.overlayView];
[UIView animateWithDuration:1.3 animations:^{
self.overlayView.alpha = 0.9;
}];
Now if I press the button on the overlayView I want it to call a method of the MainViewController, which is doing some stuff and lets the overlayView disappear. For this case I used a NSNotificationCenter.
But by pressing this button (on the overlayView), the following error occurs in main.m:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x128a60cd0)
First I thought, the problem was caused by the NSNotificationCenter. So I tried to call the method using Delegation. But it didn't help.
Delegation Code:
OverlayViewController.h
#class OverlayViewController;
#protocol OverlayViewControllerDelegate
- (void) setToNormalAction;
#end
#interface OverlayViewController : UIViewController
#property (weak, nonatomic) id <OverlayViewControllerDelegate> delegate;
#property (strong, nonatomic) IBOutlet UIView *overlayView;
- (IBAction)buttonTouchUpInside:(id)sender;
#end
Button Method:
- (IBAction)buttonTouchUpInside:(id)sender
{
[self.delegate setToNormalAction];
}
In the MainViewController.h I implemented the created "OverlayViewControllerDelegate" as known and in .m I used the declared method to fadeOut the overlayView and do some other stuff.
Do you have an idea to resolve this ?
Thanks in advance
Try...
UIViewController* rvc = [self.storyboardinstantiateViewControllerWithIdentifier:#"overlayView"];
self.overlayView = rvc.view;
[self addChildViewController:rvc];
[self.view addSubview:self.overlayView];
You could just design it as a view in a nib then there's no need for an extra VC just to have somewhere to put it, and all the hassles that is going to bring.
There's nothing that says you can't continue to use nibs in addition to a having a storyboard.

Communicating between 2 ViewControllers in Tab Bar Controller Project

I'm using a Tab Bar Controller in my project where the FirstViewController has a Mapbox map view and the SecondViewController has buttons that when pressed add a tile layer to the map view. Here's what I've tried. It creates error ***Use of undeclared identifier '_mapView' in the SecondViewController.m
//FirstViewController.h
#import <UIKit/UIKit.h>
#import <MapBox/MapBox.h>
#import "SecondViewController.h"
#import "SecondViewController.m"
#interface FirstViewController : UIViewController
#property (strong, nonatomic) IBOutlet RMMapView *mapView;
#end
//SecondViewController.h
#import <UIKit/UIKit.h>
#import <MapBox/MapBox.h>
#import "FirstViewController.h"
#import "FirstViewController.m"
#interface SecondViewController : UIViewController
- (IBAction)stationingLayerButton:(id)sender;
#end
//SecondViewController.m
- (IBAction)stationingLayerButton:(id)sender {
RMMBTilesSource *stationingMap = [[RMMBTilesSource alloc] initWithTileSetURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"Stationing20" ofType:#"mbtiles"]]];
[_mapView addTileSource:stationingMap atIndex:2];
}
}
The map calls are correct because I've tested it on a project that only uses one view controller. Now that I'm trying it on a Tab Bar Controller I get this error.
My question is
1.how do I get mapView in the FirstViewController to respond to calls in the SecondViewController?
2.Can this be done? I've imported the class files thinking this would open communication between the two but I'm stuck with this error.
Using tabbar controller you can get array on all associated view controllers.
You can find more details here: UITabbarController - viewControllers property
For example :
In a tabbar, if we have two view controllers, let say VC1 and VC2, then we can have any of these reference by using below code snippet.
Accessing VC1 reference in VC2 class implementation (VC2.m):
VC1 *myVC1ref = (VC1 *)[self.tabBarController.viewControllers objectAtIndex:0];
Now we can use public properties and methods of VC1 class and it will give the same reference which tabbar has loaded.
Hope this helps.
You basically add view controller to UITabBarController. So, if you need to access a UIViewControler in a specific tab, you need to query the UITabBarController. The following answered SO question might help you
any code example of how access viewcontroller from uitabbarcontroller?
Once you get hold of the view controller, you can pass all the data you want.
Thanks to Mrunal and Naz Mir.
I added a UITabBarController Class file and assigned it to my TabBarController. I then NSLog the array description of view controllers of the TabBarController.
//TabBarController.h
#property (strong, nonatomic) NSArray *array;
//TabBarController.m
- (void)viewDidLoad
{
NSArray *array = self.viewControllers;
NSLog(#"View Controllers = %#", [array description]);
}
I then imported the FirstViewController.h to SecondViewController.h and in SecondViewController.m I wrote...
//SecondViewController.m
- (IBAction)stationingLayerButton:(id)sender {
FirstViewController *FVC = [self.tabBarController.viewControllers objectAtIndex:0];
[[FVC mapView] addTileSource:stationingMap atIndex:2];
}

Connect together: AppDelegate, ViewController and XIB

I am new to the iOS programming and got stuck with one problem.
What was done:
I have created iOS application.
Initially it had main.m, AppDelegate.h, AppDelegate.m and some other supporting files (not with code) that are usually created.
Then I manually created XIB file with interface (LoginView.xib) and manually added LoginViewController.h and LoginViewController.m to control XIB.
Added outlets to LoginViewController.h.
After all I set up file's owner class (LoginViewController) and made connections between XIB and LoginViewController.h.
Problem description:
I need to show instantiate login view controller and show login view immediately at the application's start.
I tried several attempts and read a dozen of forum threads, but no way. Nothing is shown except white window background.
How can I do it correct?
Reference code:
LoginViewController.h
#import <UIKit/UIKit.h>
#interface LoginViewController : UIViewController
{
IBOutlet UIView *_loginView;
IBOutlet UITextField *_tfLogin;
IBOutlet UITextField *_tfPassword;
IBOutlet UIButton *_btnLoginToSystem;
}
- (IBAction)attemptLogin:(id)sender;
#end
LoginViewController.m
#import "LoginViewController.h"
#interface LoginViewController ()
#end
#implementation LoginViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)attemptLogin:(id)sender
{
}
#end
AppDelegate.h
#import <UIKit/UIKit.h>
#import "LoginViewController.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) LoginViewController *loginViewController;
#end
AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
self.loginViewController = [[LoginViewController alloc] initWithNibName:#"LoginView" bundle:nil];
[self.window.rootViewController presentModalViewController:self.loginViewController animated:NO];
[self.window makeKeyAndVisible];
return YES;
}
UPDATE!!!
Guys, thanks to you all I've found another issue. Once I got your approve that my code (after appropriate edition, of course) is correct, I started simulator and saw that my app crashes with the following exception:
NSInternalInconsistencyException with the reason [UIViewController _loadViewFromNibNamed:bundle:] loaded the ... nib but the view outlet was not set.
Thanks to StackOverflow I fixed it.
Loaded nib but the view outlet was not set - new to InterfaceBuilder
Quotation of Josh Justice comment from the topic I provided link to:
Open the XIB file causing problems
Click on file's owner icon on the left bar (top one, looks like a yellow outlined box)
If you don't see the right-hand sidebar, click on the third icon above "view" in your toolbar. This will show the right-hand sidebar
In the right-hand sidebar, click on the third tab--the one that looks a bit like a newspaper
Under "Custom Class" at the top, make sure Class is the name of the ViewController that should correspond to this view. If not, enter it
In the right-hand sidebar, click on the last tab--the one that looks like a circle with an arrow in it
You should see "outlets" with "view" under it. Drag the circle next to it over to the "view" icon on the left bar (bottom one, looks like a white square with a thick gray outline
Save the xib and re-run
Probably this information aggregated into one point will help other newcomers to pass the way I passed faster.
Set the LoginViewController as your root view controller in your application:didFinishLaunchingWithOptions: method.
self.window.rootViewController = self.loginViewController;
remove this line:
[self.window.rootViewController presentModalViewController:self.loginViewController animated:NO];
You have to set the rootViewController like this in your AppDelegate.m
self.window.rootViewController = self.loginViewController;
Have you worked with creating your interface with storyboards yet? (Storyboards are new as of iOS 5) They are basically a way of laying out all your view controllers in one file and visually setting connections between them. What you are wanting to do is really easy with storyboards. When you set up view controllers on your storyboard file you will see an arrow pointing to the first storyboard you set up. That means when you run your app that is the initial view that will load. If you prefer a different view to load first simply drag that arrow to a different view controller.

Resources