2015-06-09 2 views
73

Я пытаюсь программным образом добавлять представления в UIStackView. Сейчас мой код:Добавить виды в UIStackView программно

UIView *view1 = [[UIView alloc]init]; 
view1.backgroundColor = [UIColor blackColor]; 
[view1 setFrame:CGRectMake(0, 0, 100, 100)]; 

UIView *view2 = [[UIView alloc]init]; 
view2.backgroundColor = [UIColor greenColor]; 
[view2 setFrame:CGRectMake(0, 100, 100, 100)]; 

[self.stack1 addArrangedSubview:view1]; 
[self.stack1 addArrangedSubview:view2]; 

Когда я развернуть приложение, есть только один вид, и это с черным цветом (view1 получить параметры для View2 тоже)

+0

Вы проверили свой выход? Вы регистрировали подпрограммы во время выполнения? – Wain

+0

Использование 'addArrangedSubview:', а не 'addSubview:' – pkamb

ответ

129

Представления стека используют внутренний размер содержимого, поэтому используйте ограничения компоновки, чтобы определить размеры представлений.

Существует простой способ быстро добавить ограничения (пример):

[view1.heightAnchor constraintEqualToConstant:100].active = true; 

Полный код:

- (void) setup { 

    //View 1 
    UIView *view1 = [[UIView alloc] init]; 
    view1.backgroundColor = [UIColor blueColor]; 
    [view1.heightAnchor constraintEqualToConstant:100].active = true; 
    [view1.widthAnchor constraintEqualToConstant:120].active = true; 


    //View 2 
    UIView *view2 = [[UIView alloc] init]; 
    view2.backgroundColor = [UIColor greenColor]; 
    [view2.heightAnchor constraintEqualToConstant:100].active = true; 
    [view2.widthAnchor constraintEqualToConstant:70].active = true; 

    //View 3 
    UIView *view3 = [[UIView alloc] init]; 
    view3.backgroundColor = [UIColor magentaColor]; 
    [view3.heightAnchor constraintEqualToConstant:100].active = true; 
    [view3.widthAnchor constraintEqualToConstant:180].active = true; 

    //Stack View 
    UIStackView *stackView = [[UIStackView alloc] init]; 

    stackView.axis = UILayoutConstraintAxisVertical; 
    stackView.distribution = UIStackViewDistributionEqualSpacing; 
    stackView.alignment = UIStackViewAlignmentCenter; 
    stackView.spacing = 30; 


    [stackView addArrangedSubview:view1]; 
    [stackView addArrangedSubview:view2]; 
    [stackView addArrangedSubview:view3]; 

    stackView.translatesAutoresizingMaskIntoConstraints = false; 
    [self.view addSubview:stackView]; 


    //Layout for Stack View 
    [stackView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = true; 
    [stackView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor].active = true; 
} 

Примечание: Это был протестирован на прошивкой 9

UIStackView Equal Spacing (centered)

+16

Точка использования представлений стека заключается в том, что они скрывают детали управления ограничениями от разработчика. Как вы указали, это зависит от того, какие субсчета имеют собственный размер содержимого, который по умолчанию не имеет UIViews. Если исходный плакат использовал экземпляры 'UILabel' вместо' UIView', его код работал бы так, как он ожидал. Я добавил пример, демонстрирующий это ниже. –

+0

когда я делаю это "[view1.heightAnchor constraintEqualToConstant: 100] .active = true;" im получить ошибку на ios 8.It работает только на ios 9.I знаю, что uistackview для ios 9+, но как я могу установить ограничение heightAncor для ios 8 –

+0

My StackView добавлен с помощью раскадровки. Во время выполнения я добавляю несколько файлов UIView (содержат другие подзаголовки) в stackView.После загрузки данных все представления внутри stackView имеют одинаковую высоту, они не изменяются в зависимости от содержимого. @ user1046037 –

4

Вы должны установить вас. распределение type. В коде Жюст добавить:

self.stack1.distribution = UIStackViewDistributionFillEqually; 

Или вы можете установить распределение непосредственно в интерфейсе строителя. Например:

enter image description here

Надежда, что помогает;) Lapinou.

