loading from xib and translatesautoresizingmaskintoconstraints - ios

import UIKit
class ViewController: UIViewController {
#IBOutlet weak var vsuper: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let v = view2.getView()
vsuper.backgroundColor = UIColor.black
vsuper.addSubview(v)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//xib file
import UIKit
class view2: UIView {
override func awakeFromNib() {
super.awakeFromNib()
}
static func getView()->view2{
let v = Bundle.main.loadNibNamed("view2", owner: nil, options: nil)?.first as! consentview
// v.translatesAutoresizingMaskIntoConstraints = false
return v;
}
}
While I load xib into another view in story board it doesn't get added inside that view if translateautoresizingmaskintoconstraints is set to false but if I remove that line it gets added to the view.
if I set it to false it takes space on top left otherwise it gets added inside the view. Why so ? even though I am adding it tov super

You did not set the constraints. translatesAutoresizingMaskIntoConstraints = false means you don't want the xib frame to be translated into constraints thus you will setup constraints yourself. Thats why its not assigning any bounds to the xib view on your superview. Try making some constraints with the superview after addSubview() call. such as,
v.leadingAnchor.constraint(equalTo: vsuper.leadingAnchor, constant: 0).isActive = true
v.trailingAnchor.constraint(equalTo: vsuper.trailingAnchor, constant: 0).isActive = true
v.topAnchor.constraint(equalTo: vsuper.topAnchor, constant: 0).isActive = true
v.bottomAnchor.constraint(equalTo: vsuper.bottomAnchor, constant: 0).isActive = true
vsuper.layoutIfNeeded()

Try it
import UIKit
class MyView: UIView {
// your outlets from your view can be there
// your functions for your view
func myFunc() {
}
}
import UIKit
class ViewController: UIViewController {
var myView: MyView!
override func viewDidLoad() {
super.viewDidLoad()
if let contentView = Bundle.main.loadNibNamed("MyView", owner: self, options: nil)?.first as? MyView {
myView = contentView
self.view.addSubview(myView)
}
// set background color your custom view
myView.backgroundColor = UIColor.black
// call functions for your custom view
myView.myFunc()
}
}

Related

Creating a UIView in a separate class and installing constrains

ViewController:
class ViewController: UIViewController, ViewSpecificController {
typealias RootView = CustomView
override func viewDidLoad() {
super.viewDidLoad()
view().configure()
}
override func loadView() { self.view = CustomView() }
}
UIView:
class CustomView: UIView {
func configure() {
backgroundColor = .orange
translatesAutoresizingMaskIntoConstraints = false
addConstraints()
}
func addConstraints() {
var constraints = [NSLayoutConstraint]()
constraints.append(self.leadingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leadingAnchor))
constraints.append(self.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor))
constraints.append(self.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor))
constraints.append(self.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor))
NSLayoutConstraint.activate(constraints)
}
}
Executing this code results in an error "[LayoutConstraints] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want."
I tried to initialize UIView, the same error appeared there. How to fix it?
From what i can see it looks like your CustomView class is trying to set constraints to itself. The constraints aren't needed as the ViewController will handle sizing it automatically once you replace the original in loadView(). Removing your addConstraints() method from configure() should solve your problem. See if that works...

UIView: how does the appearance() proxy work?

