UICollectionViewCell size larger the UICollectionView size - swift

I'm having the following runtime error: the item height must be less than the height of the UICollectionView minus the section insets top and bottom values, minus the content insets top and bottom values.
This started occuring after a implemented, insize my custom UICollectionViewCell a UISearchBar item. When I click in it the keyboard shows up and the cell are half slided to the top.,
These are my relevant code:
class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
func setupCollectionView() {
if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.scrollDirection = .horizontal
flowLayout.minimumLineSpacing = 0
flowLayout.invalidateLayout()
}
collectionView?.backgroundColor = UIColor.white
collectionView?.register(FeedCell.self, forCellWithReuseIdentifier: cellId)
collectionView?.register(TrendingCell.self, forCellWithReuseIdentifier: trendingCellId)
collectionView?.register(SubscriptionCell.self, forCellWithReuseIdentifier: subscriptionCellId)
collectionView?.register(MapCell.self, forCellWithReuseIdentifier: mapCellId)
collectionView?.register(AccountCell.self, forCellWithReuseIdentifier: accountCellId)
collectionView?.contentInset = UIEdgeInsetsMake(0, 0, 50, 0)
collectionView?.scrollIndicatorInsets = UIEdgeInsetsMake(0, 0, 50, 0)
collectionView?.isPagingEnabled = true
view.addSubview(menuBar)
view.addConstraintsWithFormat(format: "H:|[v0]|", views: menuBar)
view.addConstraintsWithFormat(format: "V:[v0(50)]", views: menuBar)
menuBar.bottomAnchor.constraint(equalTo: (collectionView?.bottomAnchor)!).isActive = true
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: view.frame.height - 50)
}
}
class MapCell: UICollectionViewCell{
let topContainer: TopContainerView = {
let v = TopContainerView()
return v
}()
override func setupViews() {
super.setupViews()
backgroundColor = .brown
topContainer.setupView()
addSubview(topContainer)
addConstraintsWithFormat(format: "V:[v0(40)]", views: topContainer)
addConstraintsWithFormat(format: "H:|[v0]|", views: topContainer)
addConstraint(NSLayoutConstraint(item: topContainer, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0))
addConstraint(NSLayoutConstraint(item: topContainer, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1, constant: 0))
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.endEditing(true)
}}
class TopContainerView: UIView {
func setupView(){
backgroundColor = .yellow
addSubview(searchField)
addConstraintsWithFormat(format: "V:|[v0]|", views: searchField)
addConstraintsWithFormat(format: "H:|[v0]-40-|", views: searchField)
addConstraint(NSLayoutConstraint(item: searchField, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 5))
addConstraint(NSLayoutConstraint(item: searchField, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1, constant: 5))
}
let searchField: UISearchBar = {
let sf = UISearchBar()
sf.placeholder = "Search"
return sf
}()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.endEditing(true)
}}
Does any one have any ideia?

Related

Text Cursor out of view when typing

