My code:
#interface BIDMyClass ()
#end
#implementation BIDMyClass {
UINavigationBar *settingsBar;
}
-(void)loadView {
[super loadView];
settingsBar = [[UINavigationBar alloc] init];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[settingsBar setFrame:CGRectMake(0.0f, 0.0f, 293.0f, 44.0f)];
[settingsBar.topItem setTitle:#"Settings"];
[self.view addSubview:settingsBar];
}
settingsBar is added but there is no title on it. How can I fix it?
settingsBar.topItem is probably nil. Try setting the list of items on your settingsBar:
settingsBar.items = [NSArray arrayWithObject:[[[UINavigationItem alloc] initWithTitle:#"Settings"] autorelease]];
Alternatively you may also declare your:
IBOutlet UINavigationBar *navBar;
and connect in IB. Assuming you have an XIB file with the navBar on it.
Related
I use UITapGestureRecognizer to handle An ImageviewTap actions. In the main ViewController it works great. But when i Use another ViewController in my APP, and copy the same UITapRecognizer code I get an EXC_BAD_ACCESS code=1 address: 0x80759d3a error message to the line when i add the recognizer to my imageview. What do I wrong?
My ImageView: It works
UIImageView *live;
live = [[UIImageView alloc]initWithFrame:CGRectMake(92, 230, 136, 100)];
live.image = [UIImage imageNamed:#"online.png"];
[live addSubview:onlineLabel2];
[live setUserInteractionEnabled:YES];
[self.view addSubview:live];
[super viewDidLoad];
and my Gesture Recognizer:
UITapGestureRecognizer *singleTaP3 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(onlineTap:)];
singleTaP3.numberOfTapsRequired = 1;
singleTaP3.numberOfTouchesRequired = 1;
[live addGestureRecognizer:singleTaP3];
and the last line i get the crash.
It sounds like your live view is not retain, so when you try to add the gesture, the view doesn't exist anymore. Try to record your live view as a property in your interface, and synthetise it in your implementation.
I am not sure if that this causing you to crash your code but you should call
[super viewDidLoad];
at the start of the code. (If you are using ARC than this looks fine.)
[super viewDidLoad];
UIImageView *live;
live = [[UIImageView alloc]initWithFrame:CGRectMake(92, 230, 136, 100)];
live.image = [UIImage imageNamed:#"online.png"];
[live addSubview:onlineLabel2];
[live setUserInteractionEnabled:YES];
[self.view addSubview:live];
I test the following and it works.
The interface:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (strong, nonatomic) UIView *v;
- (void)tapAction;
#end
And the implementation:
#import "ViewController.h"
#implementation ViewController
#synthesize v=_v;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_v = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 50, 50)];
[_v setBackgroundColor:[UIColor redColor]];
[self.view addSubview:_v];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapAction)];
tap.numberOfTouchesRequired = 1;
tap.numberOfTapsRequired = 1;
[_v addGestureRecognizer:tap];
}
- (void)tapAction
{
NSLog(#"tap tap");
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
My problem was in my main viewcontroller. I called the new viewcontroller wrong, and get nullpointer for it. Get it in property, and it works. The problem is not with gesturetaprecognizer.
I have a regular UITableViewController and a UITableView as its only view, and I want to have an UIActivittyIndicatorView in addition to the table view.
So I need a view structure like this:
view (UIView):
tableView
activityIndicatorView
What's the cleanest way to do it without InterfaceBuilder? I guess I need to override the loadView: method, but I haven't succeed doing it so far.
UPDATE for ARC and iOS 5.0+ (I think old version needs to be removed already as we have new, better API's:)):
Add to header .h file of your UIViewController subclass:
#property (nonatomic, weak) UIActivityIndicator *activityIndicator;
And override methods in .m file of your UIViewController subclass:
- (void)loadView {
[super loadView];
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
// If you need custom color, use color property
// activityIndicator.color = yourDesirableColor;
[self.view addSubview:activityIndicator];
[activityIndicator startAnimating];
self.activityIndicator = activityIndicator;
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
CGSize viewBounds = self.view.bounds;
self.activityIndicator.center = CGPointMake(CGRectGetMidX(viewBounds), CGRectGetMidY(viewBounds));
}
=============================================================
non-ARC version, iOS < 5.0:
You should override method
-(void)loadView {
[super loadView];
self.activityIndicator = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray] autorelease];
[self.view addSubview:self.activityIndicator];
self.activityIndicator.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2);
[self.activityIndicator startAnimating];
}
Also, add
#property (nonatomic, assign) UIActivityIndicatorView *activityIndicator;
at the header file
and
#synthesize activityIndicator;
to the .m file
In iOS, my views work individually but I can't switch between them.
Now after a lot of google-ing around I've fond that the navigation based app would work great with the stack for views. The problem is all my views are nib/xib-less and custom tailored in the source code. Because of that I need my own UINavigationController and push and pop views by hand/code. Since every tutorial is either nib/xib and IB bound or just a mash of code snippets I need a concrete example how to do it.
A simple example with 2 programmatically created view (can be empty just have to use loadView instead of initializing with a nib/xib) and a working stack (a push and a pop of the views like: load app,create some root view if needed, push one view and from that view push the second one and then pop them) would be awesome, or at least a tutorial in that way with the whole source of the project and not snippets.
Thanks in advance.
EDIT: After some extra thinking, a little more clarification wouldn't be bad. My app will basically consist of 5 or 6 views which will be called form their respective previous view, i.e. a drill-down app.
Here's a brief code, only the essential parts:
CodeViewsPushingAppDelegate.m
#import "CodeViewsPushingAppDelegate.h"
#import "ViewNumberOne.h"
#implementation CodeViewsPushingAppDelegate
#synthesize window = _window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
UINavigationController *navController = [[UINavigationController alloc] init];
ViewNumberOne *view1 = [[ViewNumberOne alloc] init];
[navController pushViewController:view1 animated:NO];
[self.window addSubview:navController.view];
[self.window makeKeyAndVisible];
return YES;
}
ViewNumberOne.h
#import <UIKit/UIKit.h>
#interface ViewNumberOne : UIViewController
{
UIButton *button;
}
- (void)pushAnotherView;
#end
ViewNumberOne.m
#import "ViewNumberOne.h"
#import "ViewNumberTwo.h"
#implementation ViewNumberOne
- (void)loadView
{
[super loadView];
button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(110, 190, 100, 20);
[button setTitle:#"Push Me!" forState:UIControlStateNormal];
[button addTarget:self action:#selector(pushAnotherView) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
- (void)pushAnotherView;
{
ViewNumberTwo *view2 = [[ViewNumberTwo alloc] init];
[self.navigationController pushViewController:view2 animated:YES];
[view2 release];
}
ViewNumberTwo.h
#import <UIKit/UIKit.h>
#interface ViewNumberTwo : UIViewController
{
UILabel *label;
}
#end
ViewNumberTwo.m
#import "ViewNumberTwo.h"
#implementation ViewNumberTwo
- (void)loadView
{
[super loadView];
label = [[UILabel alloc] init];
label.text = #"I am a label! This is view #2";
label.numberOfLines = 2;
label.textAlignment = UITextAlignmentCenter;
label.frame = CGRectMake(50, 50, 200, 200); //whatever
[self.view addSubview:label];
}
I have an application for which I use TabBar template. In one of viewcontrollers I want to add a uinavigationcontroller. I declare it in the .h file;
#import <UIKit/UIKit.h>
#import "AnotherViewController.h"
#interface SecondViewController : UIViewController <UINavigationControllerDelegate> {
UIButton *UIButton *gotoAnotherView;;
AnotherViewController *anotherView;
UINavigationController *navigationController;
}
#property(nonatomic,retain) UIButton *UIButton *gotoAnotherView;;
#property(nonatomic,retain) AnotherViewController *anotherView;
#property(nonatomic,retain) UINavigationController *navigationController;
-(void)buttonPressed:(id)sender;
#end
And here's my .m file
#import "SecondViewController.h"
#implementation SecondViewController
#synthesize navigationController, anotherView, gotoAnotherView;
-(void)buttonPressed:(id)sender {
anotherView = [[AnotherViewController alloc]init];
[navigationController pushViewController:anotherView animated:YES];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
navigationController = [[UINavigationController alloc ]initWithRootViewController:self];
[navigationController.navigationBar setFrame:CGRectMake(0, 0, 320, 44)];
[self.view addSubview:navigationController.navigationBar];
gotoAnotherView = [[UIButton alloc] initWithFrame:CGRectMake(50, 50, 40, 40)]; //kategoributonlari
UIImage *image = [UIImage imageNamed:#"1.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(110, 5, 100, 20);
[self.view addSubview:imageView];
[kategori1 setBackgroundImage:image forState:UIControlStateNormal];
[kategori1 addTarget:self
action:#selector(buttonPressed:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:kategori1];
[super viewDidLoad];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
However I can see from the navigation bar that the navigationcontroller goes one level deeper(back button appears) but the main view remains the same with my gotoAnotherView button.
I think that I might not make the navigationcontroller control the whole view.
Instead of trying to do this in code, edit the XIB for your main window (with the UITabBarController). Drag out a UINavigationController from the Library onto the tab bar. This will create a new bar item for you, with a UINavigationController. Select the UIViewController nested in the new UINavigationController, and on the Identity tab set the Class to your view controller, and on the Attributes tab specify the name of the nib file to load.
You don't need to use IB. You can setup everything in code. First create your view controllers tab1ViewController, tab2ViewController, etc. then create the navigation controller with the root view controllers of tab1ViewController etc. and then add these controllers to the tab bar controller.
Here is a sample:
UINavigationController *tab1NavigationController = [[UINavigationController alloc] initWithRootViewController:tab1ViewController];
UINavigationController *tab2NavigationController = [[UINavigationController alloc] initWithRootViewController:tab2ViewController];
UITabBarController rootViewController = [[UITabBarController alloc] init];
rootViewController.viewControllers = [NSArray arrayWithObjects:tab1NavigationController, tab2NavigationController, nil];
[tab1NavigationController release];
[tab2NavigationController release];
I'm developing on iOS and I'm building my views programmatically. I noticed that when I try to access variables that have to be changed in my view from the view controller they are null. I'll post both the view and its view controller:
RootViewController.h
#import <UIKit/UIKit.h>
#class RootView;
#interface RootViewController : UIViewController {
RootView *rootView;
}
#property (nonatomic,retain) RootView *rootView;
#end
RootViewController.m
#import "RootViewController.h"
#import "RootView.h"
#implementation RootViewController
#synthesize rootView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)dealloc
{
[rootView release];
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)loadView{
RootView *rootV = [[RootView alloc] initWithFrame:CGRectMake(10, 10, 100, 50)];
rootV.rootViewController = self;
self.view = rootV;
[rootV release];
}
- (void)viewDidLoad{
NSLog(#"TEXT: %#",self.rootView.label.text);
self.rootView.label.text=#"HELLO!";
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
[self setRootView:nil];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
RootView.h
#import <UIKit/UIKit.h>
#class RootViewController;
#interface RootView : UIView {
RootViewController *rootViewController;
UILabel *label;
}
#property (nonatomic,assign) RootViewController *rootViewController;
#property (nonatomic,retain) UILabel *label;
#end
RootView.m
#import "RootView.h"
#import "RootViewController.h"
#implementation RootView
#synthesize rootViewController;
#synthesize label;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
//Create the label
UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 100,100, 50)];
//Set the font bold
testLabel.font = [UIFont boldSystemFontOfSize:20.0];
//Set the backgroundcolor of the label to transparent
testLabel.backgroundColor = [UIColor clearColor];
//Set the text alignment of the text label to left
testLabel.textAlignment = UITextAlignmentLeft;
//Set the text color of the text label to black
testLabel.textColor = [UIColor blackColor];
testLabel.text = #"01:30";
self.label = testLabel;
[self addSubview:label];
[testLabel release];
}
return self;
}
- (void)dealloc
{
[label release];
rootViewController = nil;
[super dealloc];
}
#end
I changed the code but it seems not working.....
Ok solved I forgot this line "self.rootView = rootV;"
Your view doesn't find out what its controller is until after its -initRootView method returns, but you're trying to use the controller from within that method.
That said, it would be much better if you followed the usual Cocoa Touch pattern for a view controller creating its view. View controllers are supposed to create their views lazily, which is to say that they defer view creation and initialization until the -loadView method is called. You can override -loadView to create your view, and also override -viewDidLoad to do any setup work that needs to be done after the view is created.
Also, it's generally not advisable for a view to know about its controller. The controller should tell the view what to do, not the other way around. If you need the view to send some information to the controller, you usually provide the controller to the view as the view's delegate. But if you just need the view controller to be able to find some subview, like your label, it's probably a good idea to either provide some accessors in the container view for that (so that the view controller can just say something like self.view.label.text = #"some text";. Another options is to set the subview's tag property to some unique value and have the controller use that to find the subview.
The problem is easy to spot, but requires some work to fix.
Looking at your code, something that I immediately want to suggest is to put all your RootView initialization code the loadView method of your RootViewController. That's where it should be (see here why).
Also, if you absolutely need your RootView to have a reference back at RootViewController, you should probably do that in viewDidLoad. But I wouldn't recommend doing that.
When using the MVC pattern, it is the controller's responsibility to initialize and update views. The line self.rootViewController.rootViewLabel = testLabel; should be removed from RootView's implementation. It's not clear what your intention is there, but if you want the rootViewLabel updated, you should let the controller do that.
To sum it all up:
// RootViewController.m
- (id)initRootViewController{
self = [super init];
if(self){
// other init code here
}
return self;
}
- (void)loadView {
RootView *rootV = [[RootView alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
self.view = rootV;
[rootV release];
}
- (void)viewDidLoad {
[super viewDidLoad];
// etc...
}
// etc.
Now, as for RootView, here is what it would look like:
RootView.h
#import <UIKit/UIKit.h>
#interface RootView : UIView {
UILabel *rootViewLabel;
}
// moved from RootViewController
#property (nonatomic, retain) UILabel *rootViewLabel;
#end
RootView.m
#import "RootView.h"
#implementation RootView
#synthesize rootViewLabel;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Whatever initialization code you might have
//Create the label
UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 100,100, 50)];
//Set the font bold
testLabel.font = [UIFont boldSystemFontOfSize:20.0];
//Set the backgroundcolor of the label to transparent
testLabel.backgroundColor = [UIColor clearColor];
//Set the text alignment of the text label to left
testLabel.textAlignment = UITextAlignmentLeft;
//Set the text color of the text label to black
testLabel.textColor = [UIColor blackColor];
testLabel.text = #"01:30";
self.rootViewLabel = testLabel;
[testLabel release];
// add rootViewLabel as a subview of your this view
[self addSubView:rootViewLabel];
}
return self;
}
- (void)dealloc
{
[rootViewLabel release];
[super dealloc];
}
#end
I hope this gives you an idea on how to structure your view initialization code...
(Disclaimer, I can't test this code now, please point out any errors! Thanks)
Not sure why you're doing it like that, but you could probably make it work if you pass the controller into the view's init:
RootView *rootV = [[RootView alloc] initRootView:self];
view's init:
- (id)initRootView:(UIViewController*)controller
{
self.rootViewController = controller;
self.rootViewController.rootViewLabel = testLabel;