I have created a simple custom UIView:
final class TestView: UIView {
var testColor: UIColor = .white {
didSet {
backgroundColor = testColor
}
}
}
Then I wrote this in my view controller:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var testView: TestView!
#IBOutlet weak var testView2: TestView!
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) {
TestView.appearance().testColor = .red
}
}
}
By doing this, I get an error:
Could you help me understanding what's wrong here and how to implement the UIAppearance proxy for any custom UIView?
Thank you for your help
You need to make the property #objc and dynamic:
final class TestView: UIView {
#objc dynamic var testColor: UIColor? = .white {
didSet {
backgroundColor = testColor
}
}
}
Worth noting: the UIAppearance proxy does NOT affect views which are already part of the view hierarchy.
So, in your example, adding #objc dynamic to your property will get rid of the crash, but you will not see any change to the two #IBOutlet views.
If you call it as part of viewDidLoad() (instead of DispatchQueue.main.asyncAfter):
override func viewDidLoad() {
super.viewDidLoad()
TestView.appearance().testColor = .red
}
The two #IBOutlet views will get the red background.
Or, if you add a new view to the hierarchy, it will get the red background:
class AppearanceTestViewController: UIViewController {
#IBOutlet weak var testView: TestView!
#IBOutlet weak var testView2: TestView!
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) {
TestView.appearance().testColor = .red
self.addAnotherTestView()
}
}
func addAnotherTestView() -> Void {
let v = TestView()
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
NSLayoutConstraint.activate([
v.widthAnchor.constraint(equalToConstant: 240.0),
v.heightAnchor.constraint(equalTo: v.widthAnchor),
v.centerXAnchor.constraint(equalTo: view.centerXAnchor),
v.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
// this newly added view WILL have a red background
}
}

Displaying custom UIView in a ViewController

I am creating a UIView which I want to display in my view controller. I have created the UIView and it shows, but the problems I have now are:
When I call the UIView in my view controller, I can no longer interact with the elements of the view controller. The CustomView I created has completely prevented the interaction with my view controller and I want to be able to interact with the UIViewController.
I want to hide the status bar which includes the battery percentage and network bar and other things so the view completely covers them. I implemented a code to cover them, but it returns an error.
below is my code
class SliderView: CustomView {
#IBOutlet weak var containerView: UIView!
#IBOutlet weak var sliderImage: UIImageView!
#IBOutlet weak var sliderText: UILabel!
override func initialize() {
super.initialize()
let name = String(describing: type(of: self))
let nib = UINib(nibName: name, bundle: .main)
nib.instantiate(withOwner: self, options: nil)
self.addSubview(self.containerView)
self.containerView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
self.containerView.topAnchor.constraint(equalTo: self.topAnchor),
self.containerView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
self.containerView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
])
}
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return sliderImage.frame.contains(point)
}
override var prefersStatusBarHidden: Bool {
return true
}
// THIS THROWS an error 'Property does not override any property from its superclass'
}
my UIView is called in my Viewcontroller like
weak var sliderView: SliderView!
override func loadView() {
super.loadView()
let sliderView = SliderView()
self.view.addSubview(sliderView)
NSLayoutConstraint.activate([
sliderView.topAnchor.constraint(equalTo: self.view.topAnchor),
sliderView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
sliderView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
sliderView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
])
self.sliderView = sliderView
}
override func viewDidLoad() {
super.viewDidLoad()
sliderView.sliderText.text = "HOOOOO WORKS"
}
NSLayoutConstraint.activate([
sliderView.topAnchor.constraint(equalTo: self.view.topAnchor),
sliderView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
sliderView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
sliderView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
])
Your custom view is covering the whole UIViewController. Therefore, it is not possible to interact with the UIViewController.
Just try to replace the second constraint with the following to cover only half of the screen's height:
sliderView.topAnchor.constraint.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -UIScreen.main.bounds.height*0.5)
This is just a suggestion to see the difference, i.e., not a solution.

Referencing superview inside of view code class file

