I am trying to programmatically draw my CollectionView from within a custom class that subclasses UIView. The app loads up with no errors and the CollectionView is being drawn correctly as I can see the cell items, but the CollectionView does not respond to touch. When I try to scroll nothing happens.
I inspected the ViewController using the Debug View Hierarchy button in Xcode to see if there was possibly a view on top. There was not and I could see the cells clearly drawn separately.
Class:
class DrawUI_mainCollectionView : UIView, UICollectionViewDelegate, UICollectionViewDataSource {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
var collectionView : UICollectionView?
private func setup() {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.itemSize = CGSize(width: CGFloat(kScreenWidth),height: 137)
let offset = 120.0
let collectionViewFrame = CGRect(x: 0, y: offset, width: Double(kScreenWidth), height: Double(kScreenHeight))
self.collectionView = UICollectionView(frame: collectionViewFrame, collectionViewLayout: layout)
self.collectionView!.alwaysBounceVertical = true
self.collectionView!.delegate = self
self.collectionView!.dataSource = self
self.collectionView!.register(UINib(nibName: "MealCategoryCell", bundle:Bundle.main), forCellWithReuseIdentifier: "cell")
self.addSubview(self.collectionView!)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MealCategoryCell
cell.label.text = "test"
cell.textDescription.text = "textDescription"
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: kScreenWidth, height: 137)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("cell \(indexPath.row)")
}
required init?(coder aDecoder: NSCoder) {
fatalError("no storyboard...")
}
}
How I am implementing it on my ViewController
let collectionView = DrawUI_mainCollectionView()
self.view.addSubview(collectionView)
What am I doing wrong? Thanks in advance.
I think your main issue is not using auto layout, if you will add auto layout for the items:
view that contains the collectionView in viewController
collectionView in the view
It should work, the implementation:
In ViewController:
let collectionView = DrawUI_mainCollectionView()
collectionView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(collectionView)
NSLayoutConstraint(item: collectionView , attribute: .leading, relatedBy: .equal, toItem: self.view, attribute: .leadingMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .trailing, relatedBy: .equal, toItem: self.view, attribute: .trailingMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .topMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottomMargin, multiplier: 1.0, constant: 0.0).isActive = true
Inside the view:
private func setup() {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.itemSize = CGSize(width: CGFloat(kScreenWidth),height: 137)
let offset = 120.0
let collectionViewFrame = CGRect(x: 0, y: offset, width: Double(kScreenWidth), height: Double(kScreenHeight))
self.collectionView = UICollectionView(frame: collectionViewFrame, collectionViewLayout: layout)
self.collectionView!.alwaysBounceVertical = true
self.collectionView!.delegate = self
self.collectionView!.dataSource = self
self.collectionView!.register(UINib(nibName: "MealCategoryCell", bundle:Bundle.main), forCellWithReuseIdentifier: "cell")
self.collectionView!.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(self.collectionView!)
NSLayoutConstraint(item: collectionView , attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leadingMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailingMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .top, relatedBy: .equal, toItem: self, attribute: .topMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottomMargin, multiplier: 1.0, constant: 0.0).isActive = true
}
I started working on this App in Objective-C. Through some problems I had recently, I started using swift for some Features. Everything is working fine. Now I started building a new Feature and decided to do it in swift. I wrote the code in a Swift only Project, for testing. Everything is working fine in the test version, but when implementing it in my main Project I faced a Problem.
The Problem is that I set the view options in the delegate file like this:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let layout = UICollectionViewFlowLayout()
window?.rootViewController = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))
return true
}
But because my main Project delegate file is in Objective-C I dont know how to get this to work in my Swift file in the Objective-C Project. I tried setting the view in the viewDidLaunch file. But that doesnt work.
So i am asking myself if it is actually possible to set the code for my swift file in the Objective-C delegate method in objective-c. But for my Project I would like to set the view options inside the swift file. So this is what I tried so far:
import UIKit
class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var window: UIWindow?
override func viewDidLoad() {
super.viewDidLoad()
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let layout = UICollectionViewFlowLayout()
window?.rootViewController = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))
navigationItem.title = "Home"
collectionView?.backgroundColor = UIColor.white
collectionView?.register(VideoCell.self, forCellWithReuseIdentifier: "cellId")
}
//number of items
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
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: 200)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}
class VideoCell: UICollectionViewCell{
override init(frame:CGRect){
super.init(frame: frame)
setupViews()
}
let thumbnailImageView: UIImageView = {
let imageView = UIImageView()
imageView.backgroundColor = UIColor.blue
return imageView
}()
let userProfileImageView: UIImageView = {
let imageView = UIImageView ()
imageView.backgroundColor = UIColor.green
return imageView
}()
let separatorView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.black
return view
}()
let titleLabel: UILabel = {
let label = UILabel()
label.backgroundColor = UIColor.purple
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let subtitleTextView: UITextView = {
let textView = UITextView()
textView.backgroundColor = UIColor.red
textView.translatesAutoresizingMaskIntoConstraints = false
return textView
}()
func setupViews(){
addSubview(thumbnailImageView)
addSubview(separatorView)
addSubview(userProfileImageView)
addSubview(titleLabel)
addSubview(subtitleTextView)
//Abstand zum Bildschirmrand (Blau)
addConstraintsWithFormat(format: "H:|-16-[v0]-16-|", views: thumbnailImageView)
//Grün
addConstraintsWithFormat(format: "H:|-16-[v0(42)]", views: userProfileImageView)
//vertical constraints / v0 = Blau höhe / v1 = Grün höhe / v2 = Linie höhe
addConstraintsWithFormat(format: "V:|-32-[v0(75)]-8-[v1(44)]-16-[v2(1)]|", views: thumbnailImageView, userProfileImageView, separatorView)
//Abtrennung zwischen Zellen /zweite Zeile wird in "Große Fläche" umgesetzt
addConstraintsWithFormat(format: "H:|[v0]|", views: separatorView)
//top constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .top, relatedBy: .equal, toItem: thumbnailImageView, attribute: .bottom, multiplier: 1, constant: 8))
//left constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .left, relatedBy: .equal, toItem: userProfileImageView, attribute: .right, multiplier: 1, constant: 8))
//right constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .right, relatedBy: .equal, toItem: thumbnailImageView, attribute: .right, multiplier: 1, constant: 0))
//height constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 0, constant: 20))
//top constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .top, relatedBy: .equal, toItem: titleLabel, attribute: .bottom, multiplier: 1, constant: 4))
//left constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .left, relatedBy: .equal, toItem: userProfileImageView, attribute: .right, multiplier: 1, constant: 8))
//right constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .right, relatedBy: .equal, toItem: thumbnailImageView, attribute: .right, multiplier: 1, constant: 0))
//height constraint
addConstraint(NSLayoutConstraint(item: subtitleTextView, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 0, constant: 20))
thumbnailImageView.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension UIView {
func addConstraintsWithFormat(format: String, views: UIView...){
var viewsDictionary = [String: UIView]()
for (index, view) in views.enumerated(){
let key = "v\(index)"
view.translatesAutoresizingMaskIntoConstraints = false
viewsDictionary[key] = view
}
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutConstraint.FormatOptions(), metrics: nil, views: viewsDictionary))
}
}
In general to make swift classes available in objective-c.
Also helpful for me was another question/answer on stack.
But give a thought to fundamental changes:
it may be better, to create a new app in swift and connect to the old classes via the brindging header. The documentation is really helpful.
In future, it would be easier to add new elements in swift and use new functionallity.
It's simply not safe to do this from within viewDidLoad in a view controller, and you shouldn't even attempt it.
That's because it is possible for viewDidLoad to be executed multiple times.
If that happens, it's going to replace your window and rootViewController with new instances in the middle of your app's execution (looking to the user like the app has reset itself).
You need to initialize the window and root controller from the app delegate, there's no choice.
However, you can still write most of the code in Swift.
First, create a Swift extension on UIWindow that includes a class function which initialises and configures your window, then returns it. Make sure that extension is accessible by Objective-C by adding #objc to the declaration:
#objc extension UIWindow {
class func setRootHomeViewController() -> UIWindow {
let window = UIWindow(frame: UIScreen.main.bounds)
window.makeKeyAndVisible()
let layout = UICollectionViewFlowLayout()
window.rootViewController = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))
return window;
}
}
In your Objective-C app delegate, you then need to import your Swift header and call the new UIWindow class method that you've defined. Assign the returned window object to the app delegate's window property.
#import "YourProjectName-Swift.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
_window = [UIWindow setRootHomeViewController];
return YES;
}
#end
It's only one line of Objective-C code, but it's necessary as the app delegate is the only safe place to do this.
I'm trying to add customView into headerView of my collectionView. Here's my code:
I registed the headerView class in viewDidLoad:
collectionView.register(SearchReuseView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "reuseCell")
Then I setup the collectionView:
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
var reuseView: UICollectionReusableView?
if indexPath.section == 0 || banners.count == 0 {
let view = UICollectionReusableView(frame: CGRect.zero)
reuseView = view
} else {
if kind == UICollectionElementKindSectionHeader {
let view = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "reuseCell", for: indexPath) as! SearchReuseView
view.backgroundColor = .black
view.delegate = self
view.frame = CGRect(x: 0, y: 0, width: collectionView.frame.width, height: 100)
view.item = banners[indexPath.section % banners.count]
return view
}
}
return reuseView!
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
if section == 0 {
return CGSize.zero
}
return CGSize(width: collectionView.frame.width, height: 100)
}
But when I run on Simulator, the collectionView shows the header but nothing inside.
Here is code of SearchReuseView :
class SearchReuseView: UICollectionReusableView {
weak var delegate: SearchReuseDelegate?
let adImageView: UIImageView = {
let img = UIImageView()
img.translatesAutoresizingMaskIntoConstraints = false
img.contentMode = .scaleAspectFit
return img
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.setupViews()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
self.setupViews()
}
func setupViews() {
backgroundColor = .black
adImageView.isUserInteractionEnabled = true
adImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap)))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: self.adImageView, attribute: .bottom, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .right, relatedBy: .equal, toItem: self.adImageView, attribute: .right, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: self.adImageView, attribute: .top, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .left, relatedBy: .equal, toItem: self.adImageView, attribute: .left, multiplier: 1, constant: 0))
addSubview(adImageView)
}
var item: Banner! {
didSet {
guard let img = item.img else {return}
let url = URL(string: "\(img)")
self.adImageView.kf.setImage(with: url, placeholder: nil, options: [.transition(ImageTransition.fade(1))], progressBlock: { (receivedSize, totalSize) in
}) { (image, error, cacheType, imageURL) in
if error != nil {}
}
}
}
#objc func handleTap(){
guard let link = item.link else {
return
}
delegate?.didTapAds(link: link)
}
}
I wonder why your app is not crashing you should add subview first then add constraints to it
Replace your code with following code
func setupViews() {
backgroundColor = .black
addSubview(adImageView)
addSubview.translatesAutoresizingMaskIntoConstraints = false
adImageView.isUserInteractionEnabled = true
adImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap)))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: self.adImageView, attribute: .bottom, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .right, relatedBy: .equal, toItem: self.adImageView, attribute: .right, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: self.adImageView, attribute: .top, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .left, relatedBy: .equal, toItem: self.adImageView, attribute: .left, multiplier: 1, constant: 0))
}
Hope it is helpful
if kind == UICollectionElementKindSectionHeader {
let view = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "reuseCell", for: indexPath) as! SearchReuseView
view.backgroundColor = .black
view.delegate = self
view.frame = CGRect(x: 0, y: 0, width: collectionView.frame.width, height: 100) //delete this line
view.item = banners[indexPath.section % banners.count]
return view
}
I delete the line set frame for header view and it's works
After I run my app, it crashes:
Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view? That's illegal.
My image is subview of the cell.
What am I doing wrong?
let image = UIImageView(frame: CGRect(x: 0, y: 0, width: 300, height: 50))
image.image = UIImage.init(named: "Bitmap")
cell.contentView.addSubview(image)
let bottomConstr = NSLayoutConstraint(item: image, attribute: .bottom, relatedBy: .equal, toItem: cell.contentView, attribute: .bottom, multiplier: 1, constant: 0)
//let leftConstr = NSLayoutConstraint(item: image, attribute: .leading, relatedBy: .equal, toItem: cell.contentView, attribute: .leading, multiplier: 1, constant: 0)
//let rightConstr = NSLayoutConstraint(item: image, attribute: .trailing, relatedBy: .equal, toItem: cell.contentView, attribute: .trailing, multiplier: 1, constant: 0)
let heightConstr = NSLayoutConstraint(item: image, attribute: .height, relatedBy: .equal, toItem: nil , attribute: .notAnAttribute, multiplier: 1, constant: 10)
image.addConstraint(bottomConstr)
//image.addConstraint(leftConstr)
//image.addConstraint(rightConstr)
image.addConstraint(heightConstr)
You need to add constraint on Superview. so, add it on cell contentView.
cell.contentView.addConstraint(bottomConstr)
cell.contentView.addConstraint(heightConstr)
Constraints weren't working well for me when zooming UICollectionView. Here's how I resized a label to always fill the cell.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "mycell", for: indexPath as IndexPath) as! SliceCollectionViewCell
cell.label.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}
func collectionView(_ collectionView: UICollectionView,
willDisplay cell: UICollectionViewCell,
forItemAt indexPath: IndexPath) {
guard let cell = cell as? MyCollectionViewCell else {
print("ERROR: wrong cell type")
return
}
cell.label.frame = CGRect(x: 0, y: 0, width: cell.frame.width, height: cell.frame.height)
}
I think I have looked through a lot of questions like mine but nothing seems to work.
I am sending request to the server and in the moment I get all the data, I am starting to fill my ViewController programmatically. And all this happening in main_queue
This is the code of adding table:
if self.attachments.count > 0 {
docTableView = UITableView(frame: CGRect(x: 0.0, y: 0.0, width: self.myView.frame.width, height: 500.0), style: UITableViewStyle.Plain)
docTableView!.translatesAutoresizingMaskIntoConstraints = false
docTableView!.registerNib(UINib(nibName: "MenuCell", bundle: nil), forCellReuseIdentifier: "MenuCell")
self.myView.addSubview(docTableView!)
docTableView!.dataSource = self
docTableView!.delegate = self
self.myView.addConstraint(NSLayoutConstraint(item: docTableView!, attribute: .Top, relatedBy: .Equal, toItem: subviews!.last, attribute: .Bottom, multiplier: 1.0, constant: 5.0))
self.myView.addConstraint(NSLayoutConstraint(item: docTableView!, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
self.docTableView?.reloadData()
subviews?.append(docTableView!)
}
Then, I realized that two methods have been called : numberOfRowsInSection, heightForRowAtIndexPath and even the count of elements is greater than 0.
But cellForRowAtIndexPath is not being called and I guess that the reason that I do not see the tableView at all.
So how can I get to it?
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.docTableView {
return attachments.count
}
else {
return self.notificationViewModel!.comments.count
}
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 100.0 // I add this to show that its not zero
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if tableView == self.docTableView {
let object = attachments[indexPath.row]
UIApplication.sharedApplication().openURL(NSURL(string: object.Url!)!)
}
}
So commTableView is the same as docTableView. I need both of them and they have the same problem.
EDIT: I have this hierarchy: View->ScrollView->myView
EDIT2: My ViewController code. I have different types of data to add but all of it needs tables of attachments and comments
class NotificationViewController: UIViewController, MarkChosenDelegate, UITableViewDataSource, UITableViewDelegate {
//IBOutlets FROM STORYBOARD
#IBOutlet weak var myView: UIView!
#IBOutlet weak var headerStackView: UIStackView!
#IBOutlet weak var setMarkButton: UIButton!
#IBOutlet weak var placingWayCodeLabel: UILabel!
#IBOutlet weak var leftDaysLabel: UILabel!
#IBOutlet weak var typeLabel: UILabel!
#IBOutlet weak var regionLabel: UILabel!
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var notificationNameLabel: UILabel!
#IBOutlet weak var markColorButton: UIButton!
var docTableView:UITableView?
var commTableView:UITableView?
var delegate:NewMarkSetProtocol?
var notificationViewModel: NotificationViewModel?
var attachments:[Attachment] = []
//FIELDS FOR SEGUE TO THE CUSTOMER
var customerGuid:String?
var customerName:String?
var inn:String?
var kpp:String?
let marks = DataClass.sharedInstance.marks
var viewUtils:ViewUtils?
var notificationItem: NotificationT? {
didSet {
self.setUpTheHeaderInformation()
}
}
//VIEW CONTROLLER LIFE CYCLES METHODS
override func viewDidLoad() {
super.viewDidLoad()
self.setUpTheHeaderInformation()
viewUtils = ViewUtils()
viewUtils?.showActivityIndicator(self.view)
notificationViewModel = NotificationViewModel()
notificationViewModel?.delegateComments = self
notificationViewModel?.delegateInformation = self
if (notificationItem != nil) {
if UsefulClass.isConnectedToNetwork() == true {
notificationViewModel!.getNotification(notificationItem!)
notificationViewModel!.getComments((notificationItem?.NotificationGuid)!)
} else {
notificationViewModel!.getCoreNotification(notificationItem!)
}
}
print(setMarkButton)
}
func setUpTheHeaderInformation() {
if let notificationT = self.notificationItem {
self.navigationItem.title = notificationT.OrderName
self.notificationItem?.IsRead = true
if let label = self.notificationNameLabel {
label.text = notificationT.OrderName
self.placingWayCodeLabel.text = notificationT.getPlacingWayId()
self.leftDaysLabel.text = notificationT.getLeft()
self.typeLabel.text = notificationT.getType()
if (marks.count != 0) {
var mark:MarkClass?
for i in 0..<marks.count {
if (marks[i].Id == notificationT.MarkId) {
mark = marks[i]
}
}
if let _mark = mark {
self.setMarkButton.setTitle(String(_mark.Name!), forState: .Normal)
self.markColorButton.hidden = false
self.markColorButton.backgroundColor = UsefulClass.colorWithHexString(_mark.Color!)
} else {
self.markColorButton.hidden = true
}
}
if let code = notificationT.RegionCode {
self.regionLabel.text = UsefulClass.regionByRegionCode(code)
}
}
}
}
//TABLE VIEW
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let count:Int = 2
if tableView == self.docTableView {
print(attachments.count)
return attachments.count
}
if tableView == self.commTableView {
return self.notificationViewModel!.comments.count
}
return count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 100.0
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if tableView == self.docTableView {
let object = attachments[indexPath.row]
UIApplication.sharedApplication().openURL(NSURL(string: object.Url!)!)
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if tableView == self.docTableView {
let cell = tableView.dequeueReusableCellWithIdentifier("MenuCell", forIndexPath: indexPath) as! MenuCell
let object = attachments[indexPath.row]
let endIndex = object.FileName!.endIndex.advancedBy(-4)
let type:String = (object.FileName?.substringFromIndex(endIndex))!
cell.imageMark.image = notificationViewModel!.getImageForAttachment(type)
cell.name.text = object.FileName
cell.count.text = ""
return cell
} else {
let cell = tableView.dequeueReusableCellWithIdentifier("CommentItemCell", forIndexPath: indexPath) as! CommentTableViewCell
let object = self.notificationViewModel!.comments[indexPath.row]
if let name = object.getCreatorName() {
cell.nameUser.text = name
}
cell.textComment.text = object.Text
//cell.imageUser.image =
cell.timeComment.text = object.getTime()
return cell
}
}
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
if tableView == self.commTableView {
return true
} else {
return false
}
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
Requests.deleteComment(notificationViewModel!.comments[indexPath.row].Id!, notificationGuid: (self.notificationItem?.NotificationGuid)!)
notificationViewModel?.comments.removeAtIndex(indexPath.row)
self.commTableView!.reloadData()
} else {
}
}
extension String {
func heightWithConstrainedWidth(width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: CGFloat.max)
let boundingBox = self.boundingRectWithSize(constraintRect, options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
return boundingBox.height
}
}
extension NSAttributedString {
func heightWithConstrainedWidth(width: CGFloat) -> CGFloat {
let constraintRect = CGSize(width: width, height: CGFloat.max)
let boundingBox = self.boundingRectWithSize(constraintRect, options: NSStringDrawingOptions.UsesLineFragmentOrigin, context: nil)
return ceil(boundingBox.height)
}
func widthWithConstrainedHeight(height: CGFloat) -> CGFloat {
let constraintRect = CGSize(width: CGFloat.max, height: height)
let boundingBox = self.boundingRectWithSize(constraintRect, options: NSStringDrawingOptions.UsesLineFragmentOrigin, context: nil)
return ceil(boundingBox.width)
}
}
extension NotificationViewController:NotificationInformationUpdate {
func informationUpdate() {
var subviews:[UIView]? = [UIView]()
switch(notificationItem?.Type)! {
case 0:
let notification = notificationViewModel?.notification as! Notification_223
self.attachments = notification.attachments
if let name = notification.TenderPlanOrganisationName {
subviews = addTitleandValue("Заказчик", _value: name, _subviews: subviews!, numberOfLines: 0)
}
if let initialSum = notification.InitialSum {
subviews = addTitleandValue("Цена контракта", _value: initialSum, _subviews: subviews!, numberOfLines: 0)
} else if let maxPrice = notificationItem?.MaxPrice {
subviews = addTitleandValue("Цена контракта", _value: UsefulClass.getMaxPrice(maxPrice), _subviews: subviews!, numberOfLines: 0)
}
break
case 1:
let notification = notificationViewModel?.notification as! Notification_44
self.attachments = notification.attachments!
let customerNameTitle = UILabel()
customerNameTitle.text = "Заказчик:"
customerNameTitle.translatesAutoresizingMaskIntoConstraints = false
customerNameTitle.textColor = UIColor.grayColor()
setSimilarConstraintsToTitlesLabels(customerNameTitle, relatedView: self.headerStackView)
let customerName = UILabel()
customerName.text = notification.TenderPlanOrganisationName
customerName.textColor = UIColor.blueColor()
customerName.userInteractionEnabled = true
let tapGester = UITapGestureRecognizer(target: self, action: #selector(NotificationViewController.customerNameClick(_:)))
customerName.addGestureRecognizer(tapGester)
subviews = setSimilarConstraintsToValuesLabels(customerName, relatedView: customerNameTitle, _subViews: subviews!)
if let maxprice = notificationItem?.MaxPrice {
subviews = addTitleandValue("Цена контракта", _value: UsefulClass.getMaxPrice(maxprice), _subviews: subviews!, numberOfLines: 0)
}
break
case 2:
let notification = notificationViewModel?.notification as! B2BNotification
self.attachments = notification.attachments
subviews = addTitleandValue("Заказчик", _value: notification.TenderPlanOrganisationName!, _subviews: subviews!, numberOfLines: 0)
if let priceTotal = notification.PriceTotal {
var value = UsefulClass.getMaxPrice(priceTotal)
if let pricevat = notification.PriceVAT {
value.appendContentsOf(" (" + pricevat + ")")
}
subviews = addTitleandValue("Начальная цена всего лота", _value: value, _subviews: subviews!, numberOfLines: 0)
} else {
subviews = addTitleandValue("Начальная цена всего лота", _value: "Отсутствует поле", _subviews: subviews!, numberOfLines: 0)
}
if let priceone = notification.PriceOne {
subviews = addTitleandValue("Цена за единицу продукции", _value: UsefulClass.getMaxPrice(priceone), _subviews: subviews!, numberOfLines: 0)
}
break
case 7, 17:
let notification = notificationViewModel?.notification as! TakTorgNotification
self.attachments = notification.attachments
subviews = addTitleandValue("Наименование заказа", _value: notification.Subject!, _subviews: subviews!, numberOfLines: 0)
if let procNumber = notification.ProcedureProcedureNumber {
subviews = addTitleandValue("Номер закупки", _value: procNumber, _subviews: subviews!, numberOfLines: 0)
} else if let procNumber2 = notification.ProcedureProcedureNumber2 {
subviews = addTitleandValue("Номер закупки", _value: procNumber2, _subviews: subviews!, numberOfLines: 0)
}
if let startPrice = notification.StartPrice {
subviews = addTitleandValue("Начальная цена", _value: UsefulClass.getMaxPrice(startPrice), _subviews: subviews!, numberOfLines: 0)
}
if let peretorgPossible = notification.ProcedurePeretorgPossible {
subviews = addTitleandValue("Возможность проведения процедуры переторжки", _value: peretorgPossible, _subviews: subviews!, numberOfLines: 0)
}
if let negotiationPossible = notification.ProcedureNegotiationPossible {
subviews = addTitleandValue("Возможность проведения переговоров", _value: negotiationPossible, _subviews: subviews!, numberOfLines: 0)
}
//….
break
default:
break
}
let documentsTitle = UILabel()
documentsTitle.text = "Документы закупки"
documentsTitle.textColor = UIColor.blackColor()
documentsTitle.translatesAutoresizingMaskIntoConstraints = false
documentsTitle.font = documentsTitle.font.fontWithSize(18)
self.myView.addSubview(documentsTitle)
self.myView.addConstraint(NSLayoutConstraint(item: documentsTitle, attribute: .Top, relatedBy: .Equal, toItem: subviews!.last, attribute: .Bottom, multiplier: 1.0, constant: 12.0))
self.myView.addConstraint(NSLayoutConstraint(item: documentsTitle, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
subviews?.append(documentsTitle)
if self.attachments.count > 0 {
docTableView = UITableView()
docTableView!.translatesAutoresizingMaskIntoConstraints = false
docTableView!.registerNib(UINib(nibName: "MenuCell", bundle: nil), forCellReuseIdentifier: "MenuCell")
self.myView.addSubview(docTableView!)
docTableView!.dataSource = self
docTableView!.delegate = self
self.myView.addConstraint(NSLayoutConstraint(item: docTableView!, attribute: .Top, relatedBy: .Equal, toItem: subviews!.last, attribute: .Bottom, multiplier: 1.0, constant: 5.0))
self.myView.addConstraint(NSLayoutConstraint(item: docTableView!, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
self.myView.addConstraint(NSLayoutConstraint(item: docTableView!, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 300.0))
self.docTableView?.reloadData()
subviews?.append(docTableView!)
}
if notificationViewModel?.comments.count > 0 {
commTableView = UITableView()
commTableView?.translatesAutoresizingMaskIntoConstraints = false
commTableView!.registerNib(UINib(nibName: "CommentCell", bundle: nil), forCellReuseIdentifier: "CommentItemCell")
self.myView.addSubview(commTableView!)
self.myView.addConstraint(NSLayoutConstraint(item: commTableView!, attribute: .Top, relatedBy: .Equal, toItem: subviews!.last, attribute: .Bottom, multiplier: 1.0, constant: 5.0))
self.myView.addConstraint(NSLayoutConstraint(item: commTableView!, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
subviews?.append(commTableView!)
commTableView?.dataSource = self
commTableView?.delegate = self
}
//TITLE
let addCommentLabel = UILabel()
addCommentLabel.text = "Добавьте свой комментарий"
addCommentLabel.translatesAutoresizingMaskIntoConstraints = false
addCommentLabel.textColor = UIColor.lightGrayColor()
self.myView.addSubview(addCommentLabel)
self.myView.addConstraint(NSLayoutConstraint(item: addCommentLabel, attribute: .Top, relatedBy: .Equal, toItem: subviews!.last, attribute: .Bottom, multiplier: 1.0, constant: 10.0))
self.myView.addConstraint(NSLayoutConstraint(item: addCommentLabel, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
subviews?.append(addCommentLabel)
let textField = UITextField()
textField.translatesAutoresizingMaskIntoConstraints = false
textField.borderStyle = .RoundedRect
self.myView.addSubview(textField)
self.myView.addConstraint(NSLayoutConstraint(item: textField, attribute: .Top, relatedBy: .Equal, toItem: subviews!.last, attribute: .Bottom, multiplier: 1.0, constant: 5.0))
self.myView.addConstraint(NSLayoutConstraint(item: textField, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
self.myView.addConstraint(NSLayoutConstraint(item: textField, attribute: .Width, relatedBy: .Equal, toItem: self.myView, attribute: .Width, multiplier: 1.0, constant: -15))
subviews?.append(textField)
let sendButton = UIButton()
sendButton.setTitle("Отправить", forState: .Normal)
sendButton.translatesAutoresizingMaskIntoConstraints = false
sendButton.backgroundColor = UIColor.blueColor()
sendButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
self.myView.addSubview(sendButton)
self.myView.addConstraint(NSLayoutConstraint(item: sendButton, attribute: .Top, relatedBy: .Equal, toItem: subviews!.last, attribute: .Bottom, multiplier: 1.0, constant: 5.0))
self.myView.addConstraint(NSLayoutConstraint(item: textField, attribute: .Trailing, relatedBy: .Equal, toItem: textField, attribute: .Trailing, multiplier: 1.0, constant: 0))
subviews?.append(sendButton)
var height:CGFloat = 0.0
for i in 0..<self.myView.subviews.count {
height = height + myView.subviews[i].bounds.height
}
self.myView.frame = CGRect(x: 0, y: 0, width: self.myView.frame.width, height: self.myView.frame.height + height)
self.view.frame = CGRect(x: 0, y: 0, width: self.myView.frame.width, height: self.view.frame.height + height)
self.scrollView.frame = CGRect(x: 0, y: 0, width: self.myView.frame.width, height: self.scrollView.frame.height + height)
self.scrollView.contentSize = CGSize(width: self.myView.frame.width, height: self.scrollView.frame.height + height)
subviews = nil
self.viewUtils?.hideActivityIndicator(self.view)
}
func addPubDate(_subviews:[UIView], date:String, number:String) -> [UIView] {
var subviews = _subviews
let pubDateLabel = UILabel()
pubDateLabel.text = "Дата публикации: " + UsefulClass.covertDataWithZ(date, withTime: false)
pubDateLabel.translatesAutoresizingMaskIntoConstraints = false
pubDateLabel.textColor = UIColor.blackColor()
pubDateLabel.font = pubDateLabel.font.fontWithSize(11)
self.myView.addSubview(pubDateLabel)
self.myView.addConstraint(NSLayoutConstraint(item: pubDateLabel, attribute: .Top, relatedBy: .Equal, toItem: subviews.last, attribute: .Bottom, multiplier: 1.0, constant: 8.0))
self.myView.addConstraint(NSLayoutConstraint(item: pubDateLabel, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
subviews.append(pubDateLabel)
notificationUrlNumber(subviews, relatedView: pubDateLabel, number: number)
return subviews
}
func notificationUrlNumber(subviews:[UIView], relatedView:UILabel, number:String) {
let label = UILabel()
label.text = "Извещение №: " + number
label.textColor = UIColor.blueColor()
setSimilarConstraintsToValuesLabels(label, relatedView: relatedView, _subViews: subviews)
}
//левый заголовок для поля
func addtitle(_title:String, _subviews:[UIView]) -> [UIView] {
var subviews = _subviews
let title = UILabel()
title.text = _title
title.numberOfLines = 0
title.textColor = UIColor.blackColor()
title.translatesAutoresizingMaskIntoConstraints = false
title.font = title.font.fontWithSize(18)
self.myView.addSubview(title)
self.myView.addConstraint(NSLayoutConstraint(item: title, attribute: .Top, relatedBy: .Equal, toItem: subviews.last, attribute: .Bottom, multiplier: 1.0, constant: 12.0))
self.myView.addConstraint(NSLayoutConstraint(item: title, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
subviews.append(title)
return subviews
}
//правое значение для информационого поля
func addTitleandValue(_title:String, _value:String, _subviews:[UIView], numberOfLines:Int) -> [UIView] {
var subviews = _subviews
let title = UILabel()
title.text = _title
title.font = title.font.fontWithSize(12)
if subviews.count > 0 {
setSimilarConstraintsToTitlesLabels(title, relatedView: (subviews.last!))
} else {
setSimilarConstraintsToTitlesLabels(title, relatedView: self.headerStackView)
}
let value = UILabel()
value.text = _value
value.numberOfLines = numberOfLines
value.font = value.font.fontWithSize(12)
subviews = setSimilarConstraintsToValuesLabels(value, relatedView: title, _subViews: subviews)
return subviews
}
func addBoolEptrfValues(_title:String, _subviews:[UIView])->[UIView] {
var subviews = _subviews
let title = UILabel()
title.text = _title
title.numberOfLines = 0
setSimilarConstraintsToTitlesLabels(title, relatedView: (subviews.last!))
let value = UILabel()
value.text = notificationViewModel?.convertBoolToString(true)
value.textColor = UIColor.blackColor()
subviews = setSimilarConstraintsToValuesLabels(value, relatedView: title, _subViews: subviews)
return subviews
}
func addDeleteButton(subviews:[UIView], isDeleted:Bool) -> UILabel {
let deleteLabel = UILabel()
if isDeleted == false {
deleteLabel.text = "Удалить"
} else {
deleteLabel.text = "Восстановить"
}
deleteLabel.translatesAutoresizingMaskIntoConstraints = false
deleteLabel.textColor = UIColor.blueColor()
deleteLabel.font = deleteLabel.font.fontWithSize(11)
self.myView.addSubview(deleteLabel)
self.myView.addConstraint(NSLayoutConstraint(item: deleteLabel, attribute: .Top, relatedBy: .Equal, toItem: subviews.last, attribute: .Bottom, multiplier: 1.0, constant: 8.0))
self.myView.addConstraint(NSLayoutConstraint(item: deleteLabel, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
return deleteLabel
}
//right values next to the title
func setSimilarConstraintsToValuesLabels(subView:UILabel, relatedView:UILabel, _subViews:[UIView]) -> [UIView] {
var subViews = _subViews
subView.translatesAutoresizingMaskIntoConstraints = false
self.myView.addSubview(subView)
if (relatedView.text?.characters.count < 35 && subView.text?.characters.count < 30) {
self.myView.addConstraint(NSLayoutConstraint(item: subView, attribute: .Right, relatedBy: .Equal, toItem: self.myView, attribute: .Right, multiplier: 1.0, constant: -15))
self.myView.addConstraint(NSLayoutConstraint(item: subView, attribute: .Left, relatedBy: .Equal, toItem: relatedView, attribute: .Right, multiplier: 1.0, constant: 5))
self.myView.addConstraint(NSLayoutConstraint(item: subView, attribute: .FirstBaseline, relatedBy: .Equal, toItem: relatedView, attribute: .LastBaseline, multiplier: 1.0, constant: 0))
} else {
self.myView.addConstraint(NSLayoutConstraint(item: subView, attribute: .Top, relatedBy: .Equal, toItem: relatedView, attribute: .Bottom, multiplier: 1.0, constant: 8.0))
self.myView.addConstraint(NSLayoutConstraint(item: subView, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 8.0))
self.myView.addConstraint(NSLayoutConstraint(item: subView, attribute: .Width, relatedBy: .Equal, toItem: self.myView, attribute: .Width, multiplier: 1.0, constant: -15))
self.myView.addConstraint(NSLayoutConstraint(item: relatedView, attribute: .Width, relatedBy: .Equal, toItem: self.myView, attribute: .Width, multiplier: 1.0, constant: -15))
subViews.append(relatedView)
}
subViews.append(subView)
return subViews
}
func setSimilarConstraintsToTitlesLabels(subView:UILabel, relatedView:UIView) {
subView.translatesAutoresizingMaskIntoConstraints = false
subView.textColor = UIColor.grayColor()
subView.numberOfLines = 0
self.myView.addSubview(subView)
self.myView.addConstraint(NSLayoutConstraint(item: subView, attribute: .Top, relatedBy: .Equal, toItem: relatedView, attribute: .Bottom, multiplier: 1.0, constant: 8.0))
self.myView.addConstraint(NSLayoutConstraint(item: subView, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
}
}
The method "informationUpdate()" is called when information for showing is parsed.
Your tableView has no height Constraint, so the height is set to 0.
Then no cell are visible => cellForRow never called :)
I think you should try to create more clear code. Do not use "blind" array of subviews; do not append views directly to subviews property, you already added it to view hierarchy; if you use autolayout (translatesAutoresizingMaskIntoConstraints = false) - don't try mix it with frames in single view, go and set up all constraints; use different background colors for different views to debug view hierarchy at runtime; go to Xcode Debug\View Debugging\Capture View Hierarchy for deep explore view hierarchy at runtime
Also, if numberOfRowsInSection did called by UITableView and return value > 0 (check it!), then cellForRowAtIndexPath must be called immediately by this UITableView since dataSource property is set. If you have more than one UITableView objects - check if there is no unexpected replaces.
P.S. if you from Russia I can help on Russian lang