Adjusting UICollectionView Header height? - swift

I am trying to adjust the height of my CollectionView Header based on the height of myView's height. for example I want to be able to type:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: view.frame.width, height: 100)
} //Instead of 100 I want to say: **myView.frame.height**
but since I have created myView inside the header class I can't access it, I was wondering if anyone could help me with this or has any better way of doing this. I would really appreciate it!
This is my code:
class MyProfileCollectionView: UICollectionViewController, UICollectionViewDelegateFlowLayout {
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView?.register(MyProfileHeader.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: headerIdentifier)
}
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind:
String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier:
headerIdentifier, for: indexPath) as! MyProfileHeader
header.backgroundColor = .red
return header
} //HERE
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: view.frame.width, height: 111)
}
}
And this is my Header class where I have created myView:
class MyProfileHeader: UICollectionReusableView, UICollectionViewDelegate {
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(myView)
myView.widthAnchor.constraint(equalToConstant: 50).isActive = true
myView.heightAnchor.constraint(equalToConstant: 70).isActive = true
myView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
myView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
}
//I want my headers height be equal to myView's height so if i change myView's height the headers height changes automatically.
var myView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .gray
return view
}()
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Somehow you are using the magic number for the height of your myview inside MyProfileHeader class like myView.heightAnchor is 70. For a quick solution, you can use a static variable inside MyProfileHeader or outside.
class MyProfileHeader: UICollectionReusableView, UICollectionViewDelegate {
static var height: CGFloat = 70.0
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(myView)
myView.widthAnchor.constraint(equalToConstant: 50).isActive = true
myView.heightAnchor.constraint(equalToConstant: MyProfileHeader.height).isActive = true
myView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
myView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
}
- - - - - -
}
Now you can use that in layout return:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: view.frame.width, height: MyProfileHeader.height)
}

Related

CollectionView is not showing inside a view in Swift

