簡體   English   中英

自動布局:縱向到橫向不一致

[英]Auto Layout: portrait to landscape inconsistencies

我正在經歷“自動布局比努力更值得”階段。 我越來越好了,但是有些地方還是不會點擊,至少可以說令人沮喪
以下是有助於顯示我的位置的圖像以及它從模擬器返回的圖像:

在此處輸入圖片說明

中心“ ...”文本標簽位於中心的V&H。 所有4個按鈕在此標簽上都具有尾隨底部的空間限制。 每個按鈕之間都有一個試用空間約束。 在此處輸入圖片說明

當我在UI編輯器的外部邊緣上添加前導和尾隨空間約束時(上圖),我得到的結果如我所願(下圖)

在此處輸入圖片說明

然而,旋轉90度會導致4個按鈕壓扁並且不可見(在某些嘗試中4個按鈕彼此重疊)。

在此處輸入圖片說明

我已經嘗試了約束的所有不同組合,但是從兩個方向我都無法實現我想要的視圖。 這個問題可能會受到批評,但是老實說,這是獲得答案的唯一直接方法,甚至只是一些幫助。 我發現在線教程和示例僅說明了我必須使用哪些工具,而不必大膽嘗試UI元素的“比基本功能更多”的定位

這是我為NSLayoutConstraints編寫的自定義類別:

首先, NSLayoutConstraint+ConstructorAdditions.h文件:

//  NSLayoutConstraint+ConstructorAdditions.h
//
// The methods in this category can be used to create NSLayoutConstraints programmatically
// without taking the NSLayoutConstraints constructors.
// Note: view1 and view2 must be in the same subview hierarchy. If not, adding NSLayoutConstraints using these methods won't have no effect.
//
// Example for the right order of method calls creating Constraints:
//
// UIView* mySubview = [UIView alloc] init];
// [self.contentView addSubview: mySubview];
// [self.contentView addConstraint: [self height: 10.0 forView: mySubview]];


#import <UIKit/UIKit.h>

@interface NSLayoutConstraint (ConstructorAdditions)



// returns constraints that align view to top, leading, bottom and trailing edges of the superview according to the assigned padding value.
// the constraints in the returned array are (from index 0 to 3) in this order:
// leading, top, trailing, bottom
+ (NSArray*) makeView: (UIView*) view
fillBoundsOfSuperview: (UIView*) superview
      verticalPadding: (CGFloat) vPadding
    horizontalPadding: (CGFloat) hPadding;


// align edges of two views
// if one view is the superview, put it at the second position in the array
+ (NSLayoutConstraint*) alignEdge: (NSLayoutAttribute) edge
                          ofViews: (NSArray*) /*UIView*/ views
                         relation: (NSLayoutRelation) relation
                          spacing: (CGFloat) spacing;



// vertical spcacing between views
// the method assumes, that the first view in the array is above the second view
+ (NSLayoutConstraint*) verticalSpacing: (CGFloat) spacing
                                ofViews: (NSArray*) /*UIView*/ views
                               flexible: (BOOL) flexible
                               inMaximum: (BOOL) inMax;


// horizontal spacing between views
// the method assumes, that the first view in the array is left of the second view
+ (NSLayoutConstraint*) horizontalSpacing: (CGFloat) spacing
                             betweenViews: (NSArray*) /*UIView*/ views
                                 flexible: (BOOL) flexible
                                 inMaximum: (BOOL) inMax;




// vertical spcacing between views
// the method assumes, that the first view in the array is above the second view
+ (NSLayoutConstraint*) verticalSpacing: (CGFloat) spacing ofViews: (NSArray*) /*UIView*/ views;


// horizontal spacing between views
// the method assumes, that the first view in the array is left of the second view
+ (NSLayoutConstraint*) horizontalSpacing: (CGFloat) spacing betweenViews: (NSArray*) /*UIView*/ views;




// height constraints
+ (NSArray*) equalHeightOfViews: (NSArray*) views
                         toView: (UIView*) view
                       distance: (CGFloat) distance
                       relation: (NSLayoutRelation) relation
                     multiplier: (CGFloat) multiplier;
// fix heights
+ (NSLayoutConstraint*) height: (CGFloat) height forView: (UIView*) view;
+ (NSLayoutConstraint*) maxHeight: (CGFloat) height
                          forView: (UIView*) view;
+ (NSLayoutConstraint*) minHeight: (CGFloat) height
                          forView: (UIView*) view;

