I want to create a UIView subclass which will in its initializer add a UIView to its own view, like:
[self addSubview: someKindOfUIView];
This is how I've implemented it in the implementation file:
- (id)init
{
self = [super initWithFrame:CGRectMake(0, 0, 110, 110)];
if (self) {
self.grayView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
self.grayView.backgroundColor = [UIColor grayColor];
[self addSubview:self.grayView];
[self setBackgroundColor:[UIColor blueColor]];
}
return self;
}
But when I try to use instances of this class, the instances only show a bluebox, not a blue box containing a gray box. How can i fix that, is it possible? :)
Okay, after some testing and research I found the answer!
In my .h file I had a weak pointer to the grayView property:
#property (nonatomic,weak) UIView *grayView;
Instead, it should be:
#property (nonatomic,strong) UIView *grayView;
I sorta understand why, but i can't explain it in a good way, so if anyone can explain why (in an easy way) grayView has to have a strong pointer instead of a weak one, please comment under this answer ;)
Related
This is my custom view for video player.
Interface File : Movieplayer.h
#import <UIKit/UIKit.h>
#interface MoviePlayer : UIView{
}
#property (strong) UIButton *videoButton;
#end
Implementation File: Movieplayer.m
#import "MoviePlayer.h"
#import <MediaPlayer/MediaPlayer.h>
#implementation MoviePlayer
MPMoviePlayerViewController *movieController;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
_videoButton = [[UIButton alloc] initWithFrame:self.frame];
NSLog(#"My view frame: %#", NSStringFromCGRect(self.frame));
[_videoButton setBackgroundImage:[UIImage imageNamed:#"video-default.jpg"] forState:UIControlStateNormal];
[_videoButton addTarget:self action:#selector(showPlayer:) forControlEvents:UIControlEventTouchUpInside];
int current_tag = rand();
[_videoButton setTag:current_tag];
NSLog(#"Current tag : %d",current_tag);
[self addSubview:_videoButton];
}
return self;
}
-(void) showPlayer : (UIButton *) sender {
NSURL *movieURL = [NSURL URLWithString:#"http://km.support.apple.com/library/APPLE/APPLECARE_ALLGEOS/HT1211/sample_iTunes.mov"];
movieController = [[MPMoviePlayerViewController alloc] initWithContentURL:movieURL];
[movieController.view setFrame:_videoButton.frame];
[movieController.moviePlayer play];
[self addSubview:movieController.view];
}
#end
When i am using this class in viewcontroller, it works fully on the first control. But if i add 2 instance of the same class, the button selector is not fired for the second one.
here is how i am using it,
- (void)viewDidLoad
{
[super viewDidLoad];
UIScrollView *scrolview = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)];
// Do any additional setup after loading the view, typically from a nib.
MoviePlayer *mplayer = [[MoviePlayer alloc] initWithFrame:CGRectMake(0, 0, 320, 180)];
[scrolview addSubview:mplayer];
MoviePlayer *mplayer2 = [[MoviePlayer alloc] initWithFrame:CGRectMake(0, 180, 320, 180)];
[scrolview addSubview:mplayer2];
[self.view addSubview:scrolview];
[scrolview setContentSize:CGSizeMake(320, 600)];
}
When i click on mplayer1, it plays the video, all works here. When i click on mplayer2 nothing happens. in mplayer2, it does not call Showplayer method.
Please help.
Change the frame of the button by below way.
_videoButton = [[UIButton alloc] initWithFrame:CGRectMake(0,0,frame.size.width, frame.size.height)];
For second MoviePlayer view, the frame starts with origin.y = 180. So your button will be placed outside of your view. Change the button frame as above to solve the issue.
The problem you're having is that the _videoButton is not actually inside the bounds of its parent MoviePlayer view. In the init function, you say:
_videoButton = [[UIButton alloc] initWithFrame:self.frame];
Since the _videoButton's frame is relative to its superview, this means for your section MoviePlayer, the _videoButton gets a frame with a y value of 180. This means it is 180 points below the top of the MoviePlayer. The MoviePlayer, though, is only 180 points tall, itself, so the _videoButton is entirely outside of its parent view. This prevents you from tapping on it, even though it's visible. (By default, views don't hide subviews if they are outside of their bounds.) You can verify this by giving your MoviePlayer view a background color.
The fix is easy: don't pass your own frame to any child views. You probably instead want to do something like:
_videoButton = [[UIButton alloc] initWithFrame:self.bounds];
If you want the child view to take up the entire parent view. (Or, even better, use a nib or autolayout constraints to avoid these kinds of issues.)
I have a class which is a viewcontroller and it contains:
-(void)testNSTimer
{
[UIView animateWithDuration:1.0 delay:0 options:UIViewAnimationOptionCurveEaseIn
animations:^{ self.view.welcomeBackLabel alpha = 0;} //welcomeBackLabel does not exist.
completion:nil];
}
However welcomeBackLabel is not available in this circumstance because it is created in the controller's view AKA self.view as shown in the following code:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
welcomeBackLabel = [[UILabel alloc] initWithFrame:CGRectMake(110, -20, 100, 120)]; //welcomeBackLabel is not available for other classes to use, but I want it to be.
[welcomeBackLabel setText:#"Welcome"];
[welcomeBackLabel setTextAlignment:NSTextAlignmentCenter];
UIFont *welcomeFont = [UIFont fontWithName:#"Helvetica-Bold" size:20];
welcomeBackLabel.font = welcomeFont;
[welcomeBackLabel setTextColor:[UIColor whiteColor]];
[welcomeBackLabel setAlpha:0.65];
[self addSubview:welcomeBackLabel];
}
I created a property however it is not detected by the viewcontroller's class even after importing the view's .h file. Can anybody should me the various ways I could have welcomeBackLabel be usable in my controller class?
EDIT:
For example, in my view's .h I have:
#property(nonatomic, retain) UILabel *welcomeBackLabel;
and I have
#import "view.h"
in my controller.m but its not detecting it as a usable property o.o
EDIT2:
Ok so if I have HomeScreenView *testView = [[HomeScreenView alloc]init]; then YES i can use the property fine ala testView.welcomebackLabel.etc . It just does not work when I have set the view for the controller using [self setView:testView] and then use self.view.welcomeBackLabel... Why is this?
In a UIViewController, self.view is returned as a UIView. If you "know" that it is a particular subclass of UIView, you need to cast it so you can access methods from the subclass. You could inline this, but for clarity:
MyUIView *v = self.view;
[v myMethod];
Or if you want inline:
[(MyUIView *) self.view myMethod];
If it is sometimes the right subclass you can test:
UIView *v = self.view;
if([v isKindOfClass:[MYUIView class]]) {
[(MyUIView *) self.view myMethod];
}
Create an #property in the .h file of your class and it should be accessible from other classes well.
I have a UIView element on the screen. It is connected by an IBOutlet radioButtonGroupView. I am trying to add a subview to that element and it is not working. The subview is never added.
Here is my code:
-(id) initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
UIView *subView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
subView.backgroundColor = [UIColor yellowColor];
[self.radioButtonGroupView addSubview:subView];
return self;
}
You will probably be better off if you make this element a subclass of a UIViewController (instead of a UIView).
Then put the subview loading code inside viewDidLoad method.
- (void)viewDidLoad
{
[super viewDidLoad]; //not really needed but it doesn't hurt
UIView *subView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
subView.backgroundColor = [UIColor yellowColor];
[self.radioButtonGroupView addSubview:subView];
}
EDIT:
You say that you don't get any frame information on self.radioButtonGroupView in your viewDidLoad. That is almost a certain sign that your IBOutlet is not properly connected to the element in InterfaceBuilder. You can always make a simple test:
- (void)viewDidLoad
{
[super viewDidLoad]; //not really needed but it doesn't hurt
NSLog (#"self.radioButtonGroupView: %#",self.radioButtonGroupView);
[self.radioButtonGroupView setHidden:YES];
}
If it is still shown - then it simply isn't properly connected. IB has it's ways. Simple
deletion of IBOutlet connection and reconnecting it again might do the trick. Also: it your radioButtonGroupView is not UIView but a subclass of UIView, make sure that it's header file is imported in your MyViewController.m file and class properly defined in .xib.
I'm trying to do something very basic. I want to add a subView to my UIView subclass. I assume that I would put this in initWithFrame method as below, but view that are instances of this class do not draw this subview. What am I doing wrong?
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
redView = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 20, 20)];
[redView setBackgroundColor:[UIColor redColor]];
[self addSubview:redView];
}
return self;
}
BTW redView is a property defined in the header of the sub class, like:
#property (strong, nonatomic) UIView *redView;
Thanks for reading!
You should place your initializing code inside:
- (id)initWithCoder:(NSCoder *)aDecoder { ... }
or
- (void)awakeFromNib { ... }
These methods are called when a view is loaded from nib. Don't forget to call [super ...] in the above methods.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
HeadViewController *headViewController = [[HeadViewController alloc] initWithNibName:#"HeadViewController" bundle:nil];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 120)];
[view addSubview:headViewController.vew];
[self.view addSubview:view];
}
HeadViewController.h:
#interface HeadViewController : UIViewController
{
IBOutlet UIView *view;
}
#property (nonatomic, retain)IBOutlet UIView *view;
#end
and I connect the view to the file's owner.
And I can't see the headViewController.view.
First of all, you do not need to define the view outlet in the HeadViewController class. It is automatically inherited from the UIViewController super class.
Then, I suggest you to add directly the view of HeadViewController to your current view. Eg.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
HeadViewController *headViewController = [[HeadViewController alloc] initWithNibName:#"HeadViewController" bundle:nil];
headViewController.view.frame = CGRectMake(0, 0, 320, 120);
[self.view addSubview:headViewController.view];
}
But, if you are using ARC (Automatic Reference Counting), the headViewController instance will probably be deallocated after the end of the viewDidLoad method. It is convenient (and I'd say it is compulsory) to assign that instance to a local variable in the controller you are currently displaying. This way you will be able to handle its view's components later if needed, the instance will be retained, and everything else will work perfectly. You should have something like:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.headViewController = [[HeadViewController alloc] initWithNibName:#"HeadViewController" bundle:nil];
headViewController.view.frame = CGRectMake(0, 0, 320, 120);
[self.view addSubview:headViewController.view];
}
and
#interface MyController ()
#property (nonatomic, strong) HeadViewController *headViewController;
#end
in the hidden interface definition at the beginning of the .m class implementation file.
It looks like a typo - forgot the i in .view
[view addSubview:headViewController.vew];
i is missing in the syntax
[view addSubview:headViewController.view];