Button on subview untouchable after add to view program - swift

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])

Related

Call to IBOutlet in custom UIView from another class

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

Custom Class UIView - not changed

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()

how to add UIView with code? Without using storyboard

I am a beginner and am only able to add elements via storyboard.
Now I would like to know how to add UIView code to the screen without using a storyboard.
I need to place it at the very top, full width of the screen, replacing the NavigationBar with a UIView
import UIKit
class ChatsNavBar: UIView {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var statusLabel: UILabel!
#IBOutlet weak var imageUser: UIImageView!
#IBOutlet weak var backButton: UIButton! {
didSet {
backButton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
}
#IBOutlet weak var navView: UIView!
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() {
let bundle = Bundle(for: ChatsNavBar.self)
bundle.loadNibNamed("ChatsNavBar", owner: self, options: nil)
navView.translatesAutoresizingMaskIntoConstraints = false
addSubview(nameLabel)
addSubview(navView)
addSubview(statusLabel)
addSubview(imageUser)
addSubview(backButton)
nameLabel.frame = self.bounds
nameLabel.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}
#IBAction func backAction(_ sender: Any) {
}
}
class ChatsViewController: MessagesViewController {
init(user: MUser, chat: MChat) {
self.user = user
self.chat = chat
super.init(nibName: nil, bundle: nil)
title = "\(chat.friendUsername) \(chat.friendUserSurname)"
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
configureMessageInputBar()
let navController = UIView()
Here is how you can place it over entire screen
let viewOverLay = ChatsNavBar()
navigationController.view.addSubview(viewOverLay)
viewOverLay.frame = navigationController.navigationBar.bounds

Passing data from UIViewController to Custom UIView with XIB

I have the following swift file which controls a xib file
import UIKit
protocol SelectProfile: class {
func selectionUp(id: Int, selected: Bool)
}
class Component: UIView {
#IBOutlet weak var name: UILabel!
#IBOutlet weak var selection: UIView!
var selected: Bool = false
var profileId: Int = 6
weak var delegate: SelectProfile?
#IBAction func selProfile(_ sender: Any) {
selected = !selected
selection.isHidden = !selected
delegate?.selectionUp(id: profileId, selected: selected)
}
let nibName = "Component"
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
func commonInit() {
guard let view = loadViewFromNib() else { return }
view.frame = self.bounds
self.addSubview(view)
selection.isHidden = true
name.text = String(profileId)
}
func loadViewFromNib() -> UIView? {
let nib = UINib(nibName: nibName, bundle: nil)
return nib.instantiate(withOwner: self, options: nil).first as? UIView
}
}
In my UIViewController where I want to interact with the component I have the following code (shortened for brevity)
import UIKit
class Home: UIViewController, SelectProfile {
#IBOutlet weak var profileComponent: Component!
func selectionUp(id: Int, selected: Bool) {
print(id, selected)
}
override func viewDidLoad() {
profileComponent.delegate = self
profileComponent.profileId = 2
}
}
My delegate works nicely and I'm able to change the values for IBOutlets but I can't pass a value to variables. This line doesn't pass the data to my xib profileComponent.profileId = 2.
It seems like I have an issue with initialization of the xib but I don't know how to fix it.
The viewDidLoad of controller is called after view's init, so when you change profileId as you do, it is changed, but not reflected anywhere.
I assume the following, at least, missed:
var profileId: Int = 6 {
didSet {
name.text = String(profileId)
// call delegate here if needed as well
}
}

iOS Charts Marker View

I created a custom MarkerView from a .xib but it's always not centered in the proper set.
final class ChartMarkerView: MarkerView, ViewLoadable {
#IBOutlet weak var laValue: UILabel!
override required init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
func setUI() {
}
public override func refreshContent(entry: ChartDataEntry, highlight: Highlight) {
laValue.text = String(entry.y)
layoutIfNeeded()
}
}
protocol ViewLoadable {
var nibName: String { get }
}
extension ViewLoadable where Self: UIView {
var containerView: UIView? { return subviews.first }
var nibName: String { return String(describing: type(of: self)) }
func loadViewFromXib() -> UIView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: nibName, bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil).first as! UIView
return view
}
func xibSetup() {
let view = loadViewFromXib()
view.frame = bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight, .flexibleBottomMargin, .flexibleTopMargin]
view.autoresizesSubviews = true
backgroundColor = .clear
addSubview(view)
}
}
Turns out I just need to calculate the offset of the MarkerView and set it when loading the view:
offset.x = -self.frame.size.width / 2.0
offset.y = -self.frame.size.height - 7.0