I have multiple PDFKit annotations added into my PDF Document. When the user selects the text annotations to add text, the keyboard appears and the document scrolls upward and the cursor is no long on the screen. I have tried treating the PDF Document as a textfield but that does not work. How can I keep the cursor on screen or centered above the keyboard when the user adds text on the PDF Annotation?
Here is my code:
import UIKit
import PDFKit
class PDFfun: UIViewController {
var pdfView = PDFView()
var textFieldMultiline3 = PDFAnnotation()
let document = PDFDocument(url: Bundle.main.url(forResource: "DOCUMENT", withExtension: "pdf")!)
override func viewDidLoad() {
super.viewDidLoad()
pdfView = PDFView(frame: self.view.frame)
pdfView.document = document
pdfView.autoScales = true
pdfView.backgroundColor = UIColor.lightGray
self.insertMultilineTextBoxIntoOneOneNine(document!.page(at: 119)!)
pdfView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(pdfView)
view.addConstraints([
NSLayoutConstraint(item: pdfView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0),
NSLayoutConstraint(item: pdfView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0),
NSLayoutConstraint(item: pdfView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0),
NSLayoutConstraint(item: pdfView, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0)
])
}
func insertMultilineTextBoxIntoOneOneNine(_ page: PDFPage) {
_ = page.bounds(for: .cropBox)
let textFieldMultilineBounds3 = CGRect(x: 27, y: 50, width: 339, height: 510)
textFieldMultiline3 = PDFAnnotation(bounds: textFieldMultilineBounds3, forType: PDFAnnotationSubtype(rawValue: PDFAnnotationSubtype.widget.rawValue), withProperties: nil)
textFieldMultiline3.widgetFieldType = PDFAnnotationWidgetSubtype(rawValue: PDFAnnotationWidgetSubtype.text.rawValue)
textFieldMultiline3.backgroundColor = UIColor.white.withAlphaComponent(1)
textFieldMultiline3.font = UIFont(name: "Arial", size: 15)
textFieldMultiline3.isMultiline = true
page.addAnnotation(textFieldMultiline3)
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
if UIDevice.current.orientation.isLandscape {
print("landscape")
pdfView = PDFView(frame: view.frame)
pdfView.autoScales = true
} else {
print("portait")
pdfView = PDFView(frame: view.frame)
pdfView.autoScales = true
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
pdfView.frame = view.frame
}
override var prefersStatusBarHidden: Bool {
return false
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}

Programmatically created NSCollectionView `makeItem` returns nil even if registered

I am developing a macOS app targeting macOS 10.10 SDK and using Xcode 9.3 (Swift 4). I am not using xibs, but creating all views programmatically.
I want to create a NSCollectionView. I register a subclass of NSCollectionViewItem and then register that class to the NSCollectionView with a call to collectionView.register(:,forItemWithIdentifier). Later, in the data source, I call collectionView.makeItem(withIdentifier:,for:).
However the makeItem method always returns nil. What am I doing wrong?
I found a similar question but the solution is to call register, which I already do.
For reference, here's the minimum working to reproduce my the issue: when I put a breakpoint after the call to makeItem, I can see that the returned value is always nil.
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
window.contentViewController = TestViewController()
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
}
let cellIdentifier = NSUserInterfaceItemIdentifier(rawValue: "testIdentifier")
class TestViewController: NSViewController, NSCollectionViewDataSource {
override func loadView() {
self.view = NSView()
}
override func viewDidLoad() {
let scroll = NSScrollView()
self.view.addSubview(scroll)
scroll.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint(item: scroll, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: scroll, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: scroll, attribute: .left, relatedBy: .equal, toItem: self.view, attribute: .left, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: scroll, attribute: .right, relatedBy: .equal, toItem: self.view, attribute: .right, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: scroll, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 500).isActive = true
NSLayoutConstraint(item: scroll, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 500).isActive = true
let collection = NSCollectionView()
scroll.documentView = collection
collection.register(TestViewItem.self, forItemWithIdentifier: cellIdentifier)
collection.dataSource = self
collection.collectionViewLayout = NSCollectionViewFlowLayout()
collection.reloadData()
}
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
let item = collectionView.makeItem(withIdentifier: cellIdentifier, for: indexPath)
return item
}
}
class TestViewItem: NSCollectionViewItem {
override func loadView() {
self.view = NSView()
}
}
I think this is a bug. Workaround: set collectionViewLayout before registering the class.
Apparently the registered class is not stored if collectionViewLayout is not set. collectionViewLayout can be set to a new layout after registering the class, the registered class isn't removed.

Aligning UIImageView to the left and right programmatically in Swift

