I build ViewController with UiCollectionView, and I created my custom View to display in every cell.
This is the code on my controller to display, resize the cell.
I need to have 3 cell for every row in UiCollectionView
class HomeViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource , UICollectionViewDelegateFlowLayout{
#IBOutlet weak var collectionView: UICollectionView!
var listaCategorie = [CategoryModel]()
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.listaCategorie.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let noOfCellsInRow = 3
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let totalSpace = flowLayout.sectionInset.left
+ flowLayout.sectionInset.right
+ 30
+ (flowLayout.minimumInteritemSpacing * CGFloat(noOfCellsInRow - 1))
let size = Int((collectionView.bounds.width - totalSpace) / CGFloat(noOfCellsInRow))
return CGSize(width: 100, height: 130)
}
// UICollectionViewDelegateFlowLayout method
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAtIndex section: Int) -> UIEdgeInsets {
let cellWidthPadding = collectionView.frame.size.width / 30
let cellHeightPadding = collectionView.frame.size.height / 4
return UIEdgeInsets(top: cellHeightPadding,left: cellWidthPadding, bottom: cellHeightPadding,right: cellWidthPadding)
}
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
var category = self.listaCategorie[indexPath.row];
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cella", for: indexPath) as! CustomCellViewsCategories
var puntoLuce = self.listaCategorie[indexPath.row];
cell.labelCategoryName.text = puntoLuce.description
//cell.image.image = UIImage(named: "light-bulb-2.png");
cell.backgroundColor = getUIColorFromRGBThreeIntegers(red: 63,green: 162,blue: 217);
cell.layer.cornerRadius = 6
cell.layer.masksToBounds = false;
cell.layer.shadowColor = UIColor.black.cgColor
cell.layer.shadowOffset = CGSize(width: 0, height: 0)
cell.layer.shadowOpacity = 0.5
//RECUPERO LA DIMENSIONE
let noOfCellsInRow = 4
//FINE RECUPERO DIMENSIONE
if(puntoLuce.imageUrl != ""){
let imageUrl:NSURL = NSURL(string: puntoLuce.imageUrl!)!
DispatchQueue.global(qos: .userInitiated).async {
let imageData:NSData = NSData(contentsOf: imageUrl as URL)!
DispatchQueue.main.async {
let image = UIImage(data: imageData as Data)
cell.imageCategory.image = image
}
}
}
return cell
}
func getUIColorFromRGBThreeIntegers(red: Int, green: Int, blue: Int) -> UIColor {
return UIColor(red: CGFloat(Float(red) / 255.0),
green: CGFloat(Float(green) / 255.0),
blue: CGFloat(Float(blue) / 255.0),
alpha: CGFloat(1.0))
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.title = "ARRIVA ARRIVA"
//on click su label temp
let tap = UITapGestureRecognizer(target: self, action: #selector(HomeViewController.tapFunction))
getCategoryList()
collectionView.delegate = self // Unless you have already defined the delegate in IB
collectionView.dataSource = self // Unless you have already defined the dataSource in IB
self.collectionView.frame = self.collectionView.frame.inset(by: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0))
}
#objc func tapFunction() {
// handle label tap here
print("click");
}
func getCategoryList(){
var params = [
"" : ""
]
let postUrl = APIRequest(endPoint: "category_list")
postUrl.sendRequest(parameters: params as! [String : String]) {
responseObject, error in
let user = CategoryModel(id: "0",
description: "Tutti",
imageUrl: "")
self.listaCategorie.append(user)
guard let responseObject = responseObject, error == nil else {
print(error ?? "Unknown error")
return
}
do{
let messageData = try JSONDecoder().decode(ResponseCategoryModel.self, from: responseObject)
var array = messageData.result
for categoryModel in array {
let user = CategoryModel(id: "",
description: categoryModel.categoryName,
imageUrl: categoryModel.image)
self.listaCategorie.append(user)
}
print(array.count);
DispatchQueue.main.async { // Correct
self.collectionView.reloadData()
}
}catch{
print("errore durante la decodifica dei dati")
}
}
}
But this is the result:
As you can see from the photo there is too space from the 3 cells. There is a way to set minus space by cells?
EDIT
I try to use the code on first response. THis is the result
UICollectionViewCompositionalLayout will give you a layout that automatically adjusts to the collection view size. Remove all code you have relating to the flow layout and create a compositional layout in viewDidLoad:
// Cell will be the full height of the enclosing group
let cellHeight = NSCollectionLayoutDimension.fractionalHeight(1)
// Cell will be 1/3 width of the enclosing group
let cellWidth = NSCollectionLayoutDimension.fractionalWidth(0.333)
// The size of the cell
let size = NSCollectionLayoutSize(widthDimension: cellWidth, heightDimension: cellHeight)
// This item represents a single cell
let item = NSCollectionLayoutItem(layoutSize: size)
// The cell will be inset by these distances within the item
item.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
// The group will be a fixed height
let groupHeight = NSCollectionLayoutDimension.absolute(130)
// The group will occupy the full available width
let groupWidth = NSCollectionLayoutDimension.fractionalWidth(1)
// The group will repeat to hold as many of the cells as it can in a horizontal row before wrapping
let group = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: groupWidth, heightDimension: groupHeight), subitems: [item])
// The actual section, which consists of a single group
let section = NSCollectionLayoutSection(group: group)
// The insets of the group from the edge of the collection view
section.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
// Create and assign the layout
let layout = UICollectionViewCompositionalLayout(section: section)
collectionView.collectionViewLayout = layout
I've tried to break it up into chunks so it makes sense, these layouts can take some time to wrap your head around.
It gives you the following portrait layout:
And in landscape:
If you want a fixed cell size, then use .absoluteWidth for the cell width, and add an interItemSpacing of .flexible to the group.
Using UICollectionViewFlowLayout you can achieve a very similar result with less code than you have in your question. With a plain project, the only collection view related code I had was this in viewDidLoad():
(collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.sectionInset = .init(top: 10, left: 10, bottom: 10, right: 10)
Then this single flow layout delegate method:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
var width = (collectionView.bounds.width - 20) / 3
width -= 10
return CGSize(width: width, height: 130)
}
This gives you three columns per row in portrait or landscape.
Add the UICollectionViewDelegateFlowLayout delegate and add these methods and update your values according to your requirement like:-
let edge : CGFloat = 10.0
let spacing : CGFloat = 10.0
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let noOfColumn = 3
let collectionviewWidth = collectionView.frame.width
let bothEdge = CGFloat(edge + edge) // left + right
let excludingEdge = collectionviewWidth - bothEdge
let cellWidthExcludingSpaces = excludingEdge - ((noOfColumn-1) * spacing)
let finalCellWidth = cellWidthExcludingSpaces / noOfColumn
let height = finalCellWidth
return CGSize(width: finalCellWidth, height: height)
}
Related
I am using collectionview in tableview cell and showing collectionview height according to number of cells from JSON response according to this answer
the code:
class ViewProposalTableVIewCell: UITableViewCell, UICollectionViewDelegate,UICollectionViewDataSource {
#IBOutlet weak var attCollHeight: NSLayoutConstraint!
#IBOutlet weak var attetchmentsCollectionview: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
let width = UIScreen.main.bounds.width/2.5
let height = CGFloat(40)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
layout.itemSize = CGSize(width: width, height: height)
self.attetchmentsCollectionview.collectionViewLayout = layout
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ViewProposalTableVIewCell", for: indexPath) as! ViewProposalTableVIewCell
let bidData = viewproposalData?.result?.bids?[indexPath.row]
cell.propAmt.text = "$\(bidData?.amount ?? "")"
cell.frame = tableView.bounds
cell.layoutIfNeeded()
cell.attetchmentsCollectionview.reloadData()
cell.attCollHeight.constant = cell.attetchmentsCollectionview.collectionViewLayout.collectionViewContentSize.height;
cell.attetchmentsCollectionview.reloadData()
return cell
}
then the 0/p: but i don't want the gap between the cells how to make both cells come close
EDIT: according to below answer and removed code in awakeFromNib then the o/p
where am i wrong
Set this settings for collectionview from storybord
Add this in code
extension homeVC: UICollectionViewDelegateFlowLayout,
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let noOfCellsInRow = 2
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let totalSpace = flowLayout.sectionInset.left
+ flowLayout.sectionInset.right
+ (flowLayout.minimumInteritemSpacing * CGFloat(noOfCellsInRow - 1))
let size = Int((collectionView.bounds.width - 5) / CGFloat(noOfCellsInRow))
return CGSize(width: size, height: 20)
}
}
You need to set insets
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
let cellWidth = 50
let noOfCellsInRow = 2
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout
let space = flowLayout.minimumInteritemSpacing
let totalCellWidth = cellWidth * noOfCellsInRow
let leftInset = (collectionView.frame.width - (CGFloat(totalCellWidth) + space)) / 2
let rightInset = leftInset
return UIEdgeInsets(top: 0, left: leftInset, bottom: 0, right: rightInset)
}
I didn't like apples image picker so I decided to implement my own. I just finished the stage of getting all the users photos and displaying them in a collection view although I noticed that the difference in image quality is horrible. Here is my code:
import UIKit
import Photos
import PhotosUI
import Foundation
private let reuseIdentifier = "Cell"
var selectedImage = UIImage()
class CollectionVC: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var imageArray = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
grapPhotos()
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath as IndexPath)
let imageView = cell.viewWithTag(1) as! UIImageView
cell.layer.cornerRadius = 4
imageView.image = imageArray[indexPath.row]
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let selectedImageName = imageArray[indexPath.item]
print(selectedImageName)
selectedImage = selectedImageName
performSegue(withIdentifier: "Custom", sender: self)
}
func grapPhotos() {
let imgManager = PHImageManager.default()
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
requestOptions.deliveryMode = .highQualityFormat
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
fetchOptions.predicate = NSPredicate(format: "mediaType = %d || mediaType = %d", PHAssetMediaType.image.rawValue, PHAssetMediaType.video.rawValue)
if let fetchResult : PHFetchResult = PHAsset.fetchAssets(with: fetchOptions) {
if fetchResult.count > 0 {
for i in 0..<fetchResult.count {
imgManager.requestImage(for: fetchResult.object(at: i), targetSize: CGSize(width: 200, height: 200), contentMode: .aspectFill, options: requestOptions, resultHandler: {
image, error in
self.imageArray.append(image!)
})
}
}
else {
self.collectionView?.reloadData()
print("No Photos")
}
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.frame.width / 3 - 6
return CGSize(width: width, height: width)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 6.0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 6.0
}
}
I don't really know much about working with images so if anyone could help me out on displaying higher quality images that would be great.
This really works))
for index in 0..<fetchResult.count {
let asset = fetchResult.object(at: index) as PHAsset
let sizeFactor = UIScreen.main.scale
let deviceSize = UIScreen.main.nativeBounds.size
manager.requestImage(for: asset,
targetSize: CGSize(width: deviceSize.width * sizeFactor,
height: deviceSize.height * sizeFactor),
contentMode: .aspectFit,
options: requestOptions,
resultHandler: { (uiimage, info) in
if let image = uiimage {
allImages.append(image)
}
})
}
You only need to know ->
let sizeFactor = UIScreen.main.scale
let deviceSize = UIScreen.main.nativeBounds.size
Image quality depends on the phone your viewing on - retina screens require more pixels. You'll need to multiply your targetSize by UIScreen.main.scale.
Try setting targetSize: CGSize(width: 200 * UIScreen.main.scale, height: 200.0 * UIScreen.main.scale) in your imgManager.requestImage function.
For Retina displays, the scale factor may be 3.0 or 2.0 and one point can represented by nine or four pixels, respectively. For standard-resolution displays, the scale factor is 1.0 and one point equals one pixel.
I have a UIcollectionView with images. When I rotate the screen, the cells do not resize as expected. I have tried adding collectionView.collectionViewLayout.invalidateLayout() to the viewDidLayoutSubviews() - but this only causes a crash. Please can someone advise?
I have a UIcollectionView with images. When I rotate the screen, the cells do not resize as expected. I have tried adding collectionView.collectionViewLayout.invalidateLayout() to the viewDidLayoutSubviews() - but this only causes a crash. Please can someone advise?
Portrait:
Landdscape:
class GridPicksCollectionViewController: UICollectionViewController{
let cellId = "gridyPickCell"
var numCelPerRow: CGFloat = 3
var layout: UICollectionViewFlowLayout!
let borderInset: CGFloat = 3
let interCellSpacing: CGFloat = 3
let spacingBetweenRows: CGFloat = 3
var dataSource = [UIImage]()
var collectionViewWidth: CGFloat!
override func viewDidLoad() {
super.viewDidLoad()
generalSetup()
setUpDateSource()
setupCollectionViewLayout()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
print("viewDidLayoutSubviews")
// Update collectionViewWidth upon rotation
collectionViewWidth = self.collectionView.frame.width
//collectionView.collectionViewLayout.invalidateLayout() - causes app to crash
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
print("viewWillTransition")
}
private func generalSetup(){
navigationController?.navigationBar.barTintColor = UIColor.appDarkGreen
navigationItem.title = "Girdy Picks"
let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
navigationController?.navigationBar.titleTextAttributes = textAttributes
collectionView.backgroundColor = UIColor.white
collectionViewWidth = collectionView.frame.width
// Make sure collectionView is always within the safe area layout
if #available(iOS 11.0, *) {
collectionView?.contentInsetAdjustmentBehavior = .always
}
// Register UICollectionViewCell
collectionView.register(GirdyPickCollectionCell.self, forCellWithReuseIdentifier: cellId)
}
private func setUpDateSource(){
let images: [UIImage] = [UIImage.init(named: "buddha")!, UIImage.init(named: "sharpener")!, UIImage.init(named: "cars")!, UIImage.init(named: "houses")!, UIImage.init(named: "houses2")!, UIImage.init(named: "tower1")!, UIImage.init(named: "tower2")!]
dataSource = images
}
private func setupCollectionViewLayout(){
collectionView.delegate = self
collectionView.dataSource = self
layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
layout.minimumInteritemSpacing = interCellSpacing // distance between cells in a row
layout.minimumLineSpacing = spacingBetweenRows // distance in between rows
layout.sectionInset = UIEdgeInsets.init(top: borderInset, left: borderInset, bottom: borderInset, right: borderInset) // border inset for collectionView
}
}
extension GridPicksCollectionViewController: UICollectionViewDelegateFlowLayout{
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataSource.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! GirdyPickCollectionCell
cell.imageView.image = dataSource[indexPath.row]
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let selectedImage = dataSource[indexPath.row]
let showImageVC = ImageGridViewController()
showImageVC.modalPresentationStyle = .fullScreen
showImageVC.imageToDisplay = selectedImage
self.present(showImageVC, animated: true) {}
}
// Determine size for UICollectionCell
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
print("sizeForItemAt")
guard let collectionWidth = collectionViewWidth else{ return CGSize.init()}
let widthCell = (collectionWidth - interCellSpacing * 2 - borderInset * 2) / numCelPerRow
return CGSize.init(width: widthCell, height: widthCell)
}
}
You are wrong about your lifecycle of events. When the device is rotated, your view hierarchy becomes notified of this event, and views start to re-layout themselves based on the information they have. After this has been finished, viewDidLayoutSubviews() will be called, not before.
Since you are updating the collectionViewWidth property in this method, the layout still uses the old value when calling collectionView(_:layout:sizeForItemAt:). You need to set this value in viewWillLayoutSubviews().
Alternatively, you can write a setter for this property which will call invalidateLayout() on the collection view's layout, but this will cause an unnecessary layout pass.
I am refactoring my ViewControllers and one of them contains a collectionView but now the DataSource is not getting called anymore.
My ViewController:
class CoinPageVC: UIViewController, DependencyInjectionVC, Storyboarded {
lazy var mainView: CoinPageV = {
let v = CoinPageV()
v.collectionView.delegate = self
return v
}()
var coin: Coin!
var selectedBase: String!
var viewContainer: [UIView]!
var collectionViewViewDataSource: CollectionViewCoinPageDatasource?
func injectDependencys(dependency: CoinPageDependency) {
self.coin = dependency.coin
self.selectedBase = dependency.base
self.viewContainer = dependency.views
}
override func viewDidLoad() {
super.viewDidLoad()
self.collectionViewViewDataSource = CollectionViewCoinPageDatasource(data: viewContainer)
self.mainView.collectionView.dataSource = self.collectionViewViewDataSource
self.mainView.collectionView.reloadData()
}
}
extension CoinPageVC: SetMainView {}
extension CoinPageVC: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width:CGFloat = collectionView.bounds.width
let height:CGFloat = collectionView.bounds.height
// - (tabBarHeight + menuBar.frame.height + heightNavigationBarTop)
let output = Utility.shared.CGSizeMake(width, height)
return output
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let index = Int(targetContentOffset.pointee.x / view.frame.width)
let indexPath = IndexPath(item: index, section: 0)
mainView.menuBar.collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredHorizontally)
}
}
My Datasource class:
class CollectionViewCoinPageDatasource: NSObject, UICollectionViewDataSource {
let data: [UIView]
init(data: [UIView]){
self.data = data
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
return data.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//let outputCell: UICollectionViewCell
let row = indexPath.item
let outputCell = collectionView.dequeueReusableCell(withReuseIdentifier: Identifier.coinPageCollectionViewOverviewCell.rawValue, for:indexPath) as! CollectionViewCellView
outputCell.view = data[row]
return outputCell
}
}
My collectionView setup:
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let frame = CGRect(x: 0, y: 0, width: 0, height: 0)
let cv = UICollectionView(frame: frame, collectionViewLayout: layout)
cv.register(CollectionViewCellView.self, forCellWithReuseIdentifier: Identifier.coinPageCollectionViewOverviewCell.rawValue)
if let flowLayout = cv.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.scrollDirection = .horizontal
flowLayout.minimumLineSpacing = 0
}
cv.backgroundColor = .green
cv.isPagingEnabled = true
//cv.backgroundColor = .blue
return cv
}()
What did I miss?
I set up the datasource and also connect it to the datasource of the collectionView, but the methods do not get called.
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let frame = CGRect(x: 0, y: 0, width: 0, height: 0)
let cv = UICollectionView(frame: frame, collectionViewLayout: layout)
cv.register(CollectionViewCellView.self, forCellWithReuseIdentifier: Identifier.coinPageCollectionViewOverviewCell.rawValue)
if let flowLayout = cv.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.scrollDirection = .horizontal
flowLayout.minimumLineSpacing = 0
}
cv.backgroundColor = .green
cv.isPagingEnabled = true
//cv.backgroundColor = .blue
cv.delegate = self
return cv
}()
i am trying to add this view of labels to my collection controller which has cells and a header.
however, nothing being added after i run this. I could have just create these labels using the storyboard, but i wanna know how to do this without the storyboard.Please help and Thank you a lot!
var dayLabelContainerView : UIView {
let v = UIView()
let formatter : NSDateFormatter = NSDateFormatter()
for index in 1...7 {
let day = formatter.weekdaySymbols[index % 7] as NSString
let weekdayLabel = UILabel()
weekdayLabel.text = day.substringToIndex(2).uppercaseString
weekdayLabel.textColor = UIColor.grayColor()
weekdayLabel.textAlignment = NSTextAlignment.Center
v.addSubview(weekdayLabel)
}
self.addSubview(v)
return v
}
updated:
collectionview code:
//
// DaysViewController.swift
// Calendar
//
// Created by guiyang Fan on 12/29/16.
// Copyright © 2016 guiyang Fan. All rights reserved.
//
import UIKit
private let reuseIdentifier = "Cell"
private let headerHeight: CGFloat = 100
class DaysViewController: UICollectionViewController {
private let weekdaySymbols = DateFormatter().shortWeekdaySymbols
private let dateFormatter = DateFormatter()
private let calendar = NSCalendar.current
private var currentDate: Date = Date()
private let specificDate = NSDateComponents()
fileprivate let sectionInsets = UIEdgeInsets(top: 50.0, left: 0, bottom : 50.0, right: 20.0)
var monthInfo : [Int:[Int]] = [Int:[Int]]()
private var weekdayOffset: Int {
get{
var components = calendar.dateComponents([.year, .month, .day], from: currentDate)
components.day = 1
components.month = 2
let startOfMonth = calendar.date(from: components)
return self.calendar.component(.weekday, from: startOfMonth!)
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Register cell classes
// Do any additional setup after loading the view.
collectionView?.backgroundColor = UIColor.white
//collectionView?.register(headerView.self, forCellWithReuseIdentifier:"headerId" )
//collectionView?.register(<#T##nib: UINib?##UINib?#>, forSupplementaryViewOfKind: <#T##String#>, withReuseIdentifier: <#T##String#>)
// setupMenuBar()
}
var dayLabel : UIView {
let v = UIView()
let formatter: DateFormatter = DateFormatter()
for index in 1...7 {
let day = formatter.shortWeekdaySymbols[index] as NSString
let weekdayLabel = UILabel()
weekdayLabel.text = day as String
weekdayLabel.textAlignment = NSTextAlignment.center
v.addSubview(weekdayLabel)
}
view.addSubview(v)
return v
}
/*
let menu: MenuBar = {
let mb = MenuBar()
return mb
}()
private func setupMenuBar(){
view.addSubview(menu)
let views = ["menu" : menu]
let horizontalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|-20-[menu]|",options: [], metrics: nil, views: views)
let verticalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:|-20-[menu(50)]",options: [], metrics: nil, views: views)
view.addConstraints(horizontalConstraints)
view.addConstraints(verticalConstraints)
}
*/
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
// MARK: UICollectionViewDataSource
override func numberOfSections(in collectionView: UICollectionView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
//let range = calendar.range(of: .day, in: .month, for:currentDate)!
//return range.count
return 42
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! DaysViewCell
// Configure the cell
//let currentMonthInfo : [Int] = monthInfo[indexPath.section]!
/*
let fdIndex = currentMonthInfo[FIRST_DAY_INDEX]
let nDays = currentMonthInfo[NUMBER_DAYS_INDEX]
let fromStartOfMonthIndexPath = NSIndexPath(forItem: IndexPath.item - fdIndex, inSection: indexPath.section)
if indexPath.item
*/
var components = calendar.dateComponents([.day, .month, .year], from: currentDate)
components.month = 2
let date = calendar.date(from: components)!
let range = calendar.range(of: .day, in: .month, for:date)!
//let range = calendar.range(of: .day, in: .month, for:currentDate)!
print(range.count)
cell.backgroundColor = UIColor.white
if isValidDayCell(indexPath: indexPath as NSIndexPath) && indexPath.item < weekdayOffset + range.count
{
//print(weekdayOffset)
//var dayToDisplay = indexPath.row - weekdayOffset
cell.DaysCell.text = String(indexPath.item + 1 - weekdayOffset)
}
else
{
cell.DaysCell.text = ""
}
return cell
}
private let headerIdentifier = "headerId"
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView
{
let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: headerIdentifier, for: indexPath) as! headerView
//header.title.text = "calendar"
dateFormatter.locale = NSLocale.current
dateFormatter.dateStyle = .full
//var convertedDate = dateFormatter.string(from: currentDate)
var components = calendar.dateComponents([.day, .month, .year], from: currentDate)
components.month = 2
let monthName = DateFormatter().monthSymbols[components.month! - 1]
//header.updateMonthHeader(text: String(components.month!))
header.updateMonthHeader(text: monthName)
//header.backgroundColor = UIColor.black
return header
}
func isValidDayCell(indexPath: NSIndexPath) -> Bool {
return indexPath.row >= weekdayOffset
}
fileprivate let itemsPerRow: CGFloat = 10
// MARK: UICollectionViewDelegate
/*
// Uncomment this method to specify if the specified item should be highlighted during tracking
override func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool {
return true
}
*/
/*
// Uncomment this method to specify if the specified item should be selected
override func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
return true
}
*/
/*
// Uncomment these methods to specify if an action menu should be displayed for the specified item, and react to actions performed on the item
override func collectionView(_ collectionView: UICollectionView, shouldShowMenuForItemAt indexPath: IndexPath) -> Bool {
return false
}
override func collectionView(_ collectionView: UICollectionView, canPerformAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
return false
}
override func collectionView(_ collectionView: UICollectionView, performAction action: Selector, forItemAt indexPath: IndexPath, withSender sender: Any?) {
}
*/
}
extension DaysViewController : UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let widthPerItem = view.frame.width / itemsPerRow
return CGSize(width: widthPerItem, height: widthPerItem)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets{
return sectionInsets
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 20
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
if collectionView.dataSource != nil {
let size = CGSize(width: view.frame.width, height: headerHeight)
return size
}
else
{
return CGSize(dictionaryRepresentation: 0 as! CFDictionary)!
}
}
}
You haven't added any sizes to UIView
UIView(frame: CGRect(x: WHATEVER , y: WHATEVER, width: WHATEVER , height: WHATEVER))
So instead of
let v = UIView()
It should be
let v = UIView(frame: CGRect(x: WHATEVER , y: WHATEVER, width: WHATEVER , height: WHATEVER))
As NiravD added you should also define the UILabel frame
This may help for you :
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView?
{
let view = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 100))
//Header view
let headerView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 49))
let OrderDate = UILabel(frame: CGRect(x: 10, y: 10, width: 150, height: 30))
OrderDate.textColor = UIColor(red: 24/255, green: 24/255, blue: 24/255, alpha: 1)
OrderDate.font = UIFont(name: "JosefinSans-Regular_0.ttf", size: 23)
OrderDate.text = order_date[section]
headerView.addSubview(OrderDate)
headerView.backgroundColor = UIColor(red: 198/255, green: 198/255, blue: 198/255, alpha: 1)
headerView.addSubview(upDownImageView)
view.addSubview(headerView)
return view
}
func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
{
return 150
}