Autolayout - UIView animation from the bottom of the screen - objective-c

I am using autolayout in my application. I have a UIPicker at the bottom of screen. What I want to do is I want to open UIPicker from the bottom of screen on click of UIButton as shown in image below
I want to know
which kind of constraint I have to set initially
which kind of constraint I have to implement programmatically and how it will be implemented?
How to get back to its original position?

Initially pin top of pickerView to bottom of SuperView and then when you want it to show you can pin bottom of pickerView to bottom of superView.
OR
You can do higher animation by pinning bottom of pickerView to bottom of superView and set height to 0 and when you want to show set height constant to whatEver height is recquired.

follow the below step.
applied this constraint on your object.
after that select vertical space constraint and create IBOutlet for it.
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *TopHeight;
set your desire top margin using below code.it will set new top margin for your object with animation.
self.TopHeight.constant = 400;
[self.view setNeedsUpdateConstraints];
[UIView animateWithDuration:0.5 animations:^{
[self.view layoutIfNeeded];
}];

What I have done is, I have set 3 constraint for pickerView as follows.
Then I set outlet of the bottom space to my view.
#property (strong, nonatomic) IBOutlet NSLayoutConstraint *bottomConstraint;
after then on click of botton I write following logic and my work is done.
- (IBAction)showPicker:(id) sender{
self.bottomConstraint.constant = 0;
[self.picker setNeedsUpdateConstraints];
[UIView animateWithDuration:0.3f animations:^{
[self.view layoutIfNeeded];
}];
}

Related

Resizing UIButton Frame While Using Size Classes Requires Auto Layout

I have used storyboard to layout a custom cell in a tableview. I have a UI button in this custom cell that has an initial x,y size of 60x7. This UI button (as with all objects in the storyboard) use auto layout with size classes.
When the user clicks on an edit button in the view, I would like to change the size of the UIButton in each cell to be 60x60. Various StackOverflow solutions for changing the UIButton size do something like the following:
CGRect buttonFrame = cell.button1Left.frame;
buttonFrame.size = CGSizeMake(60, 60);
cell.button1Left.frame = buttonFrame;
But the solutions also warn that this will not work unless you turn off auto layout. However, when I try to turn off auto layout for this UIButton in the custom cell, I get the following warning:
This warning scares me. If I disable size classes, will this mess up my layout, disable my segues, and make future changes more difficult? If so, is there any other way to accomplish what I am trying?
Bonus question: is it possible to animate the resizing of the UIButton (i.e. so that it appears to stretch to the larger size)?
Try this:
1) add 2 constraints to your Button in storyboard;
2) create properties for them :
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *btnHeight;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *btnWidth;
3) add action to button click:
- (IBAction)buttonPressed:(id)sender {
UIButton *btn = (UIButton *)sender;
btn.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
self.btnHeight.constant +=50;
self.btnWidth.constant +=50;
[UIView animateWithDuration: 0.7 animations:^{
[self.view layoutIfNeeded];
}];
}
P.S. If your button is in the center of cell, you need also create top and left constraints and if you make height and width for 50 bigger you need to make top and left for 25 smaller.
I decided that the best solution for me was to create another UIButton that was already the desired size. When the user presses an edit button for the view, I hide the collapsed UIButton that was 60x7. Then I unhide the full size UIButton that is 60x60. To animate the transition so that it looks more natural, I did the following:
[UIView transitionWithView:cell.pencilButtonLeft
duration:0.6
options:UIViewAnimationOptionTransitionFlipFromBottom
animations:NULL
completion:NULL];
cell.pencilButtonLeft.hidden = NO;
As for the warning message when I tried to turn off autosizing, I decided to not turn off autoresizing and not to disable size classes. In reading it closely, I might have been ok as long as I did not have an intention of running the app on a device other than an iPhone. Thanks to #Ptah for the suggestion on the animation.

Programmatically remove UILabel that has autolayout from View

