I'm making an app with UIkit and I'm making some UITableViewCells that contain an array of user images. I want these images to be displayed in a horizontal stack and overlay each other.
This is how I want it to look:
That's how it looks:
Code:
import UIKit
import SDWebImage
class CountryTableCell: UITableViewCell {
static let reuseIdentifier = "CountryTableCell"
//MARK: - Propeties
var viewModel: CountryViewModel? {
didSet {
viewModel?.delegate = self
setUpSpace(viewModel)
}
}
//MARK: - SubViews
private let container: UIView = {
let view = UIView()
view.withSize(CGSize(width: Dimensions.maxSafeWidth, height: 150))
view.backgroundColor = .secondary_background
view.layer.cornerRadius = 20
return view
}()
private let adminsContainer: UIView = {
let view = UIView()
view.withSize(CGSize(width: (Dimensions.maxSafeWidth - 32), height: Dimensions.image.mediumHeigthWithOverlay))
view.backgroundColor = .secondary_background
return view
}()
private let adminsStack: UIStackView = {
let stack = UIStackView()
stack.axis = .horizontal
stack.alignment = .leading
stack.spacing = -10
stack.sizeToFit()
stack.distribution = .fillEqually
stack.withSize(CGSize(width: Dimensions.image.mediumHeigthWithOverlay, height: Dimensions.image.mediumHeigthWithOverlay))
return stack
}()
private let nameLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: UIFont.preferredFont(forTextStyle: .title2).pointSize, weight: .bold)
label.textColor = .primary_label
label.textAlignment = .left
label.sizeToFit()
label.numberOfLines = 0
return label
}()
var headerView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
iv.withSize(CGSize(width: Dimensions.image.headerSizeForCell.width, height: ((Dimensions.image.mediumHeigth/2) + Padding.horizontal)))
iv.backgroundColor = .secondary_background
iv.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner]
iv.layer.cornerRadius = 20
return iv
}()
//MARK: - Init
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addSubview(container)
container.center(inView: self)
addSubview(headerView)
headerView.anchor(top: container.topAnchor, left: container.leftAnchor, right: container.rightAnchor)
addSubview(nameLabel)
nameLabel.anchor(top: headerView.bottomAnchor, left: container.leftAnchor, right: container.rightAnchor, paddingLeft: Padding.horizontal, paddingRight: Padding.horizontal)
addSubview(adminsContainer)
adminsContainer.anchor(left: container.leftAnchor, bottom: headerView.bottomAnchor, right: container.rightAnchor ,paddingLeft: Padding.horizontal, paddingBottom: -(Dimensions.image.mediumHeigth/2), paddingRight: Padding.horizontal)
bringSubviewToFront(adminsContainer)
adminsContainer.backgroundColor = .clear.withAlphaComponent(0.0)
adminsContainer.addSubview(adminsStack)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//MARK: - Lifecycle
override func willRemoveSubview(_ subview: UIView) {
}
//MARK: Selectors
//MARK: - Helpers
private func setUpSpace(_ viewModel: CountryViewModel?) {
guard let viewModel = viewModel else {return}
if let url = viewModel.country.headerImage?.url {
headerView.sd_setImage(with: URL(string: url))
}
nameLabel.text = viewModel.space.name
}
}
// MARK: Extension
extension SpaceTableCell: CountryViewModelDelegate {
func didFetchAdmin(_ admin: User) {
if let admins = viewModel?.admins.count {
if admins == 1 {
adminsStack.withSize(CGSize(width: Dimensions.image.mediumHeigthWithOverlay, height: Dimensions.image.mediumHeigthWithOverlay))
} else if admins == 2 {
adminsStack.withSize(CGSize(width: ((Dimensions.image.mediumHeigthWithOverlay*2) - 10), height: Dimensions.image.mediumHeigthWithOverlay))
} else if admins == 3 {
adminsStack.withSize(CGSize(width: ((Dimensions.image.mediumHeigthWithOverlay*3) - 20), height: Dimensions.image.mediumHeigthWithOverlay))
} else if admins == 4 {
adminsStack.withSize(CGSize(width: ((Dimensions.image.mediumHeigthWithOverlay*4) - 30), height: Dimensions.image.mediumHeigthWithOverlay))
} else if admins == 5 {
adminsStack.withSize(CGSize(width: ((Dimensions.image.mediumHeigthWithOverlay*5) - 40), height: Dimensions.image.mediumHeigthWithOverlay))
}
}
let image = UserImageView(height: Dimensions.image.mediumHeigth)
image.sd_setImage(with: admin.profileImageURL)
adminsStack.addArrangedSubview(image)
}
}
class UserImageView: UIImageView {
//MARK: - Propeties
let selectedHeigth: CGFloat
init(height: CGFloat) {
self.selectedHeigth = height
super.init(frame: CGRect(x: 0, y: 0, width: selectedHeigth, height: selectedHeigth))
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
contentMode = .scaleAspectFill
clipsToBounds = true
backgroundColor = .secondary_background
layer.cornerRadius = Dimensions.userImageCornerRadious(selectedHeigth)
}
}
Can someone please help me
Thank you :)
I'd suggest a couple changes:
Change #1:
Your UIStackView's distribution set to .fillEqually. By doing this, you're giving it the permission to stretch its arrangedSubviews as and when needed to fit the width that you've provided. This does prove useful in some cases but in your case, it's better to go with .fill instead
Here's an excerpt from Apple's documentation:
For all distributions except the UIStackView.Distribution.fillEqually
distribution, the stack view uses each arranged view’s
intrinsicContentSize property when calculating its size along the
stack’s axis. UIStackView.Distribution.fillEqually resizes all the
arranged views so they’re the same size, filling the stack view along
its axis. If possible, the stack view stretches all the arranged views
to match the view with the longest intrinsic size along the stack’s
axis.
I suggest that you go through this documentation and read more about this
Change #2:
Since you've now changed the distribution to respect intrinsic size, don't set up constraints that conflict with UIStackView's distribution axis. In your case, you have a horizontal stack view and seem to be also defining its width constraints based on the number of admins you have. I'd suggest getting rid of it and leave it to your stack view to take care of it.
One more pointer:
Make sure your UserImageViews have proper unified intrinsicContentSize i.e: the images you set follow the same size. If doubtful, I'd suggest setting up constraints for its width and height respectively. To do so, in your UserImageView's init, include:
self.widthAnchor.constraint(equalToConstant: height).isActive = true
self.heightAnchor.constraint(equalToConstant: height).isActive = true
My code tutorial works for scrolling horizontally with ScrollView.
I would like to make it with ViewControllers (instead of views) from my Storyboard.
And I would like to add a vertical ScrollView (To move from center to right or left = ScrollView horizontal, and to move from center to top or bottom (vertically).
Is that possible? Could someone give me a hint ?
Thanks
For information, this is my code :
import UIKit
class ViewController: UIViewController {
lazy var view0: UIView = {
let view = UIView()
view.backgroundColor = .systemTeal
let label = UILabel()
label.text = "Page 0"
label.textAlignment = .center
view.addSubview(label)
label.edgeTo(view: view)
return view
}()
lazy var view1: UIView = {
let view = UIView()
view.backgroundColor = .systemPink
let label = UILabel()
label.text = "Page 1"
label.textAlignment = .center
view.addSubview(label)
label.edgeTo(view: view)
return view
}()
lazy var view2: UIView = {
let view = UIView()
view.backgroundColor = .systemYellow
let label = UILabel()
label.text = "Page 2"
label.textAlignment = .center
view.addSubview(label)
label.edgeTo(view: view)
return view
}()
lazy var views = [view0, view1, view2]
lazy var scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.showsHorizontalScrollIndicator = false
scrollView.isPagingEnabled = true
scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(views.count), height: view.frame.height)
for i in 0..<views.count {
scrollView.addSubview(views[i])
views[i].frame = CGRect(x: view.frame.width * CGFloat(i), y: 0, width: view.frame.width, height: view.frame.height)
}
scrollView.delegate = self
return scrollView
}()
lazy var pageControl: UIPageControl = {
let pageControl = UIPageControl()
pageControl.numberOfPages = views.count
pageControl.currentPage = 0
pageControl.addTarget(self, action: #selector(pageControlTapHandler(sender:)), for: .touchUpInside)
return pageControl
}()
#objc
func pageControlTapHandler(sender: UIPageControl) {
scrollView.scrollTo(horizontalPage: sender.currentPage, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.addSubview(scrollView)
scrollView.edgeTo(view: view)
view.addSubview(pageControl)
pageControl.pinTo(view)
}
}
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageIndex = round(scrollView.contentOffset.x / view.frame.width)
pageControl.currentPage = Int(pageIndex)
}
I have a tableview and would want to add views dynamically to it, based on the data. For every other view it is easy. Works like charm but collectionview, I don't even see the view on stackview.
The UICollectionView's cellForItem delegate is not called, the numberOfItems delegate is called but not cellForItem.
Not sure if I am missing anything.
func testView() -> UIView {
let containerView = UIView(frame: .zero)
containerView.backgroundColor = .red
let layout = KTCenterFlowLayout()
layout.minimumInteritemSpacing = 10.0
layout.minimumLineSpacing = 10.0
layout.estimatedItemSize = CGSize(width: 80, height: 100)
layout.sectionInset = UIEdgeInsetsMake(20, 30, 20, 30)
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout).then {
$0.dataSource = self
$0.isScrollEnabled = false
$0.setCollectionViewLayout(layout, animated: false)
$0.register(NPSCollectionViewCell.self, forCellWithReuseIdentifier: "npsCell")
$0.contentSize = CGSize(width: view.frame.size.width-100, height: 500.0)
containerView.addSubview($0)
}
collectionView.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
make.height.equalTo(500).priority(500)
}
return containerView
}
I am adding this above view in CellForRowAtIndexPath in
cell?.stackView.addArrangedSubview(testView())
Any pointers?
Edit: here is the screenshot
I just see a blank space
Here is my StackTableViewCell
lazy var stackView : UIStackView! = {
let stack = UIStackView()
stack.axis = .vertical
stack.distribution = .fillProportionally
stack.alignment = .center
stack.spacing = 10.0
stack.translatesAutoresizingMaskIntoConstraints = false
stack.setContentCompressionResistancePriority(UILayoutPriority.required, for: .vertical)
return stack
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(stackView)
stackView.snp.makeConstraints { (make) in
make.top.equalToSuperview().offset(10)
make.left.equalToSuperview().offset(20)
make.right.equalToSuperview().offset(-20)
make.bottom.equalToSuperview().offset(-10)
}
I had a problem that the cell wasn't displaying and I just gave it a size manually using a property of the collectionView try this approach
I'm trying to achieve the stackView arrangement shown in the middle of this figure:, but for some reason the top stack, containing a collectionView, disappears when using: a .fill distribution
stackView.distribution = .fill (stack containing collectionView disappears)
stackView.distribution = .fillEqually (collectionView appears fine in stackView)
I've been struggling with this for days, and you'll see residues in my commented out sections: setting compressionResistance/hugging priorities, attempting to change the intrinsic height, changing .layout.itemSize of UICollectionViewFlowLayout(), etc... Nothing works in my hands. The code here will run if you simply paste it in and associate it with an empty UIViewController. The top, collectionView stack contains a pickerView, and the stacks below that are a pageControllView, subStack of buttons, and a UIView. It all works fine in the .fillEqually distribution, so this is purely a layout issue. Much Thanks!
// CodeStackVC2
// Test of programmatically generated stack views
// Output: nested stack views
// To make it run:
// 1) Assign the blank storyboard VC as CodeStackVC2
// 2) Move the "Is Inital VC" arrow to the blank storyboard
import UIKit
class CodeStackVC2: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate,UICollectionViewDelegateFlowLayout, UIGestureRecognizerDelegate {
let fruit = ["Apple", "Orange", "Plum", "Qiwi", "Banana"]
let veg = ["Lettuce", "Carrot", "Celery", "Onion", "Brocolli"]
let meat = ["Beef", "Chicken", "Ham", "Lamb"]
let bread = ["Wheat", "Muffin", "Rye", "Pita"]
var foods = [[String]]()
let button = ["bread","fruit","meat","veg"]
var sView = UIStackView()
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
foods = [fruit, veg, meat, bread]
setupViews()
}
//MARK: Views
lazy var cView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
layout.sectionInset = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
layout.itemSize = CGSize(width: self.view.frame.width, height: 120)
let cv = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
cv.backgroundColor = UIColor.lightGray
cv.isPagingEnabled = true
cv.dataSource = self
cv.delegate = self
cv.isUserInteractionEnabled = true
// var intrinsicContentSize: CGSize {
// return CGSize(width: UIViewNoIntrinsicMetric, height: 120)
// }
return cv
}()
lazy var pageControl: UIPageControl = {
let pageC = UIPageControl()
pageC.numberOfPages = self.foods.count
pageC.pageIndicatorTintColor = UIColor.darkGray
pageC.currentPageIndicatorTintColor = UIColor.white
pageC.backgroundColor = .lightGray
pageC.addTarget(self, action: #selector(changePage(sender:)), for: UIControlEvents.valueChanged)
// pageC.setContentHuggingPriority(900, for: .vertical)
// pageC.setContentCompressionResistancePriority(100, for: .vertical)
return pageC
}()
var readerView: UIView = {
let rView = UIView()
rView.backgroundColor = UIColor.brown
// rView.setContentHuggingPriority(100, for: .vertical)
// rView.setContentCompressionResistancePriority(900, for: .vertical)
return rView
}()
func makeButton(_ name:String) -> UIButton{
let newButton = UIButton(type: .system)
let img = UIImage(named: name)?.withRenderingMode(.alwaysTemplate)
newButton.setImage(img, for: .normal)
newButton.contentMode = .scaleAspectFit
newButton.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleButton)))
newButton.isUserInteractionEnabled = true
newButton.backgroundColor = .orange
return newButton
}
//Make a 4-item vertical stackView containing
//cView,pageView,subStackof 4-item horiz buttons, readerView
func setupViews(){
cView.register(FoodCell.self, forCellWithReuseIdentifier: cellId)
//generate an array of buttons
var buttons = [UIButton]()
for i in 0...foods.count-1 {
buttons += [makeButton(button[i])]
}
let subStackView = UIStackView(arrangedSubviews: buttons)
subStackView.axis = .horizontal
subStackView.distribution = .fillEqually
subStackView.alignment = .center
subStackView.spacing = 20
//set up the stackView
let stackView = UIStackView(arrangedSubviews: [cView,pageControl,subStackView,readerView])
stackView.axis = .vertical
//.fillEqually works, .fill deletes cView, .fillProportionally & .equalSpacing delete cView & readerView
stackView.distribution = .fillEqually
stackView.alignment = .fill
stackView.spacing = 5
//Add the stackView using AutoLayout
view.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.topAnchor.constraint(equalTo: view.topAnchor, constant: 5).isActive = true
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
func handleButton() {
print("button pressed")
}
//pageControl page changer
func changePage(sender: AnyObject) -> () {
let x = CGFloat(pageControl.currentPage) * cView.frame.size.width
cView.setContentOffset(CGPoint(x:x, y:0), animated: true)
}
//MARK: horizontally scrolling Chapter collectionView
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// let scrollBarLeft = CGFloat(scrollView.contentOffset.x) / CGFloat(book.chap.count + 1)
// let scrollBarWidth = CGFloat( menuBar.frame.width) / CGFloat(book.chap.count + 1)
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let index = targetContentOffset.pointee.x / view.frame.width
pageControl.currentPage = Int(index) //change PageControl indicator
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return foods.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! FoodCell
cell.foodType = foods[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 120)
}
}
class FoodCell:UICollectionViewCell, UIPickerViewDelegate, UIPickerViewDataSource {
var foodType: [String]? {
didSet {
pickerView.reloadComponent(0)
pickerView.selectRow(0, inComponent: 0, animated: true)
}
}
lazy var pickerView: UIPickerView = {
let pView = UIPickerView()
pView.frame = CGRect(x:0,y:0,width:Int(pView.bounds.width), height:Int(pView.bounds.height))
pView.delegate = self
pView.dataSource = self
pView.backgroundColor = .darkGray
return pView
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
func setupViews() {
backgroundColor = .clear
addSubview(pickerView)
addConstraintsWithFormat("H:|[v0]|", views: pickerView)
addConstraintsWithFormat("V:|[v0]|", views: pickerView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if let count = foodType?.count {
return count
} else {
return 0
}
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let pickerLabel = UILabel()
pickerLabel.font = UIFont.systemFont(ofSize: 15)
pickerLabel.textAlignment = .center
pickerLabel.adjustsFontSizeToFitWidth = true
if let foodItem = foodType?[row] {
pickerLabel.text = foodItem
pickerLabel.textColor = .white
return pickerLabel
} else {
print("chap = nil in viewForRow")
return UIView()
}
}
}
The problem is that you have a stack view with a fixed height that contains two views (cView and readerView) that have no intrinsic content size. You need to tell the layout engine how it should size those views to fill the remaining space in the stack view.
It works when you use a .fillEqually distribution because you are telling the layout engine to make all four views in the stack view have an equal height. That defines a height for both the cView and readerView.
When you use a .fill distribution there is no way to determine how high the cView and readerView should be. The layout is ambiguous until you add more constraints. The content priorities do nothing as those views have no intrinsic size that can be stretched or squeezed. You need to set the height of one of the views with no intrinsic size and the other will take the remaining space.
The question is how high should the collection view be? Do you want it to be the same size as the reader view or maybe some proportion of the container view?
For example, suppose your design calls for the collection view to be 25% of the height of the container view with the readerView using the remaining space (the two other views are at their natural intrinsic content size). You could add the following constraint:
NSLayoutConstraint.activate([
cView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.25)
])
A Simpler Example
To reduce the layout to its most basic elements. You have a stack view pinned to its superview with four arranged subviews two of which have no intrinsic content size. For example, here is a view controller with two plain UIView, a label and a button:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
private func setupViews() {
let blueView = UIView()
blueView.backgroundColor = .blue
let titleLabel = UILabel()
titleLabel.text = "Hello"
let button = UIButton(type: .system)
button.setTitle("Action", for: .normal)
let redView = UIView()
redView.backgroundColor = .red
let stackView = UIStackView(arrangedSubviews: [blueView, titleLabel, button, redView])
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.spacing = 8
view.addSubview(stackView)
NSLayoutConstraint.activate([
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
stackView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor),
stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
blueView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.25)
])
}
}
Here is how it looks on an iPhone in portrait with the blue view using 25% of the vertical space:
UIStackView works well with arranged subviews that are UIView but not directly with UICollectionView.
I suggest you put all your subviews items inside a UIView before stack them in a UIStackView, also you can use .fill distribution without use intrinsic content size, use instead constraints to make your subviews proportional as you need.
This solution also work seamless with autolayout without force translatesAutoresizingMaskIntoConstraints = false which make you less compliant with trait changes if you know what I mean.
/GM
Set the top, bottom, leading and trailing constraint of desired controls inside xib or storyboard.
Provide distribution of stack .fill.
Then provide height constraint of all stacks in Xib or storyboard.
Then set appropriate heights for every stacks inside code.
Hopefully it works for you.
I had the same issue, and for me it worked when I gave height and width constraints to the collection view which was placed inside the stack view.
I experienced this behavior with Xamarin CollectionView and tracked it down to an interaction being made with the CollectionView after the page was removed from the MainPage as the result of a web api call. Even blocking that, though it still had issues reloading the page. I finally resolved to clearing the collection list when the page is about to be hidden and saving a backup copy of the items, then on display of the page, running an async task that waited 10ms and then reinstalled the items. Failing to clear the list or installing items into the list immediately upon redisplay both leads to the error. The following shows in the console list and the CollectionView seems to flag itself to longer try to work after this message:
2022-04-16 19:56:33.760310-0500 .iOS[30135:2117558] The behavior of the UICollectionViewFlowLayout is not defined because:
2022-04-16 19:56:33.760454-0500 .iOS[30135:2117558] the item width must be less than the width of the UICollectionView minus the section insets left and right values, minus the content insets left and right values.
2022-04-16 19:56:33.760581-0500 .iOS[30135:2117558] Please check the values returned by the delegate.
2022-04-16 19:56:33.760754-0500 .iOS[30135:2117558] The relevant UICollectionViewFlowLayout instance is <Xamarin_Forms_Platform_iOS_ListViewLayout: 0x7f99e4c4e890>, and it is attached to <UICollectionView: 0x7f99e562a000; frame = (0 0; 420 695); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x6000015ad9b0>; layer = <CALayer: 0x600005be5860>; contentOffset: {0, 0}; contentSize: {0, 0}; adjustedContentInset: {0, 0, 0, 0}; layout: <Xamarin_Forms_Platform_iOS_ListViewLayout: 0x7f99e4c4e890>; dataSource: <Xamarin_Forms_Platform_iOS_GroupableItemsViewController_1: 0x7f99e4c7ace0>>.
2022-04-16 19:56:33.760829-0500 .iOS[30135:2117558] Make a symbolic breakpoint at UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the debugger.
There are three views from top to bottom: redView, yellowView, blueView.
I want to hide yellowView and change the constraint of blueView in order to let blueView below redView.
The picture is below:
this picture is original
this picture is what I want
The code is below:
private lazy var redView: UIView = {
let redView = UIView()
redView.backgroundColor = UIColor.red
return redView
}()
private lazy var yellowView: UIView = {
let yellowView = UIView()
yellowView.backgroundColor = UIColor.yellow
return yellowView
}()
private lazy var blueView: UIView = {
let blueView = UIView()
blueView.backgroundColor = UIColor.blue
return blueView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(redView)
view.addSubview(yellowView)
view.addSubview(blueView)
redView.snp.makeConstraints { (make) in
make.top.left.right.equalTo(view)
make.height.equalTo(40)
}
yellowView.snp.makeConstraints { (make) in
make.top.equalTo(redView.snp.bottom)
make.left.right.height.equalTo(redView)
}
blueView.snp.makeConstraints { (make) in
make.top.equalTo(yellowView.snp.bottom)
make.left.right.height.equalTo(yellowView)
}
}
if yellowView.isHidden == true {
//how is the code?
} else {
//how is the code?
}
You need set height constraint for yellow view and take IBOutlet for its height constraint of yellowView and modify its constant as per hide/show .
if yellowView.isHidden == true {
//how is the code?
ibHeightOutletOfYellow.constant = 0; // hide here
} else {
//how is the code?
ibHeightOutletOfYellow.constant = 50; // as per your needed
}