-2

Try ниже кода,

UIView *view1 = [[UIView alloc]init]; 
view1.backgroundColor = [UIColor blackColor]; 
[view1 setFrame:CGRectMake(0, 0, 50, 50)]; 

UIView *view2 = [[UIView alloc]init]; 
view2.backgroundColor = [UIColor greenColor]; 
[view2 setFrame:CGRectMake(0, 100, 100, 100)]; 

NSArray *subView = [NSArray arrayWithObjects:view1,view2, nil]; 

[self.stack1 initWithArrangedSubviews:subView]; 

Надеется, что это работает. Пожалуйста, дайте мне знать, если вам нужно больше разъяснений.

78

Swift 3,0

//Image View 
let imageView = UIImageView() 
imageView.backgroundColor = UIColor.blue 
imageView.heightAnchor.constraint(equalToConstant: 120.0).isActive = true 
imageView.widthAnchor.constraint(equalToConstant: 120.0).isActive = true 
imageView.image = UIImage(named: "buttonFollowCheckGreen") 

//Text Label 
let textLabel = UILabel() 
textLabel.backgroundColor = UIColor.yellow 
textLabel.widthAnchor.constraint(equalToConstant: self.view.frame.width).isActive = true 
textLabel.heightAnchor.constraint(equalToConstant: 20.0).isActive = true 
textLabel.text = "Hi World" 
textLabel.textAlignment = .center 

//Stack View 
let stackView = UIStackView() 
stackView.axis = UILayoutConstraintAxis.vertical 
stackView.distribution = UIStackViewDistribution.equalSpacing 
stackView.alignment = UIStackViewAlignment.center 
stackView.spacing = 16.0 

stackView.addArrangedSubview(imageView) 
stackView.addArrangedSubview(textLabel) 
stackView.translatesAutoresizingMaskIntoConstraints = false 

self.view.addSubview(stackView) 

//Constraints 
stackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true 
stackView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true 

А вот Swift 2,0 версия:

//Image View 
let imageView    = UIImageView() 
imageView.backgroundColor = UIColor.blueColor() 
imageView.heightAnchor.constraintEqualToConstant(120.0).active = true 
imageView.widthAnchor.constraintEqualToConstant(120.0).active = true 
imageView.image = UIImage(named: "buttonFollowCheckGreen") 

//Text Label 
let textLabel    = UILabel() 
textLabel.backgroundColor = UIColor.yellowColor() 
textLabel.widthAnchor.constraintEqualToConstant(self.view.frame.width).active = true 
textLabel.heightAnchor.constraintEqualToConstant(20.0).active = true 
textLabel.text = "Hi World" 
textLabel.textAlignment = .Center 

//Stack View 
let stackView = UIStackView() 
stackView.axis = UILayoutConstraintAxis.Vertical 
stackView.distribution = UIStackViewDistribution.EqualSpacing 
stackView.alignment = UIStackViewAlignment.Center 
stackView.spacing = 16.0 

stackView.addArrangedSubview(imageView) 
stackView.addArrangedSubview(textLabel) 
stackView.translatesAutoresizingMaskIntoConstraints = false; 

self.view.addSubview(stackView) 

//Constraints 
stackView.centerXAnchor.constraintEqualToAnchor(self.view.centerXAnchor).active = true 
stackView.centerYAnchor.constraintEqualToAnchor(self.view.centerYAnchor).active = true 

на основе @ user1046037 ответить

