Subviews not drawing in subclassed UIView - iphone

I have a subclassed UIView that will not draw it's subviews. Or at least, it's not showing it's subviews. The whole view is loaded from a nib.
Also, strangely, it will not draw the background I set in IB. (I'm using Xcode 4.2).
But it will draw the parent view what I specify in awakeFromNib such as background, border, and corner.
The opaque property is set to NO. Any suggestions are appreciated!

When you load a view from a nib, e.g. using
[[NSBundle mainBundle] loadNibNamed: owner:self]
you still need to then add that loaded view as a subview to one of the views currently visible in your window for that view to become visible. Having an outlet to it from your owner ensures that the view is loaded and you have a reference to it - but that alone does not cause it to be added as a subview to the owner.
So (assuming self is the parent view and the owner in the nib) make sure first that you definitely have the outlet set in the nib from the owner to the view being loaded, and then that you are doing a
[self addSubview:loadedView]
(Where loaded view is the view in the nib who's owner is self).

I think you might get that result if you override drawRect. Try commenting that out and see what happens. If you want to both draw your own content and include subviews, you might be able to do that by calling [super drawRect] at the beginning of your drawRect.

Related

Change view with xib

I have one xib in portrait view and one in landscape view. I am changing xib in rotation like this:
[[NSBundle mainBundle] loadNibNamed:[NSString stringWithFormat:#"%#_landscape", NSStringFromClass([self class])]
owner: self
options: nil];
It's working fine but if I open one view as a subview in the current view then it disappears. For example, on any button click I am adding one view (like a popover) in the current view, but in the rotation subview it disappears. How can I solve this issue?
Any help is appreciated.
You need to make property for that view and when ever you perform rotation you need to re add same view on the top of rest of the views by simply use addSubview function of UIView.
Instead of changing views for different mode,use autoresizing.It will let you work on single view autoResize when rotate.Here is fine example you can learn.
AutoResizing
I think this is not a good approach. You should take one UIViewController with XIB. Now take two views(one for landscape and another for portrait connect it with outlets) outside ViewController's view, and on at rotation time
yourCurrentView = landscapeView/portraitView;
[self.view addSubview:yourCurrentView];
and set it [self.view sendSubviewToBack:yourCurrentView]; //because what ever view added dynamically on self.view remains on top, now your view which was added always show at every mode.
I hope it will help you.

How do you add pointsInside:withEvent to xib view?

I'm just learning iOS programming, so sorry if this is a dumb question.
I have a view in a xib that's acting as an overlay, but I want that view to be "transparent", so that people can manipulate (tap) the views below it. I read that pointsInside:withEvent will do it (if set to return NO), but where do I put this method?
I have a viewController that owns my xib, but putting the method there doesn't do anything...
How do I add my method to a xib view? Do I have to make another view (programmatically) and add my overlay xib as a subview?
Thanks
You can set userInteractionEnabled to NO on the view instead. Overriding pointInside:withEvent: is really for modifying the "shape" of the view.
If you do want to override pointInside:withEvent: you will need to make a UIView subclass and do it there. However you can still add this view inside your xib. Select the view in the xib, and in the Identity Inspector pane set the class to your subclass.

Make self.view a UIScrollView?

I'm experimenting with a TabBarController and the default project creates the UITabBarController and also gives you two view controllers.
I want the view of one of these view controllers to be a UIScrollView, i.e. when calling self.view on FirstViewController I want to get back a UIScrollView * and not just a UIView *.
The view controller gets initialised with initWithNibName: but I can't see anything assigning the view property in there.
If this all sounds a bit weird, maybe I'm doing this wrong? I realise I can drop a UIScrollView onto the view that's already created with me, but it just seemed a bit pointless to have a parent view in this case.
Thanks in advance.
Ok, just realised how to do this.
I can do a cast in my code to make UIView a UIScrollView. Like so...
UIScrollView *tempScrollView = (UIScrollView *)self.view;
tempScrollView.contentSize = self.view.bounds.size;
Then, in Interface Builder, you can use the inspector to set a custom class for your UIView. I set the class as UIScrollView in here and all seems to work!
If you want to use interface builder. Just load up your nib, delete the view on the left panel, and drag a UIScrollView into the area.
Next link from Files Owner to the new UIScrollView as the view property.
The only downside to doing it this way is in your code, whenever you want specific UIScrollView functions you will have to typecast the view property (using (UIScrollView *)self.view ), or put it in a variable like so
UIScrollView *sview = self.view;
//Then use sview for your changes
The best way would be to do it in code however.

How can I modify an existing UIViewController to allow scrolling?

I have already built a UIViewController subclass with a bunch of controls in it, and just realized that if I rotate the iPhone, half of the controls become invisible. So, I would like to somehow make the UIViewController's UIView scrollable so that when the device (or the Simulator) rotates, the user can scroll the view to see all the controls.
I was hoping to do this all in Interface Builder. I tried to change the class of the view from UIView to UIScrollView in the Class Identity editor, but nothing scrolls. The base class of my view controller is a simple UIViewController <UIScrollViewDelegate>.
Is there an easy way to make the main view in my view controller scrollable without having to recreate the whole thing in IB?
For people who are using storyboard, this is quite easy to do
in Document Outline select the topmost View of the UIViewController
then in Identity Inspecter, under Custom Class, for class enter UIScrollView
That's it.
Add a UIScrollView and make all your controls and widgets and labels subviews of the scroll view by dragging them from wherever they are "into" or "inside" the scroll view. This makes them subviews of the scroll view, which is what you want.
You can do this as follows:
Open your nib file and Create a UIScrollView object under your UIView Object.
Move all your controls onto the UIScrollView
Open your header file (.h) and add a new property for the scroll view:
#property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
Open your implementation file (.m) and insert the following:
#synthesize scrollView;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Enable scrolling for portrait
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width, 600);
}
Go back to your nib file and wire up the scrollView on the file's owner to your UIScrollView object.
The real trick here is setting the scrollView.contentSize. Once this is set, the scrolling should occur.
If you wanted to enable scrolling for when the device is in portrait orientation, you could use this:
// Enable scrolling for landscape orientation
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width, scrollView.frame.size.height);
This should give you some frame of reference.
Flea
It would be helpful to understand what your interface is displaying, but I'd suggest one of the following:
Don't allow rotation by returning NO from shouldAutorotateToInterfaceOrientation
Use Interface Builder to adjust your springs and struts so that all of your interface elements fit in landscape view
Add a new UIScrollView in Interface Builder and drag your UIView into it, then re-assign the view property of your File's Owner to the scroll view.
I was able to do this by adding a scroll view to the view in IB, making the view controller a UIScrollViewDelegate, hooking up the scrollview to a UIScrollView object in IB, hooking the delegate up to file owner, and adding this line in the viewDidLoad:
- (void) viewDidLoad {
scrollView.contentSize = CGSizeMake(1280, 960);
}
Scrolling behavior is only invoked if the contentSize of a UIScrollView is larger than its bounds.
Add a Scrollbar into Xib file and then drag & drop controls in to the Scrollbar. Inside load view use
scrollView.contentSize = CGSizeMake(CONTENT_WIDTH, CONTENT_HEIGHT);