I'm working on a chat app with message bubbles. I've figured out how to get the messages conditionally formatted (color, size, etc.) based on who sent the message; however I'm having difficulty getting the chat bubbles to align to the left or right side of the view controller. Right now all items are aligned to the left. I've searched through SO and was unable to find an answer so I decided to ask.
UPDATED: Showing remaining code of setCell function which determines the format of the message based on the value of 'incoming'. Also include tableView function to show cell configuration. The last function is the setup function.
func setCell(cell: ConversationCell, incoming: [Int], indexPath: IndexPath) {
var layoutAttribute: NSLayoutAttribute
var layoutConstant: CGFloat
var smavalayoutConstant: CGFloat
for i in 0 ..< self.incoming.count {
if (self.incoming[indexPath.row] == 1) {
cell.bubbleImageView.image=#imageLiteral(resourceName: "chat_bubble_received")
cell.messageLbl.textColor = UIColor.black
cell.messageLbl.textAlignment = .left
cell.messageLbl?.numberOfLines = 0
cell.messageLbl?.lineBreakMode = .byWordWrapping
layoutAttribute = .left
layoutConstant = 0
cell.contentView.addConstraint(NSLayoutConstraint(item: cell.bubbleImageView, attribute: .left, relatedBy: .equal, toItem: cell.contentView, attribute: layoutAttribute, multiplier: 1, constant: layoutConstant))
cell.contentView.addConstraint(NSLayoutConstraint(item: cell.smavaImg, attribute: .left, relatedBy: .equal, toItem: cell.contentView, attribute: layoutAttribute, multiplier: 1, constant: layoutConstant))
cell.contentView.addConstraint(NSLayoutConstraint(item: cell.postpictureImg, attribute: .left, relatedBy: .equal, toItem: cell.contentView, attribute: layoutAttribute, multiplier: 1, constant: layoutConstant))
}
if (self.incoming[indexPath.row] == 0) {
cell.bubbleImageView.image = #imageLiteral(resourceName: "chat_bubble_sent")
cell.messageLbl.textColor = UIColor.white
cell.messageLbl.textAlignment = .right
layoutAttribute = .right
layoutConstant = -100
smavalayoutConstant = 300
cell.contentView.addConstraint(NSLayoutConstraint(item: cell.bubbleImageView, attribute: .leftMargin, relatedBy: .lessThanOrEqual, toItem: cell.contentView, attribute: layoutAttribute, multiplier: 1, constant: layoutConstant))
cell.contentView.addConstraint(NSLayoutConstraint(item: cell.bubbleImageView, attribute: .right, relatedBy: .equal, toItem: cell.contentView, attribute: layoutAttribute, multiplier: 1, constant: layoutConstant))
cell.contentView.addConstraint(NSLayoutConstraint(item: cell.smavaImg, attribute: .right, relatedBy: .equal, toItem: cell.smavaImg, attribute: layoutAttribute, multiplier: 1, constant: smavalayoutConstant))
cell.contentView.addConstraint(NSLayoutConstraint(item: cell.smavaImg, attribute: .left, relatedBy: .equal, toItem: cell.smavaImg, attribute: .left, multiplier: 1, constant: 300))
}
}
}
//cell config
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ConversationCell
// shortcuts
let hhpost = hhmessages[indexPath.row]
let image = avas[indexPath.row]
let smimages = images[indexPath.row]
let messagetext = hhpost["messagetext"] as? String
let date = hhpost["date"] as? String
cell.messageLbl.text = messagetext
cell.dateLbl.text = date
cell.smavaImg.image = image
cell.postpictureImg.image = smimages
DispatchQueue.main.async {
tableView.transform = CGAffineTransform(rotationAngle: -CGFloat.pi)
cell.transform = CGAffineTransform(rotationAngle: CGFloat.pi)
self.setCell(cell: cell, incoming: self.incoming, indexPath: indexPath)
}
return cell
}
public func setup() {
bubbleImageView = UIImageView(image: #imageLiteral(resourceName: "chat_bubble_sent"), highlightedImage: #imageLiteral(resourceName: "chat_bubble_sent"))
bubbleImageView.isUserInteractionEnabled = true
messageLbl = UILabel(frame: CGRect.zero)
messageLbl.font = UIFont.systemFont(ofSize: 15)
messageLbl.numberOfLines = 0
messageLbl.isUserInteractionEnabled = true
selectionStyle = .none
contentView.addSubview(bubbleImageView)
contentView.addSubview(smavaImg)
bubbleImageView.addSubview(messageLbl)
messageLbl.translatesAutoresizingMaskIntoConstraints = false
bubbleImageView.translatesAutoresizingMaskIntoConstraints = false
contentView.addConstraint(NSLayoutConstraint(item: bubbleImageView, attribute: .left, relatedBy: .equal, toItem: contentView, attribute: .left, multiplier: 1, constant: 10))
contentView.addConstraint(NSLayoutConstraint(item: bubbleImageView, attribute: .top, relatedBy: .equal, toItem: contentView, attribute: .top, multiplier: 1, constant: 4.5))
bubbleImageView.addConstraint(NSLayoutConstraint(item: bubbleImageView, attribute: .width, relatedBy: .equal, toItem: messageLbl, attribute: .width, multiplier: 1, constant: 30))
contentView.addConstraint(NSLayoutConstraint(item: bubbleImageView, attribute: .bottom, relatedBy: .equal, toItem: contentView, attribute: .bottom, multiplier: 1, constant: -4.5))
bubbleImageView.addConstraint(NSLayoutConstraint(item: messageLbl, attribute: .centerX, relatedBy: .equal, toItem: bubbleImageView, attribute: .centerX, multiplier: 1, constant: -2))
bubbleImageView.addConstraint(NSLayoutConstraint(item: messageLbl, attribute: .centerY, relatedBy: .equal, toItem: bubbleImageView, attribute: .centerY, multiplier: 1, constant: -0.5))
messageLbl.preferredMaxLayoutWidth = 218
bubbleImageView.addConstraint(NSLayoutConstraint(item: messageLbl, attribute: .height, relatedBy: .equal, toItem: bubbleImageView, attribute: .height, multiplier: 1, constant: -15))
contentView.addConstraint(NSLayoutConstraint(item: smavaImg, attribute: .centerX, relatedBy: .equal, toItem: smavaImg, attribute: .centerX, multiplier: 1, constant: -2))
contentView.addConstraint(NSLayoutConstraint(item: smavaImg, attribute: .centerY, relatedBy: .equal, toItem: smavaImg, attribute: .centerY, multiplier: 1, constant: -0.5))
}
Take a look in my git hub project in your Playground
// Maximo Lucosi: https://github.com/lucosi/ChatTableView
You can create your tableViewCell with all constraints and change the constraints inside the cell.
Open the project in your Playgournd > View > Assistant Editor > Show Assistant Editor
class MyViewController: UIViewController {
// Messages for test
var messages: [Message] = []
// Table View here + basic configuration
lazy var tableView: UITableView = {
let view = UITableView()
view.translatesAutoresizingMaskIntoConstraints = false
view.delegate = self
view.dataSource = self
view.backgroundColor = .white
view.separatorStyle = .none
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
// Set the screen size befor implement layour. NOTICE: Only for playground test
self.view.frame = frame
// Messages for test //
self.messages.append(Message.init(message: "I'm working on a chat app with message bubbles.",
image: UIImage.init(),
incoming: 0))
self.messages.append(Message.init(message: "What is your dificulte.",
image: UIImage(),
incoming: 1))
self.messages.append(Message.init(message: "I'm having difficulty getting the chat bubbles to align to the left or right side of the view controller.",
image: UIImage.init(),
incoming: 0))
self.messages.append(Message.init(message: "One more for me",
image: UIImage(),
incoming: 1))
self.messages.append(Message.init(message: "I have already implemented a function that redraws UILabels with a passed ratio. So all I need to find is the text in UILabel from my view that would require the maximum ratio to redraw UILabels. So finally I need to do something like this:",
image: UIImage(), incoming: 1))
// End //
// Add the tableView
self.view.addSubview(tableView)
// Register teh cell in the tableView
self.tableView.register(ConversationCell.self, forCellReuseIdentifier: cellId)
// Criate a contraint for the table view
NSLayoutConstraint.activate(
[
tableView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 44),
tableView.leftAnchor.constraint(equalTo: self.view.leftAnchor),
tableView.rightAnchor.constraint(equalTo: self.view.rightAnchor),
tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor)
]
)
}
}
extension String {
//* Calculeta the hight string Function
func calculateTextFrameRect(
objectsInPlaceHeight: CGFloat,
objectsInPlaceWidth: CGFloat,
fontSize: CGFloat,
fontWeight: CGFloat) -> CGSize
{
let bounding = CGSize(width: UIScreen.main.bounds.width - objectsInPlaceWidth, height: .infinity)
let rect = NSString(string: self).boundingRect(
with: bounding,
options: NSStringDrawingOptions.usesFontLeading.union(NSStringDrawingOptions.usesLineFragmentOrigin),
attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: fontSize, weight: UIFont.Weight(rawValue: fontWeight))],
context: nil)
return CGSize(width: UIScreen.main.bounds.width, height: rect.height + objectsInPlaceHeight )
}
}
// Conform table view with delegate and data source
extension MyViewController: UITableViewDelegate, UITableViewDataSource {
// Change the hight of the cell
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// Calculate the hight of the cell
let text = self.messages[indexPath.item].message
let frameSize = text.calculateTextFrameRect(
objectsInPlaceHeight: 44 + 10,
objectsInPlaceWidth: 20 + 44 + 20 + self.view.frame.width * 0.4,
fontSize: UIFont.preferredFont(forTextStyle: UIFontTextStyle.body).pointSize,
fontWeight: UIFont.Weight.medium.rawValue)
return frameSize.height
}
// Number os cells
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.messages.count
}
// Return cell to display on the tableView
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! ConversationCell
cell.messageData = self.messages[indexPath.item]
return cell
}
}
//****** Custom cell class ******///
class ConversationCell: UITableViewCell {
var messageData: Message? {
didSet {
// Umrap the value incide the cell
if let message = messageData {
// Confiture the constraints for cell
if message.incoming == 0 {
// Text
self.messageTextView.textAlignment = .left
self.bubleImage.backgroundColor = .orange
// Constraints
self.lefBubleConstraint.isActive = true
self.rightBubleConstraint.isActive = false
} else {
// Text
self.messageTextView.textAlignment = .right
self.bubleImage.backgroundColor = .blue
// Constraints
self.lefBubleConstraint.isActive = false
self.rightBubleConstraint.isActive = true
}
if lefBubleConstraint.isActive == true {
self.leftMessageLable.isActive = true
self.rightMessageLable.isActive = false
} else {
self.leftMessageLable.isActive = false
self.rightMessageLable.isActive = true
}
// Set the data
self.messageTextView.text = message.message
self.bubleImage.image = message.image
}
}
}
// Create and config the image
let bubleImage: UIImageView = {
let view = UIImageView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .blue
view.layer.cornerRadius = 22
view.layer.masksToBounds = true
return view
}()
// Create and config the lable for the text
let messageTextView: UITextView = {
let view = UITextView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5)
view.layer.cornerRadius = 10
view.textContainerInset = UIEdgeInsetsMake(5, 5, 5, 5)
view.isUserInteractionEnabled = false
return view
}()
// Constraints for configuration on didSet data
var lefBubleConstraint: NSLayoutConstraint!
var rightBubleConstraint: NSLayoutConstraint!
var leftMessageLable: NSLayoutConstraint!
var rightMessageLable: NSLayoutConstraint!
// Init the cell with local congiguration
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: nil)
self.addSubview(bubleImage)
self.addSubview(messageTextView)
// Permanent constraints
NSLayoutConstraint.activate(
[
self.bubleImage.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -10),
self.bubleImage.heightAnchor.constraint(equalToConstant: 44),
self.bubleImage.widthAnchor.constraint(equalToConstant: 44),
self.messageTextView.topAnchor.constraint(equalTo: self.topAnchor, constant: 10),
self.messageTextView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -10),
// NOTICE: Use the frame with as parameter for mesure the hight of cell on the main view
self.messageTextView.widthAnchor.constraint(equalToConstant: self.frame.width * 0.7)
]
)
// Buble constraint for configuration
self.lefBubleConstraint = self.bubleImage.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 10)
self.rightBubleConstraint = self.bubleImage.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -10)
// Message constrait for congiguration
self.rightMessageLable = self.messageTextView.rightAnchor.constraint(equalTo: self.bubleImage.leftAnchor, constant: -10)
self.leftMessageLable = self.messageTextView.leftAnchor.constraint(equalTo: self.bubleImage.rightAnchor, constant: 10)
}
// requerid init
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

