UICollectionView Cell with a thick border - swift

I am attempting to create a round collection view cell.
In the cell I have a red UIView that is 0 from top, leading, trailing, and bottom. Inside of that cell I have another view which is white and it is 4 from the top, leading, trailing, and bottom. Within that view is a UILabel and a UIImageView.
The goal would be to have 2 cells per column and it is has a red ring around a white circle and text and an image.
To create the round UIViews I have an extension for UIView like this
extension UIView {
func createRoundView() {
layer.cornerRadius = frame.size.width/2
clipsToBounds = true
}
}
Inside of my cellForItemAt I say
cell.whiteBackgroundView.createRoundView()
cell.colorStatusView.createRoundView()
The goal is on the left, but what is happening is on the right.
Here is my Storyboard
The constraints are all blue, nothing red.
And to get the 2 cell per column I use this delegate method
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let padding: CGFloat = 25
let collectionCellSize = collectionView.frame.size.width - padding
return CGSize(width: collectionCellSize/2, height: collectionCellSize/2)
}
Any idea what I might be doing wrong?
In the end it doesn't matter if I have a view within a view. I change the ring or border color based on other data....so I just need to be able to easily change that border color.

This code is not enough, to tell what's going on there... try to set all
backgroundColors to .clear
then set those properties to your view
customView.layer.cornerRadius = half of your width
customView.layer.borderWidth = 5
customView.layer.borderColor = UIColor.red.cgColor

Using #blinkmeoff answer I figured it out mostly (although follow up question to come)
Inside the cell class I added the following
self.backgroundViewContainer.layoutIfNeeded()
self.backgroundViewContainer.layer.cornerRadius = min(backgroundViewContainer.frame.size.width, backgroundViewContainer.frame.size.height)/2
self.backgroundViewContainer.clipsToBounds = true
I kept getting weird shapes by just doing the /2 so I added the min(ba...
and that got me perfect circles

Related

Auto-Layout for CollectionViewCell: Trailing/Leading constraints change cell size

I just can´t get familar with auto layout in Xcode. When I set trailing and leading constrains for Header Stack View, Bottom Stack View or the image between them, then the size (height/width) of my cell changes. Why does it happen and how can I avoid it? I think something isn´t right with the kind I build layouts. I am very grateful for any help.
I set the cell size with this code:
extension MainVC: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let height = view.frame.size.height
let width = view.frame.size.width
return CGSize(width: width * 0.42, height: height * 0.3)
}
}
My cell layout:
This is how the app looks when I use constrains for the Bottom Stack View.
This is without constrains for the Bottom Stack View (correct cell size).
Cells can now self-size with auto layout and ignore what you return in collectionView(_:layout:sizeForItemAt:). If you want to use collectionView(_:layout:sizeForItemAt:), change Estimate size to None in the storyboard.
https://stackoverflow.com/a/58369142/14351818

Dynamic height of two UIView's in a ViewController

I have the following ViewController, with 3 UIViews and content inside. The red lines are my constraints.
The black one has always a fixed height.
The red UIView has a CollectionView inside, which will grow, depending on it's items.
The green is a UITableView which should shrink, depending on the size of the red UICollectionView.
I tried to set the height constraint of the red (UICollectionView) to greater than or equal, and the green (UITableView) height to less than or equal, but Swift is telling me to set a x or height value.
What is the correct approach to get two dynamic Views inside my ViewController?
Create NSLayoutConstraint for CollectionView Height,Then set the height on cellForItemAt function
var collHeight:NSLayoutConstraint? //In class scope
Assign CollectionView height anchor to collHeight
collHeight = collectionView.heightAnchor.constraint(equalToConstant: 0)
collHeight!.isActive = true
Then set the height on cellForItemAt function
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
collHeight.constant = collectionView.contentSize.height
}
it will expand the size of collectionview height according to item count. Next set the tableview top anchor to collectionview bottom anchor

Corner Radius for UIImageView not working for UICollectionViewCell with dynamic size

