Programlı olarak UIStackView'da görünüm ekleme


158

Programlı olarak UIStackView'da görünümler eklemeye çalışıyorum. Şimdilik Kodum:

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];

Ben uygulamayı dağıttığınızda, sadece 1 görünüm ve siyah renk ile. (View1 de view2 için parametreleri almak)


Akıl sağlığınızı kontrol ettiniz mi? Alt görünümleri çalışma zamanında kaydettiniz mi?
Wain

10
Kullanın addArrangedSubview:, değiladdSubview:
pkamb

Yanıtlar:


245

Yığın görünümleri gerçek içerik boyutunu kullanır, bu nedenle görünümlerin boyutlarını tanımlamak için mizanpaj kısıtlamalarını kullanın.

Hızla kısıtlama eklemenin kolay bir yolu vardır (örnek):

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

Kodun Tamamı:

- (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;
}

Not: Bu, iOS 9'da test edildi

UIStackView Eşit Aralık (ortalanmış)


27
Yığın görünümlerini kullanmanın amacı, kısıtlama yönetiminin ayrıntılarını geliştiriciden gizlemesidir. İşaret ettiğiniz gibi, bu, varsayılan UIViewsolmayan , gerçek bir içerik boyutuna sahip alt görünümlere dayanır . Orijinal poster UILabelbunun yerine örnekleri kullansaydı UIView, kodu beklendiği gibi çalışırdı. Bunu aşağıda gösteren bir örnek ekledim.
Greg Brown

bunu yaptığımda "[view1.heightAnchor constraintEqualToConstant: 100] .active = true;" im 8.It tek uistackview ios içindir 9+ ama iOS 9.I bilmesi çalışan ios üzerinde hata alıyorum nasıl ben heightAncor ios 8 için sınırlaması ayarlayabilirsiniz can
selimko Nuridin

StackView'ım film şeridi kullanılarak eklenir. Çalışma zamanında stackView için birkaç UIViews (diğer alt görünümleri içerir) ekliyorum. Veri yüklendikten sonra stackView içindeki tüm görünümler aynı yüksekliğe sahiptir, içeriğe göre yeniden boyutlandırılmaz. @ user1046037
Mansuu ....

Boyutlarının içeriğe göre değişmesi için bu ayrı görünümler için ayarlanmış kısıtlamalarınız var mı?
user1046037

Bu, eşit genişliklerde veya yüksekliklerde görünümleri yönetmenin en iyi ve en iyi yoludur
Kampai

156

Swift 5.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  = NSLayoutConstraint.Axis.vertical
stackView.distribution  = UIStackView.Distribution.equalSpacing
stackView.alignment = UIStackView.Alignment.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

@ User1046037 yanıtına göre.


2
İOS 8'den başlayarak , kısıtlamaları toplu olarak etkinleştirmek mümkündür activate(_:)ve bu şekilde yapmak genellikle daha etkilidir geliştirici.apple.com/
Jonathan Cabrera


17

UIStackViewdüzenlenmiş alt görünümlerini konumlandırmak için dahili olarak kısıtlamalar kullanır. Tam olarak hangi kısıtlamaların yaratıldığı, yığın görünümünün kendisinin nasıl yapılandırıldığına bağlıdır. Bir yığın görünümü, varsayılan olarak, düzenlenmiş alt görünümlerini yatay bir çizgide düzenleyerek ön ve arka görünümleri kendi ön ve arka kenarlarına sabitler. Böylece kodunuz aşağıdaki gibi bir düzen oluşturur:

|[view1][view2]|

Her bir alt görünüme ayrılan alan, alt görünümün gerçek içerik boyutu ve sıkıştırma direnci ve içerik sarılma öncelikleri gibi bir dizi faktör tarafından belirlenir. Varsayılan olarak, UIViewörnekler gerçek bir içerik boyutu tanımlamaz. Bu genellikle UILabelveya gibi bir alt sınıf tarafından sağlanan bir şeydir UIButton.

İçerik sıkıştırma direnci ve iki yeni UIViewörneğin içerik sarılma öncelikleri aynı olacağından ve her iki görünüm de içsel bir içerik boyutu sağlamadığından, düzen motoru her görünüme hangi boyutun tahsis edilmesi gerektiği konusunda en iyi tahminde bulunmalıdır. Sizin durumunuzda, ilk görünümü kullanılabilir alanın% 100'ü ve ikinci görünüme hiçbir şey atamıyor.

Kodunuzu UILabelbunun yerine örnekleri kullanacak şekilde değiştirirseniz daha iyi sonuçlar alırsınız:

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];

Kendiniz için herhangi bir kısıtlama yaratmanın gerekli olmadığını unutmayın. Bu kullanmanın ana yararıdır UIStackView- kısıtlama yönetiminin geliştiriciden (genellikle çirkin) ayrıntılarını gizler.


Bu Etiketler için çalışır, ancak TextFields (veya bu konuda Views,) için aynı sorun var. Ayrıca bulduğum tüm öğreticiler Etiketler, Görüntüler veya Düğmeler kullanır. Bu, bu kullanıcı arayüzü öğelerinden farklı bir şey için bu yöntemi kullanamayacağımız anlamına mı geliyor?
physicalattraction

