my didAddSubview is not being called.
This is what I am doing.
In my viewController
- (void)viewDidLoad {
[super viewDidLoad];
SomeView *view = [[SomeView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame))];
[self.view addSubview:view];
}
Where my SomeView is a UI view (.h file)
#import <UIKit/UIKit.h>
#interface DyteMeetingView : UIView
#end
in which I have didAddSubview like this
- (void)didAddSubview:(UIView *)subview{
[super didAddSubview:subview];
[self someFunc];
}
I placed debugger in didAddSubview but the debugger never reaches here and hence [self someFunc]; is also not called.
Since didAddSubview is a lifecycle method for UI view, I am also not calling it from anywhere.
Can someone help me in figure out the concept I missed out on/what I could be doing wrong?
PS: I don't have any xib file for UIView.
PS: Intentionally added swift tag as well since there isn't large chunk of code and I am confident that swift developers would be able to understand the question/code and might be able to help me out.
didAddSubview in SomeView will be called when a sub view is added to an instance of SomeView, but that isn't what you are doing here. You are adding a SomeView as a subview of another view.
You want didMoveToSuperview; in this method you can use the superview property of self to identify the view that it moved to.
The didAddSubview will be called in viewController.view, instead of your SomeView, because you using viewController.view.addSubview(subview)
Related
I am pretty stuck trying to create a IOS module for Titanium/Appc i am trying to intergrate https://github.com/antiguab/BAFluidView so i can use it in titanium.
I have followed the module tutorials have it working fine with just the standard view but when i try to add BAFluidView it doesnt work.
I have included the classes in xcode and have the code below.
#import "ComExampleFluidView.h"
#import "TiUtils.h"
#import "BAFluidView.h"
#import "UIColor+ColorWithHex.h"
#implementation ComExampleFluidView
- (void)initializeState
{
// Creates and keeps a reference to the view upon initialization
square = [[UIView alloc] initWithFrame:[self frame]];
BAFluidView *view = [[BAFluidView alloc] initWithFrame:view.frame];
[view fillTo:#1.0];
view.fillColor = [UIColor colorWithHex:0x397ebe];
[view startAnimation];
[square addSubview:view];
[self addSubview:square];
[super initializeState];
}
-(void)dealloc
{
// Deallocates the view
RELEASE_TO_NIL(square);
[super dealloc];
}
-(void)frameSizeChanged:(CGRect)frame bounds:(CGRect)bounds
{
// Sets the size and position of the view
[TiUtils setView:square positionRect:bounds];
}
-(void)setColor_:(id)color
{
// Assigns the view's background color
square.backgroundColor = [[TiUtils colorValue:color] _color];
}
#end
header file is
#import "TiUIView.h"
#interface ComExampleFluidView: TiUIView {
UIView *square;
}
#end
Can anyone give some suggestions on this?
since you are trying to bridge a native view, you need some layout helpers that are required to handle the Titanium-layout-system properly. Please check modules like ti.googlemaps, especially the initialization of views. In addition, your custom setters like setColor need to apply the color to your BAFluidView, not to your UIView, so you need to keep a reference of that inside your header. I guess the ti.googlemaps example should explain all concepts you are looking for. Good luck!
I am designing a custom view controller in interface builder with a XIB file and I have a custom UIView subclass that I want to add to my view controller. Here is how I've put my custom view into the view controller:
My TonerEffectButtonView class is a subclass of UIView (and has nothing to do with UIButton) and here is my code for it:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
-(void)prepareWithSelector:(SEL)selector onTarget:(id)targ withFilter:(GPUImageFilter*)filter{
self.gpuImageView = [[GPUImageView alloc] initWithFrame:self.frame];
UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:targ action:selector];
[self addGestureRecognizer:gesture];
selectedFilter = filter;
[filter addTarget:self.gpuImageView];
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
}
initWithFrame: is not called anyway as I'm creating the view through a XIB, and I don't need any customization in initWithCoder: so I haven't implemented it. I have a GPUImageView (that is a part of a library that I'm using) that I'm creating programatically inside my view, and adding camera input to it (if you ask what happens in the prepare method). Prepare method is called from outside, and I've verified my UIView's frame is correct when it is called. I have a breakpoint on [super drawRect:rect]; and it never gets called, and when I run the program, my custom view is not displayed, nor does receive touch events (but prepare method DOES get called so the instance is created with the correct frame). It's like it has never been put there in interface builder. What could be the cause of this? I've seen many posts about this, and they mostly refer to creating views programatically and indicating problems with 'initWithFrame:'. But I have nothing to do with that method, and I want to use the interface builder/XIB couple, please don't advice me to create the view controller programatically. What could be the cause of it?
Thanks,
Can.
UPDATE: I can verify that -(void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx is also not called in any way.
Ok, I've found the answer. First, I've tried to add another instance programatically, and I've found out that it has autoresizing mask set to none, whereas my original instance has it set to W+H. This clue made me realize that in fact, I was forgetting to add my GPUImageView instance as a subview into my custom view. I've added it, and it worked.
I created three files: MyViewController.h, 'MyViewController.m, MyViewController.xib. In thexib` file I created one UIScrollView as the root level element and made all necessary connections to its file owner.
In my .m file, I overwrite the loadView method to set some additional properties of the ScrollView.
-(void)loadView{
[super loadView];
UIScrollView *tmp = (UIScrollView *)[self view];
[tmp setMaximumZoomScale:3.0]; // crashed here
}
However, the code crashed at the last line of the function, the log said:
-[UIView setMaximumZoomScale:]: unrecognized selector sent to instance 0x1cda5d60
It seems that tmp was recognized as a UIView, not a UIScrollView despite the explicit cast. It's my understanding that [super loadView]; will load the view from the xib file and set the view of the ViewController. It didn't help even when I moved the crashed line of code to the viewDidLoad function.
Edit:
I found similar pattern in Apple's documentation site:
- (void)viewDidLoad {
[super viewDidLoad];
UIScrollView *tempScrollView=(UIScrollView *)self.view;
tempScrollView.contentSize=CGSizeMake(1280,960);
}
Edit 2:
I somewhat narrowed the problem. Now I've moved the code that casts [self view] to viewDidLoad, and the error occurs only when I override loadView. If I add
-(void)loadView{
[super loadView];
}
The error will occur. If I delete these three lines, no error. But isn't the call to super totally the same as not overriding at all? Why the difference?
Check whether the connections inspector for the connections to files owner is like this or not for scroll view...
See the below picture...
Then place your code like this in viewDidLoad...
- (void)viewDidLoad
{
[super viewDidLoad];
UIScrollView *tempScrollView=(UIScrollView *)self.view;
[tempScrollView setMaximumZoomScale:3.0];
}
This is working fine for me.
Edit 2:
-(void)loadView{
[super loadView];
UIScrollView *tempScrollView=(UIScrollView *)self.view;
tempScrollView.contentSize=CGSizeMake(320,960);
[tempScrollView setBackgroundColor:[UIColor grayColor]];
[tempScrollView setMaximumZoomScale:3.0];
}
This is also working fine for me.
I have some custom appearance properties in my view class (a descendant of UIView). I want to customize the view appearance according to these properties, but I can’t do that inside the initializer, since the values set using [[MyClass appearance] setFoo:…] aren’t in effect at that point:
#interface View : UIView
#property(strong) UIColor *someColor UI_APPEARANCE_SELECTOR;
#end
#implementation View
#synthesize someColor;
// Somewhere in other code before the initializer is called:
// [[View appearance] setSomeColor:[UIColor blackColor]];
- (id) initWithFrame: (CGRect) frame
{
self = [super initWithFrame:frame];
NSLog(#"%#", someColor); // nil
return self;
}
#end
They are already set in layoutSubviews, but that’s not a good point to perform the view customizations, since some customizations may trigger layoutSubviews again, leading to an endless loop.
So, what’s a good point to perform the customizations? Or is there a way to trigger the code that applies the appearance values?
One possible workaround is to grab the value directly from the proxy:
- (id) initWithFrame: (CGRect) frame
{
self = [super initWithFrame:frame];
NSLog(#"%#", [[View appearance] someColor); // not nil
return self;
}
Of course this kills the option to vary the appearance according to the view container and is generally ugly. Second option I found is to perform the customizations in the setter:
- (void) setSomeColor: (UIColor*) newColor
{
someColor = newColor;
// do whatever is needed
}
Still I’d rather have some hook that gets called after the appearance properties are set.
Why not wait until
- (void)willMoveToSuperview:(UIView *)newSuperview {
[super willMoveToSuperview:newSuperview];
if (newSuperview) {
... code here ...
}
}
if it's giving you trouble?
I believe UIAppearance properties are applied to a view when it is being added into a view hierarchy. So presumably you could access the set properties in UIView didMoveToSuperview.
Caveat: I am using Swift 2, so not sure about earlier versions of Swift / Objective-C. But I have found that didMoveToSuperview() will not work. The properties are available in layoutSubviews(), but that's not a great place to do anything like this (since it can be called more than once). The best place to access these properties in the lifeCycle of the view I have found is didMoveToWindow().
I would have thought that viewDidLoad would be best if it's a one-time thing. Otherwise, viewWillAppear.
EDIT:
If you want to do it in the view, and not it's controller then I would create a custom init for the view along the lines of:
-(id) initWithFrame:(CGRect) frame andAppearanceColor:(UIColor)theColor;
thereby passing the colour into the view at creation time.
I can't figure out what the problem is here. I have a very simple UIViewController with a very simple viewDidLoad method:
-(void)viewDidLoad {
NSLog(#"making game view");
GameView *v = [[GameView alloc] initWithFrame:CGRectMake(0,0,320,460)];
[self.view addSubview:v];
[super viewDidLoad];
}
And my GameView is initialized as follows:
#interface GameView : UIView {
and it simply has a new drawRect method:
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
NSLog(#"drawing");
}
In my console, I see "making game view" being printed, but "drawing" never is printed. Why? Why isn't my drawRect method in my custom UIView being called. I'm literally just trying to draw a circle on the screen.
Have you tried specifying the frame in the initialization of the view? Because you are creating a custom UIView, you need to specify the frame for the view before the drawing method is called.
Try changing your viewDidLoad to the following:
NSLog(#"making game view");
GameView *v = [[GameView alloc] initWithFrame:CGRectMake(0,0,320,460)];
if (v == nil)
NSLog(#"was not allocated and/or initialized");
[self.view addSubview:v];
if (v.superview == nil)
NSLog(#"was not added to view");
[super viewDidLoad];
let me know what you get.
Check if your view is being displayed. If a view is not currently on screen, drawRect will not be getting called even if you add the view to its superview. A possibility is that your view is blocked by the some other view.
And as far as I know, you don't need to write [super drawRect];
Note that even if viewDidLoad is called on a view controller it doesn't necessarily indicate the view controller's view is displayed on screen. Example: Assume a view controller A has an ivar where a view controller B is stored and view controller A's view is currently displayed. Also assume B is alloced and inited. Now if some method in A causes B's view to be accessed viewDidLoad in B will be called as a result regardless whether it's displayed.
If you're using a CocoaTouch lib or file you may need to override the initWithCoder method instead of viewDidLoad.
Objective-C:
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
//Do Stuff Here
}
return self;
}
I had a view that was offscreen, that I would load onscreen and then redraw. However, while cleaning up auto-layout constraints in XCode, it decided my offscreen view should have a frame (0,0,0,0) (x,y,w,h). And with a (0,0) size, the view would never load.
Make sure your NSView has a nonzero frame size, or else drawRect will not be called.