I need to customize a UIView by calling its drawRect method, so I subclass UIView and name it MyView. The drawing will depend on some variable(myString in this example), so I need to initialize the variable before drawRect starts. My MyView.h looks like
#interface MyView : UIView
#property (strong, nonatomic) NSString *myString;
#end
In the viewController.m, if I do the following
MyView *myView = [MyView alloc] initWithFrame:someRect];
[myView setMyString:#"string value"];
[self.view addSubview:myView];
everything works as expected, the myString is set before drawRect get called.
The problem I am trying to solve is if I want to add the MyView to the view controller by using Interface Builder(drag and drop an UIView to the view controller's view and change its class to MyView), where is the point that I can set myString before drawRect gets called?
set it in your view controller
-(void) viewDidLoad {
MyView *myView = self.view;
[myView setMyString:#"string value"];
]
Related
I need to subclass a UITabBarController so that I can completely replace the UITabBar view with a custom view that I can hopefully produce in the interface builder. I tried but am not succeeding.
First, I created a subclass of UITabBarController along with a xib. I deleted the default view in the xib, and replaced it with a new one that was only 60px tall (the size of my tabbar). I dragged the necessary buttons onto it, and configured the .h file like so:
#interface ToolbarViewController : UITabBarController
#property (strong, nonatomic) IBOutlet UIView *tabBarView;
#property (strong, nonatomic) IBOutlet UIButton* firstButton;
#property (strong, nonatomic) IBOutlet UIButton* secondButton;
#end
My xib looks like this:
When I launch the app, I see an empty space at the bottom made for the tab bar, but I am not seeing an actual tab bar:
Update: I realize that I'm not actually launching the xib file in the .m file. Anyone know how I can do this properly?
There are various different solutions for adding a custom set of buttons to a custom tab bar controller subclass. I've done it years ago following this guide: http://idevrecipes.com/2010/12/16/raised-center-tab-bar-button/.
The idea is to add a custom UIView over the tab bar of your UITabBarController subclass. The CustomTabBarController class doesn't have to have a xib. Instead, I have a subclass of UIView that can either be programmatically laid out, or created using a xib for a UIView. Here's the header file for my CustomTabBarView class:
#interface CustomTabBarView : UIView
{
CALayer *opaqueBackground;
UIImageView *tabBG;
IBOutlet UIButton *button0;
IBOutlet UIButton *button1;
IBOutlet UIButton *button2;
NSArray *tabButtons;
int lastTab;
}
#property (nonatomic, weak) id delegate;
-(IBAction)didClickButton:(id)sender;
You'll either connect the desired buttons to button0, button1, button2, etc in the xib file, or do it programmatically on init for the view. Note that this is the UIView subclass.
In CustomTabBarView.m:
-(IBAction)didClickButton:(id)sender {
int pos = ((UIButton *)sender).tag;
// or some other way to figure out which tab button was pressed
[self.delegate setSelectedIndex:pos]; // switch to the correct view
}
Then in your CustomTabBarController class:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
tabView = [[CustomTabBarView alloc] init];
tabView.delegate = self;
tabView.frame = CGRectMake(0, self.view.frame.size.height-60, 320, 60);
[self.view addSubview:tabView];
}
When the buttons are clicked in the CustomTabBarView, it will call its delegate function, in this case the CustomTabBarController. The call is the same function as if you clicked on a tab button in the actual tab bar, so it will jump to the tabs if you have set up the CustomTabBarController correctly like a normal UITabBarController.
Oh, on a slightly separate note, the correct way to add a custom xib as the interface for a subclass of UIView:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil];
UIView *mainView = [subviewArray objectAtIndex:0];
//Just in case the size is different (you may or may not want this)
mainView.frame = self.bounds;
[self addSubview:mainView];
}
return self;
}
In the xib file, make sure the File's Owner has its Custom class set as CustomTabBarView.
I have two UIView contained in a UIViewController - firstView and secondView - that I initialize pragmatically. I have a UILabel in the firstView, and a UIButton in the secondView. I would like the button in the second view to change the label in the first view. In the implementation file of the second view I have the following code:
- (void) changeLabel: (UIButton *) sender{
firstView *view = [[firstView alloc] init];
view.label.text = #"Changed Text";
}
However I figured out that the above method just initializes a new class of firstView and does not link to the existing UIView. How can I change properties of firstView from within secondView?
Create properties in your view controller's header file for the views:
#property (nonatomic, retain) UIView *firstView;
#property (nonatomic, retain) UILabel *label;
When you create the view and label assign them to the properties:
self.firstView = // create your view here
self.label = // create your label here
Create a button property on your UIView object so you can access it later:
#property (nonatomic, retain) UIButton *button;
Then in your view controller file, when you create everything, access the view's button property and add a target, like this:
[firstView.button addTarget:self action:#selector(changeLabel) forControlEvents:UIControlEventTouchUpInside];
Then you can simply have the method your button calls be like this:
- (void)changeLabel {
self.label.text = #"Changed Text.";
}
Ive created a UIView in code using the addSubview:view method. If I want this to be a custom class rather than the standard UIView, does all this customisation have to take place in the view controllers viewDidLoad method? Seems like there will be alot of code in the viewDidLoad if this is the case! This is the first time ive attempted to create a view in code - the other times ive done it in IB where Ive created a custom class and changed the class of the view in the identity inspector.
Create a new UIView subclass
// MyView.h
#interface MyView : UIView
// public properties, method declarations here
#end
// MyView.m
#implementation MyView
// implementation here, including anything you want to customize this view's
// look or behavior
#end
Then instantiate it in your view controller by importing and referring to the custom class
// ViewController.m
#import "MyView.h"
- (void)viewDidLoad {
[super viewDidLoad];
MyView *myView = [[MyView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:myView];
}
I'm working with creating my own custom view templates programmatically for the app I'm working on. To achieve this i have a custom view controller MyVC with a a custom view myView added on to it which is a property of MyVC. The class looks something like this:
MyVC.h
#import <UIKit/UIKit.h>
#interface MyVC : UIViewController{
MyCustomView *myView;
}
#property(nonatomic, retain) MyCustomView *myView
#end
In the implementation i want to assign a background color to 'myView' and i do something like this in the viewDidLoad (after synthesizing my property of corse)
-(void)viewDidLoad{
self.myView = [[MyCustomView alloc] initWithFrame:someFrame];
self.myView.backgroundColor = [UIColor clearColor];
}
Now when i analyze my code i get a 'potential leak of an object' message when i assign the color. Is it because myView or the background color or both are being retained?
In any case id like to know how this can be done correctly without potential leaks?
If you don't using ARC you should release over retained property:
-(void)viewDidLoad{
//allocate and initialize myView
self.myView = [[[MyCustomView alloc] initWithFrame:someFrame] autorelease];
self.myView.backgroundColor = [UIColor clearColor];
}
I have create a UIVeiw class and a .xib. Within this .xib view I have its set to freeform with the dimensions of 400x200 and I have assigned it to my custom class with the same name:
Storyboard: blogView
Class Files: blogView.h & blogView.m
Within in the .xib i have added a label and a text field and linked them up to variable within the .h files etc (See code below).
blogCont.h
#import <UIKit/UIKit.h>
#interface blogCont : UIView
#property (strong, nonatomic) IBOutlet UILabel *lbBlogDate;
#property (strong, nonatomic) IBOutlet UITextView *txtBlogTitle;
#end
blogCont.m
#import "newsStoryView.h"
#implementation blogCont
#synthesize lbBlogDate;
#synthesize txtBlogTitle;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code place a log to see if it loads
NSLog(#"View Loaded");
}
return self;
}
#end
Now with in my main viewController.m file i have added the following code to init this view class, and I have added a background colour to see if this loads in.
viewController.m
UIView *blogCont = [[blogView alloc] init];
blogCont.backgroundColor = [UIColor purpleColor];
[subview addSubview:blogCont];
Now when I run this it all works well but as I do not see the purple background it looks as if the view does not load, but within the log I do see the NSLog message I have within this view NSLog(#"View Loaded"); so it seems it initiating this, but I cannot for the life of me get this to display?
Now if I change the code slightly to my main View Controller.m fiel to:
CGRect blogFrame;
blogFrame.origin.x = 20;
blogFrame.origin.y = 20;
blogFrame.size = CGRectMake(400,200);;
newsStoryView *blogCont = [[blogView alloc] blogFrame];
blogCont.backgroundColor = [UIColor purpleColor];
[subview addSubview:blogCont];
Then I get my view display a nice purple box, so this shows up when I set a frame size and the init the view with it 'blogFrame', bu tI thought that all this would be set within the .xib settings so no need to do this?
SO how can I create this external view class and assign it into another view and then manipulate its data, as accessing the label in the .xib using blogCont.lbBlogDate.text does not seem to work that is it probably does but as I cannot view it i cannot confirm it.
What am i doing wrong?
Thanks
Seems I nearly answered my own question then did:
I was not setting the size within my separate class view I was asking for a size when init it:
- (id)initWithFrame:(CGRect)frame
this is asking for a size
so I could do the following to the above:
- (id)init
{
self = [super initWithFrame:CGRectMake(0, 0, 478, 220)];
.... rest of code
Setting the size within the view load.
But I could also set it when I init it in my main view controller as below:
newsStoryView *blogCont = [[blogView alloc] initWithFrame:CGRectMake(0, 0, 400, 200)];
This is better as I can control the position of each one. Hope this helps anyone