I have a uiviewcontroller that contains a uiview as a subview.
The idea is to change the uiview displayed (loading the uiview to display from a nib) by clicking on a button.
Currently I made it, by overriding the initWithFrame: method, by doing:
self = [[[NSBundle mainBundle] loadNibNamed:#"myUIView" owner:self options:nil] objectAtIndex:0];
Now, it loads perfectly. I can change between views with no problems, but,
in one of my views, I have a button: when the user clicks it, it's supposed to show an uipicker sliding from the bottom (initially hidden) to the center of the view. Altough I'm implementing the IBAction, and using:
[UIView animateWithDuration:2 delay: 0 options: 0 animations:
^(void) {
_myPicker.frame = theNewFrame;
}
completion: nil];
When I hit the button, nothing happens. No animation is shown.
What am I doing wrong?
Thanks in advance
Related
I have almost lost what's left of my sanity today ladies and gentelmen. Interface Builder is about to take it away.
I am new in iOS dev and going through a book right now with all kinds of different tasks.
What I am trying to do is to call a view using a double tap. This isn't about gesture recognizer and the taps, it is purely about the outlet.
1) I have a xib file, where a small menu is drawn.
2) Upon a double tap gesture I want this menu to come out.
This is the way I got it working for me:
- (void)displayPanel:(UIGestureRecognizer *)gesture{
CGRect frame = CGRectMake(0, self.window.frame.size.height-100, self.window.frame.size.width, 90);
NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:#"colorMenuView" owner:self options:nil];
UIView *colorView = [nibContents lastObject];
[colorView setFrame:frame];
[self.window addSubview:colorView];
[self.window setNeedsDisplay];
}
A nice little menu is drawn at the bottom.
But I want to do that not with the NSBundle's last object, I don't think it is a good approach. I want to do this by making an outlet connection to the UIView that holds my menu.
(I would've posted some pictures but I haven't got enough reputation yet)
When I try to make a connection I can't, the outlet isn't highlighting
When I change the Class of the View from UIView to CustomView I can connect the subviews, such as labels and buttons, which does seem to be how it should work. I still cannot connect the view though.
Now I add another standard view to the IB. And try to make a connection. It works! And if I try to connect the Custom View, it doesn't.
Now I change the Custom View back to standard. Neither of views can be connected.
Ok lets change one of the views to the Custom and connect another one. It works.
Let's do the implementation of another way of calling the menu now:
- (void)displayPanel:(UIGestureRecognizer *)gesture{
CGRect frame = CGRectMake(0, self.window.frame.size.height-100, self.window.frame.size.width, 90);
[[NSBundle mainBundle] loadNibNamed:#"colorMenuView" owner:self options:nil];
UIView *menu = self.menuView; // the outlet
self.menuView.frame = frame;
[self.window addSubview:menu];
[self.window setNeedsDisplay];
}
I have no errors for the chunk above. But the menu is still not shown. And it's nil, so it was never actually initiated.
Please help me to understand 2 things:
1) why IB does what it does?
2) why is the menu I finally got connected is nil?
In your second sample you set owner param of loadNibNamed to be self, but doesn't seem to have properly configured File's owner placeholder in the xib file. This results in nil outlet reference.
You should setup File's owner placeholder of colorMenuView xib to be an instance of specific class, eg. ColorMenuViewController (using Identity inspector). This will let you connect view outlet of used view controller with your top level view. This view can be then loaded using one of following approaches:
// 1
ColorMenuViewController* vc = [[ColorMenuViewController alloc] initWithNibName:#"colorMenuView" bundle:[NSBundle mainBundle]];
UIView* colorView = vc.view;
// 2
ColorMenuViewController* vc = [ColorMenuViewController new];
[[NSBundle mainBundle] loadNibNamed:#"colorMenuView" owner:vc options:nil];
UIView* colorView = vc.view;
Your base class, which implements gesture recognizer actions, can be used as the File's owner as well.
I have a UITableView with a bunch of rows. When a user taps on a row, a custom pop-up (which is a custom UIView) will appear on top of the table:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
PopUp *myPopUp = [[PopUp alloc] initWithFrame:CGRectMake(0, 0, 320, 568)];
[self.view addSubview:myPopUp];
}
I'm loading my custom UIView PopUp from a nib:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self loadNib];
}
return self;
}
- (void) loadNib
{
NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:#"PopUp" owner:self options:nil];
UIView *mainView = [subviewArray objectAtIndex:0];
[self addSubview:mainView];
}
In the PopUp, there is a button when pressed that causes the PopUp to close:
- (IBAction)closePopUp:(id)sender
{
[self removeFromSuperview];
}
The PopUp disappears when the button is pressed. However, the UITableView underneath cannot be interacted with anymore (i.e. the user cannot scroll the table, cannot tap on another row, etc.). I would like the PopUp to disappear and have the table be fully interactive again. Can anyone explain why this is happening and how I may fix this? Thanks!
Edited with screenshots
UITableView with a row of data: http://imgur.com/PlIufHI,xGKxUul,qkt27oZ#0
When a row is selected, myPopUp appears on top: http://imgur.com/PlIufHI,xGKxUul,qkt27oZ#1
When the "x" custom button is pressed, it calls closePopUp, which removes myPopUp from the superview: http://imgur.com/PlIufHI,xGKxUul,qkt27oZ#2
User is unable to interact with the table now. User cannot select a row, scroll through the table, etc.
You are actually removing the view that you loaded from the nib file, but the parent is another blank UIView that is capturing every touch within the (0, 0, 320, 568) rect.
Try removing the superview from the closePopUp method:
[self.superview removeFromSuperview];
I don't know what's going on in your specific case, but I can tell you that adding subviews to a UITableView may lead to unexpected behavior like this and it's generally a bad idea.
In order to fix what's happening and get a cleaner structure, I would suggest you to add the popup view to the window, rather than to the table view.
[self.view.window addSubview:myPopUp];
I have a UISegmentedControl set up in my XIB. I want it to appear on viewDidLoad and if the user taps the area of the screen it's in, and then to disappear if the user taps it again or to fade out if the user leaves it alone.
In looking around for how to manage this I've found a lot of stuff about fading UIViews, but not as much on fading individual subviews, and little at all on fading elements in the XIB. I tried to adapt the UIView stuff but failed.
How can I make this work?
EDIT: Okay, I've got the appearance at viewDidLoad and the fade out working. But when the user taps the area where the UISegmentedControl is (now invisible because alpha=0), nothing happens. This is the code I'm using:
- (IBAction)tapInvisibleSegContr
//This is connected to the UISegmentedControl with the action Touch Up Inside. Until now, the segmented control has been at alpha=0 since fading after viewDidLoad.
{
self.segContrAsOutlet.alpha=1.0;
[self fadeMethodThatWorksInViewDidLoad];
NSLog(#"Yup, tapped.");
}
I'm not even getting the NSLog. I've got the action hooked up to the UISegmentedControl, with the action Touch Up Inside. What am I missing?
If it is resident in a xib, just put his alpha to 0, do the properly connections: an Outlet and an IBAction for value changed
Then in the viwDidLoad right after [super viewDidLoad] write:
[UIView animateWithDuration:1 animations:^{self.mySegOutlet.alpha = 1;}];
Inside the IBAction right after you code the answer before the last } write:
[UIView animateWithDuration:1 animations:^{self.mySegOutlet.alpha = 0;}];
This is the easiest method.
Bye
In the xib set your control's alpha to 0.0, then use UIView animation methods to animate its alpha to 1.0. For example:
[UIView animateWithDuration:1.0 animations:^{
self.segmentedControl.alpha = 1.0f;
}];
EDIT: To your problem with not getting the action called, try attaching it for the value changed control event - I don't think UISegmentedControl sends for touch up inside.
Upon a certain user action, I wish to add to my UIViewController another UIView that will be half transparent; i.e. when it loads, the UIViewController view in the back will still be visible in the background, and the new UIView will appear as a layer above it.
The "Half Transparent" UIView should have several images and buttons in it, so I prefer to create a separated h, m and xib files for it so I can control it.
How should I do that?
Try this:
UIView *view = [[UIView alloc] init];
[view setAlpha:0.5];
[mainview addSubview:view]
Subclass UIView, create the nib file
Change the nib class to your custom subclass name
Change the file owner to become your view controller
In your view controller, declare a #property for the custom view using IBOutlet
Select the nib, drag from the file owner to the custom view and connect the outlet
In your button action, when you are ready to load the view, use
[[NSBundle mainBundle] loadNibNamed:#"NibName" owner:self options:nil];
Once this is done, your custom will be loaded from the nib and assigned to the property you declared.
This is a strange problem. I have an iPhone view controller for creating a new user with some text fields that require animation to avoid the keyboard when it is shown, i.e. the view animates up and down to keep a minimum clearance between the top of the keyboard and the lower edge of the text field. That worked fine when it was presented modally from the login existing user screen, the initial view controller in the storyboard.
Then I decided to change the app a bit so that the login/create user views would belong to the same view controller. They transition like so:
if(accountCreateView == nil) {
UINib *nib = [UINib nibWithNibName:#"NewAccountView" bundle:nil];
NSArray *nibViews = [nib instantiateWithOwner:self options:nil];
accountCreateView = [nibViews objectAtIndex:0];
}
[UIView transitionFromView:(displayingLoginView ? loginView : accountCreateView)
toView:(displayingLoginView ? accountCreateView : loginView)
duration:0.6
options:(displayingLoginView ?
UIViewAnimationOptionTransitionFlipFromRight :
UIViewAnimationOptionTransitionFlipFromLeft)
completion:^(BOOL finished) {
if (finished) {
displayingLoginView = !displayingLoginView;
}
}
];
This works fine too. However the code that does animation of the views does not. When a text field becomes active the code to check proximity of the text field to the keyboard is called but nothing happens when the animation block executes.
So I checked:
if([UIView areAnimationsEnabled])
NSLog(#"Animations are enabled");
else
NSLog(#"Animations are disabled");
Animations are certainly enabled.
So I moved it back further to viewDidLoad, trying a simple animation to see what works, before anything else:
CGRect viewFrame = loginNameTextField.frame;
viewFrame.origin.y = 400.f;
[UIView animateWithDuration:1.f
delay:0.f
options:UIViewAnimationOptionCurveEaseInOut
animations:^ {
loginNameTextField.frame = viewFrame;
}
completion:NULL];
This works fine! Text field moves slowly down the window.
This does nothing, and that is the confusing part:
CGRect viewFrame = self.view.frame;
viewFrame.origin.y = 400.f;
[UIView animateWithDuration:1.f
delay:0.f
options:UIViewAnimationOptionCurveEaseInOut
animations:^ {
self.view.frame = viewFrame;
}
completion:NULL];
viewFrame when set from self.view.frame has origin 0,20 and size 320,460 as expected.
I tried setting the frame property directly:
CGRect viewFrame = self.view.frame;
viewFrame.origin.y = 400.f;
self.view.frame = viewFrame;
Looks like I can change the frame of subviews of self.view but not of self.view. A fix might be to leave the initial view controller as a blank view in the storyboard and create xibs for both the login view and create user view and load them in viewDidLoad - but why?
edit: Yes, switching the storyboard version of the view controller to a plain empty view and adding the view containing the actual UI from a xib as a subview does make animations work again. Still don't know why though.
If all you need to do is keep your text fields above your keyboard, why not drop the UIViewController and change to a UITableViewController and use static cells? You place one text field per cell (creating enough cells to meet your needs) and style it how you like. When you don't have a first responder and there are few enough cells to fit on the screen, it won't scroll. It there are more than what will fit, then it will scroll to reach the bottom/top cells. Yet no matter how many cells you have, if you select a text field that will be covered up by the keyboard, the device will automatically scroll the cell to a viewable position. It's all built in and I use this feature all the time. It works with text fields and text views. Just remember to comment out the number of sections, number of rows per section, and the cell for index path methods so the static cells will work correctly. It saves a lot of coding.
HTH
Rob