Add textfiled and Send Button (mail to) in xcode - swift

i'm build a simple app that allows you to reserve information equipment or a seat in a classroom. In my table view i insert an image and some text. How can i add a text field and a button in the bottom that send me a mail with the summary of the booking?
This is the code that i build until now.
TableViewController
import UIKit
struct CellData {
let image : UIImage?
let message : String?
}
class TableViewController: UITableViewController {
var data = [CellData] ()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
data = [CellData.init(image: imageLiteral(resourceName: "printer"), message: "Stampante 3D"),CellData.init(image: imageLiteral(resourceName: "printer"), message: "Stampante 3D"),CellData.init(image: imageLiteral(resourceName: "printer"), message: "Stampante 3D")]
self.tableView.register(CustomCell.self, forCellReuseIdentifier: "custom")
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 200
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "custom") as! CustomCell
cell.mainImage = data[indexPath.row].image
cell.message = data[indexPath.row].message
cell.layoutSubviews()
return cell
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
}
Custom Cell
import Foundation
import UIKit
class CustomCell: UITableViewCell {
var message : String?
var mainImage : UIImage?
var messageView : UITextView = {
var textView = UITextView()
textView.translatesAutoresizingMaskIntoConstraints = false
textView.isScrollEnabled = false
return textView
}()
var mainImageView : UIImageView = {
var imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.addSubview(mainImageView)
self.addSubview(messageView)
mainImageView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
mainImageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
mainImageView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
mainImageView.widthAnchor.constraint(equalToConstant: 100).isActive = true
mainImageView.heightAnchor.constraint(equalToConstant: 100).isActive = true
messageView.leftAnchor.constraint(equalTo: self.mainImageView.rightAnchor).isActive = true
messageView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
messageView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
messageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
}
override func layoutSubviews() {
super.layoutSubviews()
if let message = message {
messageView.text = message
}
if let image = mainImage{
mainImageView.image = image
} }
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Thanks!

I think you are referring to create a chat like window, if this is correct, one way to resolve this is add handlers for the keyboard events, in order to move the top views. In this case you can start with the following ones:
First you need to add some observers to the Notification center to listen when the keyboard is shown or when is hidden.
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
}
Then, you need to create the functions to be triggered when the events occurs. As you can see in the following code, the view frame of the view is modified accordingly to the keyboardSize.
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
self.view.frame.origin.y -= keyboardSize.height
}
}
func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
self.view.frame.origin.y += keyboardSize.height
}
}
So, just for clarification, you need to create a second view below the table, in which you will add the textfield and the send button.

Related

Unable to add constraints to my NSTableView in Cocoa Application