@physicalattraction Bir yığın görünümüne eklediğiniz görünümlerin gerçek içerik boyutu olmalıdır. Hatırladığım gibi, bir metin alanının gerçek boyutu, alanın içeriğine dayanır (bu gariptir). UIViewKendisinin örneklerinin gerçek boyutu yoktur. Yığın görünümünün bunları ne kadar büyük yapacağını bilmesi için bu görünümlere ek kısıtlamalar uygulamanız gerekebilir.
Greg Brown

Mantıklı, bu yüzden deniyorum. Şimdi 30 piksellik açık bir yükseklik kısıtlaması verdiğim bir metin alanına sahip bir xib'de bir Görünüm oluşturdum. Ayrıca, aşağıdaki iki kısıtlamayı yapıyorum: MyTextField.top = top+20ve bottom = MyTextField.bottom+20. Bunun bakış açımdan 70 yüksekliğe sahip olmasını beklerdim, ama bunun yerine çelişkili kısıtlamalardan şikayet eder. Burada neler olduğunu biliyor musunuz? Benim UIStackView içine koymak istiyorum bu Görünüm.
fiziksel fizyoterapi

Sanırım sorunun ne olduğunu biliyorum. Bir yığın görünümü, son düzenlenmiş alt görünümünü otomatik olarak alt kenarına sabitler. Bu nedenle, yığın görünümü, kapınızın kendisiyle aynı boyutta görünmesini sağlamaya çalışıyor. Ancak, bu görüşe 70 piksel uzunluğunda olması gerektiğini söylediniz, bu da bir çatışma yaratıyor. Kapsayıcı görünümünüzden hemen sonra ek bir boş görünüm oluşturmayı deneyin ve bu görüntüye 0 dikey içerik sarılma önceliği verin. Kapsayıcı görünümünüze 1000 dikey içerik sarılma önceliği verin. Bu, boş görünümün yığındaki boş alanı dolduracak şekilde gerilmesine neden olur. görünüm.
Greg Brown

Bu arada dikey yığın görünümü kullandığınızı varsayıyorum. Yığın görünümleri hakkında yazdığım bu makaleye de göz atmak isteyebilirsiniz: dzone.com/articles/…
Greg Brown

13

Swift 4.2 içinde

let redView = UIView()
    redView.backgroundColor = .red

    let blueView = UIView()
    blueView.backgroundColor = .blue

    let stackView = UIStackView(arrangedSubviews: [redView, blueView])
    stackView.axis = .vertical
    stackView.distribution = .fillEqually

    view.addSubview(stackView)

    //        stackView.frame = CGRect(x: 0, y: 0, width: 200, height: 200)

    // autolayout constraint
    stackView.translatesAutoresizingMaskIntoConstraints = false

NSLayoutConstraint.activate([stackView.topAnchor.constraint(equalTo: view.topAnchor), stackView.leftAnchor.constraint(equalTo: view.leftAnchor), stackView.rightAnchor.constraint(equalTo: view.rightAnchor), stackView.heightAnchor.constraint(equalToConstant: 200)])

8

Dağıtım türünü ayarlamanız gerekir. Kodunuzda juste add:

self.stack1.distribution = UIStackViewDistributionFillEqually;

Ya da dağıtımı doğrudan arabirim oluşturucunuzda ayarlayabilirsiniz. Örneğin:

resim açıklamasını buraya girin

Umarım yardımcı olur;) Lapinou.


8

İki satırı takip etmek sorunumu çözdü

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

Hızlı sürüm -

    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

8

Yığın görünümü içinde herhangi bir görünümü gizlemeye çalıştığınızda kabul edilen yanıt için, kısıtlama düzgün çalışmıyor.

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)>"
)

Nedeni ne zaman gizlemek olduğu viewde stackViewbu hareketlerin için 0 yüksekliğini belirler.

Çözüm , kısıtlamayı priorityaşağıdaki gibi değiştirin .

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
    }

}

5
    //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 Popov'un yanıtı üzerine geliştirildi


4

Benim durumumda ile karışıklık beklediğim şey bu çizgi eksik oldu:

stackView.translatesAutoresizingMaskIntoConstraints = false;

Bundan sonra, düzenlenmiş alt görünümlerim için herhangi bir kısıtlama ayarlamanıza gerek kalmaz, yığın görünümü bununla ilgilenir.


4

Oleg Popov'un user1046037'nin cevabına dayanan cevabının Swift 5 versiyonu

//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  = NSLayoutConstraint.Axis.vertical
stackView.distribution  = UIStackView.Distribution.equalSpacing
stackView.alignment = UIStackView.Alignment.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

1

Çok benzer bir sorunla karşılaştım. Yığın görünümünün boyutları, daha önce de belirtildiği gibi, düzenlenmiş alt görüntülerin bir gerçek içerik boyutuna bağlıdır. İşte Swift 2.x ve aşağıdaki görünüm yapısında benim çözüm:

görünümü - UIView

customView - CustomView: UIView

stackView - UISTackView

düzenlenmiş alt görünümler - özel UIView alt sınıfları

    //: [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

Aşağıdaki kodu deneyin,

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];

Umarım çalışır. Daha fazla açıklamaya ihtiyacınız varsa lütfen bana bildirin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.