// width constraints
+ (NSArray*) equalWidthOfViews: (NSArray*) views
                        toView: (UIView*) view
                      distance: (CGFloat) distance
                      relation: (NSLayoutRelation) relation
                    multiplier: (CGFloat) multiplier;
// fix widths
+ (NSLayoutConstraint*) width: (CGFloat) width forView: (UIView*) view;
+ (NSLayoutConstraint*) maxWidth: (CGFloat) width
                         forView: (UIView*) view;
+ (NSLayoutConstraint*) minWidth: (CGFloat) width
                         forView: (UIView*) view;




// center vertically
+ (NSLayoutConstraint*) centerView: (UIView*) view
             verticallyInContainer: (UIView*) container;



// center horizontally
+ (NSLayoutConstraint*) centerView: (UIView*) view
            hoizontallyInContainer: (UIView*) container;



@end

這里是NSLayoutConstraint+ConstructorAdditions.m文件:

#import "NSLayoutConstraint+ConstructorAdditions.h"

@implementation NSLayoutConstraint (ConstructorAdditions)






+ (NSArray*) makeView: (UIView*) view fillBoundsOfSuperview: (UIView*) superview verticalPadding: (CGFloat) vPadding horizontalPadding: (CGFloat) hPadding
{
    /* padding must be > 0 !*/
    hPadding = hPadding < 0 ? 0 : hPadding;
    vPadding = vPadding < 0 ? 0 : vPadding;
    NSLayoutConstraint* top = [NSLayoutConstraint alignEdge: NSLayoutAttributeTop ofViews: @[view, superview] relation: NSLayoutRelationEqual spacing: vPadding];
    NSLayoutConstraint* leading = [NSLayoutConstraint alignEdge: NSLayoutAttributeLeading ofViews: @[view, superview] relation: NSLayoutRelationEqual spacing: hPadding];
    NSLayoutConstraint* trailing = [NSLayoutConstraint alignEdge: NSLayoutAttributeTrailing ofViews: @[view, superview] relation: NSLayoutRelationEqual spacing: hPadding];
    NSLayoutConstraint* bottom = [NSLayoutConstraint alignEdge: NSLayoutAttributeBottom ofViews: @[view, superview] relation: NSLayoutRelationEqual spacing: vPadding];
    //NSLayoutConstraint* width = [NSLayoutConstraint equalWidthOfViews: @[view, superview] distance: -2*hPadding relation: NSLayoutRelationEqual multiplier: 1.0][0];
    //NSLayoutConstraint* height = [NSLayoutConstraint equalHeightOfViews: @[view, superview] distance: -2*vPadding relation: NSLayoutRelationEqual multiplier: 1.0][0];
    return @[leading, top, trailing, bottom];
}







// align edges of two views
// if one view is the superview, put it at the second position in the array
+ (NSLayoutConstraint*) alignEdge: (NSLayoutAttribute) edge
                          ofViews: (NSArray*) /*UIView*/ views
                         relation: (NSLayoutRelation) relation
                          spacing: (CGFloat) spacing {
    NSLayoutConstraint* constraint = nil;
    if (views.count == 2) {
        if (edge == NSLayoutAttributeBaseline || edge == NSLayoutAttributeTrailing || edge == NSLayoutAttributeBottom || edge == NSLayoutAttributeRight) {
            spacing = -spacing;
        }
        constraint = [NSLayoutConstraint constraintWithItem: [views objectAtIndex: 0]
                                                  attribute: edge
                                                  relatedBy: relation
                                                     toItem: [views objectAtIndex: 1]
                                                  attribute: edge
                                                 multiplier: 1.0
                                                   constant: spacing];
    }
    return constraint;
}


// vertical spcacing between views
// the method assumes, that the first view in the array is above the second view
+ (NSLayoutConstraint*) verticalSpacing: (CGFloat) spacing
                                ofViews: (NSArray*) /*UIView*/ views
                               flexible: (BOOL) flexible
                               inMaximum: (BOOL) inMax {
    NSLayoutConstraint* constraint = nil;

    NSLayoutRelation relation = flexible ? (inMax ? NSLayoutRelationGreaterThanOrEqual : NSLayoutRelationLessThanOrEqual) : NSLayoutRelationEqual;

    if (views.count == 2) {
        constraint = [NSLayoutConstraint constraintWithItem: [views objectAtIndex: 0]
                                                  attribute: NSLayoutAttributeBottom
                                                  relatedBy: relation
                                                     toItem: [views objectAtIndex: 1]
                                                  attribute: NSLayoutAttributeTop
                                                 multiplier: 1.0
                                                   constant: -spacing];
    }
    return constraint;
}