Below is my code in view controller
import Cocoa
class ViewController : NSViewController, NSTableViewDelegate, NSTableViewDataSource {
let stepperBtn: NSSegmentedControl = {
let stepperBtn = NSSegmentedControl()
stepperBtn.segmentCount = 2
stepperBtn.setImage(NSImage(systemSymbolName: "plus.circle", accessibilityDescription: "plus"), forSegment: 0)
stepperBtn.setImage(NSImage(systemSymbolName: "minus.circle", accessibilityDescription: "minus"), forSegment: 1)
stepperBtn.translatesAutoresizingMaskIntoConstraints = false
return stepperBtn
}()
var tableView: NSTableView {
let tablview = NSTableView()
tablview.translatesAutoresizingMaskIntoConstraints = false
return tablview
}
override func loadView() {
self.view = NSView(frame: NSMakeRect(0.0, 0.0, 550.0, 300.0))
tableView.delegate = self
tableView.dataSource = self
self.view.addSubview(tableView)
self.view.addSubview(stepperBtn)
tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
}
override func viewDidLayout() {
}
override func viewDidLoad() {
super.viewDidLoad()
}
func numberOfRows(in tableView: NSTableView) -> Int {
return 5
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
I get below error : "NSTableView:0x7f9beb851600.top"> and <NSLayoutYAxisAnchor:0x600000bcc400 "NSView:0x7f9beaa184e0.top"> because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal.
How to add constraints programatically to NSTableView

Table View Design overlapping

I am new to swift .I want to display the records with image view in table view cell . I have defined the property with leadingAnchor , trailingAnchor, widthAnchor, heightAnchor with content view . But when I run the app it overlapping the view .
Here is the code in cell .
import UIKit
class PeopleCell: UITableViewCell {
static let identifier = "PeopleCell"
let containerView:UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.clipsToBounds = true // this will make sure its children do not go out of the boundary
return view
}()
let profileImageView:UIImageView = {
let img = UIImageView()
img.contentMode = .scaleAspectFill // image will never be strecthed vertially or horizontally
img.translatesAutoresizingMaskIntoConstraints = false // enable autolayout
img.layer.cornerRadius = 35
img.clipsToBounds = true
return img
}()
let firstnameTitleLabel:UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 20)
label.textColor = .black
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let lastnameTitleLabel:UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 14)
label.textColor = .white
label.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)
label.layer.cornerRadius = 5
label.clipsToBounds = true
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.contentView.addSubview(profileImageView)
containerView.addSubview(firstnameTitleLabel)
containerView.addSubview(lastnameTitleLabel)
self.contentView.addSubview(containerView)
profileImageView.centerYAnchor.constraint(equalTo:self.contentView.centerYAnchor).isActive = true
profileImageView.leadingAnchor.constraint(equalTo:self.contentView.leadingAnchor, constant:10).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant:70).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant:70).isActive = true
containerView.centerYAnchor.constraint(equalTo:self.contentView.centerYAnchor).isActive = true
containerView.leadingAnchor.constraint(equalTo:self.profileImageView.trailingAnchor, constant:10).isActive = true
containerView.trailingAnchor.constraint(equalTo:self.contentView.trailingAnchor, constant:-10).isActive = true
containerView.heightAnchor.constraint(equalToConstant:40).isActive = true
firstnameTitleLabel.topAnchor.constraint(equalTo:self.containerView.topAnchor).isActive = true
firstnameTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
firstnameTitleLabel.trailingAnchor.constraint(equalTo:self.containerView.trailingAnchor).isActive = true
lastnameTitleLabel.topAnchor.constraint(equalTo:self.firstnameTitleLabel.bottomAnchor).isActive = true
lastnameTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
lastnameTitleLabel.topAnchor.constraint(equalTo:self.firstnameTitleLabel.bottomAnchor).isActive = true
lastnameTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configureCell(firstName: String, lastName: String) {
firstnameTitleLabel.text = "Firstname :\(firstName)"
lastnameTitleLabel.text = "Lastname : \(lastName)"
}
func configureImageCell(row: Int, viewModel: ViewModel) {
profileImageView.image = nil
viewModel
.downloadImage(row: row) { [weak self] data in
let image = UIImage(data: data)
self?.profileImageView.image = image
}
}
}
Here is the view controller code .
import UIKit
import Combine
class PeopleViewController: UIViewController {
var coordinator: PeopleBaseCoordinator?
init(coordinator: PeopleBaseCoordinator) {
super.init(nibName: nil, bundle: nil)
self.coordinator = coordinator
title = "People"
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private let viewModel = ViewModel()
private var subscribers = Set<AnyCancellable>()
var activityIndicator = UIActivityIndicatorView(style: .medium)
private lazy var tableView: UITableView = {
let tableview = UITableView()
tableview.translatesAutoresizingMaskIntoConstraints = false
tableview.dataSource = self
tableview.prefetchDataSource = self
tableview.showsVerticalScrollIndicator = false
tableview.register(PeopleCell.self, forCellReuseIdentifier: PeopleCell.identifier)
return tableview
}()
override func viewDidLoad() {
super.viewDidLoad()
activityIndicator.startAnimating()
setUpUI()
setUpBinding()
self.activityIndicator.stopAnimating()
// Do any additional setup after loading the view.
}
private func setUpUI() {
view.backgroundColor = .white
title = "People List "
view.addSubview(tableView)
tableView.topAnchor.constraint(equalTo:view.safeAreaLayoutGuide.topAnchor).isActive = true
tableView.leftAnchor.constraint(equalTo:view.safeAreaLayoutGuide.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo:view.safeAreaLayoutGuide.rightAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor).isActive = true
// Creating constrain for Indecator
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(activityIndicator)
activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
private func setUpBinding() {
viewModel
.$peoples
.receive(on : RunLoop.main)
.sink { [weak self ] _ in
self?.tableView.reloadData()
}
.store(in: &subscribers)
viewModel.getPeople()
}
}
extension PeopleViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.peoples.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: PeopleCell.identifier, for: indexPath) as? PeopleCell
else { return UITableViewCell() }
let row = indexPath.row
let people = viewModel.peoples[row]
cell.configureCell(firstName: people.firstName, lastName: people.lastName)
cell.configureImageCell(row: row, viewModel: viewModel)
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
}
extension PeopleViewController: UITableViewDataSourcePrefetching {
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
viewModel.getPeople()
}
}
Here is the result .
This is rather tricky because it seems your constraints are fine, assuming that your tableview height is 100, but the screenshot tableview cells seem a little shorter than 100. Let's assume the cell height is 100 correct.
I suggest you try configuring the imageView (and other views) in override func layoutSubViews(), which is a function that renders whenever the contentView's bound change. It should also be noted that better practice is where the imageSize is relative to the cell/contentView's frame instead of hardcoded values.
So it should look like
import UIKit
class PeopleCell: UITableViewCell {
let profileImageView:UIImageView = {
let img = UIImageView()
return img
}()
override func layoutSubviews() {
super.layoutSubviews()
profileImageView.translatesAutoresizingMaskIntoConstraints = false profileImageView.centerYAnchor.constraint(equalTo:self.contentView.centerYAnchor).isActive = true
profileImageView.leadingAnchor.constraint(equalTo:self.contentView.leadingAnchor, constant:10).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant:self.frame.width * 0.7).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant:self.frame.width * 0.7).isActive = true
//You may want to try with other type of contentMode such as aspectFit, etc
profileImageView.contentMode = .scaleAspectFill
profileImageView.layer.cornerRadius = self.frame.width / 2
profileImageView.clipsToBounds = true
}
//If above doesn't work, you may want to look into the imageConfiguration function you made and ensure that contentMode is applied properly.
func configureImageCell(row: Int, viewModel: ViewModel) {
profileImageView.image = nil
viewModel
.downloadImage(row: row) { [weak self] data in
let image = UIImage(data: data)
self?.profileImageView.image = image
self?.profileImageView.contentMode = .scaleAspectFill
}
}
If all of the above code doesn't work, try to find the profileImageView size values by using breakpoints or ViewHierarchy within Xcode. To check the height of image or cell itself, they should be sufficient for you to find clues to resolve the issue.
All the best.