CollectionView delegate error

I have made a collection view programmatically but when set collectionView.delegate = self and collectionView.dataSource = self I get a nil while unwrapping an optional. I don't know what I did wrong here.
class MainFeedViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, UICollectionViewDelegate, UIViewControllerTransitioningDelegate, UIGestureRecognizerDelegate, MyCollectionCell {
let transition = CircularAnimation()
var collectionView: UICollectionView!
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapEdit(recognizer:)))
func MyCollectionCell() {
let vc = DescriptionViewController()
self.present(vc, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.isHidden = true
collectionView.delegate = self
collectionView.dataSource = self
view.backgroundColor = .white
UIApplication.shared.isStatusBarHidden = false
UIApplication.shared.statusBarStyle = .default
view.addSubview(Settings)
view.addSubview(topBar)
view.addSubview(separatorView)
view.addSubview(separatorView2)
Settings.translatesAutoresizingMaskIntoConstraints = false
Settings.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 15).isActive = true
Settings.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
Settings.widthAnchor.constraint(equalToConstant: 50).isActive = true
Settings.heightAnchor.constraint(equalToConstant: 50).isActive = true
separatorView.translatesAutoresizingMaskIntoConstraints = false
separatorView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 40).isActive = true
separatorView.heightAnchor.constraint(equalToConstant: 1).isActive = true
view.addConstraint(NSLayoutConstraint(item: separatorView, attribute: .left, relatedBy: .equal, toItem: Settings, attribute: .right, multiplier: 1, constant: 15))
view.addConstraint(NSLayoutConstraint(item: separatorView, attribute: .right, relatedBy: .equal, toItem: topBar, attribute: .right, multiplier: 1, constant: 0))
separatorView2.translatesAutoresizingMaskIntoConstraints = false
separatorView2.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 40).isActive = true
separatorView2.heightAnchor.constraint(equalToConstant: 1).isActive = true
view.addConstraint(NSLayoutConstraint(item: separatorView2, attribute: .right, relatedBy: .equal, toItem: Settings, attribute: .left, multiplier: 1, constant: -15))
view.addConstraint(NSLayoutConstraint(item: separatorView2, attribute: .left, relatedBy: .equal, toItem: topBar, attribute: .left, multiplier: 1, constant: 0))
topBar.translatesAutoresizingMaskIntoConstraints = false
topBar.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
topBar.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
topBar.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
view.addConstraint(NSLayoutConstraint(item: topBar, attribute: .bottom, relatedBy: .equal, toItem: separatorView, attribute: .top, multiplier: 1, constant: 0))
view.insertSubview(topBar, belowSubview: Settings)
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
let height = (view.frame.width - 16 - 16) * 9/16
layout.sectionInset = UIEdgeInsets(top: 80, left: 0, bottom: 0, right: 0)
layout.itemSize = CGSize(width: view.frame.width, height: height + 16 + 80)
collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
collectionView?.scrollIndicatorInsets = UIEdgeInsetsMake(80, 0, 0, 0)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(Cell.self, forCellWithReuseIdentifier: "cellId")
collectionView.backgroundColor = UIColor.clear
collectionView.addGestureRecognizer(tapGesture)
tapGesture.delegate = self
self.view.addSubview(collectionView)
view.insertSubview(collectionView, belowSubview: topBar)
}
let Settings : UIButton = {
let btn = UIButton()
btn.setTitle("Clotho", for: .normal)
btn.setTitleColor(.white, for: .normal)
btn.layer.cornerRadius = 25
btn.backgroundColor = UIColor.rgb(displayP3Red: 255, green: 165, blue: 0)
btn.titleLabel?.font = UIFont(name: "Pacifico-Regular", size: 16)
btn.addTarget(self, action:#selector(settingsTab), for: .touchUpInside)
return btn
}()
let topBar: UIView = {
let bar = UIView()
bar.backgroundColor = .white
return bar
}()
let separatorView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.rgb(displayP3Red: 211, green: 211, blue: 211)
return view
}()
let separatorView2: UIView = {
let view2 = UIView()
view2.backgroundColor = UIColor.rgb(displayP3Red: 211, green: 211, blue: 211)
return view2
}()
#objc func tapEdit(recognizer: UITapGestureRecognizer) {
if recognizer.state == UIGestureRecognizerState.ended {
let tapLocation = recognizer.location(in: self.collectionView)
if let tapIndexPath = self.collectionView.indexPathForItem(at: tapLocation) {
if (self.collectionView.cellForItem(at: tapIndexPath) as? Cell) != nil {
//do what you want to cell here
}
}
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! Cell
cell.Delegate = self
return cell
}
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
transition.transitionMode = .present
transition.startingPoint = Settings.center
transition.circleColor = Settings.backgroundColor!
return transition
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
transition.transitionMode = .dismiss
transition.startingPoint = Settings.center
transition.circleColor = Settings.backgroundColor!
return transition
}
#objc func settingsTab(){
let secondVC = SettingsViewController()
secondVC.transitioningDelegate = self
secondVC.modalPresentationStyle = UIModalPresentationStyle.custom
self.present(secondVC, animated: true, completion: nil)
}
}
I set a var Delegate: MyCollectionCell? in my cell with a protocol
import UIKit
protocol MyCollectionCell {
func MyCollectionCell()
}
class Cell: UICollectionViewCell {
var Delegate: MyCollectionCell?
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
let TapGesture = UITapGestureRecognizer(target: self, action: #selector(Cell.tapEdit(sender:)))
addGestureRecognizer(TapGesture)
TapGesture.delegate = MainFeedViewController()
}
//other setup code...
#objc func tapEdit(sender: UITapGestureRecognizer) {
Delegate?.MyCollectionCell()
}
You haven't actually created the collection view anywhere.
This line:
var collectionView: UICollectionView!
creates a variable ready to hold the collection view (and the ! character indicates you should populate the variable in the viewDidLoad method) but you don't actually create the instance of the UICollectionView and assign it to that variable.
So when you try to set the delegate and data source the collection view variable is still nil and hence you get an error.
You need to actually create the instance of a UICollectionView which is also going to involve creating an instance of a UICollectionViewLayout (or a subclass of it like UICollectionViewFlowLayout).
At the most basic level you should do something like this:
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: 100, height: 100)
collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: 500, height: 500), collectionViewLayout: layout)
although of course you should adjust the frame and the parameters of the layout to suit your usage requirements.