// horizontal spacing between views
// the method assumes, that the first view in the array is left of the second view
+ (NSLayoutConstraint*) horizontalSpacing: (CGFloat) spacing
                             betweenViews: (NSArray*) /*UIView*/ views
                                 flexible: (BOOL) flexible
                                 inMaximum: (BOOL) inMax {
    NSLayoutConstraint* constraint = nil;
    NSLayoutRelation relation = flexible ? (inMax ? NSLayoutRelationGreaterThanOrEqual : NSLayoutRelationLessThanOrEqual) : NSLayoutRelationEqual;
    if (views.count == 2) {
        constraint = [NSLayoutConstraint constraintWithItem: [views objectAtIndex: 0]
                                                  attribute: NSLayoutAttributeTrailing
                                                  relatedBy: relation
                                                     toItem: [views objectAtIndex: 1]
                                                  attribute: NSLayoutAttributeLeading
                                                 multiplier: 1.0
                                                   constant: -spacing];
    }
    return constraint;
}






// vertical spcacing between views
// the method assumes, that the first view in the array is above the second view
+ (NSLayoutConstraint*) verticalSpacing: (CGFloat) spacing ofViews: (NSArray*) /*UIView*/ views
{
    NSLayoutConstraint* verticalSpacing = nil;
    if (views.count == 2) {
        verticalSpacing = [NSLayoutConstraint constraintWithItem: [views objectAtIndex: 0] attribute: NSLayoutAttributeBottom relatedBy: NSLayoutRelationEqual toItem: [views objectAtIndex: 1] attribute: NSLayoutAttributeTop multiplier: 1.0 constant: -spacing];
    }
    return verticalSpacing;
}



// horizontal spacing between views
// the method assumes, that the first view in the array is left of the second view
+ (NSLayoutConstraint*) horizontalSpacing: (CGFloat) spacing
                             betweenViews: (NSArray*) /*UIView*/ views
{
    NSLayoutConstraint* horizontalSpacing = nil;
    if (views.count == 2) {
        horizontalSpacing = [NSLayoutConstraint constraintWithItem: [views objectAtIndex: 0] attribute: NSLayoutAttributeTrailing relatedBy: NSLayoutRelationEqual toItem: [views objectAtIndex: 1] attribute: NSLayoutAttributeLeading multiplier: 1.0 constant: -spacing];
    }
    return horizontalSpacing;
}








+ (NSArray*) equalHeightOfViews: (NSArray*) views
                         toView: (UIView*) view
                       distance: (CGFloat) distance
                       relation: (NSLayoutRelation) relation
                     multiplier: (CGFloat) multiplier {
    NSMutableArray* constraints = [[NSMutableArray alloc] initWithCapacity: views.count];

    for (UIView* aView in views) {
        [constraints addObject: [NSLayoutConstraint  constraintWithItem: aView
                                                              attribute: NSLayoutAttributeHeight
                                                              relatedBy: relation
                                                                 toItem: view
                                                              attribute: NSLayoutAttributeHeight
                                                             multiplier: multiplier
                                                               constant: distance]];
    }
    return constraints;
}



+ (NSLayoutConstraint*) height: (CGFloat) height forView: (UIView*) view {
    NSLayoutConstraint* constraint = nil;
    constraint = [NSLayoutConstraint constraintWithItem: view
                                              attribute: NSLayoutAttributeHeight
                                              relatedBy: NSLayoutRelationEqual
                                                 toItem: nil
                                              attribute: NSLayoutAttributeNotAnAttribute
                                             multiplier: 1.0
                                               constant: height];
    return constraint;
}


+ (NSLayoutConstraint*) maxHeight: (CGFloat) height
                          forView: (UIView*) view {
    NSLayoutConstraint* constraint = [NSLayoutConstraint constraintWithItem: view
                                                                  attribute: NSLayoutAttributeHeight
                                                                  relatedBy: NSLayoutRelationLessThanOrEqual
                                                                     toItem: nil
                                                                  attribute: NSLayoutAttributeNotAnAttribute
                                                                 multiplier: 1.0
                                                                   constant: height];
    return constraint;

}