3
//Image View 
    let imageView    = UIImageView() 
    imageView.backgroundColor = UIColor.blueColor() 
    imageView.heightAnchor.constraintEqualToConstant(120.0).active = true 
    imageView.widthAnchor.constraintEqualToConstant(120.0).active = true 
    imageView.image = UIImage(named: "buttonFollowCheckGreen") 

    //Text Label 
    let textLabel    = UILabel() 
    textLabel.backgroundColor = UIColor.greenColor() 
    textLabel.widthAnchor.constraintEqualToConstant(self.view.frame.width).active = true 
    textLabel.heightAnchor.constraintEqualToConstant(20.0).active = true 
    textLabel.text = "Hi World" 
    textLabel.textAlignment = .Center 


    //Third View 
    let thirdView    = UIImageView() 
    thirdView.backgroundColor = UIColor.magentaColor() 
    thirdView.heightAnchor.constraintEqualToConstant(120.0).active = true 
    thirdView.widthAnchor.constraintEqualToConstant(120.0).active = true 
    thirdView.image = UIImage(named: "buttonFollowMagenta") 


    //Stack View 
    let stackView = UIStackView() 
    stackView.axis = UILayoutConstraintAxis.Vertical 
    stackView.distribution = UIStackViewDistribution.EqualSpacing 
    stackView.alignment = UIStackViewAlignment.Center 
    stackView.spacing = 16.0 

    stackView.addArrangedSubview(imageView) 
    stackView.addArrangedSubview(textLabel) 
    stackView.addArrangedSubview(thirdView) 
    stackView.translatesAutoresizingMaskIntoConstraints = false; 

    self.view.addSubview(stackView) 

    //Constraints 
    stackView.centerXAnchor.constraintEqualToAnchor(self.view.centerXAnchor).active = true 
    stackView.centerYAnchor.constraintEqualToAnchor(self.view.centerYAnchor).active = true 

Улучшение на ответ на @Oleg Попов

6

UIStackView использует ограничения внутри, чтобы расположить свои организованные подсмотры. Точно, какие ограничения создаются, зависит от того, как настроено представление стека. По умолчанию представление в стеке создаст ограничения, которые выстраивают его организованные подсмотры в горизонтальной линии, привязывая ведущий и конечный виды к своим собственным ведущим и задним краям. Так что ваш код будет производить макет, который выглядит следующим образом:

|[view1][view2]| 

Пространство, которое выделяется каждому подвид определяется целым рядом факторов, включая присущую размер контента в подвид и это сопротивление сжатию и приоритеты содержания обниматься.По умолчанию UIView экземпляров не определяют собственный размер содержимого. Это то, что обычно предоставляется подклассом, например UILabel или UIButton.

Поскольку сопротивление сжатию содержимого и приоритеты в отношении содержимого двух новых экземпляров UIView будут одинаковыми, и ни один из представлений не содержит внутренний размер содержимого, механизм компоновки должен сделать все возможное, чтобы определить, какой размер должен быть выделен для каждого вида , В вашем случае он присваивает первое представление 100% доступного пространства, и ничто для второго представления.

Если изменить код, чтобы использовать UILabel экземпляров вместо этого, вы получите лучшие результаты:

UILabel *label1 = [UILabel new]; 
label1.text = @"Label 1"; 
label1.backgroundColor = [UIColor blueColor]; 

UILabel *label2 = [UILabel new]; 
label2.text = @"Label 2"; 
label2.backgroundColor = [UIColor greenColor]; 

[self.stack1 addArrangedSubview:label1]; 
[self.stack1 addArrangedSubview:label2]; 

Обратите внимание, что не нужно создавать Явно какие-либо ограничения самостоятельно. Это основное преимущество использования UIStackView - он скрывает (часто уродливые) детали управления ограничениями от разработчика.

+0

У меня та же проблема, что и для меток, но не для TextFields (или Views, если на то пошло). Также все обучающие программы, которые я нахожу, используют ярлыки, изображения или кнопки. Означает ли это, что для чего-либо другого, чем эти элементы пользовательского интерфейса, мы не можем использовать этот метод? – physicalattraction

+0

@physicalattraction Представления, которые вы добавляете в представление стека, должны иметь собственный размер содержимого. Насколько я помню, внутренний размер текстового поля основан на содержимом поля (которое является нечетным). Экземпляры 'UIView' сами по себе не имеют собственного размера. Возможно, вам придется применять дополнительные ограничения для этих представлений, чтобы представление стека знало, как сильно их сделать. –

+0