I'm currently trying to learn constraints and styling programmatically in Swift. I'm also trying to maintain clean and modularized code by splitting up code that relates to "styling".
I simply have my LoginViewController:
import UIKit
class LoginViewController: UIViewController {
var loginView: LoginView!
override func viewDidLoad() {
super.viewDidLoad()
loginView = LoginView(frame: CGRect.zero)
self.view.addSubview(loginView)
// AutoLayout
loginView.autoPinEdgesToSuperviewEdges(with: UIEdgeInsets.zero, excludingEdge: .bottom)
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}
Then my LoginView:
import UIKit
class LoginView: UIView {
var shouldSetupConstraints = true
var headerContainerView: UIView!
override init(frame: CGRect) {
super.init(frame: frame)
// Header Container View
headerContainerView = UIView(frame: CGRect.zero)
headerContainerView.backgroundColor = UIColor(red:0.42, green:0.56, blue:0.14, alpha:1.0) // #6B8E23
headerContainerView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(headerContainerView)
headerContainerView.topAnchor.constraint(equalTo: self.superview!.topAnchor)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func updateConstraints() {
if(shouldSetupConstraints) {
// AutoLayout constraints
shouldSetupConstraints = false
}
super.updateConstraints()
}
}
Where I am getting stuck is with just simply trying to add this headerContainerView to the top of my superview. I want to be able to add it so it pins itself to the top, left and right of the superview and only 1/3 of the superview's height. I continue to try and reference the superview with no success and I cannot find a solution that helps me understand on the internet. Any suggestions on how I can complete this?
Thank you for taking the time for those that respond.
NOTE: I did start out using PureLayout which is really nice. However, I am an individual that likes to understand what is going on behind the scenes or at least how to write the code at its base level. You can see that I am using a PureLayout function in my LoginViewController, but I am looking to change that. I would prefer a solution that doesn't add a third party library.
Here self in the custom UIView class is the parent view of headerContainerView so , You can add this , Also I recommend to learn constraints first without 3rd party libraries to fully understand the concept as you will learn a lot from seeing conflicts and other things , once done , shift to libraries
override init(frame: CGRect) {
super.init(frame: frame)
// Header Container View
headerContainerView = UIView(frame: CGRect.zero)
headerContainerView.backgroundColor = UIColor(red:0.42, green:0.56, blue:0.14, alpha:1.0) // #6B8E23
headerContainerView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(headerContainerView)
headerContainerView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
headerContainerView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
headerContainerView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
headerContainerView.heightAnchor.constraintEqualToAnchor(self.heightAnchor, multiplier:1.0/3.0, constant: 0.0).active = true
}
// loginView layout
override func viewDidLoad() {
super.viewDidLoad()
loginView = LoginView(frame: CGRect.zero)
self.view.addSubview(loginView)
loginView.translatesAutoresizingMaskIntoConstraints = false
loginView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
loginView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
loginView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
loginView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
headerContainerView.snp.makeConstraints { (make) in
make.top.equalTo(self)
make.leading.and.trailing.equalTo(self)
make.height.equalTo(self.frame.height/3)
}
With SnapKit.
With SnapKit, you can do the following:
override func viewDidLoad() {
super.viewDidLoad()
loginView = LoginView(frame: CGRect.zero)
self.view.addSubview(loginView)
// AutoLayout
loginView.snp.makeConstraints { (make) in
make.left.equalTo(view.snp.left)
make.right.equalTo(view.snp.right)
make.top.equalTo(view.snp.top)
make.height.equalTo(view.snp.height).multipliedBy(1/3)
}
}

Adding progress bar under navigation bar in swift?

Say me please how to add a ProgressView under navigation bar?
I try to use solution in this post: adding progress bar under navigation bar, but there code was written on ObjectiveC language... I try to translate to Swift. This is the code, which i added in my NavigationController SubClass
import UIKit
class CustomNavigationController: UINavigationController {
#IBOutlet var Secondprogress: UIProgressView!
override func viewDidLoad() {
super.viewDidLoad()
NSLayoutConstraint.deactivateConstraints(self.view.constraints())
Secondprogress?.setTranslatesAutoresizingMaskIntoConstraints(false)
var navBar = self.navigationController?.navigationBar
Secondprogress.tag = 1
self.view.addSubview(Secondprogress)
var Constraint = NSLayoutConstraint(item: self.Secondprogress,
attribute:NSLayoutAttribute.Bottom,
relatedBy:NSLayoutRelation.Equal,
toItem:navBar,
attribute:NSLayoutAttribute.Bottom,
multiplier:1.0,
constant:-0.5);
self.view.addConstraint(Constraint);
Constraint = NSLayoutConstraint(item: self.Secondprogress,
attribute:NSLayoutAttribute.Left,
relatedBy:NSLayoutRelation.Equal,
toItem:navBar,
attribute:NSLayoutAttribute.Left,
multiplier:1.0,
constant:0);
self.view.addConstraint(Constraint);
Constraint = NSLayoutConstraint(item: self.Secondprogress,
attribute:NSLayoutAttribute.Right,
relatedBy:NSLayoutRelation.Equal,
toItem:navBar,
attribute:NSLayoutAttribute.Right,
multiplier:1.0,
constant:0);
self.view.addConstraint(Constraint);
Secondprogress.setTranslatesAutoresizingMaskIntoConstraints(false)
Secondprogress.hidden = false
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
But when i compile my app, i don't see the ProgressView under Navigation Bar.
Where is my mistake?
My problem was solved.
Add the Progress View to View Controller.(Drag and drop)
Make a IBOutlet.
Write the code:
override func viewDidLoad() {
super.viewDidLoad()
var navBar = self.navigationController?.navigationBar
var navBarHeight = navBar?.frame.height
var ProgressFrame = self.Progress.frame
var pSetX = ProgressFrame.origin.x
var pSetY = CGFloat(navBarHeight!)
var pSetWidth = self.view.frame.width
var pSetHight = ProgressFrame.height
Progress.frame = CGRectMake(pSetX, pSetY, pSetWidth, pSetHight)
self.navigationController?.navigationBar.addSubview(Progress)
Progress.setTranslatesAutoresizingMaskIntoConstraints(false)
}
4.Success!
Have a look at http://www.appcoda.com/webkit-framework-intro/ - below the "Displaying Progress" part.
It's written in Swift, but they use interface builder to create the constraints.

Resources