+ (NSLayoutConstraint*) minHeight: (CGFloat) height
                          forView: (UIView*) view {
    NSLayoutConstraint* constraint = [NSLayoutConstraint constraintWithItem: view
                                                                  attribute: NSLayoutAttributeHeight
                                                                  relatedBy: NSLayoutRelationGreaterThanOrEqual
                                                                     toItem: nil
                                                                  attribute: NSLayoutAttributeNotAnAttribute
                                                                 multiplier: 1.0
                                                                   constant: height];
    return constraint;
}



+ (NSArray*) equalWidthOfViews: (NSArray*) views
                        toView: (UIView*) view
                      distance: (CGFloat) distance
                      relation: (NSLayoutRelation) relation
                    multiplier: (CGFloat) multiplier {
    NSMutableArray* constraints = [[NSMutableArray alloc] initWithCapacity: views.count];

    for (UIView* aView in views) {
        [constraints addObject: [NSLayoutConstraint  constraintWithItem: aView
                                                              attribute: NSLayoutAttributeWidth
                                                              relatedBy: relation
                                                                 toItem: view
                                                              attribute: NSLayoutAttributeWidth
                                                             multiplier: multiplier
                                                               constant: distance]];
    }
    return constraints;
}



+ (NSLayoutConstraint*) width: (CGFloat) width forView: (UIView*) view {
    NSLayoutConstraint* constraint = [NSLayoutConstraint constraintWithItem: view
                                                                  attribute: NSLayoutAttributeWidth
                                                                  relatedBy: NSLayoutRelationEqual
                                                                     toItem: nil
                                                                  attribute: NSLayoutAttributeNotAnAttribute
                                                                 multiplier: 1.0
                                                                   constant: width];
    return constraint;
}


+ (NSLayoutConstraint*) maxWidth: (CGFloat) width forView: (UIView*) view {
    NSLayoutConstraint* constraint = [NSLayoutConstraint constraintWithItem: view
                                                                  attribute: NSLayoutAttributeWidth
                                                                  relatedBy: NSLayoutRelationLessThanOrEqual
                                                                     toItem: nil
                                                                  attribute: NSLayoutAttributeNotAnAttribute
                                                                 multiplier: 1.0
                                                                   constant: width];
    return constraint;
}


+ (NSLayoutConstraint*) minWidth: (CGFloat) width forView: (UIView*) view {
    NSLayoutConstraint* constraint = [NSLayoutConstraint constraintWithItem: view
                                                                  attribute: NSLayoutAttributeWidth
                                                                  relatedBy: NSLayoutRelationGreaterThanOrEqual
                                                                     toItem: nil
                                                                  attribute: NSLayoutAttributeNotAnAttribute
                                                                 multiplier: 1.0
                                                                   constant: width];
    return constraint;
}



// center vertically
+ (NSLayoutConstraint*) centerView: (UIView*) view verticallyInContainer: (UIView*) container {
    NSLayoutConstraint* centerY = [NSLayoutConstraint constraintWithItem: view
                                                               attribute: NSLayoutAttributeCenterY
                                                               relatedBy: NSLayoutRelationEqual
                                                                  toItem: container
                                                               attribute: NSLayoutAttributeCenterY
                                                              multiplier: 1.0
                                                                constant: 0];
    return centerY;
}



// center horizontally
+ (NSLayoutConstraint*) centerView: (UIView*) view hoizontallyInContainer: (UIView*) container {
    NSLayoutConstraint* centerX = [NSLayoutConstraint constraintWithItem: view
                                                               attribute: NSLayoutAttributeCenterX
                                                               relatedBy: NSLayoutRelationEqual
                                                                  toItem: container
                                                               attribute: NSLayoutAttributeCenterX
                                                              multiplier: 1.0
                                                                constant: 0];


    return centerX;
}





@end

在您的初始圖片中,標簽之所以顯示為橙色的原因是因為您的約束存在歧義:具體來說,它們沒有任何內容告訴他們相對於x軸應位於何處。 它們在垂直方向上連接到中心,但是在水平方向上它們僅彼此連接,並且由於它們都沒有作為x軸錨點連接到邊緣或其他任何東西,因此存在歧義。

在第二張圖片中,您已通過將鏈條的兩側錨定到視圖的邊緣來解決此問題。 但是,在縱向模式中,這會擠壓它們,因為那些外部錨點正試圖保持在原位,並且它選擇擠壓標簽上的寬度約束。

解決此問題的方法如下:選擇一個標簽(不一定是全部標簽)並將其約束到容器的水平中心,在本例中為superview。

這將告知標簽相對於x軸的位置,同時還可以防止標簽被縱向視圖的側面擠壓。

水平中心

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM