I have a ViewController Container that is 400 high on the iphone5. When I use it on a iphone4 it squashes the view like it does to everything. In this case I want the view to appear the same size on all phones.
vc.h
#property (strong, nonatomic) IBOutlet UIView *viewForContainer;
vc.m
#synthesize viewForContainer
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect rect = [viewForContainer frame];
rect.size.height = 400;
[viewForContainer setFrame:rect];
}
Why can't I just force the height like this?
.. am I going to have to make a new storyboard for it?
Short answer:
Select the view and choose Editor > Pin > Height. Now get rid of the unnecessary bottom constraint.
Long answer:
You really should stop everything you're doing and understand what you're doing - in particular, about autolayout. It's everywhere, by default, whether we like it or not, so one may as well know about it.
Related
I have a problem about Xcode storyboard and dynamically showed views.
I have 3 vertically aligned views in my storyboard and each one is linked with each other with top-bottom relationship with constraints
However during runtime I want to hide the 2nd view and replace its place with the 3'rd view (which is a tableview) and to fill the both 2nd and 3rd places I'm trying to extend the height of tableview.
However I cannot succeed. I have tried lots of things but closest thing I get is to transform the 3rd view to 2nd place but the height remains the same
My latest code is in below
if (status) {
self.filterView.hidden = NO;
self.contentTable.frame = contentTableFrame;
} else {
self.filterView.hidden = YES;
CGFloat predictedHeight = self.contentTable.frame.size.height+(self.contentTableFrame.origin.y-self.filterView.frame.origin.y);
self.contentTable.transform = CGAffineTransformMakeTranslation(0, self.filterView.frame.origin.y-self.contentTable.frame.origin.y);
for (NSLayoutConstraint *constraint in self.contentTable.constraints) {
if (constraint.firstAttribute == NSLayoutAttributeHeight) {
constraint.constant = predictedHeight;
}
}
}
You can also find the screenshot of the 3rd view's constraints. What should I do to fix that? Does anyone have any idea about it?
I also have another solution to this problem . But I've another problem on that too.
When I executed the below line of code my 3rd view move to 2nd view's place but its height remains the same so on the bottom of the page it happens to seems a blank space.
self.contentTable.transform = CGAffineTransformMakeTranslation(0, self.filterView.frame.origin.y-self.contentTable.frame.origin.y);
In order to fix that I've tried to change its height(with .frame = CGRectMake(.....) )
but it didn't work.Then I've tried to scale the 3rd view(which is a tableview) and it succeed but because I've scaled it all the cells inside the tableview scaled too and the visual appearance of the table has broken. So I couldn't able to find a solution to that problem.
It seemed like a challenge.
Thanks
Sorry it is in objective-c.
I get the top contraint from the TableView (Storyboard). When I hide the topView, I get the height of my topView and change the top constraint constant. You can see it in #IBAction. Finally, the tableView is stretched and takes the space left from the topView. Is that what you were looking ?
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UIView *topView;
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *topTableViewConstraint;
- (IBAction)pushTest:(id)sender;
#end
ViewController.m
- (IBAction)pushTest:(id)sender {
if (self.topView.hidden) {
self.topTableViewConstraint.constant = 0;
}else{
self.topTableViewConstraint.constant = -self.topView.bounds.size.height;
}
self.topView.hidden = !self.topView.hidden;
}
you can hide filterview but you can't replace it by tableview.
if you want to replace it by table view.You need to use method BringSubviewToFront for That Tableview.it will bring that tablview to front and set filterview to back which is hidden for ui.
I made a special test app for this case. (I'm sorry it is already removed)
I added a view on my controller's view in Storyboard, set up AutoLayout constraints in Interface Builder and made one of them (vertical space) is defferent for different size classes. Screenshot from IB
So the value is 100 for Any height, Any width and 0 for Regular height, Regular width.
It works well, on iPhone vertical distance from top is 100, when on iPad it is 0.
Also I made IBOutlet for this constraint and want to change it in runtime to 10
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *topVerticalConstraint;
it seemed I couldn't change it because it gives no effect
- (void)viewDidLoad
{
[super viewDidLoad];
self.topVerticalConstraint.constant = 10; // it doesn't work
}
Although it works when I remove value for Regular height, Regular width in Interface Builder.
Am I miss something about the size classes?
The problem is that constraints are not fully defined yet until Layout events happen between -viewWillLayoutSubviews and -viewDidLayoutSubviews where all the parameters from IB comes into play.
My rule of thumb is:
if you use frames to position your views manually you can do it as early as -viewDidLoad,
if you use autolayout constraints for positioning, make adjustments as early as -viewDidLayoutSubviews;
The second statements only considers code adjustments to constraints that have been made in IB. Adjustments that you are making in -viewDidLoad will be overridden by parameters set in IB during layout. If you add constraints with code you can set them in -viewDidLoad, since there will be nothing to override them.
I've changed your code a bit and it works:
#import "ViewController.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *topVerticalConstraint;
#property (weak, nonatomic) IBOutlet UIView *square;
#property (assign, nonatomic) BOOL firstLayout;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.firstLayout = YES;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (self.firstLayout) {
self.topVerticalConstraint.constant = 10;
self.firstLayout = NO;
}
}
#end
Notice that -viewDidLayoutSubviews is called many times during the lifetime of a ViewController, so you have to make sure that your adjustments happen only once on initial load.
The problem:
If you set up different value for different size classes in IB for the constraint like this:
then you can't change constant value in code like this:
self.adHeightConstraint.constant = 0; // value set to 0
[self.view layoutIfNeeded]; // value get back to IB value (44 or 36)
In this situation you may see that your constant value persists only until views recalculates. So, after [self.view layoutIfNeeded] the value of constant reset back to whatever was set in IB.
The solution:
Add the second constraint of the same attribute (in my case it was the height) with desired value. You may set this value in IB or change it in the code.
Set low priority for this new constraint. Since it's low priority, it won't be any conflict.
Now when you need to apply the new constant, simple disable the first constraint:
self.adHeightConstraint.active = NO;
[self.view layoutIfNeeded];
I have experienced the same issue, but it doesn't seem to have anything to do with viewDidLoad vs viewDidLayoutSubviews. Interface Builder can manage alternate constraint constants for different size classes, but when you try to update NSLayoutConstraint.constant in code, that constant isn't associated with any particular size class (including the active one).
From Apple docs, Changing Constraint Constants for a Size Class (XCode 7, Interface Builder)
My solution has been to remove the alternate constants from IB, and manage the size-based constraint constant switch in code, only for those specific constraints that are updated/modified in code. Any constraints that are only managed via storyboard/IB can use the alternate-size constants as normal.
// XCode 7.0.1, Swift 2.0
static var isCompactHeight : Bool = false;
static var heightOffset : CGFloat {
return (isCompactHeight ? compactHeightOffset : regularHeightOffset);
}
/* applyTheme can be called as early as viewDidLoad */
func applyTheme() {
// This part could go wherever you handle orientation changes
let appDelegate = UIApplication.sharedApplication().delegate;
let window = appDelegate?.window;
let verticalSizeClass = window??.traitCollection.verticalSizeClass ?? UIUserInterfaceSizeClass.Unspecified;
isCompactHeight = (verticalSizeClass == UIUserInterfaceSizeClass.Compact);
// Use heightOffset
changingConstraint.constant = heightOffset;
}
I'm hoping that some later version of Swift/XCode introduces getters & setters that take size-based alternates into account, mirroring the functionality that's already available via IB.
I check same scenario in sample project it was working may be you are forget to connect NSLayoutConstraint topVerticalConstraint with storyboard.
Change constraint's constant in viewDidLayoutSubviews
- (void) viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
if (IS_IPHONE4) {
self.topConstraint.constant = 10;
self.bottomButtonTop.constant = 10;
self.pageControlTopConstraint.constant = 5;
}
}
Easiest solution:
if (self.view.traitCollection.verticalSizeClass == UIUserInterfaceSizeClassRegular && self.view.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) {
// for iPhone
cnicTopConstraint.constant = -60;
} else {
// for iPad
cnicTopConstraint.constant = -120;
}
I'm using code to resize a UIImageView by reducing its width to .5 its original value.
The code is
- (void)viewDidLoad
{
[super viewDidLoad];
self.allisonHall.newWidth = .5;
self.allisonHall.frame = CGRectMake(self.allisonHall.frame.origin.x,
self.allisonHall.frame.origin.y,
self.allisonHall.frame.size.width*self.allisonHall.newWidth,
self.allisonHall.frame.size.height);
self.allisonHall.contentMode = UIViewContentModeLeft;
self.allisonHall.clipsToBounds = YES;
NSLog(#"%f",self.allisonHall.frame.size.width);
}
and the result of the NSLog is 140, .5*280 as expected.
However, in the view the UIImageView remains at its original width.
The UIImageView is linked as
#property (weak, nonatomic) IBOutlet XYZdiningHall *allisonHall;
within the view controller's .h file, where XYZdiningHall is a subclass of UIImageView
Should the UIImageView's frame be changing given this code or do I need to call another method to fire the change?
Do you need to use UIViewContentModeLeft? You can use UIViewContentModeScaleAspectFit or UIViewContentModeScaleAspectFill and the image will be redrawn (the aspect modes are related to the image view bounds, Left isn't).
I have to create an effect like in the images but I don't know how to do it (and also don't know how to call this effect to search). You can see in the pictures, at first we have an image at the top of page. After that, when we scroll up, the image moves up while the content moves with higher speed to cover the image. Can you give me a link or a suggestion?
First of all take imageview and scrollview in your apps with IBOutlet.
In your YourViewController.h file
#property(nonatomic,retain) IBOutlet UIImageView *imagev;
#property(nonatomic,retain) IBOutlet UIScrollView *scr;
In your YourViewController.m file
- (void)viewDidLoad
{
scr.contentSize = CGSizeMake(320,850);
scr.decelerationRate = UIScrollViewDecelerationRateNormal;
[super viewDidLoad];
}
Set imagev frame according to scrolling in scrollview delegate.
pragma mark - ScrollView Delegate
-(void)scrollViewDidScroll:(UIScrollView *)callerScrollView
{
NSLog(#"%f",callerScrollView.contentOffset.y);
[imagev setFrame:CGRectMake(imagev.frame.origin.x, - 0.5 *callerScrollView.contentOffset.y, imagev.frame.size.width, imagev.frame.size.height)];
}
Output :
My app displays banner ads at the bottom of the screen.
Above these ads are several UIViews/UIImageViews etc.
If the user removes the ads, via IAP, there is an empty gap where the banner used to be, as expected.
However, I would like to move these views down vertically, so as to reduce the obvious gap in the screen.
The code I've been trying doesn't seem to be working -
UIView *moveView = [self.view viewWithTag:5];
CGRect frame = moveView.frame;
[moveView removeFromSuperview];
frame.origin.y = frame.origin.y + 25.0;
moveView.frame = frame;
[self.view addSubview:moveView];
The answer below suggested to remove autolayout, however I needed autolayout for my storyboard.
I simply needed to remove the autolayout for one UIView.
What I ended up using was
[moveView settranslatesautoresizingmaskintoconstraints:YES]
This simple line allowed me to move my view around without worrying about autolayout.
You can create an IBOutlet and connect it to a UIView in storyboard.
#property (nonatomic, retain) IBOutlet UIView *moveView;
then turn off auto layout in your storyboard.
Once that is done then try your code.
or try this
[moveView setFrame:CGRectMake(0,0,320,480)];
mmmbaileys is right.!!
Small Change:
[self.yourview setTranslatesAutoresizingMaskIntoConstraints:YES];
use this in viewDidLoad.