superview and parentviewcontroller nil after adding a subview

I think I'm missing something fundamental and so I want to ask the community for some help. I'm building an app based around a basic iPhone Utility Application. My MainView and FlipsideView share some elements so I have created separate ViewControllers and nib files for those pieces. In order to do this I have done the following:
1. Created a viewcontroller called searchDateViewController which is the file's owner of searchDateView.xib
2. searchDateView.xib is basically a UIView with a UILabel inside, the view is wired up correctly
3. Inside both MainViewController.m and FlipsideViewController.m I add a subview as folllows:
- (void)loadView{
[super loadView];
searchDateViewController = [[SearchDateViewController alloc] initWithNibName:#"SearchDateView" bundle:nil];
[[searchDateViewController view] setFrame:[searchDateView frame]];
[[self view] addSubview:[searchDateViewController view]];
...
}
Everything displays and works just fine. Basically depending on actions that happen in each of the main and flipside views the UILabel of the nib is changed. However, I wanted to do something slightly different if the searchDateViewController is loaded from the MainView or the FlipsideView. However, I can't seem to figure out which ViewController is adding the searchDateViewController subview.
In searchDateViewController I tried:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"superview %#", self.view.superview);
NSLog(#"parentviewcontroller %#", self.parentViewController);
}
In both cases I get nil.
So my question is - can I find out which ViewController is adding searchDateViewController a a subview? If so how? Or if my logic here is completely messed up, how should I be doing this?
Thanks!
viewDidLoad is invoked when the view controller has loaded its view. In your case, that happends in this line:
[[searchDateViewController view] setFrame:[searchDateView frame]];
At that moment, you haven't yet called addSubview: so it is no wonder the view's superview is nil.
To solve your problem, you should define a property inside SearchDateViewController to distinguish between the different cases. This property would then be set accordingly by the parent controller that creates the SearchDateViewController instance.
Generally, I do not think it is a good idea to use a UIViewController subclass as a controller for a view that is used as a subview of one or several fullscreen views rather than be used as a fullscreen view itself. Much of UIViewController's logic works on the assumption that it is used to manage a fullscreen view. For instance, with your design, I think it's possible that SearchDateViewController will modify the view's frame when the device orientation changes etc. Since you don't need all this functionality for a non-fullscreen subview, I suggest you subclass your SearchDateViewController directly from NSObject.
ViewController and views are completely separate.
In most cases, when you add a subview to a parent view you don't add its controller to the parent's viewController. The exception to this rule is the navigation controller which adds the controller instead of the view to maintain a hierarchy of view controllers.
Your SearchDate viewController can't find a parent controller because you never assigned one and the system does not do it automatically. You can just assign a parent controller when you evoke the view from another controller.
searchDateViewController.parentController=self;