I have cell which consist of a UIImageView which has a height of 70% of the cell size and the rest of the 30% is used up by the label.
The cell's have a dynamic size which is calculated according to the device width.
I have made sure the cells are are square and the UIImageView contained within the cell's also has 1:1 ratio for their height and width
I am setting the corner radius of the UIImage in the cellForItem delegate method of the Collection View
cell.userImage.layer.cornerRadius = cell.userImage.bounds.width / 2
cell.userImage.clipsToBounds = true
So can anyone point me in the right direction as why this is happening ?
When should I set the corner radius of the Image in the cell lifecycle ?
This doesn't happen if I give the image view static size, but I want the size to be dynamic according to the screen size
try cell.userImage.layer.maskToBounds = true
Better to wrap imageView inside a UIView . Then set UIView propertiesbound.size.width/2
You are taking the width of "bounds". Try taking the width/height of cell.userImage.
cell.userImage.layer.cornerRadius = cell.userImage.bounds.width / 2
Also, is the ratio of the image 1:1?
hey use this delegate UICollectionViewDelegateFlowLayout to set the size for each item in cell. something like below
...
collectionView.delegate = self
...
// then make your view controller confirm to the UICollectionViewDelegateFlowLayout
// then overide this method like below
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
CGSize(width: MyLayoutConstants.collectionViewItemWidth,
height: collectionView.frame.height)
}
this is just an example from my case. the main idea is that use the delagate above.

Center align stackView while maintaining fixed spacing

I have a UITableViewCell that is supposed to show two labels out of which one can be either 1 or 2 lines in height. The labels are supposed to have a fixed spacing between each other. Together they are always expected to vertically centered within the cell.
I thought that a UIStackView would be a good solution for this but none of the distribution options allow for a fixed spacing between the items. What's a good solution to the scenario described? I've attached an illustration (gray = cell, line = cell's vertical center) to make this easier
You're images are not actually showing the labels centered vertically.
With one line in each label, they are both 20.5-pts tall (assuming default font/size), with a 12-pt gap. Fine. Easy enough to center on the Y axis.
With two lines in the top label, it becomes (20.5-pts + 0-gap + 20.5-pts), and then 12-pt gap, and then 20.5-pt single-line label. So it's not an even distribution of the lines of text, which is why vertical centering of the stack view doesn't place the center-line through the center-line of the second line of text.
If you examine your image (which I'm assuming you laid-out by hand), you have 201 pixels between the top of the view and the top of the top label, but only 198 pixels between the bottom of the bottom label and the bottom of the view.
If that's really how you want it to lay out, you can do this:
set a fixed row height
give your stack view a centerYAxis constraint
keep a reference to that constraint
Then, override willDisplay cell:
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if let c = cell as? ExampleCell {
cell.layoutIfNeeded()
let topHeight = c.topLabel.frame.height
let botHeight = c.bottomLabel.frame.height
if topHeight > botHeight {
c.stackViewCenterYConstraint.constant = 6.0
} else if botHeight > topHeight {
c.stackViewCenterYConstraint.constant = -6.0
} else {
c.stackViewCenterYConstraint.constant = 0.0
}
}
}
The value of 6.0 is 1/2 of the stack view spacing (12 * 0.5 == 6), so you'll need to change that if you change your spacing.
Here is the result (red line is vertical mid-line):

UICollectionView sticky header not working iOS 10

I am having an issue with a sticky header in my collection view not working in iOS 10. I have a collectionView that has a header in the second section only - implemented by setting the size in the first section as CGSize.zero and the size in the second section as the appropriate size:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
if section == 0 {
return CGSize.zero
}
return CGSize(width: collectionView.width, height: 80.0)
}
I make the sticky header sticky with these lines in viewDidLoad:
theCollectionView.delegate = self
theCollectionView.dataSource = self
if let flowLayout = theCollectionView.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.sectionHeadersPinToVisibleBounds = true
}
Everything works great in iOS 11. When you scroll the collection view up, the header sticks to the top.
However, in iOS 10, this does not work. The header sticks - but not to the top of the screen - it sticks to its initial location and the collection view cells in the second section can be seen scrolling underneath it. There is a gap at the top of the screen. I've attached two screenshots illustrating my problem. Any help would be much appreciated!
Fixed by changing the top auto layout constraint in my storyboard. It was set from the Collection View top to the Safe Area top. Changed from the Collection View top to the Superview top.