I have a view with a collection view inside it. I am adding this view to another view but the collection view is not showing. What am I doing wrong here?
I have a view which has a collection view
class GiftFilterView: UIView {
var giftImageIcon: [UIImage] = [#imageLiteral(resourceName: "Gift Mic Icon"), #imageLiteral(resourceName: "Gift Smile Icon"), #imageLiteral(resourceName: "Gift Gif Icon"), #imageLiteral(resourceName: "Gift Camera Icon"), #imageLiteral(resourceName: "Gift Gift Icon"), #imageLiteral(resourceName: "Gift Three Dot Icon")]
//MARK:- Properties
weak var delegate: sendMessageToChatScreenDelegate?
weak var giftIcondelegate: GiftIconCellActionDeleate?
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.translatesAutoresizingMaskIntoConstraints = false
cv.backgroundColor = .white
cv.delegate = self
cv.dataSource = self
cv.isScrollEnabled = false
return cv
}()
lazy var customInputView: CustomInputAccesoryView = {
let customView = CustomInputAccesoryView()
customView.delegate = self
return customView
}()
//MARK:- Lifecycles
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(customInputView)
customInputView.anchor(top: topAnchor, left: leftAnchor, right: rightAnchor, paddingTop: 5)
addSubview(collectionView)
collectionView.anchor(top: customInputView.bottomAnchor, left: leftAnchor, paddingTop: 10)
collectionView.setDimensions(width: self.frame.size.width, height: 30)
backgroundColor = .white
self.collectionView.register(GiftFilterCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
//MARK:- UICollectionViewDataSource, UICollectionViewDelegate
extension GiftFilterView: UICollectionViewDataSource, UICollectionViewDelegate{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return giftImageIcon.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as? GiftFilterCollectionViewCell else {
return UICollectionViewCell()
}
cell.imageIcon = giftImageIcon[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
giftIcondelegate?.changeKeyboardheight()
}
}
//MARK:- UICollectionViewDelegateFlowLayout
extension GiftFilterView: UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: frame.width / CGFloat(giftImageIcon.count), height: 40)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
}
I am adding this view to another view
class GiftAccessoryCollectionView: UIView {
//MARK:- Properties
weak var delegate: sendMessageToChatScreenDelegate?
weak var giftIcondelegate: GiftIconCellActionDeleate?
private lazy var filterView: GiftFilterView = {
let giftView = GiftFilterView()
giftView.translatesAutoresizingMaskIntoConstraints = false
return giftView
}()
//MARK:- Lifecycles
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(filterView)
filterView.anchor(top: topAnchor, left: leftAnchor, right: rightAnchor,height: 130)
addSubview(collectionView)
collectionView.anchor(top: filterView.bottomAnchor, left: leftAnchor, paddingTop: 10)
collectionView.setDimensions(width: self.frame.size.width, height: 260)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
But the collection view is not showing when I am adding the view to another view.
It looks like you need to activate your anchors either by using isActive property or for multiple views the following would be more useful:
NSLayoutConstraint.activate([
...
])

Adding a CollectionViewController as a subView

Using Swift 5.1.3, iOS13.3, XCode11.3,
I try to display a horizontal collectionView that is wider than the view's width.
By dragging, the collectionView cells shall scroll horizontally.
The problem now is the following: As soon as I click to drag, the collectionView content "disappears" (i.e. turns transparent). If you look carefully, you can see that the scrollbar is still there.
Why is does the collectionView content turns transparent as soon as I click into it ?
Here is a video illustrating the error behaviour:
Below you will find the corresponding code:
Here is the code:
Inside my Main-ViewController I add the collectionView:
override func viewDidLoad() {
super.viewDidLoad()
let cardsHorizontalController = CardsHorizontalController()
self.view.addSubview(cardsHorizontalController.view)
cardsHorizontalController.view.translatesAutoresizingMaskIntoConstraints = false
cardsHorizontalController.view.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 100.0).isActive = true
cardsHorizontalController.view.heightAnchor.constraint(equalToConstant: 279).isActive = true
cardsHorizontalController.view.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width).isActive = true
}
Here is the collectionView controller class:
class CardsHorizontalController: BaseListController, UICollectionViewDelegateFlowLayout {
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
collectionView.backgroundColor = .clear
collectionView.register(CardHeaderCell.self, forCellWithReuseIdentifier: cellId)
if let layout = collectionViewLayout as? UICollectionViewFlowLayout {
layout.scrollDirection = .horizontal
}
collectionView.contentInset = UIEdgeInsets(top: 100, left: 0, bottom: 0, right: 0)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return .init(width: view.frame.width - 48, height: view.frame.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return .init(top: 0, left: 16, bottom: 0, right: 0)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
return cell
}
}
And its corresponding parent class:
class BaseListController: UICollectionViewController {
init() {
super.init(collectionViewLayout: UICollectionViewFlowLayout())
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
And here the collectionView cell at play:
class CardHeaderCell: UICollectionViewCell {
let imageView = UIImageView(cornerRadius: 8)
override init(frame: CGRect) {
super.init(frame: frame)
imageView.backgroundColor = .red
let stackView = VerticalStackView(arrangedSubviews: [
// companyLabel,
// titleLabel,
imageView
], spacing: 12)
addSubview(stackView)
stackView.fillSuperview(padding: .init(top: 16, left: 0, bottom: 0, right: 0))
}
required init?(coder aDecoder: NSCoder) {
fatalError()
}
}
I finally found a solution:
The collectionView-Controller (i.e. CardsHorizontalController()) needs to be added as a ChildController!
Inside Main-ViewController's viewDidLoad()(in first paragraph of code above), please replace the following line...
self.view.addSubview(cardsHorizontalController.view)
with the following:
self.addChild(cardsHorizontalController)
self.view.addSubview(cardsHorizontalController.view)
self.didMove(toParent: cardsHorizontalController)
Having done so, everything works as expected !
You find a working project (stripped-down with only the CollectionView) in this GitHub repo: https://github.com/iKK001/HorizontalCollectionViewExample
And since I'm so happy - here a video of the working horizontal CollectionView:
Have you tried changing return .init(width: view.frame.width - 48, height: view.frame.height) inside sizeForItemAt to return .init(width: collectionView.frame.width - 48, height: collectionView.frame.height)?

Swift - Draw lines between several random CGPoints

I am trying to create a simple line graph that should display the average monthly user score. So far I have created a collectionView with a white dot at the top of each cell, but now I would like to have a straight line between each dot. I have added a temporary array for testing purposes.
Since it will be variable server data (the last six months), the location of the dots can be different each time. What should I do to connect the first dot with the second one and the second one with the next one (until all dots are connected)?
User profile data controller
class UserProfileData: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var cellId = "cellId"
let values: [CGFloat] = [4.5, 3.2, 4.8, 5.0, 2.3, 2.9]
init() {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = UICollectionViewScrollDirection.horizontal
super.init(collectionViewLayout: layout)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView?.dataSource = self
self.collectionView?.delegate = self
collectionView?.backgroundColor = Constants.MAIN_THEME_COLOR
collectionView?.isScrollEnabled = false
collectionView?.register(BarCell.self, forCellWithReuseIdentifier: cellId)
}
// MARK: UICollectionViewDataSource
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return values.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 50, height: view.frame.height - 20)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! BarCell
if let max = values.max() {
let value = values[indexPath.item]
let ratio = value / max
cell.barHeightConstraint?.constant = view.frame.height * ratio
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 4, bottom: 0, right: 4)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
}
My custom cell
// Create custom cell(s)
class BarCell: UICollectionViewCell {
let barView: UIView = {
let view = UIView()
view.backgroundColor = .clear
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let barLabel: UILabel = {
let label = UILabel()
label.text = "."
label.textColor = .white
label.font = UIFont.systemFont(ofSize: 70)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
var barHeightConstraint: NSLayoutConstraint?
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(barView)
barView.addSubview(barLabel)
barHeightConstraint = barView.heightAnchor.constraint(equalToConstant: 300)
barHeightConstraint?.isActive = true
barHeightConstraint?.constant = 100
barView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
barView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
barView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
barLabel.centerXAnchor.constraint(equalTo: barView.centerXAnchor).isActive = true
barLabel.topAnchor.constraint(equalTo: barView.topAnchor, constant: 5).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
A UICollectionView has a backgroundView property. You should be able to set the backgroundView of your UICollectionView to a custom UIView that draws the lines between your items.

uicollectionviewcells not showing [duplicate]

I have got this Swift code
`
let cellId="cellId"
class FeedController: UICollectionViewController{
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Centill"
collectionView?.reloadData()
collectionView?.backgroundColor = UIColor(white: 0.95, alpha: 1)
collectionView?.register(FeedCell.self, forCellWithReuseIdentifier: cellId)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell=collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath);
cell.backgroundColor = .yellow
return cell
}
}
class FeedCell: UICollectionViewCell {
override init(frame: CGRect){
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews(){
backgroundColor = .yellow
}
}
`
But unfortunately my cells are not showing.It only shows navigation bar and background color.what may be the problem with my code?
Try This code:
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
layout.itemSize = CGSize(width: 60, height: 60)
let myCollectionView:UICollectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
myCollectionView.dataSource = self
myCollectionView.delegate = self
myCollectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "MyCell")
myCollectionView.backgroundColor = UIColor.whiteColor()
self.view.addSubview(myCollectionView)
You have to provide the size for collection view cell. add the below code snippet
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// calculate and return the height
}
In your cellForItemAt dataSource method you need to give custom UICollectionCell Class
let cell=collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! FeedCell
cell.backgroundColor = .yellow
return cell
Then you will able to see cell.
Try it.
You add in the class
UICollectionViewDataSource and UICollectionVIewDelegate.

Adding WebView to CollectionView without using MainStoryboard

I've been working on CollectionView with ImageView in each cells. Now I'm wondering how to add WebView working the same way as ImageView. I want it working as an element in each cell, is it possible? In addition, I am not using storyboard.
import UIKit
class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Home"
collectionView?.backgroundColor = UIColor.white
collectionView?.register(WebCell.self, forCellWithReuseIdentifier: "cellId")
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: view.frame.height - 500)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}
class WebCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
let StronaSzkolna: UIImageView = {
let webview = UIImageView()
webview.backgroundColor = UIColor.blue
webview.translatesAutoresizingMaskIntoConstraints = false
return webview
}()
func setupViews() {
addSubview(StronaSzkolna)
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-16-[v0]-16-|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0":StronaSzkolna]))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-16-[v0]-16-|", options: NSLayoutFormatOptions(), metrics: nil, views: ["v0":StronaSzkolna]))
StronaSzkolna.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}