I have CalenderVC which consist of Container View named PickerController.
PickerController consist of one toolbar,datepicker.Everytime i want to add date i use PickerController but
my problem is on somecondition i also want to set minimum date.I also passed minimumdate using customdelegate but still datepicker not set minimum date.
//CalendarVC added PickerController
- (void)displayContentView
{
UIStoryboard *story=[UIStoryboard storyboardWithName:#"Pagebar" bundle:nil];
objContent=[story instantiateViewControllerWithIdentifier:#"pickerVCID"];
objContent.datePicker.hidden=false;
self.dtDelegate=objContent;
objContent.view.frame=CGRectMake(0,0, self.view.frame.size.width, 280);
if(isFromDate==false)
{
// delegate method that set minimum date of picker
[self.dtDelegate setMinDate:minimumDate];
}
_pickerContainerVw.hidden=false;
[self addChildViewController:objContent];
[self.view addSubview:_pickerContainerVw];
[objContent didMoveToParentViewController:self];
}
-(void)removeContentView
{
_pickerContainerVw.hidden=true;
[objContent willMoveToParentViewController:nil];
[objContent.view removeFromSuperview];
[objContent removeFromParentViewController];
objContent.view.hidden=true;
}
// In pickercontroller
-(void)setMinDate:(NSDate *)minDate
{
[self.datePicker setMinimumDate:minDate];
[self.view addSubview:self.datePicker];
NSLog(#"minimum date %#",minDate);
}
There are several potential problems with your code.
First make sure you have connected your outlets in pickerVCID, especially datePicker.
Then I wonder why you add the picker to the view pickercontroller in setMinDate:? Since you seem to have designed it as a storyboard view controller you already have it as a child in the correct view. In that case you can just hide/show it.
Also, where do you set _pickerContainerVw? Is it the same as objContent.view? You are adding the objContentas a child view controller, but _pickerContainervW as sub-view. Probably you want to add the objContent.view as a sub-view instead.
With the risk of introducing side-effects with my changes, since I haven't seen all of your code, I have fixed some of the above.
//CalendarVC added PickerController
- (void)displayContentView
{
// Instantiate picker
UIStoryboard *story=[UIStoryboard storyboardWithName:#"Pagebar" bundle:nil];
objContent=[story instantiateViewControllerWithIdentifier:#"pickerVCID"];
self.dtDelegate=objContent;
objContent.view.frame=CGRectMake(0,0, self.view.frame.size.width, 280);
// Add it as a child VC
[self addChildViewController:objContent];
[self.view addSubview:objContent.view];
[objContent didMoveToParentViewController:self];
// Start with hidden date picker, show if needed
objContent.datePicker.hidden = YES;
if(isFromDate==false)
{
// delegate method that set minimum date of picker
objContent.datePicker.hidden = NO;
[self.dtDelegate setMinDate:minimumDate];
}
}
-(void)removeContentView
{
[objContent willMoveToParentViewController:nil];
[objContent.view removeFromSuperview];
[objContent removeFromParentViewController];
}
// In pickercontroller
-(void)setMinDate:(NSDate *)minDate
{
[self.datePicker setMinimumDate:minDate];
NSLog(#"minimum date %#",minDate);
}
Related
Setting:
Assume I have 2 TableViewControllers(All in their own NavigationControllers), which contain TypeA&B items correspondingly.
In any TableView, If I tap "+" button, it will segue to a Add[?]ItemViewController("?" is The Type of Item: A or B).So normally, even if I already in the AddView, I can also switch to another View By tapping Tab Bar Icon, right?
SO How can I inhibit user to switch if they already entered one AddView?
Use the Swift code? or just change the storyboard structure?
Here is the Structure of Main.storyboard:
We've done exactly the same in our application. To hide the default
TabBar, simply override the hidesBottomBarWhenPushed method in your
parent view controller (or in every view controller in your App)
#pragma mark - Overriden UIViewController methods
- (BOOL)hidesBottomBarWhenPushed {
return YES;
}
another Solution
You can also Hide Tab bar
// pass a param to describe the state change, an animated flag and a completion block matching UIView animations completion
- (void)setTabBarVisible:(BOOL)visible animated:(BOOL)animated completion:(void (^)(BOOL))completion {
// bail if the current state matches the desired state
if ([self tabBarIsVisible] == visible) return;
// get a frame calculation ready
CGRect frame = self.tabBarController.tabBar.frame;
CGFloat height = frame.size.height;
CGFloat offsetY = (visible)? -height : height;
// zero duration means no animation
CGFloat duration = (animated)? 0.3 : 0.0;
[UIView animateWithDuration:duration animations:^{
self.tabBarController.tabBar.frame = CGRectOffset(frame, 0, offsetY);
} completion:completion];
}
// know the current state
- (BOOL)tabBarIsVisible {
return self.tabBarController.tabBar.frame.origin.y < CGRectGetMaxY(self.view.frame);
}
// illustration of a call to toggle current state
- (IBAction)pressedButton:(id)sender {
[self setTabBarVisible:![self tabBarIsVisible] animated:YES completion:^(BOOL finished) {
NSLog(#"finished");
}];
}
another Solution
You can set the UIViewController.hidesBottomBarWhenPushed instead:
DetailViewController *detailViewController = [[DetailViewController alloc] init];
detailViewController.hidesBottomBarWhenPushed = YES;
[[self navigationController] pushViewController:detailViewController animated:YES];
When I give a good swipe to my tableView and press the "Back" button before the tableView ended it's scrolling, my app crashes. I've tried the following:
- (void) closeViewController
{
[self killScroll];
[self.navigationController popToRootViewControllerAnimated:YES];
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)killScroll
{
CGPoint offset = sellersTableView.contentOffset;
[sellersTableView setContentOffset:offset animated:NO];
}
That didn't work, same crash. I don't see why, the error I'm getting is the following:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource must return a cell from tableView:cellForRowAtIndexPath:'
So that means that the tableView is still requesting a cell when everything is already being deallocated. Makes no sense.
Then I tried this:
- (void) closeViewController
{
[self.navigationController popToRootViewControllerAnimated:YES];
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)dealloc
{
sellersTableView.dataSource = nil;
sellersTableView.delegate = nil;
sellersTableView = nil;
}
Gives me the same error. Any ideas?
Update:
My delegate methods
creation
if (textField == addSellerTextField) {
sellersTableView = [[UITableView alloc] initWithFrame:CGRectMake(addSellerTextField.frame.origin.x + addSellerTextField.frame.size.width + 10, addSellerTextField.frame.origin.y - [self heightForTableView] + 35, 200, [self heightForTableView])];
sellersTableView.delegate = self;
sellersTableView.dataSource = self;
sellersTableView.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:0.05];
sellersTableView.separatorColor = [[UIColor grayColor] colorWithAlphaComponent:0.15];
sellersTableView.rowHeight = 44;
sellersTableView.layer.opacity = 0;
[self.companyView addSubview:sellersTableView];
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{sellersTableView.layer.opacity = 1;} completion:nil];
}
cellForRowAtIndexPath
if (tableView == sellersTableView) {
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.backgroundColor = [UIColor clearColor];
if ([sellersArray count] > 0) {
cell.textLabel.text = [sellersArray objectAtIndex:indexPath.row];
} else {
UILabel *noSellersYetLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, sellersTableView.frame.size.width, [self heightForTableView])];
noSellersYetLabel.text = #"no sellers yet";
noSellersYetLabel.textAlignment = NSTextAlignmentCenter;
noSellersYetLabel.textColor = [UIColor grayColor];
[cell addSubview:noSellersYetLabel];
sellersTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
}
}
removing
- (void) textFieldDidEndEditing:(UITextField *)textField
{
if (textField == addSellerTextField) {
[self updateSellers:textField];
}
}
- (void)updateSellers:(UITextField *)textField
{
[textField resignFirstResponder];
[self hideSellersTableView];
}
- (void)hideSellersTableView
{
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{sellersTableView.layer.opacity = 0;} completion:nil];
sellersTableView.dataSource = nil;
sellersTableView.delegate = nil;
[sellersTableView removeFromSuperview];
sellersTableView = nil;
}
Solution
So apparently putting the dataSource = nil and delegate = nil into textFieldDidEndEditing fixed the problem. Thanks everybody for the answers!
It's strange behaviour of UITableView. The easiest way to resolve this issue just set the dataSource and delegate property of UITAbleView to nil before you make a call of function popToRootViewControllerAnimated. Furthermore you can use more common solution and add the code that set the properties to nil into the -dealloc method. In addition you no need the -killScroll method.
After a short research I have realized what the problem is. This unusual behaviour appeared in iOS 7. The scroll view retained by its superview may send message to delegate after the delegate is released. It happens due to -removeFromSuperview implementation UIScrollView triggers -setContentOffset: and, eventually, send message to delegate.
Just add following lines at the beginning of dealloc method:
sellersTableView.delegate = nil;
sellersTableView.dataSource = nil;
No need to use hacks like your killScroll method.
Also, I can't see why you want to call both popToRootViewController and dismissViewController.
If you dismiss a view controller which is embedded in a navigation controller, navigation controller itself as well as all contained view controllers will be released.
In your case you'll have just weird animation.
setContentOffset method won't help you, try to set
sellersTableView.dataSource = nil;
somewhere in your viewWillDisappear method.
This is not a good practice of course.
Change you closeViewController like below and see if works
(void) closeViewController
{
sellersTableView.dataSource = nil;
sellersTableView.delegate = nil;
[self.navigationController popToRootViewControllerAnimated:YES];
[self dismissViewControllerAnimated:YES completion:nil];
}
I don't think that setting the tableView (or it's delegate) to nil is the issue. You should be able to perform both dismissViewControllerAnimated or popToRootViewController individually without having to modify the tableView in this way.
So the issue is most likely due to calling both of these methods at the same time (and with animated = YES), and in doing so asking your viewController setup to do something unnatural.
Looks like upon tapping a "close" button you are both popping to a rootViewController of a UINavigationController, as well as dismissing a modal viewController.
In doing so, you're dismissing a modal viewController which is likely presented by the topViewController of the navigationController (so top vc is holding a reference to modal vc). AND you're trying to kill the top vc via the popToRootViewController method call. And you're doing both of these things using animated = YES, which means they take some time to complete, and you can't be sure when each finishes (ie you can't be sure when dealloc will be called).
Depending on your needs you could do one of several things.
Consider adding a delegate property to your modal vc. Dismiss the modal vc, and in the completionBlock of the modal vc tell its delegate that it's finished dismissing. At that point call popToRootViewController (because at this point you can be sure that the modal is gone and scrolling wasn't interrupted).
If it's your navController that's been presented modally, then do this in the opposite order. Notifying the delegate that the pop operation has completed, and do the modal dismissal then.
iOS unfortunately doesn't have a dropdown picker like html does with the tag. I decided that I was finally going to create one for my app, and it looks and works great. My dropdown object is a subclass of UITextField. However, I changed something and now it only works some of the time.
User interaction is enabled, but I don't want the textfield to be editable. The class in which my dropdown subclass resides is UITextField delegate, and should receive delegate methods for UITextField.
I have - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{ where I check to see if the textfield in question is a dropdown menu, and if it is, I call a method to instantiate a popover and disable editing, but the dropdown only appears on every other tap.
For example, i'll tap the "textfield" and my popover displays. I tap out so the popover goes away, then I tap on the "textfield" and nothing happens. I tap on the textfield once again and the popover appears. No idea why this is happening, here is what i'm doing:
.h
subclass : UIViewController<UITextFieldDelegate>
.m
dropdownTextField.delegate = self;
...
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
if(textField == self.measurementSelect){
NSLog(#"IM CALLED");
[self showPopover:textField];
return NO;
}
return YES;
}
-(void)showPopover:(id)sender{
if (_measurementPicker == nil) {
_measurementPicker = [[iPadMeasurementSelect alloc] initWithStyle:UITableViewStylePlain];
_measurementPicker.delegate = self;
}
if (_measurementPopover == nil) {
_measurementPopover = [[UIPopoverController alloc] initWithContentViewController:_measurementPicker];
[_measurementPopover presentPopoverFromRect:self.measurementSelect.frame inView:self.conversionView permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
}
else {
[_measurementPopover dismissPopoverAnimated:YES];
_measurementPopover = nil;
}
}
Every tap gets nslogged, so I assume my popover method is the culprit of this problem. Any ideas?
Let's rewrite by teasing apart existence of the UI elements and the visible state of the popover:
// canonical lazy getters for UI elements
- (iPadMeasurementSelect *)measurementPicker {
if (!_measurementPicker) {
_measurementPicker = [[iPadMeasurementSelect alloc] initWithStyle:UITableViewStylePlain];
_measurementPicker.delegate = self;
}
return _measurementPicker;
}
- (UIPopoverController *)measurementPopover {
if (!_measurementPopover) {
_measurementPopover = [[UIPopoverController alloc] initWithContentViewController:self.measurementPicker];
}
return _measurementPopover;
}
// now the show/hide method makes sense. it can take a bool about whether to show or hide
-(void)showPopover:(BOOL)show {
if (show) {
[self.measurementPopover presentPopoverFromRect:self.measurementSelect.frame inView:self.conversionView permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
} else {
[self.measurementPopover dismissPopoverAnimated:NO];
// if you want/need to create a new one each time it is shown, nil the popover here, like this:
// self.measurementPopover = nil;
}
}
When the textField begins editing, show the popover like this:
[self showPopover:YES];
And when the delegate gets the didEndEditing message:
[self showPopover:NO];
In my app on button click i have add pickerview to the windows below is the code show that
- (IBAction)btnMake:(id)sender
{
pickerViewMake = [[UIPickerView alloc] initWithFrame:pickerFrame];
pickerViewMake.showsSelectionIndicator = YES;
pickerViewMake.dataSource = self;
pickerViewMake.delegate = self;
[pickerViewMake setBackgroundColor:[UIColor clearColor]];
[viewPicker addSubview:pickerViewMake];
[self.view.window addSubview:pickerViewMake];
}
-(void)removeAllPicker
{
[pickerViewMake removeFromSuperview];
[pickerViewModel removeFromSuperview];
[pickerViewYear removeFromSuperview];
[pickerViewTrim removeFromSuperview];
}
remove all picker is the method used for removing the picker from superview
it works
The problem is that on multiple clicking btnMake number of the picker view cones up then
removeallPicker method call than also pickerview does not remove from superview.
Do one Thing create one BOOL variable and set in viewdidload yes and check in function if it is yes then picker come and also make it no in btnmake method.
Try in the following way
if (<instance>)
{
[<instance> removeFromSuperview],<instance> = nil;
}
After this create your picker then it won't create multiple times, it will create only once.
I'm looking for popover in iPhone and i want to make it like iOS 5 Reader feature:
After little research i found WEPopover and FPPopover but i'm looking if there anything like this API built-in iphone SDK.
You could make a UIView with some custom artwork and display it with an animation on top of your view as a "popover" with some buttons like so:
UIView *customView = [[UIView alloc] initWithFrame:CGRectMake(25, 25, 100, 50)]; //<- change to where you want it to show.
//Set the customView properties
customView.alpha = 0.0;
customView.layer.cornerRadius = 5;
customView.layer.borderWidth = 1.5f;
customView.layer.masksToBounds = YES;
//Add the customView to the current view
[self.view addSubview:customView];
//Display the customView with animation
[UIView animateWithDuration:0.4 animations:^{
[customView setAlpha:1.0];
} completion:^(BOOL finished) {}];
Don't forget to #import <QuartzCore/QuartzCore.h>, if you want to use the customView.layer.
Since iOS8 we are now able to create popovers, that will be the same on iPhone, as on iPad, which would be especially awesome for those who make universal apps, thus no need to make separate views or code.
You can get the class as well as demo project here: https://github.com/soberman/ARSPopover
All you need to do is subclass UIViewController, conform to the UIPopoverPresentationControllerDelegate protocol and set desired modalPresentationStyle along with the delegate value:
// This is your CustomPopoverController.m
#interface CustomPopoverController () <UIPopoverPresentationControllerDelegate>
#end
#implementation CustomPopoverController.m
- (instancetype)init {
if (self = [super init]) {
self.modalPresentationStyle = UIModalPresentationPopover;
self.popoverPresentationController.delegate = self;
}
return self;
}
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
return UIModalPresentationNone; //You have to specify this particular value in order to make it work on iPhone.
}
Afterwards, instantiate your newly created subclass in the method from which you want to show it and assign two more values to sourceView and sourceRect. It looks like this:
CustomPopoverController *popoverController = [[CustomPopoverController alloc] init];
popoverController.popoverPresentationController.sourceView = sourceView; //The view containing the anchor rectangle for the popover.
popoverController.popoverPresentationController.sourceRect = CGRectMake(384, 40, 0, 0); //The rectangle in the specified view in which to anchor the popover.
[self presentViewController:popoverController animated:YES completion:nil];
And there you have it, nice, neat blurred popover.