I parse Json data and I set it on some UILabels, What I want is that when there's no text for a specific label It has to be removed from the UIView, I tried with 2 methods but with no results because the labels has constraints.
What I tried is:
Set their frame to 0 and the height constraint to 0
CGRect noFrame = _prepTime.frame;
noFrame.size.width = 0;
noFrame.size.height = 0;
[_prepTime setFrame:noFrame];
prepTimeHeight = 0;
But the height of the UILabel still remains,
The I tried with:
[_prepTime removeFromSuperView];
With this one the UILabel gets removed but the interface changes since it has constraints and by removing the UILabel I destroy the layout.
Is there any method to remove the UILabel from the view even if it has constraints?
You can set hidden if you don't want to affect all other subviews.
When using layout constraint it's not a good idea to edit the frame of your element. Instead you should add a IBOutlet property for your NSLayoutConstraint and link it to the height constraint of your label in your storyboard, then edit the constant value of the NSLayoutConstraint.
Someting like that in your viewcontroller #implementation:
#property IBoutlet NSLayoutConstraint *myLabelHeightConstraint;
and later when you want to hide your label :
self.myLabelHeightConstraint.constant = 0;
[self.view layoutIfNeeded];

UIView height before a table section

I'm trying to add a view with hight of 50 before table sections, i added the view in interface builder and resize it to 50 and everything looks good in interface builder but once i test it on a device or simulator the view show up with a maximum screen height and it doesn't seem that i can control its height whatever value i use the view takes all the screen hight
How can i force the view height to 50?
Try to use autolayout and set a height constant.
Uncheck "Autoresize Subview" attribute for the parent view in which these view added and check the output. This might solve the problem if some constraint tries to resize the view which was added.
If you want add and UIView before a table section, this view will be before the tableView also. And At least you do by code this view won't be scrolled.
You must change you TabelViewController to a ViewController and adding the tableView Protocols delegate. And no sure but you must have something like that:
#interface TestTableViewController : UITableViewController
And you should be:
#interface TestTableViewController : UIViewController <UITableViewDataSource,UITableViewDelegate>
Then: In Storyboard add the View and the tableview (Both should have in the same level). Add constrains, connect delegates, and create a IBOutlet for both:
#property (nonatomic,strong) IBOutlet UIView *superHeader;
#property (nonatomic, strong) IBOutlet UITableView *tableView;
With this two outlet if you want you can code to the superHeader disappear when you scrolling until a point, here an example (Remember tableView is a scrollView son).
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView.contentOffset.y > 100)
{
[UIView animateWithDuration:0.3 animations:^{
// Be carfuly if you are navigationBar (64 ptos) and depens of transparency property
self.tableView.frame = CGRectMake(0, -50, self.view.bounds.size.width, 50);
self.tableView.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);
}];
} else if(scrollView.contentOffset.y < 80) {
[UIView animateWithDuration:0.3 animations:^{
// Be carfuly if you are navigationBar (64 ptos) and depens of transparency property
self.tableView.frame = CGRectMake(0, 0, self.view.bounds.size.width, 50);
self.tableView.frame = CGRectMake(0, 50, self.view.bounds.size.width, self.view.bounds.size.height - 50);
}];
}
}
How did you add the view to the UITableView in Interface Builder?
Do you want to have the view displayed before every section?
Then you can add it as a header view for each sections using
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section.
You can specify the height for it using
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
These are both UITableViewDelegate methods.
If you don't want it for every section but rather need one view that is displayed at the top of the TableView, then you can try the tableHeaderView property of UITableView.
You can set any UIView as the header using this property.
See this StackOverflow thread: Adding iOS UITableView HeaderView (not section header)
If you want 50 fixed height then add a constraint to the view "fixed height : 50"
The reason for unchanged frame is the auto layout. SetFrame will work fine when you disable the auto layout.
Hope this will help you
I feel you are not using the prototypecell of tableViewcontroller. Try to add the customisation into that. It may work.

