xib中is proportional toheight to superview怎么设置

ios - Change UITableView height dynamically - Stack Overflow
to customize your list.
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.
J it only takes a minute:
Join the Stack Overflow community to:
Ask programming questions
Answer and help your peers
Get recognized for your expertise
I want to change the height of my tableview from another viewcontroller based on the sum of its cells' heights, as they are dynamic. Is it at all possible? Thanks
What I basically have is a UserProfileViewController that has a containerview on half of the screen. There I add different other viewcontrollers:
In the case of the wall button this is how I add the viewcontroller and it's subsequent tableview:
- (IBAction)wallButtonPressed:(id)sender
//Check if there is an instance of the viewcontroller we want to display. If not make one and set it's tableview frame to the container's view bounds
if(!_userWallViewController) {
self.userWallViewController = [[WallViewController alloc] init];
self.userWallViewController.activityFeedTableView.frame = self.containerView.
[self.userWallViewController.containerView addSubview:self.userWallViewController.activityFeedTableView];
//If the currentviewcontroller adn it's view are already added to the hierarchy remove them
[self.currentViewController.view removeFromSuperview];
[self.currentViewController removeFromParentViewController];
//Add the desired viewcontroller to the currentviewcontroller
self.currentViewController = self.userWallViewC
//Pass the data needed for the desired viewcontroller to it's instances
self.userWallViewController.searchURLString = [NSString stringWithFormat:@"event/user/%@/", self.userID];
self.userWallViewController.sendCommentURLString = [NSString stringWithFormat:@"event/message/%@", self.userID];
[self.userWallViewController.activityFeedTableView reloadData];
self.userWallViewController.totalCellHeight = ^(float totalCellHeight){
self.scrollView.contentSize = CGSizeMake(320.0, totalCellHeight);
CGRect newFrame = self.userWallViewController.containerView.
newFrame.size.height = totalCellHeight + 33.0;
self.userWallViewController.containerView.frame = newF
self.userWallViewController.activityFeedTableView.frame = self.containerView.
//Add this containerview to the desired viewcontroller's containerView
self.userWallViewController.containerView = self.containerV
//Add the needed viewcontroller and view to the parent viewcontroller and the containerview
[self addChildViewController:self.userWallViewController];
[self.containerView addSubview:self.userWallViewController.view];
//CLEAN UP THE CONTAINER VIEW BY REMOVING THE PREVIOUS ADDED TABLE VIEWS
[self.userFansViewController.userSimpleTableView removeFromSuperview];
[self.fanOfViewController.userSimpleTableView removeFromSuperview];
[self.userPublishedMovellaListViewController.gridView removeFromSuperview];
[self.userPublishedMovellaListViewController removeFromParentViewController];
self.userPublishedMovellaListViewController =
and in that viewcontroller this is where I initialize my tableview:
-(UITableView *)activityFeedTableView
if (!_activityFeedTableView) {
_activityFeedTableView = [[UITableView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 850.0) style:UITableViewStylePlain];
return _activityFeedTableV
I am calculating he total sum of the cell's height, the problem is that the cell's height method is called way after the getter of te tableview is called. So I would need some sort of way to know when the cells' height method is done for all cells and then I can resize my tableview. Thanks
There isn't a system feature to change the height of the table based upon the contents of the tableview. Having said that, it is possible to programmatically change the height of the tableview based upon the contents, specifically based upon the contentSize of the tableview (which is easier than manually calculating the height yourself). A few of the particulars vary depending upon whether you're using the new autolayout that's part of iOS 6, or not.
But assuming you're configuring your table view's underlying model in viewDidLoad, if you want to then adjust the height of the tableview, you can do this in viewDidAppear:
- (void)viewDidAppear:(BOOL)animated
[super viewDidAppear:animated];
[self adjustHeightOfTableview];
Likewise, if you ever perform a reloadData (or otherwise add or remove rows) for a tableview, you'd want to make sure that you also manually call adjustHeightOfTableView there, too, e.g.:
- (IBAction)onPressButton:(id)sender
[self buildModel];
[self.tableView reloadData];
[self adjustHeightOfTableview];
So the question is what should our adjustHeightOfTableview do. Unfortunately, this is a function of whether you use the iOS 6 autolayout or not. You can determine if you have autolayout turned on by opening your storyboard or NIB and go to the "File Inspector" (e.g. press option+command+1 or click on that first tab on the panel on the right):
Let's assume for a second that autolayout was off. In that case, it's quite simple and adjustHeightOfTableview would just adjust the frame of the tableview:
- (void)adjustHeightOfTableview
CGFloat height = self.tableView.contentSize.
CGFloat maxHeight = self.tableView.superview.frame.size.height - self.tableView.frame.origin.y;
// if the height of the content is greater than the maxHeight of
// total space on the screen, limit the height to the size of the
// superview.
if (height & maxHeight)
height = maxH
// now set the frame accordingly
[UIView animateWithDuration:0.25 animations:^{
CGRect frame = self.tableView.
frame.size.height =
self.tableView.frame =
// if you have other controls that should be resized/moved to accommodate
// the resized tableview, do that here, too
If your autolayout was on, though, adjustHeightOfTableview would adjust a height constraint for your tableview:
- (void)adjustHeightOfTableview
CGFloat height = self.tableView.contentSize.
CGFloat maxHeight = self.tableView.superview.frame.size.height - self.tableView.frame.origin.y;
// if the height of the content is greater than the maxHeight of
// total space on the screen, limit the height to the size of the
// superview.
if (height & maxHeight)
height = maxH
// now set the height constraint accordingly
[UIView animateWithDuration:0.25 animations:^{
self.tableViewHeightConstraint.constant =
[self.view setNeedsUpdateConstraints];
For this latter constraint-based solution to work with autolayout, we must take care of a few things first:
Make sure your tableview has a height constraint by clicking on the center button in the group of buttons here and then choose to add the height constraint:
Then add an IBOutlet for that constraint:
Make sure you adjust other constraints so they don't conflict if you adjust the size tableview programmatically. In my example, the tableview had a trailing space constraint that locked it to the bottom of the screen, so I had to adjust that constraint so that rather than being locked at a particular size, it could be greater or equal to a value, and with a lower priority, so that the height and top of the tableview would rule the day:
What you do here with other constraints will depend entirely upon what other controls you have on your screen below the tableview. As always, dealing with constraints is a little awkward, but it definitely works, though the specifics in your situation depend entirely upon what else you have on the scene. But hopefully you get the idea. Bottom line, with autolayout, make sure to adjust your other constraints (if any) to be flexible to account for the changing tableview height.
As you can see, it's much easier to programmatically adjust the height of a tableview if you're not using autolayout, but in case you are, I present both alternatives.
153k17269374
create your cell by xib or storyboard. give it's outlet's contents.
now call it in CellForRowAtIndexPath.
eg. if you want to set cell height according to Comment's label text.
so set you commentsLbl.numberOfLine=0;
so set you commentsLbl.numberOfLine=0;
then in ViewDidLoad
self.table.estimatedRowHeight = 44.0 ;
self.table.rowHeight = UITableViewAutomaticD
-(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return UITableViewAutomaticD}
voila ............ you did it....
Rob's solution is very nice, only thing that in his -(void)adjustHeightOfTableview method the calling of
[self.view needsUpdateConstraints]
does nothing, it just returns a flag, instead calling
[self.view setNeedsUpdateConstraints]
will make the desired effect.
3,105113147
for resizing my table I went with this solution in my tableview controller witch is perfectly fine:
[objectManager getObjectsAtPath:self.searchURLString
parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSArray* results = [mappingResult array];
self.eventArray =
NSLog(@"Events number at first: %i", [self.eventArray count]);
CGRect newFrame = self.activityFeedTableView.
newFrame.size.height = self.cellsHeight + 30.0;
self.activityFeedTableView.frame = newF
self.cellsHeight = 0.0;
failure:^(RKObjectRequestOperation *operation, NSError *error) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
NSLog(@"Hit error: %@", error);
The resizing part is in a method but here is just so you can see it.
Now the only problem I haveis resizing the scroll view in the other view controller as I have no idea when the tableview has finished resizing. At the moment I'm doing it with performSelector: afterDelay: but this is really not a good way to do it. Any ideas?
Use simple and easy code
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -& CGFloat {
let myCell = tableView.dequeueReusableCellWithIdentifier("mannaCustumCell") as! CustomCell
let heightForCell = myCell.bounds.size.
return heightForC
I found adding constraint programmatically much easier than in storyboard.
var leadingMargin = NSLayoutConstraint(item: self.tableView, attribute: NSLayoutAttribute.LeadingMargin, relatedBy: NSLayoutRelation.Equal, toItem: self.mView, attribute: NSLayoutAttribute.LeadingMargin, multiplier: 1, constant: 0.0)
var trailingMargin = NSLayoutConstraint(item: self.tableView, attribute: NSLayoutAttribute.TrailingMargin, relatedBy: NSLayoutRelation.Equal, toItem: mView, attribute: NSLayoutAttribute.TrailingMargin, multiplier: 1, constant: 0.0)
var height = NSLayoutConstraint(item: self.tableView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: screenSize.height - 55)
var bottom = NSLayoutConstraint(item: self.tableView, attribute: NSLayoutAttribute.BottomMargin, relatedBy: NSLayoutRelation.Equal, toItem: self.mView, attribute: NSLayoutAttribute.BottomMargin, multiplier: 1, constant: screenSize.height - 200)
var top = NSLayoutConstraint(item: self.tableView, attribute: NSLayoutAttribute.TopMargin, relatedBy: NSLayoutRelation.Equal, toItem: self.mView, attribute: NSLayoutAttribute.TopMargin, multiplier: 1, constant: 250)
self.view.addConstraint(leadingMargin)
self.view.addConstraint(trailingMargin)
self.view.addConstraint(height)
self.view.addConstraint(bottom)
self.view.addConstraint(top)
Your Answer
Sign up or
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Post as a guest
By posting your answer, you agree to the
Not the answer you're looking for?
Browse other questions tagged
Stack Overflow works best with JavaScript enabledProportional Layout with Swift - 推酷
Proportional Layout with Swift
Octavio asks:
I have an Autolayout challenge for you:&I have a Square view which contains some images, labels, etc. We need that view to be full width on all iPhone screen sizes & resolutions.
The view is built at 320 x 320 (or @1x) and it is expected to scale proportionally for each and every other resolution and screen size. Basically, the view and all its elements should scale together, in unison, as if it was an image.
I emailed Erica Sadun about this, being that she’s an Autolayout expert, in hopes that she would answer, but sadly she hasn’t replied and I doubt she will.
Thanks, Octavio, for a great question/challenge!
My first reaction was: “this is a problem I had solved previously!” But to make it a bit more interesting this time I am doing it with auto layout and Swift. We might learn something in the process.
When building theiCatalog framework– which was long before auto layout – we had the same problem with interactive zones on catalog pages where we would not know the final resolution. If you position a view in a superview, normally you have to specify origin and size relative to the superview’s coordinate system.
The solution then was to save origin and size in percent of the superview’s coordinates. This way you could easily multiply the percentage with the final width/height&of the superview to arrive at the runtime coordinates.
Proportional Layout
The basic formula for any auto layout constraint is:
[view1] [attribute1] IS [relation] TO [view2] [attribute2] MULTIPLIED BY [multiplicator] PLUS [constant].
To model the same behavior as outlined above, for each view we need 4 constraints:
left: [view] [Left] IS [equal] TO [superview] [Width] x percentage PLUS 0
top: [view] [Top] IS [equal] TO [superview] [Height] x percentage PLUS 0
width: [view] [Width] IS [equal] TO [superview] [Width] x percentage PLUS 0
height: [view] [Height] IS [equal] TO [superview] [Height] x percentage PLUS 0
Each of the four values is always a percentage of the width or height of the superview. For example if the superview is {0,0, 100,100} and the view is {10,20,30,40} then the percentages would be {10%, 20%, 30%, 40%}.
Interview builder doesn’t have the ability to let us specify positions as a multiple of another view’s attribute. You can only specify it in points. This means we have to do this setup in code.
We’ll want to retain the ability to design the view in Interface Builder, but we need some code that will calculate the percentages and add the corresponding constraints to the view at runtime.
Enumerating Subviews
We need to apply the constraints to all subviews of a given view to make them scale proportionally to this outermost view. For that we need a method that will enumerate all views.
Wouldn’t it be nice if UIView had a method to do that where we could have a block be executed for each of the subviews in the entire tree? Let’s add it.
extension UIView
func enumerateSubviews(block: (view: UIView) -& ())
for view in self.subviews as! [UIView]
// ignore _UILayoutGuide
if (!view.conformsToProtocol(UILayoutSupport))
view.enumerateSubviews(block)
block(view: view)
This short function contains a few interesting lessons on Swift:
The method takes a block, so the parameter type for that is (view: UIView) -& (). It passes in the current view of the enumeration and returns nothing i.e. (Void) or ().
In iOS 8, the subviews array is still defined as [AnyObject]. So to save ourselves some explicit unwrapping later on, we can just force it to be an array of UIViews: [UIView]
iOS installs the top and bottom auto layout guides as _UILayoutGuide objects. Those are also considered subclasses of UIView so we cannot use the “if let as! UIView” pattern. But normal UIViews don’t conform to the UILayoutSupport protocol, so this trick lets us skip the layout guides in our enumeration
The innermost code recurses the function for the subview’s subviews and then calls the block. This will allow us to add the size and origin constraints to each of the subviews. So let’s get to the code for those now.
Removing Prototyping Constraints
Do you remember when Interface Builder would require you to always add all constraints? Later Xcode became smarter and would happily accept any IB layout. The difference came from IB tacitly adding as many constraints as would be required to nail down all positions and sizes.
Those prototyping constraints would clash with our proportional constraints, so we need to get rid of them – and only them.
extension UIView
func removePrototypingConstraints()
for constraint in self.constraints() as! [NSLayoutConstraint]
let name = NSStringFromClass(constraint.dynamicType)
if (name.hasPrefix(&NSIBPrototyping&))
self.removeConstraint(constraint)
We are again using the as! [Type] pattern to make sure we get a typed array of NSLayoutConstraint objects so that removeConstraint won’t complain. We convert the dynamicType to a string and if this class name has a prefix of NSIBPrototyping we remove it from the view.
Creating Size Constraints in Swift
Let’s first tackle the constraints for the size. As you will see its quite straightforward. The biggest annoyance for me when creating it was that Xcode does not have the ability to colon-align parameters.
extension UIView
func addProportionalSizeConstraints()
// there must be a superview
let superview = self.superview!
// get dimensions
let bounds = superview.
let frame = self.frame
// calculate percentages relative to bounds
let percent_width = frame.size.width / bounds.
let percent_height = frame.size.height / bounds.
// constrain width as percent of superview
let widthConstraint = NSLayoutConstraint(item: self,
attribute: .Width,
relatedBy: .Equal,
toItem: superview,
attribute: .Width,
multiplier: percent_width,
constant: 0);
superview.addConstraint(widthConstraint);
// constrain height as percent of superview
let heightConstraint = NSLayoutConstraint(item: self,
attribute: .Height,
relatedBy: .Equal,
toItem: superview,
attribute: .Height,
multiplier: percent_height,
constant: 0);
superview.addConstraint(heightConstraint);
The first line explicitly unwraps the view’s superview. This can – of course – be nil, which is why Apple made it an optional value. But since it does not make sense to call this method with no superview set we can leave it as that. We actually want this to throw an exception if we ever call this method while superview is still nil. This is our replacement for NSAssert which we would have used in Objective-C.
We calculate percentages for width and height based on the superview’s size and then add two constraints which set the view’s width and height as corresponding fractions. Next we’ll take care of the view’s origin.
Constraining Origin in Swift
Autolayout refuses to constraint Left or LeftMargin to be a fraction of another view’s Width . The workaround I found was to instead use the Right value of the superview. The other challenge is that Left cannot be ZERO times Right . In that case – if the percent value is 0 – we instead pin Left to the superview’s Left . The same is true for the vertical dimension.
extension UIView
func addProportionalOriginConstraints()
// there must be a superview
let superview = self.superview!
// get dimensions
let bounds = superview.
let frame = self.frame
// calculate percentages relative to bounds
let percent_x = frame.origin.x / bounds.
let percent_y = frame.origin.y / bounds.
// constrain left as percent of superview
if (percent_x & 0)
let leftMargin = NSLayoutConstraint(item: self,
attribute: .Left,
relatedBy: .Equal,
toItem: superview,
attribute: .Right,
multiplier: percent_x,
constant: 0);
superview.addConstraint(leftMargin);
// since a multipler of 0 is illegal for .Right instead make .Left equal
let leftMargin = NSLayoutConstraint(item: self,
attribute: .Left,
relatedBy: .Equal,
toItem: superview,
attribute: .Left,
multiplier: 1,
constant: 0);
superview.addConstraint(leftMargin);
// constrain top as percent of superview
if (percent_y & 0 )
let topMargin = NSLayoutConstraint(item: self,
attribute: .Top,
relatedBy: .Equal,
toItem: superview,
attribute: .Bottom,
multiplier: percent_y,
constant: 0);
superview .addConstraint(topMargin);
// since a multipler of 0 is illegal for .Bottom we instead make .Top equal
let topMargin = NSLayoutConstraint(item: self,
attribute: .Top,
relatedBy: .Equal,
toItem: superview,
attribute: .Top,
multiplier: 1,
constant: 0);
superview .addConstraint(topMargin);
Next, let’s tie these methods together.
A Simple Test
The sample project – which you can find in my GitHub
repo – has a view subviews put together in interface builder. The root view has a simulated size of 600 x 600 and all subviews are laid out relative to that. The effect we want to achieve is that all subviews should size and position proportionally if we rotate the view between portrait and landscape.
I couldn’t find an easy way to get the root view’s size after UIViewController had loaded it from the NIB. It always comes out at the correct resolution for the device, e.g. {0, 0, 375, 667} for iPhone 6. This would destroy our reference frame, so we need to restore it before enumerating through the subviews adding our proportional constraints.
The next auto layout pass will restore the correct root view frame and then also our proportional constraints will adjust the frames of all subviews.
class ViewController: UIViewController
override func viewDidLoad()
super.viewDidLoad()
// restore reference frame from IB
self.view.frame = CGRect(x: 0, y: 0, width: 600, height: 600)
self.view.enumerateSubviews { (view) -& () in
// remove prototyping constraints from superview
view.superview!.removePrototypingConstraints()
// add proportional constraints
view.addProportionalOriginConstraints()
view.addProportionalSizeConstraints()
Note the syntax of the block we are passing into our subview enumeration function. In Objective-C we would specify&the parameter list outside of the curly braces, like ^(UIView *view). In Swift the parameters are inside the closure and so Apple needed a way to separate the parameter header from the block code. The “in” keyword serves this function.
Inside the block we first remove any left over prototyping constraints, then we add the layout constraints for origin and size. Build and run and you will see:
All squares we had in interface builder now get proportionally resized based on the dimensions of the outermost view. The one rectangle at the upper left side also resizes as expected.
Next we add an extra square view in IB&so that we always have a square.
Layout Squared
We want the view to be a square and always be toughing the outside of the screen. This is what they call “aspect fit” if the touching sides are the ones that are closer together, or “aspect fill” if its touching the sides which are wider apart.
The tricky part here is that you need to work with two different priority levels. If auto layout cannot fulfil a lesser-priority constraint then it will ignore it. Mike Wolemer from AtomicObject wrote
that explained this this me.
The Required priority constraints are:
View’s Aspect Ration should be 1:1
Center X on superview
Center Y on superview
View’s Width should be&= superview’s Width
View’s Height&= superview’s Height
The constraints with a lesser priority are:
View’s Width = superview’s Width
View’s Height = superview’s Height
Required constraints have a priority level of 1000, for the lesser priority you can use any lower value. The only constraint on the square centering view is the one for the aspect ratio. All others are attached to the root view.
To add&the constraints referencing the root view you CMD+Click on the root view and then the centering view. Click on the add constraints button and choose Equal Widths and Equal Heights.
For the greater-than constraints you do the same, but change the relationship in the constraint inspector. Make sure that you got the order of First Item and Second Item correct. If Superview is the first item, then the relation needs to be Greater Then or Equal.
Finally we need an outlet in ViewController.swift so that we can access the squareView. Then we change the enumeration to be only this view’s subviews. Et voil&!
Bonus: Automatic Font-Adjusting
There remains one item that we didn’t touch upon: the font size in UILabels. The presented approach only adjusts the frames of views, but not their contents. For a UIImageView this is no problem if you set the View Mode to “Scale to Fill”. But the font size of a label would not automatically adjust to changes in the label’s frame.
There is no facility in auto layout which would allow us to tie the font size together with any length. But we are free to create a UILabel subclass that does exactly that.
Our FontAdjustingLabel stores its initial size and font when it awakes from NIB. This enables it to calculate an adjusted font size whenever its bounds change.
class FontAdjustingLabel: UILabel
var initialSize : CGSize!
var initialFont : UIFont!
override func awakeFromNib()
super.awakeFromNib()
// store values from IB
initialSize = self.frame.size
initialFont = self.font
override func layoutSubviews()
super.layoutSubviews()
// calculate new height
let currentSize = self.bounds.size
let factor = currentSize.height / initialSize.height
// calculate point size of font
let pointSize = initialFont.pointSize *
// make same font, but new size
let fontDescriptor = initialFont.fontDescriptor()
self.font = UIFont(descriptor: fontDescriptor,
size: pointSize)
I needed to add the ! at the end of the instance variable definitions so that the compiler won’t complain that there is no init method which initializes it. Contrary to Objective-C, Swift does not automatically nil all ivars. Adding a ! or ? makes it an optional value and those do get initialized with nil.
Note the use of a font descriptor. This preserves all font attributes except the point size which we calculated based on the view’s current height relative to the initial height.
Conclusion
By answering Octavio’s question, we learned a few things about auto layout and how to set up constraints in Swift code. We created an extension to UIView, so that we could call these methods on any subclass of UIView.
We found that you cannot set up proportional constraints in Interface Builder. And the opposite is true for square layouts: first we thought that “aspect fit” wouldn’t be possible in Interface Builder, but it actually is, using constraints of different priority levels.
Finally, adjusting the font size is not possible with auto layout. But we can subclass UILabel so that it adjusts its font automatically. This way we have the auto layout system work together with manual adjustments in code to achieve the desired effect.
已发表评论数()
已收藏到推刊!
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
排版有问题
没有分页内容
视频无法显示
图片无法显示}

我要回帖

更多关于 be proportional to 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信