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)?
Related
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([
...
])
I'm trying to add a collection view in a UIview to display users posts like Instagram has where you are able to swipe left and right on a users profile:
Can you add a collection view in the purple bit below (which is a UIView)?
So far this is what I have tried and I am not getting it to work and I'm not sure what else to try
import UIKit
private let reuseIdentifier = "Cell"
class CollectionView: UIView, UICollectionViewDataSource, UICollectionViewDelegate,
UICollectionViewDelegateFlowLayout {
//MARK: - Properties
let cellId = "cellId"
let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let view = UICollectionView(frame: .zero, collectionViewLayout: layout)
return view
}()
//MARK: - Init
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(collectionView)
collectionView.anchor(top: topAnchor, left: leftAnchor, bottom: bottomAnchor, right: rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//MARK: - UICollectionView
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection
section: Int) -> Int {
return 2
}
}
you need to set the delegate and data source for your collection view
try this
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let view = UICollectionView(frame: .zero, collectionViewLayout: layout)
view.dataSource = self
view.delegate = self
return view
}()
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.
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.
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.