How do I send subviews to front programmatically? (have tried bringSubview to front)

In my UICollectionViewCell I have an image and a label. The picture takes up the whole cell (which I want) - however, the label is placed behind the image, so it's not visible. I have tried bringSubview(toFront: titleLabel), but nothing happens... I got no clue what to do really, have done a lot of searching.
This is the code for the cell, I don't use Storyboard as you can see (sorry for messy constraints, was testing different solutions to find out if this was the problem)
import UIKit
class BaseCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
setupBasket()
}
func setupViews() {
}
func setupBasket(){
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class VideoCell: BaseCell {
var selectedItemID : String!
static let sharedInstance = VideoCell()
var video: Video? {
didSet {
titleLabel.text = video?.title
setupThumbnailImage()
}
}
func setupThumbnailImage() {
if let thumbnailImageUrl = video?.thumbnail_image_name {
thumbnailImageView.loadImageUsingUrlString(thumbnailImageUrl)
}
}
let thumbnailImageView: CustomImageView = {
let imageView = CustomImageView()
imageView.image = UIImage(named: "taylor_swift_blank_space")
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
return imageView
}()
let titleLabel: UILabel = {
let textView = UILabel()
textView.translatesAutoresizingMaskIntoConstraints = false
textView.text = "Clothes"
textView.textColor = UIColor.lightGray
return textView
}()
let separatorView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(red: 230/255, green: 230/255, blue: 230/255, alpha: 1)
return view
}()
var titleLabelHeightConstraint: NSLayoutConstraint?
let addtoBasket = UIButton(type: .contactAdd)
override func setupViews() {
addtoBasket.frame = CGRect(x: 50, y: 0, width: 20, height: 60)
addSubview(addtoBasket)
addSubview(titleLabel)
addSubview(thumbnailImageView)
addSubview(separatorView)
addSubview(addtoBasket)
titleLabel.superview!.bringSubview(toFront: titleLabel)
//horizontal constraints
addConstraintsWithFormat("H:|-0-[v0]-0-|", views: thumbnailImageView)
//vertical constraints
addConstraintsWithFormat("V:|-1-[v0]-1-|", views: thumbnailImageView)
addConstraintsWithFormat("H:|-0-[v0]-1-|", views: separatorView)
addtoBasket.translatesAutoresizingMaskIntoConstraints = false
addtoBasket.heightAnchor.constraint(equalToConstant: 20).isActive = true
addtoBasket.widthAnchor.constraint(equalToConstant: 20).isActive = true
addtoBasket.centerXAnchor.constraint(equalTo: addtoBasket.superview!.centerXAnchor, constant: 90).isActive = true
addtoBasket.centerYAnchor.constraint(equalTo: addtoBasket.superview!.centerYAnchor, constant: -50).isActive = true
//top constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .top, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 8))
//right constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1, constant: 0))
//right constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1, constant: 20))
//height constraint
titleLabelHeightConstraint = NSLayoutConstraint(item: titleLabel, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 1, constant: -10)
addConstraint(titleLabelHeightConstraint!)
}
}
Try accessing the labels layer and set its zPosition.
Try titleLabel.layer.zPosition = 1
There was clearly something wrong with the constraints, now working! Thanks