how to use two collectionview inside one ViewController with UiCollectionView Height set two fixed height and may varied according to content size ? BY using NSLayoutConstraint in UIKit.please help me on this.when I try to add cell after the spacing get added with contentSize and it detect double size of what height should be. And that where problem Occurs I was expecting size should get for 4th cell is 200 but its get 410 size
you can see what response look Like it taking more space than it should take here
here we can see I have two collection under single controller embedded in scrollview
import PhotosUI
import UIKit
class SellContractController: UIViewController, UITextViewDelegate, PHPickerViewControllerDelegate,SendSpeciality,SendPackages {
func sendPackage(data: [ContractPackage]) {
print(data)
self.itemPackages = data
contractPackagesCollectionView.reloadData()
}
func sendSpeciality(data: [String]) {
self.tagsArray = data
specialityCollectionView.reloadData()
}
@IBOutlet weak var specialityCollectionViewHeight: NSLayoutConstraint!
@IBOutlet weak var parentView: UIView!
@IBOutlet weak var imageContainerView: UIView!
@IBOutlet weak var specialityView: UIView!
@IBOutlet weak var productTitle: UITextField!
@IBOutlet weak var descriptionTextView: UITextView!
@IBOutlet weak var productName: UITextField!
@IBOutlet weak var addSpeciality: UIButton!
@IBOutlet weak var brandname: UITextField!
@IBOutlet weak var addPackages: UIButton!
@IBOutlet weak var imageCollectionView: UICollectionView!
@IBOutlet weak var contractPackagesView: UIView!
@IBOutlet weak var sellContractButton: UIButton!
@IBOutlet weak var specialityCollectionView: UICollectionView!
@IBOutlet weak var contractPackagesCollectionView: UICollectionView!
var sellContractItems:SellContractDetails?
var imageArray = [UIImage] ()
var tagsArray = [String]()
var itemPackages = [ContractPackage]()
var sellContractItem:SellContractDetails?
override func viewDidLoad() {
super.viewDidLoad()
DescriptionBorder(txtView: descriptionTextView)
viewBorder(view: specialityView)
viewBorder(view: imageContainerView)
viewBorder(view: contractPackagesView)
sellContractButton.layer.cornerRadius = 10
}
func DescriptionBorder(txtView:UITextView){
descriptionTextView.text = "Product Description"
txtView.delegate = self // Give TextViewMessage delegate Method
txtView.layer.borderColor = UIColor(red: 0.9, green: 0.9, blue: 0.9, alpha: 1.0).cgColor
txtView.layer.borderWidth = 1.0
txtView.layer.cornerRadius = 5
}
func viewBorder(view:UIView){
view.layer.cornerRadius = 10
view.layer.borderColor = UIColor(red: 0.9, green: 0.9, blue: 0.9, alpha: 1.0).cgColor
view.layer.borderWidth = 1.0
view.layer.masksToBounds = true
}
@IBAction func DoneClicked(_ sender: UIBarButtonItem) {
sellContract()
}
@IBAction func onCreateClicked(_ sender: UIButton) {
sellContract()
}
@IBAction func addPhotosClicked(_ sender: UIButton) {
askPermission()
openGallery()
}
func addBorder(txtfield:UITextField) {
txtfield.layer.cornerRadius=15
txtfield.layer.borderWidth = 2.0
txtfield.layer.borderColor = #colorLiteral(red: 0.4549019608, green: 0.768627451, blue: 0.6862745098, alpha: 1)
txtfield.layer.masksToBounds = true
txtfield.leftViewMode = .always
}
@IBAction func addPackages(_ sender: UIButton) {
self.performSegue(withIdentifier: "ContractPackageSegue", sender: self)
}
@IBAction func addSpeciality(_ sender: UIButton) {
self.performSegue(withIdentifier: "SpecialitySegue", sender: self)
}
func openGallery(){
var config = PHPickerConfiguration()
config.selectionLimit = 5
config.filter = .images
let picker = PHPickerViewController(configuration: config)
picker.delegate = self
present(picker, animated: true)
}
func askPermission()
{
PHPhotoLibrary.requestAuthorization({(status) in
if status == PHAuthorizationStatus.authorized
{
DispatchQueue.main.async{
}
}
else {
print("NO access")
}
})
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "SpecialitySegue"{
let secondvc = segue.destination as! SpecialityPopup
secondvc.tagsArray = self.tagsArray
secondvc.speciality = self
}
else if segue.identifier == "ContractPackageSegue"{
let secondvc = segue.destination as! ContractPackagesController
secondvc.itemPackages = self.itemPackages
secondvc.itempackage = self
}
}
func textViewDidBeginEditing(_ textView: UITextView) {
if textView == descriptionTextView {
if !descriptionTextView.text!.isEmpty && descriptionTextView.text! == "Product Description" {
descriptionTextView.text = ""
descriptionTextView.textColor = UIColor.black
}
}
}
func textViewDidEndEditing(_ textView: UITextView) {
if textView == descriptionTextView {
if descriptionTextView.text.isEmpty {
descriptionTextView.text = "Product Description"
descriptionTextView.textColor = UIColor.lightGray
}
}
}
func sellContract(){
var authToken = ""
TokenService().getOrGenerateToken() { result in
switch result {
case .success(let token):
authToken = token
case .failure(_):
DispatchQueue.main.async {
CustomToast.showFailure(message: "Something went wrong", controller: self)
}
}
}
guard let title = self.productTitle.text, title != "" else {
CustomToast.show(message: "please enter Title", bgColor: .black, textColor: .red, labelFont: .systemFont(ofSize: 12.0), showIn: .bottom, controller: self)
return
}
guard let brand = self.brandname.text, brand != "" else {
CustomToast.show(message: "please enter brand name", bgColor: .black, textColor: .red, labelFont: .systemFont(ofSize: 12.0), showIn: .bottom, controller: self)
return
}
guard let product = self.productName.text, product != "" else {
CustomToast.show(message: "please enter product name", bgColor: .black, textColor: .red, labelFont: .systemFont(ofSize: 12.0), showIn: .bottom, controller: self)
return
}
guard let description = self.descriptionTextView.text, description != "" else {
CustomToast.show(message: "please enter description", bgColor: .black, textColor: .red, labelFont: .systemFont(ofSize: 12.0), showIn: .bottom, controller: self)
return
}
struct Suitability:Codable{
let suitableFor: String
}
var suitabilities = [Suitability]()
tagsArray.forEach{ tag in
suitabilities.append(Suitability(suitableFor:tag))
}
struct UploadData: Codable {
let itemType: String
let title: String
let brand:String
let product:String
let description : String
let itemSuitabilities: [Suitability]?
let itemPackages:[ContractPackage]?
}
// Add data to the model
let uploadDataModel = UploadData(itemType:"CONTRACT",
title:title,
brand: brand,
product: product,
description: description,
itemSuitabilities: suitabilities,
itemPackages: self.itemPackages
)
// Convert model to JSON data
guard let jsonData = try? JSONEncoder().encode(uploadDataModel) else {
DispatchQueue.main.async {
CustomToast.showFailure(message: "Something went wrong", controller: self)
}
return
}
// Create the url request
let postUrl = BASE_URL + "items"
let escapedExistUrl = postUrl.addingPercentEncoding(withAllowedCharacters:NSCharacterSet.urlQueryAllowed)!
let url = URL(string: escapedExistUrl)
var request = URLRequest(url: url!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type") // the request is JSON
request.setValue("application/json", forHTTPHeaderField: "Accept") // the response expected to be in JSON format
request.setValue( "Bearer \(authToken)", forHTTPHeaderField: "Authorization")
request.httpBody = jsonData
URLSession.shared.dataTask(with: request) { data, response, error in
guard error == nil else {
DispatchQueue.main.async {
CustomToast.showFailure(message: "Something went wrong", controller: self)
}
return
}
guard let data = data else {
DispatchQueue.main.async {
CustomToast.showFailure(message: "Something went wrong", controller: self)
}
return
}
let response = response as? HTTPURLResponse
print(response!)
if (200 == response?.statusCode){
if let json = String(data: data, encoding: .utf8) {
print("json", json)
}
do{
let payload = try JSONDecoder().decode(SellContractDetails.self,from: data)
self.sellContractItem = payload
print(self.sellContractItem!)
if (self.imageArray.count != 0){
self.uploadImage(images:self.imageArray,id:self.sellContractItem!.id)
}
}
catch{
DispatchQueue.main.async {
print(error)
CustomToast.showFailure(message: "Something went wrong", controller: self)
}
return
}
}
else {
DispatchQueue.main.async {
CustomToast.showFailure(message: "Something went wrong", controller: self)
}
return
}
}.resume()
}
func uploadImage(images: [UIImage],id:String) {
var authToken = ""
TokenService().getOrGenerateToken() { result in
switch result {
case .success(let token):
authToken = token
case .failure(_):
DispatchQueue.main.async {
CustomToast.showFailure(message: "Something went wrong", controller: self)
}
}
}
let boundary = UUID().uuidString
let postUrl = BASE_URL + "items/upload-image/"+id+""
print(postUrl)
let escapedExistUrl = postUrl.addingPercentEncoding(withAllowedCharacters:NSCharacterSet.urlQueryAllowed)!
let url = URL(string: escapedExistUrl)
let session = URLSession.shared
// Set the URLRequest to POST and to the specified URL
var urlRequest = URLRequest(url: url!)
urlRequest.httpMethod = "POST"
// Set Content-Type Header to multipart/form-data, this is equivalent to submitting form data with file upload in a web browser
// And the boundary is also set here
urlRequest.setValue( "Bearer \(authToken)", forHTTPHeaderField: "Authorization")
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
var data = Data()
for image in images {
// let fileName = String(Int64(NSDate().timeIntervalSince1970*1000)) + ".jpg"
// Add the image data to the raw http request data
data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
data.append("Content-Disposition: form-data; name=\"images\"; filename=\"\(Int64(NSDate().timeIntervalSince1970*1000)).jpg\"\r\n".data(using: .utf8)!)
data.append("Content-Type: img/png\r\n\r\n".data(using: .utf8)!)
data.append(image.pngData()!)
data.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
}
// Send a POST request to the URL, with the data we created earlier
session.uploadTask(with: urlRequest, from: data, completionHandler: { data, response, error in
guard error == nil else {
DispatchQueue.main.async {
CustomToast.showFailure(message: "Something went wrong,312", controller: self)
}
return
}
guard let data = data else {
DispatchQueue.main.async {
CustomToast.showFailure(message: "Something went wrong,line 318", controller: self)
}
return
}
let response = response as? HTTPURLResponse
if (200 == response?.statusCode){
if let json = String(data: data, encoding: .utf8) {
print("json,line 329", json)
}
DispatchQueue.main.async {
CustomToast.showSuccess(message:"Image uploaded Successfully", controller: self)
}
}
else {
print(error!)
DispatchQueue.main.async {
CustomToast.showFailure(message:"Something went wrong,line 337", controller: self)
}
return
}
}).resume()
}
}
extension SellContractController:UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout
{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == specialityCollectionView{
return tagsArray.count
}
else if collectionView == contractPackagesCollectionView{
return itemPackages.count
}
print(imageArray.count)
return imageArray.count
}
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult])
{
dismiss(animated: true)
for result in results{
result.itemProvider.loadObject(ofClass: UIImage.self){ object,error in
if let image = object as? UIImage{
self.imageArray.append(image)
}
DispatchQueue.main.async {
self.imageCollectionView.reloadData()
}
}
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == specialityCollectionView{
let cell=specialityCollectionView.dequeueReusableCell(withReuseIdentifier: "MemberCell", for: indexPath) as! AddTagCollectionViewCell
cell.MName.text = tagsArray[indexPath.row]
cell.DeleteMember?.tag = indexPath.row
cell.DeleteMember?.addTarget(self, action: #selector(deleteTag(sender:)), for: UIControl.Event.touchUpInside)
return cell
}
else if collectionView == contractPackagesCollectionView{
let cell=contractPackagesCollectionView.dequeueReusableCell(withReuseIdentifier: "ContractPackage", for: indexPath) as! ContractPackagesCollectionViewCell
cell.packageName.text = itemPackages[indexPath.row].packageName
cell.priceandTerm.text = itemPackages[indexPath.row].contractTerm + "|" + String(itemPackages[indexPath.row].duration) + "|" + String(itemPackages[indexPath.row].price)
cell.deletePackage?.tag = indexPath.row
cell.deletePackage?.addTarget(self, action: #selector(deletePackage(sender:)), for: UIControl.Event.touchUpInside)
return cell
}
let cell=imageCollectionView.dequeueReusableCell(withReuseIdentifier:"ImageCell", for: indexPath) as! ProductImages
cell.productImage.image = imageArray[indexPath.row]
cell.deleteImage?.tag = indexPath.row
cell.deleteImage?.addTarget(self, action: #selector(deleteImage(sender:)), for: UIControl.Event.touchUpInside)
cell.productImage.layer.cornerRadius = 10
cell.productImage.layer.borderColor = UIColor(red: 0.9, green: 0.9, blue: 0.9, alpha: 1.0).cgColor
cell.productImage.layer.borderWidth = 1.0
return cell
}
/* delete Images */
@objc func deleteImage(sender:UIButton) {
let i = sender.tag
imageArray.remove(at: i)
imageCollectionView.reloadData()
}
/* delete Tags*/
@objc func deleteTag(sender:UIButton) {
let i = sender.tag
tagsArray.remove(at: i)
specialityCollectionView.reloadData()
}
@objc func deletePackage(sender:UIButton) {
let i = sender.tag
itemPackages.remove(at: i)
contractPackagesCollectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView == specialityCollectionView
{
specialityCollectionViewHeight.constant = self.specialityCollectionView.collectionViewLayout.collectionViewContentSize.height
// print(specialityCollectionViewHeight.constant)
print(collectionView.frame.height)
return CGSize(width: (collectionView.frame.width-10), height:specialityCollectionViewHeight.constant)
}
else if collectionView == contractPackagesCollectionView{
return CGSize(width: collectionView.frame.width-10, height: collectionView.frame.height)
}
return CGSize(width: (collectionView.frame.width-10)/3, height: collectionView.frame.height/2)
}
}
I Was expecting the size 210 but getting 410