TextField rejected resignFirstResponder when being removed from hierarchy

I'm trying to make a custom textfield/sendbutton view that overrides inputAccessoryView, but I'm having 2 problems I can't seem to solve:
When the custom view becomes the first responder, I get this warning twice:
CustomKeyboardProject[5958:3107074] API error:
<_UIKBCompatInputView: 0x119e2bd70; frame = (0 0; 0 0);
layer = <CALayer: 0x283df9e00>> returned 0 width,
assuming UIViewNoIntrinsicMetric
Then when I try to resign the custom view as the first responder, Xcode throws this warning:
CustomKeyboardProject[5958:3107074] -[UIWindow
endDisablingInterfaceAutorotationAnimated:] called on <UITextEffectsWindow:
0x11a055400; frame = (0 0; 375 667); opaque = NO; autoresize = W+H; layer =
<UIWindowLayer: 0x283df78a0>> without matching
-beginDisablingInterfaceAutorotation. Ignoring.
Has anyone been able to silence these warnings?
Heres my code:
protocol CustomTextFieldDelegate: class {
func sendMessage()
}
class CustomTextField: UITextField {
override var canBecomeFirstResponder: Bool {
return true
}
override var canResignFirstResponder: Bool {
return true
}
}
class CustomKeyboardView: UIView {
let textField: CustomTextField = {
let textField = CustomTextField()
textField.backgroundColor = .green
textField.textColor = .white
return textField
}()
let attachButton: UIButton = {
let button = UIButton()
button.backgroundColor = .red
button.setTitle("Attach", for: .normal)
return button
}()
let sendButton: UIButton = {
let button = UIButton()
button.backgroundColor = .blue
button.setTitle("Send", for: .normal)
button.addTarget(self, action: #selector(sendMessage), for: .touchUpInside)
return button
}()
#objc func sendMessage() {
delegate?.sendMessage()
}
weak var delegate: CustomTextFieldDelegate?
init() {
super.init(frame: .zero)
isUserInteractionEnabled = true
setViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setViews() {
let subviews = [attachButton, sendButton, textField]
subviews.forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
addSubview($0)
}
autoresizingMask = .flexibleHeight
subviews.forEach {
NSLayoutConstraint.activate([
$0.centerYAnchor.constraint(equalTo: centerYAnchor),
])
}
layoutSubviews()
[attachButton, sendButton].forEach {
NSLayoutConstraint.activate([
$0.widthAnchor.constraint(equalTo: $0.heightAnchor),
$0.heightAnchor.constraint(equalTo: textField.heightAnchor)
])
}
NSLayoutConstraint.activate([
textField.topAnchor.constraint(equalTo: topAnchor),
attachButton.leftAnchor.constraint(equalTo: leftAnchor),
textField.leadingAnchor.constraint(equalTo: attachButton.trailingAnchor),
sendButton.leadingAnchor.constraint(equalTo: textField.trailingAnchor),
sendButton.trailingAnchor.constraint(equalTo: trailingAnchor),
])
}
override var intrinsicContentSize: CGSize {
return .zero
}
}
class CustomTableView: UITableView {
let keyboardView = CustomKeyboardView()
override init(frame: CGRect, style: UITableView.Style) {
super.init(frame: frame, style: style)
keyboardDismissMode = .interactive
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var canBecomeFirstResponder: Bool {
return true
}
override var canResignFirstResponder: Bool {
return true
}
override var inputAccessoryView: UIView? {
return keyboardView
}
}
private let reuseId = "MessageCellId"
class ExampleViewController: UITableViewController {
private let customTableView = CustomTableView()
var messages = [String]()
override func loadView() {
tableView = customTableView
view = tableView
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.becomeFirstResponder()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: reuseId)
customTableView.keyboardView.delegate = self
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
DispatchQueue.main.async {
self.customTableView.keyboardView.textField.becomeFirstResponder()
}
}
// tableView delegate methods
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messages.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: reuseId)
cell?.textLabel?.text = messages[indexPath.row]
return cell!
}
override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
customTableView.keyboardView.textField.resignFirstResponder()
}
}
extension ExampleViewController: CustomTextFieldDelegate {
func sendMessage() {
// double check something is in textField
let textField = customTableView.keyboardView.textField
guard let body = textField.text, body != "" else { return }
messages.append(body)
tableView.reloadData()
view.endEditing(true)
customTableView.keyboardView.textField.text = ""
}
}

