skip to Main Content

As I’m integrating a native iOS screen in a Flutter plugin I have to set constraints programmatically for the ui as there is no storyboard.

I have these UI components:

    var overlayMaskView: UIView = UIView()
    var previewView: UIView = UIView()
    var stillImagePreviewView: UIImageView = UIImageView()
    var viewFinderShapeLabel: UILabel = UILabel()
    var viewfinderShapeType: UISegmentedControl = UISegmentedControl()
    var vehicleTypeLabel: UILabel  = UILabel()
    var vehicleType: UISegmentedControl = UISegmentedControl()

I’m reading their constraints from the storyboard but I’m struggling to replicate them programmatically.
I was able to set constraints for overlayMaskView, previewView and stillImagePreviewView four anchors to the safe area anchors.

//        view.translatesAutoresizingMaskIntoConstraints = false
        
        previewView.translatesAutoresizingMaskIntoConstraints = false
        previewView.backgroundColor = UIColor.black//.black
        previewView.contentMode = .scaleToFill
        previewView.isUserInteractionEnabled = true
        previewView.isOpaque = true
        previewView.clearsContextBeforeDrawing = true
        previewView.clipsToBounds = false
        previewView.autoresizesSubviews = true
        view.addSubview(previewView)
        previewView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
        previewView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
        previewView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
        previewView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true


        stillImagePreviewView.translatesAutoresizingMaskIntoConstraints = false
        stillImagePreviewView.contentMode = .scaleAspectFit
        stillImagePreviewView.isUserInteractionEnabled = false
        stillImagePreviewView.isOpaque = true
        stillImagePreviewView.clearsContextBeforeDrawing = true
        stillImagePreviewView.clipsToBounds = true
        stillImagePreviewView.autoresizesSubviews = true
        view.addSubview(stillImagePreviewView)
        stillImagePreviewView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
        stillImagePreviewView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
        stillImagePreviewView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
        stillImagePreviewView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true

        overlayMaskView.translatesAutoresizingMaskIntoConstraints = false
        overlayMaskView.contentMode = .scaleToFill
        overlayMaskView.isUserInteractionEnabled = true
        overlayMaskView.isOpaque = true
        overlayMaskView.clearsContextBeforeDrawing = true
        overlayMaskView.clipsToBounds = false
        overlayMaskView.autoresizesSubviews = true
        view.addSubview(overlayMaskView)
        overlayMaskView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
        overlayMaskView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
        overlayMaskView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
        overlayMaskView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true

Then the first label viewFinderShapeLabel which has center x aligned to the view x axis, a top anchor to the safe area top anchor with a constant of 8, leading and trailing anchors to the safe area leading and trailing anchors with a constant of 16.
So i set them all like so and it’s at desired position :

        viewFinderShapeLabel.translatesAutoresizingMaskIntoConstraints = false
        viewFinderShapeLabel.text = "Formato targa"
        viewFinderShapeLabel.textAlignment = .center
        viewFinderShapeLabel.textColor = UIColor.white
        viewFinderShapeLabel.isEnabled = true
        viewFinderShapeLabel.isUserInteractionEnabled = false
        viewFinderShapeLabel.isOpaque = false
        viewFinderShapeLabel.clearsContextBeforeDrawing = true
        viewFinderShapeLabel.autoresizesSubviews = true
        view.addSubview(viewFinderShapeLabel)
        viewFinderShapeLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0).isActive = true
        viewFinderShapeLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 8).isActive = true
        viewFinderShapeLabel.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16).isActive = true
        viewFinderShapeLabel.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16).isActive = true

Then there is the first segmented controller which also has center x aligned to the view x axis, leading and trailing anchors to the safe area leading and trailing anchors with a constant of 16, but its top anchor to the viewFinderShapeLabel’s bottom anchor with a constant of 8.

        viewfinderShapeType.translatesAutoresizingMaskIntoConstraints = false
        viewfinderShapeType = UISegmentedControl(items: ["RETTANGOLARE", "QUADRATA"])
        viewfinderShapeType.setEnabled(true, forSegmentAt: 0)
        viewfinderShapeType.setEnabled(true, forSegmentAt: 1)
        viewfinderShapeType.selectedSegmentIndex = 0
        viewfinderShapeType.isEnabled = true
        viewfinderShapeType.isUserInteractionEnabled = true
        viewfinderShapeType.clearsContextBeforeDrawing = true
        viewfinderShapeType.autoresizesSubviews = true
        view.addSubview(viewfinderShapeType)
        viewfinderShapeType.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0).isActive = true
        viewfinderShapeType.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16).isActive = true
        viewfinderShapeType.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16).isActive = true
        viewfinderShapeType.topAnchor.constraint(equalTo: viewFinderShapeLabel.bottomAnchor, constant: 8).isActive = true

This setup fails as the segmented control is placed at the top left corner without any spacing.