Set a UIPickerView to bottom of UITableview regardless of scroll position

I'd like to present a UIPickerView snapped to the bottom of a UITableView regardless of where it is scrolled.
Currently I have a UIPickerView added to a UITableView that I present when a button is pressed, but when I scroll the table the UIPickerView goes out of view, and if I'm scrolled out of range of where I've presented it, the UIPickerView appears to have never been called.
Does anyone know how to accomplish this?
Thank
The use of UITableViewController is great unless you need to add subview that don't scroll with the table view. It can't really be done. The solution is to use a UIViewController instead and add your own table view, setup the table view dataSource and delegate protocols and replicate the basic table view controller plumbing.
Once your view controller works like a normal table view controller again, you can now add subviews to the view controller's view that won't scroll with the table.
if u add tableview programatically
SearchtableView.frame = CGRectMake(450, 90, 318, 600);
SearchtableView = [[UITableView alloc] initWithFrame:CGRectMake(623, 90, 400, 400)style:UITableViewStyleGrouped];
[self.view addSubview:SearchtableView];
//belove the tableview//
//Add UIPickerView to the self.view]//
Something told me that there must be a simpler alternative to the answers that I'd been given, and I found a solution.
I decided to find the y coordinate of the scroll point using scrollViewDidScroll: and then animating the UIPickerView to the desired location.
...
[UIView beginAnimations:nil context:NULL];
CGFloat pointY = self.scrollPoint.y;
[self.sortPicker setFrame:CGRectMake(0, pointY + 200, 320, 216)];
[UIView commitAnimations];
...
The UIPickerView will only appear if the scroll has been stopped so it's necessary to implement a method to stop the scroll on touch:
- (void)stopScroll:(UITableView *)tableview
{
CGPoint offset = tableview.contentOffset;
[tableview setContentOffset:offset animated:NO];
}
This will allow you to display and dismiss the UIPickerView at any moment at any given destination.

UISplitViewController: remove divider line

