Ketika "baris" UIStackView saya tertekan, mereka mengeluarkan AutoLayout
peringatan. Namun, mereka ditampilkan dengan baik dan tidak ada yang salah selain jenis logging ini:
Tidak dapat memenuhi batasan secara bersamaan. Mungkin setidaknya salah satu kendala dalam daftar berikut adalah yang tidak Anda inginkan. Coba ini: (1) lihat setiap kendala dan coba cari tahu yang tidak Anda harapkan; (2) temukan kode yang menambahkan batasan atau batasan yang tidak diinginkan dan perbaiki. (Catatan: Jika Anda melihat
NSAutoresizingMaskLayoutConstraints
bahwa Anda tidak mengerti, lihat dokumentasi untukUIView
propertitranslatesAutoresizingMaskIntoConstraints
) (
Jadi, saya belum yakin bagaimana cara memperbaikinya, tetapi sepertinya tidak merusak apa pun selain hanya mengganggu.
Apakah ada yang tahu bagaimana mengatasinya? Menariknya, batasan tata letak sering diberi tag dengan 'UISV-hiding' , yang menunjukkan bahwa mungkin harus mengabaikan ketinggian minimum untuk subview atau sesuatu dalam contoh ini?
sumber
Jawaban:
Anda mendapatkan masalah ini karena saat menyetel subview dari dalam
UIStackView
menjadi tersembunyi, pertama-tama akan membatasi tingginya ke nol untuk menghidupkannya.Saya mendapatkan kesalahan berikut:
2015-10-01 11:45:13.732 <redacted>[64455:6368084] 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. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) ( "<NSLayoutConstraint:0x7f7f5be18c80 V:[UISegmentedControl:0x7f7f5bec4180]-(8)-| (Names: '|':UIView:0x7f7f5be69d30 )>", "<NSLayoutConstraint:0x7f7f5be508d0 V:|-(8)-[UISegmentedControl:0x7f7f5bec4180] (Names: '|':UIView:0x7f7f5be69d30 )>", "<NSLayoutConstraint:0x7f7f5bdfbda0 'UISV-hiding' V:[UIView:0x7f7f5be69d30(0)]>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7f7f5be18c80 V:[UISegmentedControl:0x7f7f5bec4180]-(8)-| (Names: '|':UIView:0x7f7f5be69d30 )> Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
Apa yang saya coba lakukan, adalah menempatkan
UIView
dalam sayaUIStackView
yang berisiUISegmentedControl
inset oleh 8pts di setiap sisi.Ketika saya menyetelnya ke tersembunyi, itu akan mencoba untuk membatasi tampilan kontainer ke ketinggian nol tetapi karena saya memiliki sekumpulan batasan dari atas ke bawah, ada konflik.
Untuk mengatasi masalah ini, saya mengubah prioritas 8pt atas dan batasan bawah dari 1000 menjadi 999 sehingga
UISV-hiding
batasan tersebut dapat diprioritaskan jika diperlukan.sumber
Saya mengalami masalah serupa yang tidak mudah diselesaikan. Dalam kasus saya, saya memiliki tampilan tumpukan yang disematkan dalam tampilan tumpukan. UIStackView internal memiliki dua label dan spasi bukan nol yang ditentukan.
Saat Anda memanggil addArrangedSubview (), secara otomatis akan membuat batasan yang mirip dengan berikut ini:
V:|[innerStackView]| | = outerStackView V:|[label1]-(2)-[label2]| | = innerStackView
Sekarang saat Anda mencoba menyembunyikan innerStackView, Anda mendapatkan peringatan batasan yang ambigu.
Untuk memahami mengapa, pertama-tama mari kita lihat mengapa ini tidak terjadi bila
innerStackView.spacing
sama dengan0
. Saat Anda memanggilinnerStackView.hidden = true
, @liamnichols benar ...outerStackView
kehendak secara ajaib akan mencegat panggilan ini, dan membuat batasan penyembunyian UISV0
ketinggian dengan prioritas 1000 (diperlukan). Agaknya ini untuk memungkinkan elemen dalam tampilan tumpukan dianimasikan keluar dari tampilan jika kode persembunyian Anda dipanggil di dalam blok. Sayangnya, tampaknya tidak ada cara untuk mencegah penambahan batasan ini. Namun demikian, Anda tidak akan mendapatkan peringatan "Unable to concored satisfaints" (USSC), karena hal berikut terjadi:UIView.animationWithDuration()
Jelas terlihat bahwa 4 kendala tersebut dapat dipenuhi. Tampilan tumpukan hanya memoles semuanya menjadi piksel 0-tinggi.
Sekarang kembali ke contoh buggy, jika kita menyetel
spacing
ke2
, kita sekarang memiliki batasan ini:Tampilan tumpukan tidak boleh setinggi 0 piksel dan isinya setinggi 2 piksel. Kendala tidak bisa dipenuhi.
Catatan: Anda dapat melihat perilaku ini dengan contoh yang lebih sederhana. Cukup tambahkan UIView ke tampilan tumpukan sebagai subview yang diatur. Kemudian setel batasan ketinggian pada UIView dengan prioritas 1000. Sekarang coba panggil hide tentang itu.
Catatan: Untuk alasan apa pun, ini hanya terjadi jika tampilan tumpukan saya adalah subview dari UICollectionViewCell atau UITableViewCell. Namun, Anda masih bisa mereproduksi perilaku ini di luar sel dengan memanggil
innerStackView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
run loop berikutnya setelah menyembunyikan tampilan tumpukan dalam.Catatan: Meskipun Anda mencoba menjalankan kode di UIView.performWithoutAnimations, tampilan tumpukan akan tetap menambahkan batasan ketinggian 0 yang akan menyebabkan peringatan USSC.
Setidaknya ada 3 solusi untuk masalah ini:
spacing
ke 0. Ini mengganggu karena Anda perlu membalikkan proses (dan mengingat spasi asli) setiap kali Anda menampilkan konten lagi.removeFromSuperview
. Ini bahkan lebih menjengkelkan karena ketika Anda membalik proses, Anda perlu mengingat di mana harus memasukkan item yang dihapus. Anda dapat mengoptimalkan hanya dengan memanggil removeArrangedSubview lalu bersembunyi, tetapi ada banyak pembukuan yang masih perlu dilakukan.spacing
) dalam UIView. Tentukan setidaknya satu batasan sebagai prioritas yang tidak diperlukan (999 atau lebih rendah). Ini adalah solusi terbaik karena Anda tidak perlu melakukan pembukuan apa pun. Dalam contoh saya, saya membuat batasan teratas, memimpin, dan tertinggal pada 1000 antara tampilan tumpukan dan tampilan pembungkus, lalu membuat batasan 999 dari bagian bawah tampilan tumpukan ke tampilan pembungkus. Dengan cara ini, saat tampilan tumpukan luar membuat batasan ketinggian nol, batasan 999 rusak dan Anda tidak melihat peringatan USSC. (Catatan: Ini mirip dengan solusi untuk Haruskah contentView.translatesAutoResizingMaskToConstraints subkelas UICollectionViewCell disetel kefalse
)Singkatnya, alasan Anda mendapatkan perilaku ini adalah:
Seandainya Apple (1) mengizinkan Anda menentukan prioritas batasan (terutama spacer), atau (2) mengizinkan Anda memilih keluar dari batasan penyembunyian UISV otomatis , masalah ini akan mudah diselesaikan.
sumber
UIStackView
anak dari suatuUIStackView
kebutuhan untuk dibungkusUIView
atau hanya yang ingin Anda sembunyikan / sembunyikan?UIStackView
cenderung samar dan sulit dipahami.Sering kali, kesalahan ini dapat diatasi dengan menurunkan prioritas batasan untuk menghilangkan konflik.
sumber
Saat Anda menyetel tampilan menjadi tersembunyi,
UIStackview
kehendak mencoba untuk membuatnya menjauh. Jika Anda menginginkan efek itu, Anda harus menetapkan prioritas yang tepat untuk batasan sehingga tidak bertentangan (seperti yang disarankan banyak orang di atas).Namun jika Anda tidak peduli dengan animasinya (mungkin Anda menyembunyikannya di ViewDidLoad), maka Anda bisa sederhana
removeFromSuperview
yang akan memiliki efek yang sama tetapi tanpa masalah dengan batasan karena itu akan dihapus bersama dengan tampilan.sumber
Berdasarkan jawaban @ Senseful, berikut adalah ekstensi UIStackView untuk menggabungkan tampilan tumpukan dalam tampilan dan menerapkan batasan yang dia rekomendasikan:
/// wraps in a `UIView` to prevent autolayout warnings when a stack view with spacing is placed inside another stack view whose height might be zero (usually due to `hidden` being `true`). /// See http://stackoverflow.com/questions/32428210 func wrapped() -> UIView { let wrapper = UIView() translatesAutoresizingMaskIntoConstraints = false wrapper.addSubview(self) for attribute in [NSLayoutAttribute.Top, .Left, .Right, .Bottom] { let constraint = NSLayoutConstraint(item: self, attribute: attribute, relatedBy: .Equal, toItem: wrapper, attribute: attribute, multiplier: 1, constant: 0) if attribute == .Bottom { constraint.priority = 999 } wrapper.addConstraint(constraint) } return wrapper }
Alih-alih menambahkan Anda
stackView
, gunakanstackView.wrapped()
.sumber
Pertama, seperti yang disarankan orang lain, pastikan batasan yang dapat Anda kontrol, yaitu bukan batasan yang melekat pada UIStackView yang disetel ke prioritas 999 sehingga dapat diganti saat tampilan disembunyikan.
Jika Anda masih mengalami masalah, kemungkinan masalahnya karena jarak di StackView yang tersembunyi. Solusi saya adalah menambahkan UIView sebagai spacer dan mengatur jarak UIStackView ke nol. Kemudian setel batasan View.height atau View.width (bergantung pada tumpukan vertikal atau horizontal) ke jarak StackView.
Kemudian sesuaikan prioritas memeluk konten dan ketahanan kompresi konten dari tampilan yang baru Anda tambahkan. Anda mungkin harus mengubah distribusi StackView induk juga.
Semua hal di atas bisa dilakukan di Interface Builder. Anda mungkin juga harus menyembunyikan / menampilkan beberapa tampilan yang baru ditambahkan secara terprogram sehingga Anda tidak memiliki spasi yang tidak diinginkan.
sumber
Saya baru-baru ini bergumul dengan kesalahan tata letak otomatis saat menyembunyikan file
UIStackView
. Daripada melakukan banyak pembukuan dan membungkus tumpukanUIViews
, saya memilih untuk membuat outlet untuk sayaparentStackView
dan outlet untuk anak-anak yang ingin saya sembunyikan / perlihatkan.@IBOutlet weak var parentStackView: UIStackView! @IBOutlet var stackViewNumber1: UIStackView! @IBOutlet var stackViewNumber2: UIStackView!
Di storyboard, inilah tampilan parentStack saya:
Ini memiliki 4 anak dan masing-masing anak memiliki banyak tampilan tumpukan di dalamnya. Saat Anda menyembunyikan tampilan tumpukan, jika ada elemen UI yang juga merupakan tampilan tumpukan, Anda akan melihat aliran kesalahan tata letak otomatis. Daripada menyembunyikan, saya memilih untuk menghapusnya.
Dalam contoh saya,
parentStackViews
berisi array dari 4 elemen: Top Stack View, StackViewNumber1, Stack View Number 2, dan Stop Button. IndeksnyaarrangedSubviews
masing-masing adalah 0, 1, 2, dan 3. Ketika saya ingin menyembunyikannya, saya cukup menghapusnya dariparentStackView's
arrangedSubviews
array. Karena tidak lemah, itu tetap ada di memori dan Anda bisa meletakkannya kembali ke indeks yang Anda inginkan nanti. Saya tidak menginisialisasi ulang, jadi itu hanya hang sampai dibutuhkan, tapi tidak mengasapi memori.Jadi pada dasarnya, Anda dapat ...
1) Seret IBOutlets untuk tumpukan orang tua Anda dan anak-anak yang ingin Anda sembunyikan / tampilkan ke storyboard.
2) Saat Anda ingin menyembunyikannya, hapus tumpukan yang ingin Anda sembunyikan dari
parentStackView's
arrangedSubviews
array.3) Telepon
self.view.layoutIfNeeded()
denganUIView.animateWithDuration
.Perhatikan bahwa dua stackView terakhir tidak
weak
. Anda harus menyimpannya saat Anda memperlihatkannya.Katakanlah saya ingin menyembunyikan stackViewNumber2:
parentStackView.removeArrangedSubview(stackViewNumber2) stackViewNumber2.removeFromSuperview()
Kemudian animasikan:
UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 2.0, initialSpringVelocity: 10.0, options: [.curveEaseOut], animations: { self.view.layoutIfNeeded() }, completion: nil)
Jika Anda ingin "memperlihatkan"
stackViewNumber2
nanti, Anda dapat memasukkannya ke dalamparentStackView
arrangedSubViews
indeks yang diinginkan dan menganimasikan pembaruan.parentStackView.removeArrangedSubview(stackViewNumber1) stackViewNumber1.removeFromSuperview() parentStackView.insertArrangedSubview(stackViewNumber2, at: 1) // Then animate it UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 2.0, initialSpringVelocity: 10.0, options: [.curveEaseOut], animations: { self.view.layoutIfNeeded() }, completion: nil)
Saya menemukan itu jauh lebih mudah daripada melakukan pembukuan pada kendala, mengutak-atik prioritas, dll.
Jika Anda memiliki sesuatu yang ingin disembunyikan secara default, Anda bisa meletakkannya di storyboard dan menghapusnya
viewDidLoad
dan memperbarui tanpa menggunakan animasiview.layoutIfNeeded()
.sumber
Saya mengalami kesalahan yang sama dengan Stack Views yang disematkan, meskipun semuanya bekerja dengan baik saat runtime.
Saya memecahkan kesalahan batasan dengan menyembunyikan semua tampilan sub-tumpukan terlebih dahulu (pengaturan
isHidden = true
) sebelum menyembunyikan tampilan tumpukan induk.Melakukan hal ini tidak memiliki semua kerumitan untuk menghapus tampilan yang tersusun, mempertahankan indeks saat perlu menambahkannya kembali.
Semoga ini membantu.
sumber
Senseful telah memberikan jawaban yang sangat baik untuk akar masalah di atas jadi saya akan langsung menuju solusinya.
Yang perlu Anda lakukan adalah menyetel semua prioritas batasan stackView lebih rendah dari 1000 (999 akan melakukan pekerjaan itu). Misalnya jika stackView dibatasi kiri, kanan, atas, dan bawah ke superview-nya, maka keempat batasan harus memiliki prioritas lebih rendah dari 1000.
sumber
Anda mungkin telah membuat batasan saat bekerja dengan kelas ukuran tertentu (contoh: wCompact hRegular) dan kemudian Anda membuat duplikat saat Anda beralih ke kelas ukuran lain (misal: wAny hAny). periksa batasan objek UI dalam kelas ukuran yang berbeda dan lihat apakah ada anomali dengan batasan tersebut. Anda akan melihat garis merah yang menunjukkan kendala bertabrakan. Saya tidak bisa memasang gambar sampai saya mendapatkan 10 poin reputasi. Maaf: /
sumber
Saya ingin menyembunyikan seluruh UIStackView sekaligus tetapi saya mendapatkan kesalahan yang sama dengan OP, ini memperbaikinya untuk saya:
for(UIView *currentView in self.arrangedSubviews){ for(NSLayoutConstraint *currentConstraint in currentView.constraints){ [currentConstraint setPriority:999]; } }
sumber
priority = 1000
) menjadi tidak diperlukan (priority <= 999
).Saya memiliki deretan tombol dengan batasan ketinggian. Ini terjadi jika satu tombol disembunyikan. Menyetel prioritas batasan ketinggian tombol ke 999 telah menyelesaikan masalah.
sumber
Kesalahan ini tidak ada hubungannya dengan UIStackView. Itu terjadi ketika Anda memiliki konflik yang dibatasi dengan prioritas yang sama. Misalnya, jika Anda memiliki batasan yang menyatakan bahwa lebar tampilan Anda adalah 100, dan Anda memiliki batasan lain pada saat yang sama yang menyatakan bahwa lebar tampilan adalah 25% dari penampungnya. Jelas ada dua kendala yang saling bertentangan. Solusinya adalah dengan menghapusnya.
sumber
NOP dengan [mySubView removeFromSuperview]. Saya harap ini bisa membantu seseorang :)
sumber