I have a Custom NSView. This view had a xib with all desing
import Cocoa
class CustomView: NSView {
#IBOutlet var contentView: NSView!
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
Bundle.main.loadNibNamed("CustomView", owner: self, topLevelObjects: nil)
addSubview(contentView)
contentView.frame = contentView.bounds
contentView.autoresizingMask = [.height, .width]
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
// Drawing code here.
}
}
When I try to add this view into NSStackView doesn't work.
This is the code in my ViewController
override func viewDidLoad() {
super.viewDidLoad()
let view = CustomView()
self.stackView.addArrangedSubview(view)
}
Any idea.
Related
I am looking for a way to refer to the IBOutlet variable in a custom class UIView, from another class. I found layoutSubviews, but each change only works on the first call, and not on each subsequent call. Thanks for help!
ViewController class:
var SB = StatusBar()
SB.update(1)
SB.update(2)
SB.update(3)
StatusBar class:
class StatusBar: UIView {
#IBOutlet var view: UIView!
#IBOutlet weak var label: UILabel!
var ActualStatus: Int!
required init?(coder: NSCoder) {
super.init(coder: coder)
xibSetup()
}
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
func update(status) {
ActualStatus = status
self.layoutSubviews()
}
override func layoutSubviews() {
super.layoutSubviews()
label.text = ActualStatus
}
func xibSetup() {
view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth, UIView.AutoresizingMask.flexibleHeight]
addSubview(view)
}
func loadViewFromNib() -> UIView {
let bundle = Bundle(for: type(of:self))
let nib = UINib(nibName: "StatusBar", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
return view
}
}
Result: label.text is 1, change only works on the first call
Why in the code below, text changes as value, but there is no change in UIVIew. How do I refresh the data in a custom class? The value changes but does not refresh in the view. I have no ideas anymore.
ViewController.swift:
let SB = StatusBar()
SB.update()
StatusBar.swift:
class StatusBar: UIView {
#IBOutlet var view: UIView!
#IBOutlet weak var Status: UITextField!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
func update() {
Status.text = "ok"
print(Status.text)
print("status updated.")
}
func xibSetup() {
view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth, UIView.AutoresizingMask.flexibleHeight]
addSubview(view)
}
func loadViewFromNib() -> UIView {
let bundle = Bundle(for: type(of:self))
let nib = UINib(nibName: "StatusBar", bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
return view
}
}
You are not calling update(). In xibSetup(), add update()
I try to add a subview to a view, but after added, the button on subview is untouchable. I have check the status of button, user interaction is enable. and after add subview, the UI of subview are show up correctly.
The subview class:
class ErrorInfoView: UIView {
#IBOutlet var containerView: UIView!
#IBOutlet weak var messageLabel: UILabel!
var callback: (()->())?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
func commonInit() {
Bundle.main.loadNibNamed("ErrorInfoView", owner: self, options: nil)
containerView.frame = self.bounds
containerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
containerView.backgroundColor = UIColor.clear
addSubview(containerView)
}
func configure(message: String, callback: #escaping ()->()) {
self.messageLabel.text = message
self.callback = callback
}
#IBAction func pressRetryButton(_ sender: UIButton) {
self.callback?()
}
}
The parent view:
let errorView = ErrorInfoView(frame: self.tableViewContainer.frame)
errorView.configure(message: error) {
// do something, but not be called
}
self.tableViewContainer.addSubview(errorView)
self.tableViewContainer.bringSubviewToFront(errorView)
errorView.translatesAutoresizingMaskIntoConstraints = false
let horizontalConstraint = errorView.centerXAnchor.constraint(equalTo: self.tableViewContainer.centerXAnchor)
let verticalConstraint = errorView.centerYAnchor.constraint(equalTo: self.tableViewContainer.centerYAnchor)
self.tableViewContainer.addConstraints([horizontalConstraint, verticalConstraint])
I have problems in getting my custom NSSlider control updated live within Xcode's Interface Builder.
I have implemented #IBDesignable and prepareForInterfaceBuilder as shown in many other posts and tutorials. My little test just removes the knob from the slider control.
Here is the code I am using at the moment:
import Cocoa
#IBDesignable
class ColorSlider2: NSSlider {
override func setNeedsDisplay(_ invalidRect: NSRect) {
super.setNeedsDisplay(invalidRect)
}
override func awakeFromNib() {
super.awakeFromNib()
setupView()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setupView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
}
private func setupView() {
if ((self.cell?.isKind(of: ColorSlider2Cell.self)) == false) {
let cell = ColorSlider2Cell()
self.cell = cell
}
self.alphaValue = 0.5
self.floatValue = 0.4
}
}
class ColorSlider2Cell: NSSliderCell {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init() {
super.init()
}
override func drawKnob(_ knobRect: NSRect) {
return
}
}
The preview in Interface Builder is neither removing the knob nor updating the floatValue:
Do you have any idea why this is the case?
I want to put all subview properties and my subview setup code in a UIView subclass and load that into my UIViewController subclass using loadView(). Then access the UIView subclass members without casting the view property of UIViewController all the time.
This is my UIView subclass AwesomeClass
class AwesomeView: UIView {
lazy var testView:UIView = {
let view = UIView()
view.backgroundColor = UIColor.red
self.addSubview(view)
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
testView.frame = CGRect(x: 10
, y: 10
, width: self.bounds.size.width - 20
, height: 100)
}
}
And my UIViewController subclass AwesomeViewController
class AwesomeViewController: UIViewController {
override func loadView() {
let view = AwesomeView()
self.view = view
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I could do something like:
var subclassedView:AwesomeView {
get {
return self.view as! AwesomeView
}
}
and
subclassedView.testView.backgroundColor = UIColor.blue
But is there a way to call testView directly with self.view in the AwesomeViewController?
Edit:
What I am looking for is Covariant return type in swift.
You can you something like this:
Instantiate an instance of AwesomeViewController in AwesomeView
class AwesomeView: UIView {
var exampleColorVariable:UIColor?
//here you instantiate your view controller
var awesomeViewController = AwesomeViewController()
lazy var testView:UIView = {
let view = UIView()
view.backgroundColor = UIColor.red
self.addSubview(view)
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
testView.frame = CGRect(x: 10
, y: 10
, width: self.bounds.size.width - 20
, height: 100)
}
}
then you can access any method in AwesomeView changing a little bit your code
class AwesomeViewController: UIViewController {
lazy var awesomeView: AwesomeView = {
let view = AwesomeView()
view.awesomeViewController = self
return view
}()
func setupView() {
view.addSubview(awesomeView)
// your constraints here
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setupView()
// NOW YOU CAN ACCESS ANY METHOD IN YOUR VIEW awesomeView.yourFunction()
// or you access that variable
awesomeView.exampleColorVariable = .red // you can now omit UIColor in swift3
}
}