What am I doing wrong causing these latest constraints not to work?

2

Answers


  1. I don’t quite understand how you want to create the UI… Below is an example based on your code that could help you, the part that changes color is already an imageView:

    import UIKit
    
    var overlayMaskView = UIView()
    var previewView = UIView()
    var stillImagePreviewView = UIImageView()
    var viewFinderShapeLabel = UILabel()
    var viewfinderShapeType = UISegmentedControl()
    var vehicleTypeLabel = UILabel()
    var vehicleType = UISegmentedControl()
    
    class ViewController: UIViewController {
    
    override func viewDidLoad() {
    super.viewDidLoad()
    
    view.backgroundColor = .black
    
    previewView.translatesAutoresizingMaskIntoConstraints = false
    previewView.backgroundColor = UIColor.red //.black
    view.addSubview(previewView)
    previewView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
    previewView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
    previewView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
    previewView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
    
    viewFinderShapeLabel.translatesAutoresizingMaskIntoConstraints = false
    viewFinderShapeLabel.text = "Formato targa"
    viewFinderShapeLabel.font = .systemFont(ofSize: 16, weight: .bold)
    viewFinderShapeLabel.textAlignment = .center
    viewFinderShapeLabel.textColor = .white
    previewView.addSubview(viewFinderShapeLabel)
    viewFinderShapeLabel.heightAnchor.constraint(equalToConstant: 30).isActive = true
    viewFinderShapeLabel.topAnchor.constraint(equalTo: previewView.topAnchor, constant: 16).isActive = true
    viewFinderShapeLabel.leadingAnchor.constraint(equalTo: previewView.leadingAnchor, constant: 16).isActive = true
    viewFinderShapeLabel.trailingAnchor.constraint(equalTo: previewView.trailingAnchor, constant: -16).isActive = true
    
    let items = ["RETTANGOLARE", "QUADRATA"]
    viewfinderShapeType = UISegmentedControl(items: items)
    viewfinderShapeType.selectedSegmentIndex = 0
    viewfinderShapeType.layer.cornerRadius = 5.0
    viewfinderShapeType.backgroundColor = .white.withAlphaComponent(0.5)
    viewfinderShapeType.addTarget(self, action: #selector(change), for: .valueChanged)
    viewfinderShapeType.translatesAutoresizingMaskIntoConstraints = false
    
    previewView.addSubview(viewfinderShapeType)
    viewfinderShapeType.topAnchor.constraint(equalTo: viewFinderShapeLabel.bottomAnchor, constant: 10).isActive = true
    viewfinderShapeType.centerXAnchor.constraint(equalTo: previewView.centerXAnchor).isActive = true
    
    stillImagePreviewView.translatesAutoresizingMaskIntoConstraints = false
    stillImagePreviewView.contentMode = .scaleAspectFit
    stillImagePreviewView.isUserInteractionEnabled = false
    stillImagePreviewView.backgroundColor = .white
    view.addSubview(stillImagePreviewView)
    stillImagePreviewView.leadingAnchor.constraint(equalTo: previewView.leadingAnchor, constant: 0).isActive = true
    stillImagePreviewView.trailingAnchor.constraint(equalTo: previewView.trailingAnchor, constant: 0).isActive = true
    stillImagePreviewView.topAnchor.constraint(equalTo: viewfinderShapeType.bottomAnchor, constant: 20).isActive = true
    stillImagePreviewView.bottomAnchor.constraint(equalTo: previewView.bottomAnchor, constant: 0).isActive = true
    }
    
    @objc fileprivate func change() {
    if stillImagePreviewView.backgroundColor == .white {
        stillImagePreviewView.backgroundColor = .systemOrange
    } else {
        stillImagePreviewView.backgroundColor = .white
      }
     }
    }
    

    enter image description here

    Login or Signup to reply.
  2. You have created a segmented control as a property of your class:

    var viewfinderShapeType: UISegmentedControl = UISegmentedControl()
    

    The reason your code puts the segmented control at top left is due to these two lines:

    viewfinderShapeType.translatesAutoresizingMaskIntoConstraints = false
    viewfinderShapeType = UISegmentedControl(items: ["RETTANGOLARE", "QUADRATA"])
    

    The first line sets .translatesAutoresizingMaskIntoConstraints = false on the control which is a property of your class.

    The second line creates a NEW UISegmentedControl … which does not have .translatesAutoresizingMaskIntoConstraints set to false … and assigns that new control to the class property.

    You could either swap the order of those two lines (create the new instance and then set translates…), or,

    declare your control like this:

    var viewfinderShapeType: UISegmentedControl = {
        let v = UISegmentedControl(items: ["RETTANGOLARE", "QUADRATA"])
        return v
    }()
    

    and get rid of this line:

    //viewfinderShapeType = UISegmentedControl(items: ["RETTANGOLARE", "QUADRATA"])
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search