Имеет смысл, поэтому я пытаюсь. Теперь я создал представление в xib с текстовым полем, которое я даю явное ограничение высоты 30 пикселей. Я также создаю следующие два ограничения: 'MyTextField.top = top + 20' и' bottom = MyTextField.bottom + 20'. Я бы ожидал, что это даст моему взгляду внутреннюю высоту 70, но вместо этого он жалуется на противоречивые ограничения. Вы знаете, что здесь происходит? Именно этот вид, который я хочу разместить внутри моего UIStackView. – physicalattraction

6

Следующие две строки фиксированной мой вопрос

view.heightAnchor.constraintEqualToConstant(50).active = true; 
    view.widthAnchor.constraintEqualToConstant(350).active = true; 

Swift версия -

var DynamicView=UIView(frame: CGRectMake(100, 200, 100, 100)) 
    DynamicView.backgroundColor=UIColor.greenColor() 
    DynamicView.layer.cornerRadius=25 
    DynamicView.layer.borderWidth=2 
    self.view.addSubview(DynamicView) 
    DynamicView.heightAnchor.constraintEqualToConstant(50).active = true; 
    DynamicView.widthAnchor.constraintEqualToConstant(350).active = true; 

    var DynamicView2=UIView(frame: CGRectMake(100, 310, 100, 100)) 
    DynamicView2.backgroundColor=UIColor.greenColor() 
    DynamicView2.layer.cornerRadius=25 
    DynamicView2.layer.borderWidth=2 
    self.view.addSubview(DynamicView2) 
    DynamicView2.heightAnchor.constraintEqualToConstant(50).active = true; 
    DynamicView2.widthAnchor.constraintEqualToConstant(350).active = true; 

    var DynamicView3:UIView=UIView(frame: CGRectMake(10, 420, 355, 100)) 
    DynamicView3.backgroundColor=UIColor.greenColor() 
    DynamicView3.layer.cornerRadius=25 
    DynamicView3.layer.borderWidth=2 
    self.view.addSubview(DynamicView3) 

    let yourLabel:UILabel = UILabel(frame: CGRectMake(110, 10, 200, 20)) 
    yourLabel.textColor = UIColor.whiteColor() 
    //yourLabel.backgroundColor = UIColor.blackColor() 
    yourLabel.text = "mylabel text" 
    DynamicView3.addSubview(yourLabel) 
    DynamicView3.heightAnchor.constraintEqualToConstant(50).active = true; 
    DynamicView3.widthAnchor.constraintEqualToConstant(350).active = true; 

    let stackView = UIStackView() 
    stackView.axis = UILayoutConstraintAxis.Vertical 
    stackView.distribution = UIStackViewDistribution.EqualSpacing 
    stackView.alignment = UIStackViewAlignment.Center 
    stackView.spacing = 30 

    stackView.addArrangedSubview(DynamicView) 
    stackView.addArrangedSubview(DynamicView2) 
    stackView.addArrangedSubview(DynamicView3) 

    stackView.translatesAutoresizingMaskIntoConstraints = false; 

    self.view.addSubview(stackView) 

    //Constraints 
    stackView.centerXAnchor.constraintEqualToAnchor(self.view.centerXAnchor).active = true 
    stackView.centerYAnchor.constraintEqualToAnchor(self.view.centerYAnchor).active = true 
0

Я просто наткнулся на очень похожие проблемы. Точно так же, как упоминалось ранее, размеры измерений в стеке зависят от одного внутреннего размера содержимого расположенных подзонов. Вот мое решение в Swift 2.x и следующую структуру вида:

вид - UIView

customView - CustomView: UIView

stackView - UISTackView

расположены подвидов - пользовательские UIView подклассов

//: [Previous](@previous) 

import Foundation 
import UIKit 
import XCPlayground 

/**Container for stack view*/ 
class CustomView:UIView { 

    override init(frame: CGRect) { 
     super.init(frame: frame) 
    } 

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
    } 


    init(){ 
     super.init(frame: CGRectZero) 

    } 

} 

