UI is programmatically generated in my app. I have few buttons and texboxes in the UI. I have developed a custom uidatapicker object, which pops up from the top and animates to the middle of the screen. When uidatapicker pops up I draw another UIView(called helper view) with the size of the screen so all other uiobjects in the screen except uidatepicker become disabled.
But when the UIDatePicker is animating a button in the UI jumps to another location. Also I have three buttons in my UI. It happens with only one button(one UIButon in the UIView). Other two buttons are ok. Also there is no significant difference between those buttons except the button text.
I removed the earlier described view(helper view), but still the
problem is occurring.
I need to know why this is occurring how to
prevent it.
Also I have lot of other pages which works fine.
The code
-(void)openEditDateTime:(UIDatePickerMode) mode {
if ([clientView viewWithTag:9]) {
[self cancelPressed];
}
CGRect toolbarTargetFrame = CGRectMake((clientView.frame.size.width/2)-160, (clientView.frame.size.height/2)+91, 320, 44);
CGRect datePickerTargetFrame = CGRectMake((clientView.frame.size.width/2)-160, (clientView.frame.size.height/2)-125, 320, 216);
backgroundView = [[UIView alloc] initWithFrame:clientView.bounds];
backgroundView.alpha = 0;
backgroundView.backgroundColor = [UIColor blackColor];
backgroundView.tag = 9;
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(cancelPressed:)];
[backgroundView addGestureRecognizer:tapGesture];
[clientView addSubview:backgroundView];
[self bringToFront:backgroundView];
datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, self.bounds.size.height+44, 320, 216)];
datePicker.tag = 10;
datePicker.datePickerMode = mode;
[clientView addSubview:datePicker];
[clientView bringSubviewToFront:datePicker];
[datePicker becomeFirstResponder];
[self bringToFront:datePicker];
if(date != nil){
datePicker.date = date;
}
toolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, self.bounds.size.height, 320, 44)];
toolBar.tag = 11;
toolBar.barStyle = UIBarStyleBlackTranslucent;
UIBarButtonItem *spacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(donePressed:)];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:#selector(cancelPressed:)];
[toolBar setItems:[NSArray arrayWithObjects:spacer, doneButton, cancelButton, nil]];
[clientView addSubview:toolBar];
[clientView bringSubviewToFront:toolBar];
[UIView beginAnimations:#"MoveIn" context:nil];
toolBar.frame = toolbarTargetFrame;
datePicker.frame = datePickerTargetFrame;
backgroundView.alpha = 0.5;
[UIView commitAnimations];
}
- clientView is a UIScrollView.
- backgroundView is the helper view described earlier.
This is how I add buttons. I wil put only a part of the button rendering code as putting all the code is unnecessary and it has lot other dependencies as well.
-(RenderedElement*)renderElement:(NSObject*)element:(ParentView*)parent:(PageView*)page:(Page*)modelPage:(RenderedElement*)parentRenderedElement {
UIButton *buttonView = nil;
Button *templateElement = nil;
buttonView = [UIButton buttonWithType:UIButtonTypeCustom];
[buttonView setLineBreakMode:UILineBreakModeWordWrap];
[buttonView addTarget:parent action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[parent addSubview:buttonView];
}
UPDATE
When I change the order of rendering and if I render the buttons first the jumping effect is not happening. The UI works fine. It temporally solves the problem. But I want find the reason and have a better solution.
Maybe you can add
[UIView setAnimationBeginsFromCurrentState:YES];
after
[UIView beginAnimations:#"MoveIn" context:nil];
Did you actually say which button is moving? Kind of hard to help without some more detail. But here are some suggestions to look at:
Rather than adding the datepicker to the bottom of the stack and then pulling it forward:
[clientView addSubview:datePicker];
[clientView bringSubviewToFront:datePicker];
Why don't you try to try adding it by:
[clientView insertSubview:datePicker atIndex:0];
Also, you are adding the toolbar, which I assume contains the offending button, after adding the datPicker and then pulling that forward. Do you want the toolbar to be above the datepicker in the view hierachy?
Perhaps insert it at:
[clientView insertSubview:toolBar aboveSubview:datePicker];
Finally, do you need to animate the toolbar frame?
The only thing i can imagine is that may be you have this button on the client view. and since you are adding and moving this
[clientView addSubview:datePicker];
[clientView bringSubviewToFront:datePicker];
this may cause readjusting of your UIButton's frame. and since that happens during this procedure it also animates its movement which may appear as a jumping button..so i guess you should try
[jumpingButton setAnimationsEnabled:NO]; //you-know jumping button is the outlet of the -you-know-who
Related
I have a UIPickerview that is created in interface builder. And via code I placed a toolbar as its subview and a done button as the toolbars bar button item. I want to execute an action when the done button is clicked (hide the pickerview and some extra stuff). But for some reason the action for the done button is not working. Here is the code to create the toolbar and the bar button item in viewDidLoad.
UIToolbar *toolBar= [[UIToolbar alloc] initWithFrame:CGRectMake(0,0,320,44)];
toolBar.barTintColor = [UIColor colorWithRed:70/250.0f green:70/250.0f blue:70/250.0f alpha:1.0];
UIBarButtonItem *barButtonDone = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonItemStyleDone target:self action:#selector(doneButtonTapped:)];
UIBarButtonItem *flexible = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
toolBar.items = #[flexible, barButtonDone, flexible];
barButtonDone.tintColor=[UIColor colorWithRed:227/255.0f green:178/255.0f blue:49/255.0f alpha:1.0];
[picker addSubview:toolBar];
[picker bringSubviewToFront:toolBar];
And here is the method doneButtonTapped:
-(void)doneButtonTapped:(UIBarButtonItem *)sender{
NSLog(#"Done button tapped");
picker.hidden = true;
[self.view bringSubviewToFront:txtCity];
[self.view bringSubviewToFront:advancedSearchLine];
[self.view bringSubviewToFront:txtCityLine];
}
I checked in layout debugger while running the app and indeed the done button is in the front of the view, so nothing in front of it to prevent it from working. What am I doing wrong?
you cannot add toolbar as subview of picker view.create a container in UIView add toolbar and picker as subview.
UIView *inputView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, toolBar.frame.size.height + picker.frame.size.height)];
inputView.backgroundColor = [UIColor clearColor];
[inputView addSubview:picker];
[inputView addSubview:toolBar];
In my iOS app I have a media player with UIToolbar for the controls. I want to make UIBarButtonItem slide from the left onto the UIToolbar as I touch on the player screen.
This is what I've tried, and it does add the UIBarButtonItem from the left, but there is no animation part.
// create new button
UIBarButtonItem* b = [[UIBarButtonItem alloc] initWithTitle:#"b"
style:UIBarButtonItemStyleBordered
target:self
action:nil];
NSMutableArray* temp = [toolbar.items mutableCopy]; // store the items from UIToolbar
NSMutableArray* newItems = [NSMutableArray arrayWithObject:b]; // add button to be on the left
[newItems addObjectsFromArray:temp]; // add the "old" items
[toolbar setItems:newItems animated:YES];
Any kind of help is highly appreciated!
I had a similar issue where the designer wanted that kind of animation in a navbar.
Assuming that your app does not need the other buttons to move, then you can do it like this:
// create a UIButton instead of a toolbar button
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setTitle:#"b" forState:UIControlStateNormal];
// Save the items *before* adding to them
NSArray *items = toolbar.items;
// Create a placeholder view to put into the toolbar while animating
UIView *placeholderView = [[UIView alloc] initWithFrame:button.bounds];
placeholderView.backgroundColor = [UIColor clearColor];
[toolbar setItems:[items arrayByAddingObject:[[UIBarButtonItem alloc] initWithCustomView:placeholderView]]
animated:NO];
// get the position that is calculated for the placeholderView which has been added to the toolbar
CGRect finalFrame = [toolbar convertRect:placeholderView.bounds fromView:placeholderView];
button.frame = CGRectMake(-1*button.bounds.size.width, finalFrame.origin.y, button.bounds.size.width, button.bounds.size.height);
[toolbar addSubview:button];
[UIView animateWithDuration:duration
animations:^{ button.frame = finalFrame; }
completion:^(BOOL finished) {
// swap the placeholderView with the button
[toolbar setItems:[items arrayByAddingObject:[[UIBarButtonItem alloc] initWithCustomView:button]]
animated:NO];
}];
If your app does need to move the other buttons, then it's a bit trickier b/c you have to use only customView bar button items and get the initial position of all of them, pull them into the toolbar (and out of the list of items), animate them, and then put everything back. (Easy, right?) Good luck!
I have a tableview controller that has a navigation controller. I have added a toolbar to the bottom of the view and now I need to add a custom button. I have the following code (from viewDidLoad), which is producing strange results. When the view loads, I see the custom button for a brief second, then an empty toolbar. At the moment I am only trying to get one custom button to load.
self.navigationController.toolbar.barStyle = UIBarStyleBlackTranslucent;
[self.navigationController.toolbar sizeToFit];
CGFloat toolbarHeight = [self.navigationController.toolbar frame].size.height + 20;
[self.navigationController.toolbar setFrame:CGRectMake(CGRectGetMinX(self.view.bounds),
CGRectGetMaxY(self.view.bounds) - toolbarHeight,
CGRectGetWidth(self.view.bounds),
toolbarHeight)];
UIBarButtonItem *btn = [[UIBarButtonItem alloc] initWithImage:[UIImage
imageNamed:#"stub_fav.png"]
style:UIBarButtonItemStylePlain
target:self action:#selector(addFavorite)];
[btn setTintColor:[UIColor whiteColor]];
[btn setImage:[UIImage imageNamed:#"stub_fav.png"]];
NSArray *toolbarItems = [[NSArray alloc] initWithObjects:btn, nil];
[self.navigationController.toolbar setItems:toolbarItems];
Any ideas? Thanks!
Im not sure what btnAddFave is for but it's not the subview of anything. I assume btw and btnAddFave should have the same background image, if so you spelled stub_fav.png wrong. shouldn't it be stub_fave.png
I have a UIPickerView with 2 components where the user can select a font and a font size.
I want to dismiss the view once the user has selected both.
Can I somehow do this using the didSelectRow:inComponent method?
Yes, if you record the component that is provided to the method then when all of your components have had a selection made you can dismiss.
Note that users may not like it very much and adding a toolbar above the picker with a done button might work better.
I would suggest creating a container view to hold the picker and the toolbar (subviews), then show / hide the container view with whatever animations you like (instead if where you currently show the picker view). The picker and the toolbar don't need to be linked in any way, just laid out nicely in the container.
I hope it will help you
UIActionSheet *action = [[UIActionSheet alloc] init];
action.actionSheetStyle = UIActionSheetStyleBlackTranslucent;
UIPickerView *pickerFromage=[[UIPickerView alloc]initWithFrame:CGRectMake(0, 44, 0 , 0)];
UIToolbar *pickerAgeToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
pickerAgeToolbar.barStyle = UIBarStyleBlackOpaque;
[pickerAgeToolbar sizeToFit];
NSMutableArray *barItems = [[NSMutableArray alloc] init];
UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
[barItems addObject:flexSpace];
UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(PickerDoneClick)];
[doneBtn setTintColor:[UIColor blackColor]];
[barItems addObject:doneBtn];
[pickerAgeToolbar setItems:barItems animated:YES];
pickerFromage.delegate=self;
pickerFromage.dataSource=self;
pickerFromage.tag=value;
pickerFromage.showsSelectionIndicator=YES;
[action addSubview:pickerAgeToolbar];
[action addSubview:pickerFromage];
[action showInView:self.view];
[action setBounds:CGRectMake(0,0, 320, 464)];`
-(void)PickerDoneClick{
[action dismissWithClickedButtonIndex:0 animated:YES];
action=nil;
}
You can do it this way:
Take a UIView in xib and then add a UIPickerView and a toolbar with UIButton on it. Give the delegate to the UIPickerView and assign an action to the UIButton. Take an outlet of UIView and in your implementation file(ie. .m file). Hide the UIView and assign the frame to the bottom of the screen. Lets say you have named the view as myPickerView.
myPickerView.frame = CGRectMake(CGRectGetMinX(self.view.bounds),
CGRectGetMaxY(self.view.bounds),
CGRectGetWidth(myPickerView.frame),
CGRectGetHeight(myPickerView.frame));
myPickerView.hidden = YES;
After doing this you can animate the view from bottom to upwards by setting the frame again in animation block, and can also unhide it.
When you press done, again animate the view and set the frame as above.
Below is the code for animating
- (IBAction)showPicker:(UIButton *)sender {
self.myPickerView.hidden = NO;
[UIView animateWithDuration:0.5 animations:^{
[self.myPickerView setFrame:CGRectMake(0,
100,
CGRectGetWidth(self.myPickerView.frame),
CGRectGetHeight(self.myPickerView.frame))];
}];
}
action for done button:
-(IBAction)doneClicked:(id)sender {
self.myPickerView.hidden = NO;
[UIView animateWithDuration:0.5 animations:^{
[self.myPickerView setFrame:CGRectMake(CGRectGetMinX(self.view.bounds),
CGRectGetMaxY(self.view.bounds),
CGRectGetWidth(self.myPickerView.frame),
CGRectGetHeight(self.myPickerView.frame))];
}];
}
Hope this helps.
I have a UITableCell and on that cell i have a UITextBox, when the textbox is clicked instead of a keyboard being shown, a UIDatePicker is being displayed with the code below. But i am having trouble positioning the UIDatePicker. I need it to start from the very bottom of the page at at the moment it appears to start from the top of the table section where the textbox was pressed. The code fires when the user clicks the Preferred Date label. Any pointers? I have attached an image to show where it is currently rendering. Thanks.
- (IBAction)selectDateBegin:(id)sender {
//Disable Keyboard
[self.txtBookingDate resignFirstResponder];
//Disable Scrolling
[_tableForm setScrollEnabled:false];
if ([self.view viewWithTag:9]) {
return;
}
CGRect toolbarTargetFrame = CGRectMake(0, self.view.bounds.size.height-216-44, 320, 44);
CGRect datePickerTargetFrame = CGRectMake(0, self.view.bounds.size.height-216, 320, 216);
UIView *darkView = [[UIView alloc] initWithFrame:self.view.bounds];
darkView.alpha = 0;
darkView.backgroundColor = [UIColor blackColor];
darkView.tag = 9;
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissDatePicker:)] ;
[darkView addGestureRecognizer:tapGesture];
[self.view addSubview:darkView];
UIDatePicker *datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, self.view.bounds.size.height+44, 320, 216)] ;
datePicker.tag = 10;
[datePicker addTarget:self action:#selector(changeDate:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:datePicker];
UIToolbar *toolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, self.view.bounds.size.height, 320, 44)];
toolBar.tag = 11;
toolBar.barStyle = UIBarStyleBlackTranslucent;
UIBarButtonItem *spacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(dismissDatePicker:)];
[toolBar setItems:[NSArray arrayWithObjects:spacer, doneButton, nil]];
[self.view addSubview:toolBar];
[UIView beginAnimations:#"MoveIn" context:nil];
toolBar.frame = toolbarTargetFrame;
datePicker.frame = datePickerTargetFrame;
darkView.alpha = 0.5;
[UIView commitAnimations];
}
What I suggest you to do is replacing the inputView of your textField (the default is the keyboard) with this instruction:
UIDatePicker *datePicker = [[UIDatePicker alloc] init] ;
[datePicker addTarget:self action:#selector(changeDate:) forControlEvents:UIControlEventValueChanged];
[preferredDateField setInputView:datePicker];
It is more appropriate and in compliance with Apple Human Interface Guideline
Don't do it that way. Create a date picker and set it as the inputView of your text field. Then the system will present it for you, in the right place, with the right animation, instead of the keyboard.