I'm looking to create a sizeable subview that's draggable like this:
If there is an IBAction that takes you to the next View (SecondViewController) and when it does, there's another IBAction there and when you click on that one, it creates a SubView that's about half of the size of the current screen you're in (SecondViewController) that shows the third view controller that would be created? Also, how would you make that subView draggable? Thank you for helping.
Sorry, just to be clear, you want your second view controller to have a button that when tapped, adds your third view controller taking up half the screen at the bottom?
If this is the case then you can do this with the new view controller containers in iOS5.
Ok, so you have three view controllers. For the sake of this lets say your class are called FirstViewController, SecondViewController and ThirdViewController.
I assume from what you say that you already have you instance of FirstViewController with a button, that moves you on to an instance of SecondViewController, and that the issue is then getting SecondViewController to add an instance of ThirdViewController to the bottom half of the screen when a button is pressed.
The .m file for SecondViewController will need to do something like this:
#import "ThirdViewController.h"
#interface SecondViewController ()
#property (retain) ThirdViewController *thirdViewConroller;
- (void)buttonTap;
#end
#implementation SecondViewController
#synthesize thirdViewConroller = _thirdViewConroller;
- (void)dealloc {
self.thirdViewConroller = nil;
[super dealloc];
}
- (void)loadView {
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.titleLabel.text = #"Show third controller";
[button addTarget:self action:#selector(buttonTap) forControlEvents:UIControlEventTouchUpInside];
button.frame = // Some CGRect of where you want the button to be
[self.view addSubview:button];
}
- (void)buttonTap {
// When the button is tapped, create an instance of your ThirdViewController and add it
self.thirdViewConroller = [[ThirdViewController alloc] initWithFrame:/* Some CGRect where you want the controller to be */ ];
[self.thirdViewConroller willMoveToParentViewController:self];
[self addChildViewController:self.thirdViewConroller];
[self.thirdViewConroller didMoveToParentViewController:self];
}
#end
This should give you a button on your second controller, that will create and add you third controller. Make sure yo us till have all the standard methods that you had before, this should be in addition to what you have.
In your interface for ThirdViewController:
#interface ThirdViewController : UIViewController <NSObject>
- (id)initWithFrame:(CGRect)frame;
#end
Then in the implementation of your ThirdViewController:
- (id)initWithFrame:(CGRect)frame {
self = [super initWithNibName:nil bundle:nil];
if (self) {
self.view.frame = frame;
// Do your init stuff here
}
return self;
}
It should then handle adding the views and such forth.
Make sure your thirdViewController class has a valid initWithFrame: initialiser method.
This should do the trick, if you need any further help let me know :)
Related
I want to create a different class with a view and call that class on screen.
When I run the app, the view does not appear. If I delete that structure and create the button on the main file, it works fine. When I put it on a different class, it does not work.
MyView.h
#import <UIKit/UIKit.h>
#interface viewHome : UIViewController
-(UIView*) myHome;
#end
MyView.m (Creating a button for test)
#import "viewHome.h"
#implementation viewHome
-(UIView*) myHome {
UIView * myScreen = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
myScreen.backgroundColor = [UIColor whiteColor];
UIButton * myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
myButton.frame = CGRectMake(100,100,100,44);
[myButton setTitle:#"Login" forState:UIControlStateNormal];
[myScreen addSubview:myButton];
return myScreen;
}
#end
viewController.m
[...]
- (void)viewDidLoad
{
[super viewDidLoad];
viewHome * fncScreen;
UIView * homeScreen = [fncScreen myHome];
[self.view addSubview:homeScreen];
}
Thanks
Its a bad practice to add one viewController's view as a subview to an another viewcontroller. (unless you are using certain classes/methods that let you have childViewControllers).
Its exactly for this reason, your view doesn't appear in one case, and appears in the other case.
try adding the -(UIView*) myHome method in your viewController.m, and do a
[self.view addsubview: [self myHome]];
here's a good SO post about Nested UIViewControllers:
Is it wise to "nest" UIViewControllers inside other UIViewControllers like you would UIViews?
You could call the method [fncScreen myHome] after allocation your view homeScreen.
like this -
UIView *homeScreen = [[UIView alloc] init];
homeScreen = [funScreen myHome];
[self.view addSubView: homeScreen];
[homeScreen release];
Hope this will help you.
One obvious mistake I see in your code is this line:
viewHome * fncScreen;
OK, that's a pointer declaration, but you didn't actually create the object.
You need something like this:
viewHome * fncScreen = [[viewHome alloc] init];
Then you can call methods on such initialized object.
I have three buttons like this each corresponds to a different UIViewController:
For example, I press button 1. It will pass to the start button the view controller corresponding to that number that it will show.
I need to be able to pass it in this button:
Is it possible?
Yes, just create the UIButton as property on the view controller shown on button tap. Then, in the handler for the button tap, use the button property on the new controller to assign the button before showing the new controller.
Sample code:
//here's your method invoked when pressing the button 1
- (IBAction) pressedButtonOne:(id) sender {
NewViewController *newVc = [[NewViewController alloc] initWithNibName:#"NewViewController" bundle:nil];
newVc.startButton = self.startButton;
}
Here's the code in the controller created when pressing button 1
NewViewController.h
#import <UIKit/UIKit.h>
#interface NewViewController : UIViewController
#property (nonatomic, retain) UIButton *startButton;
//NewViewController.m
- (void) viewDidLoad {
//use self.startButton here, for whatever you need
}
If I understand the question correctly: Let's talk for button one (you can generalize it to the other buttons and VC's). Say the associated viewController is called button1ViewController.
In your button1ViewController, declare a property called button (#property(strong,non atomic) UIButton *button - also synthesize)..
In your IBAction method.
-(IBAction) button1Tapped:(id)sender {
button1ViewController.button = sender;
[self presentViewController:button1ViewController;
}
Edit: I think I get the question now.
In your mainView controller declare an instance variable: UIViewController *pushedController.
Also declare instances Button1ViewController *button1ViewController;
, Button2ViewController *button2ViewController, Button3ViewController *button3ViewController.
Now:
-(IBAction) button1Pressed:(id)sender {
if (button1ViewController==nil) {
button1ViewController = [Button1ViewController alloc] init];
}
pushedController = button1ViewController;
}
-(IBAction) button2Pressed:(id)sender {
if (button2ViewController==nil) {
button2ViewController = [Button2ViewController alloc] init];
}
pushedController = button2ViewController;
}
//same thing for button 3 pressed with button 3 controller
-(IBAction) startButtonPressed:(id) sender {
if (pushedViewController!=nil)
[self presentViewController:pushedViewController animated:YES completion:NULL];
}
I think this should work, however I haven't tried the code myself.
i'm trying to build a quiz that sets the value of a UILabel dynamically through code.
i've done this successfully before, but for some reason it's not working this time. i suspect it's because the structure of this app is different. i've tried different fixes but haven't been able to get it to work.
the way my app is set up, i have a view controller with a view that has a segmented control. when you press one of the switches on the segmented control, it inserts a subview like this:
menuTable.hidden = YES;
additionPracticeController *additionPractice = [[additionPracticeController alloc]
initWithNibName:#"additionPractice"
bundle:nil];
self.addPracticeController = additionPractice;
[self.view insertSubview:additionPractice.view atIndex:0];
[additionPractice release];
the view controller for that subview displays its view like this:
- (void)viewWillAppear:(BOOL)animated{
firstNumberString = [NSString stringWithFormat:#"%d",arc4random() % 10];
firstNumberLabel.text = firstNumberString;
secondNumberLabel.text = secondNumberString;
[super viewWillAppear:animated]}
my outlets are connected and i can get the values to appear by setting them statically from the nib (even though that's not what i want). i've tried to set firstNumberString equal to all sorts of values, but nothing shows up when i set the values through code.
i'd really appreciate it if someone could help me solve this problem.
It sounds like you have the label connected in Interface Builder. I would need to see more code to know exactly what you are doing wrong. Make sure you are using a property for your label. The below code is a simple example of how this works.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
{
IBOutlet UILabel *_displayMessage;
}
#property (nonatomic, retain) UILabel *displayMessage;
#end
ViewController.m
#import "ViewController.h"
#implementation ViewController
#synthesize displayMessage = _displayMessage;
- (void)viewDidLoad
{
[super viewDidLoad];
self.displayMessage.text = #"Text Changed!";
}
- (void)viewDidUnload
{
self.displayMessage = nil;
[super viewDidUnload];
}
- (void)dealloc
{
[_displayMessage release];
[super dealloc];
}
#end
Instead of making your class a subclass of UIControl just implement this method below. When the user hits done or return the keypad will resign
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
To make the text field dismiss when the user taps outside of the text field.
Place this in ViewDidLoad:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
Place this method within the class:
-(void)dismissKeyboard
{
[aTextField resignFirstResponder];
}
Also if you want to dismiss the text field from another button spefically and not just a screen tap. Then just call this from within the button.
[your_textfield_name resignFirstResponder];
I have a UINavigationController (to use like a wizard page) which I create programmatically and I need to display a "Cancel" button to cancel the process in any UIViewController.
Creating the UINavigationController:
FirstVC *firstVC = [[[FirstVC alloc] initWithNibName:#"FirstPage" bundle:nil] autorelease];
firstVC.delegate = self;
navigationController = [[UINavigationController alloc] initWithRootViewController:firstVC];
[self.view addSubview:navigationController.view];
Adding Cancel Button:
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:#selector(cancelRequestNewLeave:)];
navigationController.topViewController.navigationItem.rightBarButtonItem = cancelButton;
[cancelButton release];
But when I push a second page to UINavigationController the cancel button is not shown on the UINavigationBar. If I go back to first page, the cancel button is there. So, apparently the button is added only for the first view. I believe this is because I'm not subclassing UINavigationController, because I need to use it in a subview. But I don't know how to set the rightBarButtonItem in a UINavigationController which is created programmatically.
navigationController.topViewController.navigationItem.rightBarButtonItem = cancelButton;
Can someone shed a light on this?
Thanks in advance.
The navigation item is per view controller. The navigation bar draws its contents from the navigation item of the view controller whose view it's currently framing, which corresponds to the view controller at the top of the navigation controller's stack.
You basically need each view controller to stick a cancel button in its navigation item. You can do any of the following:
Copy-paste the code into all relevant view controllers.
Move the code into a utility function or class and call that.
Create a common superclass for all relevant view controllers that handles setting up the cancel button for its subclasses.
You can also subclass UINavigationcontroller and overide few methods like this:
- (id)initWithRootViewController:(UIViewController *)rootViewController {
self = [super initWithRootViewController:rootViewController];
if (self) {
[self setCloseButtonToController:rootViewController];
}
return self;
}
- (void)dismissController {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)setCloseButtonToController:(UIViewController *)viewController {
UIBarButtonItem *closeItem = [[UIBarButtonItem alloc] initWithTitle:#"Close" style:UIBarButtonItemStylePlain target:self action:#selector(dismissController)];
[viewController.navigationItem setRightBarButtonItem:closeItem];
}
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
[super pushViewController:viewController animated:animated];
[self setCloseButtonToController:viewController];
}
You can instead adopt the UINavigationControllerDelegate protocol in the class which creates the UINavigationController instance. You can also create the cancelButton in advance and then implement navigationController:willShowViewController:animated: like this,
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
viewController.navigationItem.rightBarButtonItem = cancelButton;
}
You will have to remember to create and hold the cancelButton and not release it. This will also mean cancelRequestNewLeave: will have to be a method in class that creates the UINavigationController instance which is what it is right now I guess.
create CommonViewController
create FirstViewController (extends from CommonViewController)
create SecondeViewController (extends from CommonViewController)
add function common functions in the CommonViewController
like that
CommonViewController.h
#interface CommonViewController : UIViewController
-(void) initializeCartBarButton;
#end
CommonViewController.m
#import "CommonViewController.h"
#interface CommonViewController ()
#end
#implementation CommonViewController
-(void) initializeCartBarButton {
UIBarButtonItem *cartBarButton = [[UIBarButtonItem alloc] init];
cartBarButton.title = #"cart";
[cartBarButton setTarget: self];
[cartBarButton setAction: #selector(goToCart:)];
self.navigationItem.rightBarButtonItem = cartBarButton;
}
- (IBAction) goToCart:(id)sender {
NSLog(#"");
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
FirstViewController.h
#import <UIKit/UIKit.h>
#import "CommonViewController.h"
#interface FirstViewController : CommonViewController
#end
FirstViewController.m
#import "FirstViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initializeCartBarButton];
}
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#import "CommonViewController.h"
#interface SecondViewController : CommonViewController
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initializeCartBarButton];
}
#end
note: you can add the code of initializeCartBarButton in the viewDidLoad of CommonViewController and delete this fuction from CommonViewController and from child class's
This is how I did it with UINavigationController subclass that is capable of dismissing every viewController pushed into it.
class CustomNavigationController: UINavigationController, UINavigationControllerDelegate{
//TODO: Use when we have more right bar button types.
var rightBarButtonType: RightBarButtonType = .Close
enum RightBarButtonType{
case Close
}
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
// MARK: Private Functions
private func addRightBarButtonTo(viewController: UIViewController){
let barButtonItem: UIBarButtonItem!
switch self.rightBarButtonType {
case .Close:
barButtonItem = UIBarButtonItem(image: UIImage(named: "ic_close_white"), style: .Done, target: self, action: #selector(CustomNavigationController.dismiss(_:)))
}
viewController.navigationItem.rightBarButtonItem = barButtonItem
}
// MARK: UINavigationController Delegate
func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
self.addRightBarButtonTo(viewController)
}
#objc func dismiss(sender: AnyObject){
self.presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
}
}
You'll need to add the button in every view controller. You cannot do it by setting one once or sharing one between view controllers (in a sensible fashion). A good place to add the button is in the viewDidLoad method of your view controllers. You can create one basic UIViewConteoller subclass for them if you feel this gets to repetitive.
You can add a custom 'Cancel' UIButton directly to the NavigationBar's view instead of using the UIBarButtonItem.
UIButton *cancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
cancelButton.imageView = // Some custom image
cancelButton.frame = CGRectMake(...); // Something far to the right.
[self.navigationController.navigationBar addSubview: cancelButton];
The normal way to do this is to add that cancel button to the navigationItem of every single view controller in your navigation stack. The above approach can make it simpler by allowing you to write less code, but it is a tiny bit of a hack.
Add this code in your rootview viewDidLoad method and implement the cancelMethod in rootview controller.This will be available in all the view controllers. you can adjust the button location by changing button frame.For orientation change you have manually adjust the location of button.
UIButton *btnCancel = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btnCancel addTarget:self
action:#selector(cancelMethod)
forControlEvents:UIControlEventTouchDown];
[btnCancel setBackgroundImage:[UIImage imageNamed:#"image"]
forState:UIControlStateNormal];
btnCancel.frame = CGRectMake(280, 27, 45, 25);
[self.navigationController.view addSubview: btnCancel];
In my viewbased application i loaded oneview as mainview and another view as subview of mainview. Its work well the code snippet is ,
In mainviewcontroller,
IBOutlet UIView *subView;
#property(nonatomic,retain) UIView *subView;
#synthesize subView;
[subView release];
//add subview
[self.view addSubview:subView];
//removefromsubview
[subView removeFromSuperview];
This code works fine.....
I dont want to create subview in mainviewcontroller, so i created a new UIView class and its named as subView, now i deleted all declarations of subView from mainviewcontroller and just import subView class in mainviewcontroller. And using this [self.view addSubview:subView];
This things not work great. Can anyone help me ... How can i interact a separate UIView class with UIViewcontroller.One more thing is that UIView class have labels and textboxes can i set values from UIViewController to UIView labels and textboxes ......
Is it possible ?
Thanks in advance.......Sorry for my bad english
You have a sub-class called Subview which is declared as a UIView, i.e.
#interface Subview : UIView {
UILabel *foo;
}
#property (nonatomic, retain) UILabel *foo;
#end
Now you want to use this sub-class inside of your main UIView, which you had from the start. There are a few things you need to do.
#import the Subview in your header file, and add an instance of it to your class.
#import "Subview.h"
and inside of your #interface's {}'s,
Subview *mySubview;
In the viewDidLoad class for your main view controller, around the bottom, add something like:
mySubview = [[Subview alloc] init];
[self.view addSubview:mySubview];
[mySubview release];
First line will allocate a new "Subview" for you, second line will add this to your view so you get the stuff it has, and third line will release it. It's okay to release it here, because "self.view" will now be responsible for it, so it won't vanish.
Lastly you need to set the view up in the init method for Subview. In Subview.m, do something like:
- (id)init
{
if (self = [super init]) {
foo = [[UILabel alloc] init];
foo.text = #"Hello!";
[self addSubview:foo];
}
return self;
}
And I think that should take care of it. You also want to release foo in -dealloc for Subview but you probably know how to do that stuff already.