Why is my NSTableView displaying my data wrong?

My NSTableView seems to be mirroring all content which draws a String.
I have never seen something like this before and hope somebody has a tip on how to solve this Problem. I already looked it up, but couldn't find anything. I also filed a bug report, but apple didn't respond.
First idea, that I have: It must have something to do with the NSTextField and NSPopUpButton being disabled at start. They are only enabled as soon as you click one cell. And when they are enabled the text gets displayed the right way. But I don't want to enable them at start to prevent changing values by accidentally clicking one cell.
My Code seems to be fine and compiled without problems.
The Program is a simple Database Program which takes an own created file type and reads its content. From the content it creates Database, Table, Column and cell objects at runtime to display the database content.
Here is my NSTableView Code:
import Cocoa
class TableContentViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
#IBOutlet weak var tableContent: NSTableView!
var columnDragFrom:Int = -1
override func viewDidLoad() {
super.viewDidLoad()
tableContent.dataSource = self
tableContent.delegate = self
// Do view setup here.
tableContent.backgroundColor = NSColor(named: "darkColor")!
NotificationCenter.default.addObserver(self, selector: #selector(reloadData(_:)), name: .tableUpdated, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(cellSelection(_:)), name: .cellSelection, object: nil)
tableContent.selectionHighlightStyle = .none
}
#objc func cellSelection(_ notification: Notification) {
if let cell = notification.object as? NSTableCellView {
nxSelectionHandler.currentRow = tableContent.row(for: cell)
nxSelectionHandler.currentColumn = tableContent.column(for: cell)
nxSelectionHandler.highlightCell(sender: tableContent)
}
}
#objc func reloadData(_ notification: Notification) {
setupTable()
tableContent.reloadData()
}
func setupTable() {
tableContent.rowHeight = 30
while(tableContent.tableColumns.count > 0) {
tableContent.removeTableColumn(tableContent.tableColumns.last!)
}
if nxSelectionHandler.currentTable != nil {
for column in (nxSelectionHandler.currentTable?.nxColumns)! {
let newColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: column.title))
newColumn.title = column.title
tableContent.addTableColumn(newColumn)
}
}
}
func numberOfRows(in tableView: NSTableView) -> Int {
if nxSelectionHandler.currentTable != nil {
var rowCounts:[Int] = []
for column in (nxSelectionHandler.currentTable?.nxColumns)! {
rowCounts.append(column.nxCells.count)
}
return rowCounts.max()!
}
return 0
}
func tableView(_ tableView: NSTableView, mouseDownInHeaderOf tableColumn: NSTableColumn) {
self.columnDragFrom = tableView.tableColumns.firstIndex(of: tableColumn)!
}
func tableView(_ tableView: NSTableView, didDrag tableColumn: NSTableColumn) {
nxSelectionHandler.currentTable?.nxColumns.swapAt(columnDragFrom, tableView.tableColumns.firstIndex(of: tableColumn)!)
tableView.reloadData()
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let column = tableView.tableColumns.firstIndex(of: tableColumn!)
if nxSelectionHandler.currentTable != nil {
let nxCell = nxSelectionHandler.currentTable?.nxColumns[column!].nxCells[row]
switch nxCell! {
case .nxString(let value):
var StringCellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "nxString"), owner: self) as? StringCell
if StringCellView == nil {
tableView.register(NSNib(nibNamed: "StringCellNib", bundle: nil), forIdentifier: NSUserInterfaceItemIdentifier(rawValue: "nxString"))
StringCellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "nxString"), owner: self) as? StringCell
}
StringCellView?.textField?.stringValue = value
return StringCellView
case .nxCheckbox(let state):
var CheckboxCellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "nxCheckbox"), owner: self) as? CheckboxCell
if CheckboxCellView == nil {
tableView.register(NSNib(nibNamed: "CheckboxCellNib", bundle: nil), forIdentifier: NSUserInterfaceItemIdentifier("nxCheckbox"))
CheckboxCellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "nxCheckbox"), owner: self) as? CheckboxCell
}
CheckboxCellView?.column = column!
CheckboxCellView?.row = row
CheckboxCellView?.checkbox.state = state
return CheckboxCellView
case .nxSelection(let selection, let options):
var SelectionCellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "nxSelection"), owner: self) as? SelectionCell
if SelectionCellView == nil {
tableView.register(NSNib(nibNamed: "SelectionCellNib", bundle: nil), forIdentifier: NSUserInterfaceItemIdentifier(rawValue: "nxSelection"))
SelectionCellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "nxSelection"), owner: self) as? SelectionCell
}
SelectionCellView?.column = column!
SelectionCellView?.row = row
for option in options {
SelectionCellView?.selection.addItem(withTitle: option)
}
SelectionCellView?.selection.selectItem(at: selection)
return SelectionCellView
}
}
return nil
}
}
The objects used in the Code are all class types and cells are loaded from Nibs, where the cells all have constraints and are displayed the right way. A Screenshot of the NSTableView displaying the content wrong can be seen below.
Code of one of the custom cells:
import Cocoa
class StringCell: NSTableCellView, NSTextFieldDelegate {
var isSelected: Bool = false {
didSet {
self.needsDisplay = true
}
}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
// Drawing code here.
self.textField?.focusRingType = .none
self.textField?.textColor = NSColor.white
self.textField?.delegate = self
self.wantsLayer = true
self.layer?.borderWidth = 2
self.layer?.cornerRadius = 2
if isSelected {
self.layer?.borderColor = NSColor.systemBlue.cgColor
} else {
self.layer?.borderColor = NSColor.clear.cgColor
self.textField?.isEnabled = false
self.textField?.isEditable = false
}
}
override func mouseDown(with event: NSEvent) {
if self.isSelected {
self.textField?.isEditable = true
self.textField?.isEnabled = true
self.textField?.selectText(self)
} else {
self.isSelected = true
NotificationCenter.default.post(name: .cellSelection, object: self)
}
}
func controlTextDidEndEditing(_ obj: Notification) {
if let textField = obj.object as? NSTextField {
nxSelectionHandler.currentCell = nxCell.nxString(textField.stringValue)
}
}
}
Yeah, that's weird. Did you check if you have any active content filters in the View Effects inspector?
View Effects inspector