When using UISplitViewController on the iPad there's a black vertical divider line between the root and detail view. Is there any way to remove this line?
Thanks
Excellent answer by #bteapot. I tested this and it works, even gets rid of the line between master/detail nav bars.
You can do this in storyboard by adding the "gutterWidth" key path and the value 0 to the USplitViewController runtime attributes.
Actuly I have some modification to answer of (Dylan)'s answer
in the appDelegate we need to add image in spliteview controller rather then window
self.splitViewController.view.opaque = NO;
imgView = [[UIImageView alloc] initWithImage:
[UIImage imageNamed:#"FullNavBar.png"]];
[imgView setFrame:CGRectMake(0, 0, 1024, 44)];
[[self.splitViewController view] insertSubview:imgView atIndex:0];
[[self.splitViewController view] setBackgroundColor:[UIColor clearColor]];
here self is object of AppDelegate.
now Apply the answer of this thread : iPhoneOS SDK - Remove Corner Rounding from views (iPad problem) answer by (abs)
edit in above post's answer is
-(void) fixRoundedSplitViewCorner {
[self explode:[[UIApplication sharedApplication] keyWindow] level:0];
}
-(void) explode:(id)aView level:(int)level
{
if ([aView isKindOfClass:[UIImageView class]]) {
UIImageView* roundedCornerImage = (UIImageView*)aView;
roundedCornerImage.hidden = YES;
}
if (level < 2) {
for (UIView *subview in [aView subviews]) {
[self explode:subview level:(level + 1)];
}
}
imgView.hidden = FALSE;
}
** make imgView.hidden to FALSE
declare imgView to the AppDelegate.h file**
and dont forget to call this
-(void)didRotateFromInterfaceOrientation:
UIInterfaceOrientation)fromInterfaceOrientation
{
[yourAppDelegate performSelector:#selector(fixRoundedSplitViewCorner)
withObject:NULL afterDelay:0];
}
chintan adatiya answer covers only the corners and the navigation bar, but I found an trick how to cover the line between the Master and the Detail view.
It is not nice but it works like a charm.
First create an image which is 1 px wide and 704 pixels high.
In the didFinishLaunchingWithOptions add the following code:
UIView *coverView = [[UIView alloc] initWithFrame:CGRectMake(320, 44, 1, 704)];
[coverView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"divider_cover.png"]]];
[splitViewController.view addSubview:coverView];
And done.
When you want a background image which is continues create 3 images:
Master: width: 320, height: 704
Detail: width: 703, height: 704
Divider:width: 1, height: 704
First post here, hi everyone.
I discovered how to do it accidentally... when I tried to find why I had LOST the divider line. Here's how to hide it, if you're still interested:
1) In your Detail (right-side) view, make sure you have a subview that spans the whole view.
2) Offset this subview view to (-1, 0).
3) Make sure that the Detail View has its "Clip Subviews" option unchecked.
VoilĂ , enjoy.
You can mostly get rid of it by setting another image behind it in the main window's views. This is from the app delegate didFinishLaunchingWithOptions
// Add the split view controller's view to the window and display.
splitViewController.view.opaque = NO;
splitViewController.view.backgroundColor = [UIColor clearColor];
[window addSubview:splitViewController.view];
[window insertSubview:bgImageView belowSubview:splitViewController.view];
[window makeKeyAndVisible];
But it still leaves two visual artifacts at the top and the bottom that appear to be custom drawn by the splitviewcontroller.
Interestingly, In the app that I'm working on I want a black background color for both views in the UISplitViewController. I'd like to change the color of the divider line to white (so that you can see it). Making both background colors black is one way to get rid of (make invisible) the dividing line but that's probably not a solution for most people.
Tested on iOS10 (probably will work on iOS9 too).
splitviewController.view.backgroundColor = UIColor.white
it removes divider. Apparently divider is just a gap between master and detail container.
I looked around for a while, and came to the conclusion that theres no way to do this, other than to create your own custom split view.
Try the MGSplitViewController by Matt Gammell
http://mattgemmell.com/2010/07/31/mgsplitviewcontroller-for-ipad
I may be late here, but I DO have a solution that works. It even works for the iOS 8+ splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible; and seamlessly slides in and out when you press the Full Screen toggle button.
Here is the trick :
first Subclass UISplitViewController.m
In the header add the follwing :
#property (strong, nonatomic) UIView *fakeNavBarBGView;
In the viewDidLoad method add the following code :
CGFloat fakeNavBarWidth = 321; // It is important to have it span the width of the master view + 1 because it will not move when the split view slides it's subviews (master and detail)
CGFloat navbarHeight = self.navigationController.navigationBar.frame.size.height + 20;
self.fakeNavBarBGView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, fakeNavBarWidth, navbarHeight)];
self.fakeNavBarBGView.backgroundColor = [UIColor redColor];
// Add Fake navbar to back of view
[self.view insertSubview:self.fakeNavBarBGView atIndex:0];
// SplitView Controller
UISplitViewController *splitViewController = self;
DetailViewController *detailVC = [navigationController.viewControllers lastObject];
detailVC.fakeNavBarSubView = self.fakeNavBarBGView;
detailVC.SVView = self.view;
In the DetailViewController.h add the following :
#property (strong, nonatomic) UIView *SVView;
#property (strong, nonatomic) UIView *fakeNavBarSubView;
Now here is the final trick : in the DetailViewController.m, add the following in the viewDidLoad method (called every time you click the Master table) :
[self.SVView sendSubviewToBack:self.fakeNavBarSubView];
[self.SVView bringSubviewToFront:self.view];
Run it and watch the magic ;-)
Private API (can cause App Store rejection):
[splitViewController setValue:#0.0 forKey:#"gutterWidth"];
I did this accidentally by setting the backgroundColor property of the first viewController's view - possibly to clearColor, I don't remember now.
UIManager.put("SplitPaneDivider.draggingColor", new Color(255, 255, 255, 0));