I have a UIView and inside this UIView I have another UIView, lets say parent and child UIView. I have set height and width of parent UIView to 400 in storyboard and set child view constraint to take 8px margin from top, left right and bottom from its superview.
But When I change size of parent view to 200, size of child view remain same. I have tried this in both viewdidload and viewdidappear
CGRect frm = self.mainTimerView.frame;
frm.size.width = size;
frm.size.height = size;
self.mainTimerView.frame = frm;
when I change parent view to 200 child should set it self to 200-16 height and width according to constraints.
You should not mix using uiconstraint with using frame.If you want to change the size when using uiconstraint, you should make the outlet of the constraint, and then change the constraint's constant property.Call layoutIfNeeded,then you can get the right frame.
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIButton *mainTimerView;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *mainTimerViewHeightConstraint;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.view layoutIfNeeded];
NSLog(#"%#",#(self.mainTimerView.frame.size.width));
self.mainTimerViewHeightConstraint.constant = 100;
[self.view layoutIfNeeded];
NSLog(#"%#",#(self.mainTimerView.frame.size.height));
}
#end
Calling layoutIfNeeded aim to to force the layout of subviews before drawing, then viewDidLayoutSubviews will be called. Note that you can get the correct frame in viewDidLayoutSubviews. In other words, you can get the right frame after viewDidLayoutSubviews has been called.
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
NSLog(#"%#",NSStringFromCGRect(self.mainTimerView.frame));
}
1) Change the height constraint of the mainview.
2) Call the layoutIfNeeded method.
3) Do it on viewDidAppear.
Have you tried calling setNeedsLayout on the parent view? This call is used to ask a view to layout its subviews. From the setNeedsLayout's discussion section:
Call this method on your application’s main thread when you want to adjust the layout of a view’s subviews. This method makes a note of the request and returns immediately. Because this method does not force an immediate update, but instead waits for the next update cycle, you can use it to invalidate the layout of multiple views before any of those views are updated. This behavior allows you to consolidate all of your layout updates to one update cycle, which is usually better for performance.
Calling layoutIfNeeded might be another option. But according to the docs, it forces an immediate layout, and therefore does not provide the consolidation benefit gained by using setNeedsLayout.
layoutIfNeeded documention:
Lays out the subviews immediately.
Plz create the IBOutlet of height Constraint of parent view.
IBOutlet NSLayoutConstraint *RedViewHeightconstraint;
- (void)viewWillAppear:(BOOL)animated
{
RedViewHeightconstraint.constant = 500;
}
it will work for you
You just need to create IBOutlets of constraints of height and width of mainTimerView. Once you do so add these lines of code :
constraintOuterViewHt.constant = 200
constraintOuterViewWidth.constant = 200
You don't need to do anything else.
Check screen shot here
Related
I am trying to make a vertical progress bar in iOS that can be placed as a UIView in interface builder, and given a progress bar view class. Here are my class files:
ProgressBar.h:
#interface ProgressBar : UIView
#property (nonatomic, retain) IBOutlet UIView *barView
-(void)setBarValue:(float)value;
#end
ProgressBar.m:
-(id)initWithCoder:(NSCoder *)aDecoder {
id s = [super initWithCoder:aDecoder];
if (s) {
self.backgroundColor = [UIColor clearColor];
}
return s;
}
-(void)setBarValue:(float)val {
[self.barView setBackgroudnColor:TURQUOISE];
CGRect frame = self.barView.frame;
frame.size.height = self.barview.frame.size.height * val;
[self.barView setFrame:frame];
}
The only constraint I have on the 'barView' inside the ProgressBar element is 'align bottom edges'. The setFrame method never seems to update the bar, and even at full height, the inner self.barView isn't the same height as the ProgressBar view. The properties are all correctly linked in the Storyboard.
Any ideas?
The key issue is that, if using autolayout, you should add your constraints for this subview in IB, too. (I assume you already added constraints for the ProgressView.) And you should not change the frame of barView, but rather change its constraints and then call setNeedsLayout. The easiest way will be to add leading/trailing/top constraints of zero and then create a final height constraint. You can then add an IBOutlet for that height constraint. You can then programmatically set the constant of that constraint (and if you're going to use a multiplicative factor, it should be the product of this factor and the overall progress view, not a factor of the bar, itself), and then call setNeedsLayout.
OK I have a view-controller that sits in a container of another view.
MainView
View
Someview
ContainerView (contains ContainedViewController)
Otherview
ContainedViewController
ContainedView (height can get resized during run).
UILabel (varying height)
UIView (fixed size, width & height)
Here's the thing... the view in ContainedViewController needs to get resized at runtime. It contains a label (that can grow depending on the text in it) and a static view directly below it, that never changes size
So, I have a constraint on the UILabel for it's height, and I change that at runtime, depending on how big it needs to be. There's a vertical constraint between the label and the fixed-view, and all of the "standard" constraints to the main superview.
When I run, though, I get "unable to simultaneously satisfy constraints", followed by the constraint log. Among the conflicting constraints are my new UILabel height, and then the height of ContainedView. I get a "UIView-Encapsulated-View-Height" problem with the ContainedView.
Apparently, "ContainedView"'s height is being dictated by the height of MainView's ContainerView.
What I want is for the ContainedView's height to change when the UILabel's height changes, and then have the propagate back up the containers, all the way to MainView. But I can't seem to get this to work.
How can I get the superview, and it's container view to resize when I change the size of my label?
In your main view controller, declare the following override:
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
// Layout the container's content and get its resulting size
[self.containedViewController.view layoutIfNeeded];
CGSize containedViewSize = [self.containedViewController contentSize];
// Now, use containedViewSize to set constraints on the view controller.
self.containerHeightConstraint.constant = containedViewSize.height;
self.containerWidthConstraint.constant = containedViewHeight.width;
}
Then, in your contained view controller, declare these properties:
#property (nonatomic, weak) IBOutlet UIView * contentView;
#property (nonatomic, weak) UIViewController * mainViewController;
In your storyboard make contentView a subview of the contained view controller's main view. Pin it with constraints to the main view's top left corner. Put whatever content you want in contentView, including constraints that determine contentView's size. (DON'T pin the contentView's length and width to the main view, however; that will cause conflicting constraints you described above.)
mainViewController should be set when preparing for the embed segue that sets up the container view controller.
And this method:
- (CGSize)contentSize {
return self.contentView.frame.size;
}
Now, whenever you do something in the container view controller that affects the size of contentView, make the following call:
[self.mainViewController.view setNeedsLayout];
Sorry this isn't simpler, but it's the best solution I've found to this problem so far.
I am facing an issue while using storyboard auto layout with UIScrollView. I am updating a constraint of a UIScrollView, and after that setting the content size of scrollview. But UIScrollView constraint takes a bit of time to update and initially UIScrollView is not able to scroll because of more height than a view. I can not change the current implementation.
Is there any way, notification or any delegate method to check that the constraints are updated, so that I can do further changes?
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *scrollViewHieghtConstraint;
self.scrollViewHieghtConstraint.constant = 500;
[self.scrollView updateConstraints];
[self.scrollView setContentSize:CGSizeMake(0, 1000)];
You can use - (void)updateViewConstraints selector of UIViewController.
You can also use - (void)updateConstraints selector of UIView if you have extended said view.
You can't call -updateConstraints directly. You have to mark the view's constraints as dirty and iOS will call that method on the next update cycle.
On a UIViewController's implementation, add this when you need the constraint to change:
self.scrollViewHieghtConstraint.constant = 500;
[self.view setNeedsLayout];
I'm assuming that UIScrollView is a subview of the UIViewController's view. If it's not, then call -setNeedsLayout on the scrollview's parent view.
And if you need to know when the subviews are already on their right place, you have a callback for UIViewController, called -viewDidLayoutSubviews
I originally had a normal view with a bunch of stuff in it, and I want that view to be an UIScrollView, so I created a new ScrollView and dragged everything over. The view is not scrolling.
After looking around - I unchecked use autolayout, but that didn't work. I also realize that this could be solved by setting contentSize, but I have access to this view through a variable that is of type UIView, and not UIScrollView. In other words I would be doing -
self.someController.view.contentSize = //something
where self.someController.view is only an UIView and contentSize is not a property of UIView(or at least that's what I'm seeing- I get compiler warnings).
Why is this scroll view not scrolling?
EDIT -
So I stupidly forgot I can cast - I did that, but it's still not working -
UIScrollView* basicCardView = ((UIScrollView *)self.detailController.view);
basicCardView.contentSize = CGSizeMake(basicCardView.frame.size.width * 12,
basicCardView.frame.size.height);
You need to connect your scrollview to Iboutlet var in .m .
Create var in your interface:
IBOutlet UIScrollView *scrollview;
And connect to your scrollview in storyboard, then you can set contentsize.
[scrollview setContentSize:CGSizeMake(2000,200)];
Elto has it correct. To elaborate: In your view controller .m say it's called MyViewController:
#interface MyViewController ()
#property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
#end
Go back to storyboard, select your view controller and select the connections tab (last one on the upper right). You should now see an outlet called scrollView. Drag a connection from that outlet to the scroll view that you added to the scene.
Now the content size code can be written. Just to get it working, use large constants in content size, like:
self.scrollView.contentSize = CGSizeMake(1000, 1000);
The size you're setting in the post (on the wrong view) looks like it's just the size of one of the subviews. You want the content size of the scroll view to be more like a multiple of the scrollView's size. You want the rectangle it can scroll within to at least encompass the frame (not the bounds) of every subview it contains.
I'm re-writting an app under IOS6 with autolayout but have problems accessing the size of a subclass of UIView
#property (weak, nonatomic) IBOutlet MyView *myView1;
in
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"myView1: %#",self.myView1);
}
The size of the UIView is fully defined in the StoryBoard but comes out as zero when I run the code. Is this todo with auto layout or is the subview simply not defined yet? Am I doing something basically wrong here?
Just found one possible answer here. Running the methods
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
forces a calculation of UIViews dimensions causing the expected values to appear in the log and also be known unto the UIView subclass itself.
I just printed the frame of a subview.
It was 0 in viewDidLoad.
It had a non-zero value inside the viewDidLayoutSubviews callback.
Inside the viewDidLoad you should only expect that the value of the viewcontroller's view to be non-zero. Inside viewDidLoad is actually where sometimes you add subviews and stuff. So it's not correct to expect the frame to get calculated in the very callback that you're settings constraints for it.
Basically what needs to be understood is that first a viewController is drawn, then as it goes through its life cycle events, its subviews will get laid out