UILabel not showing up in the view

Problem
I'm trying to fully understand building a Swift app entirely programmatically but I'm getting hung up on layout anchors. I have a tableview and if a row is selected it will push a new viewcontroller into the view.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let currentCell = tableView.cellForRow(at: indexPath)! as! CoinCell
if let coin = currentCell.coin {
let newViewController = CoinViewController(coin)
self.navigationController?.pushViewController(newViewController, animated: true)
}
tableView.deselectRow(at: indexPath, animated: true)
}
Below is my code for the viewcontroller that is being pushed. I'm able to see that the nameLabel has text while debugging but I can't seem to have the labels actually show in the view.
var coin: Coin? {
didSet {
nameLabel.text = coin?.name
}
}
init(_ coin: Coin) {
super.init(nibName: nil, bundle: nil)
self.coin = coin
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
view.addSubview(nameLabel)
view.addSubview(testLabel)
setupView()
}
let nameLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let testLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "TEST"
return label
}()
func setupView() {
nameLabel.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
nameLabel.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
nameLabel.widthAnchor.constraint(equalToConstant: 50).isActive = true
nameLabel.heightAnchor.constraint(equalToConstant: 50).isActive = true
}
I'm still a beginner with this so I'm not sure of the best way to actually debug an issue like this. Thanks for the help.
Since you are precisely making sure that your controller receive data (or non optional data) via the initializer, you should replace the property observer (didSet) to just a simple property.
let coin: Coin
init(_ coin: Coin) {
self.coin = coin
super.init(nibName: nil, bundle: nil)
}
// now in viewDidLoad() you can set the text of your label i.e namelabel.text = self.coin.something
You try to set the text nameLabel in the property observer:
var coin: Coin? {
didSet {
nameLabel.text = coin?.name
}
}
But didSet will not be called from the initializer, therfore the label will remain empty.
In iOS (Cocoa Touch), you should fill your views after/within viewDidLoad (or viewDidAppear) or - in your case - in setupView:
func setupView() {
nameLabel.text = coin?.name
// ...
}