/**Custom Subclass*/ 
class CustomDrawing:UIView{ 
    override init(frame: CGRect) { 
     super.init(frame: frame) 
     setup() 
    } 

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
     setup() 

    } 

    func setup(){ 
     // self.backgroundColor = UIColor.clearColor() 
     print("setup \(frame)") 
    } 

    override func drawRect(rect: CGRect) { 
     let ctx = UIGraphicsGetCurrentContext() 
     CGContextMoveToPoint(ctx, 0, 0) 
     CGContextAddLineToPoint(ctx, CGRectGetWidth(bounds), CGRectGetHeight(bounds)) 
     CGContextStrokePath(ctx) 

     print("DrawRect") 

    } 
} 



//: [Next](@next) 
let stackView = UIStackView() 
stackView.distribution = .FillProportionally 
stackView.alignment = .Center 
stackView.axis = .Horizontal 
stackView.spacing = 10 


//container view 
let view = UIView(frame: CGRectMake(0,0,320,640)) 
view.backgroundColor = UIColor.darkGrayColor() 
//now custom view 

let customView = CustomView() 

view.addSubview(customView) 

customView.translatesAutoresizingMaskIntoConstraints = false 
customView.widthAnchor.constraintEqualToConstant(220).active = true 
customView.heightAnchor.constraintEqualToConstant(60).active = true 
customView.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor).active = true 
customView.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor).active = true 
customView.backgroundColor = UIColor.lightGrayColor() 

//add a stack view 
customView.addSubview(stackView) 
stackView.centerXAnchor.constraintEqualToAnchor(customView.centerXAnchor).active = true 
stackView.centerYAnchor.constraintEqualToAnchor(customView.centerYAnchor).active = true 
stackView.translatesAutoresizingMaskIntoConstraints = false 


let c1 = CustomDrawing() 
c1.translatesAutoresizingMaskIntoConstraints = false 
c1.backgroundColor = UIColor.redColor() 
c1.widthAnchor.constraintEqualToConstant(30).active = true 
c1.heightAnchor.constraintEqualToConstant(30).active = true 

let c2 = CustomDrawing() 
c2.translatesAutoresizingMaskIntoConstraints = false 
c2.backgroundColor = UIColor.blueColor() 
c2.widthAnchor.constraintEqualToConstant(30).active = true 
c2.heightAnchor.constraintEqualToConstant(30).active = true 


stackView.addArrangedSubview(c1) 
stackView.addArrangedSubview(c2) 


XCPlaygroundPage.currentPage.liveView = view 
2

Для принятого ответа, когда вы пытаетесь скрыть любой вид внутри представления стека, ограничение работает неправильно.

Unable to simultaneously satisfy constraints. 
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
     (1) look at each constraint and try to figure out which you don't expect; 
     (2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x618000086e50 UIView:0x7fc11c4051c0.height == 120 (active)>", 
    "<NSLayoutConstraint:0x610000084fb0 'UISV-hiding' UIView:0x7fc11c4051c0.height == 0 (active)>" 
) 

Причина когда Скройте view в stackView будет установить высоту 0, чтобы оживить его.

Решение изменить ограничение priority как показано ниже.

import UIKit 

class ViewController: UIViewController { 

    let stackView = UIStackView() 
    let a = UIView() 
    let b = UIView() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     a.backgroundColor = UIColor.red 
     a.widthAnchor.constraint(equalToConstant: 200).isActive = true 
     let aHeight = a.heightAnchor.constraint(equalToConstant: 120) 
     aHeight.isActive = true 
     aHeight.priority = 999 

     let bHeight = b.heightAnchor.constraint(equalToConstant: 120) 
     bHeight.isActive = true 
     bHeight.priority = 999 
     b.backgroundColor = UIColor.green 
     b.widthAnchor.constraint(equalToConstant: 200).isActive = true 

     view.addSubview(stackView) 
     stackView.backgroundColor = UIColor.blue 
     stackView.addArrangedSubview(a) 
     stackView.addArrangedSubview(b) 
     stackView.axis = .vertical 
     stackView.distribution = .equalSpacing 
     stackView.translatesAutoresizingMaskIntoConstraints = false 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 

    // Just add a button in xib file or storyboard and add connect this action. 
    @IBAction func test(_ sender: Any) { 
     a.isHidden = !a.isHidden 
    } 

} 
Смежные вопросы