Swift: динамическое наложение подпредставлений внутри суперпредставления - PullRequest
0 голосов
/ 01 апреля 2019

Я пытаюсь создать логин на странице, которая должна выглядеть так, как указано ниже.Код, который я написал, должен отображать этот вид без логотипа и кнопки переключения [Логин | Регистрация].Высота и ширина моего ящика тоже разные, но меня это не касается.

enter image description here

В настоящее время я получаю этот вывод.Я обеспокоен тем, как все слова перекрывают друг друга наверху.

enter image description here

В коде, который я перечислил ниже, я создаю свои 3 текстовых поля, моя кнопка и контейнер для моих текстовых полей.Я считаю, что в функции fieldConstraints что-то не так.В этой функции я просматриваю массив всех моих текстовых полей и назначаю им необходимые ограничения.Все они получают одинаковые ограничения, за исключением того, что topAnchor каждого текстового поля после первого устанавливается равным bottomAnchor разделителя, который был помещен под текстовым полем ранее.Эти синие линии между текстовыми полями являются разделителями.

Основной класс

class SignIn: UIViewController {

    override func loadView() {
        super.loadView()
        let inputContainer = inputDataContainer()
        constraintsToCenterSubview(forView: inputContainer, width: 100, height: 100)
        let nameField = field(for: "Name")
        let emailField = field(for: "Email address")
        let passField = field(for: "Password")
        let fields = [nameField, emailField, passField]
        let button = loginButton()
        fieldConstraints(subviews: fields, superview: inputContainer)
        self.centerViewBelow(forView: button, whichIsBelow: inputContainer, increaseWidthBy: 0)
    }

    func inputDataContainer() -> UIView{
        let inputView = UIView(frame: CGRect(x: self.view.center.x, y: self.view.center.y, width: CGFloat(100), height: CGFloat(100)))
        inputView.backgroundColor = UIColor.white
        inputView.translatesAutoresizingMaskIntoConstraints = false
        inputView.layer.cornerRadius = 5
        inputView.layer.masksToBounds = true
        self.view.addSubview(inputView)
        //inputView = centerViewBelow(forView: inputView, whichIsBelow: self.view, increaseWidthBy: 100)
        return inputView
    }

    func loginButton() -> UIButton {
        let button = UIButton()
        button.backgroundColor = UIColor(r: 80, g: 101, b: 161)
        button.setTitle("Submit", for: [])
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setTitleColor(UIColor.white, for: [])
        button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
        self.view.addSubview(button)
        return button
    }

    func field(for name: String) -> UITextField{
        let tf = UITextField()
        tf.placeholder = name
        tf.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(tf)
        return tf
    }

    func fieldSep() -> UIView {
        let view = UIView()
        view.backgroundColor = UIColor(r: 220, g: 220, b: 220)
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }

    func fieldConstraints(subviews: [UIView], superview: UIView) {
        var sep: UIView?
        let len = subviews.endIndex
        for (idx, subview) in subviews.enumerated(){
            superview.addSubview(subview)
            subview.leftAnchor.constraint(equalTo: superview.leftAnchor)
            subview.rightAnchor.constraint(equalTo: superview.rightAnchor)
            subview.widthAnchor.constraint(equalTo: superview.widthAnchor)
            subview.heightAnchor.constraint(equalTo: superview.heightAnchor, multiplier: CGFloat(1/len))
            if (sep != nil){
                subview.topAnchor.constraint(equalTo: sep!.bottomAnchor)
            }else{
                subview.topAnchor.constraint(equalTo: superview.topAnchor)
            }
            sep = fieldSep()
            if idx < subviews.endIndex-1 {
                self.view.addSubview(sep!)
                sep?.leftAnchor.constraint(equalTo: superview.leftAnchor)
                sep?.rightAnchor.constraint(equalTo: superview.rightAnchor)
                sep?.topAnchor.constraint(equalTo: subview.bottomAnchor)
            }
        }


    }
}

Расширения

extension UIColor {
    convenience init(r:CGFloat, g:CGFloat, b: CGFloat) {
        self.init(red: r/255, green: g/255, blue: b/255, alpha: 1)
    }
}

extension UIViewController {
    func centerViewBelow(forView view: UIView, whichIsBelow topView: UIView, increaseWidthBy constant: CGFloat){
        let topConstraint = NSLayoutConstraint(item: view, attribute: .top, relatedBy: .equal, toItem: topView, attribute: .bottom, multiplier: 1, constant: 20)
        let widthConstraint = NSLayoutConstraint(item: view, attribute: .width, relatedBy: .equal, toItem: topView, attribute: .width, multiplier: 1, constant: constant)
        let centerConstraint = NSLayoutConstraint(item: view, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1, constant: 0)
        let heightConstraint = NSLayoutConstraint(item: view, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 50)
        NSLayoutConstraint.activate([topConstraint, widthConstraint, centerConstraint, heightConstraint])
        //return view
    }

    func constraintsToCenterSubview(forView view: UIView, width: Int, height: Int){
        let centerXConstraint = NSLayoutConstraint(item: view, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1, constant: 0)
        let centerYConstraint = NSLayoutConstraint(item: view, attribute: .centerY, relatedBy: .equal, toItem: self.view, attribute: .centerY, multiplier: 1, constant: 0)
        let widthConstraint = NSLayoutConstraint(item: view, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1, constant: CGFloat(width))
        let heightConstraint = NSLayoutConstraint(item: view, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: CGFloat(height))
        NSLayoutConstraint.activate([centerXConstraint, centerYConstraint, widthConstraint, heightConstraint])
    }

}

Спасибо


----------------------------------------------------------------------------------------------------------


Обновление

Так что я в значительной степени смог сделать этоизменив мой контейнер в виде стека.Но это сделало так, что мои углы больше не были закруглены.Кто-нибудь знает, как это исправить?

func inputDataContainer() -> UIStackView{
    let inputView = UIStackView(frame: CGRect(x: self.view.center.x, y: self.view.center.y, width: CGFloat(100), height: CGFloat(100)))
    inputView.backgroundColor = UIColor.white
    inputView.translatesAutoresizingMaskIntoConstraints = false
    inputView.layer.cornerRadius = 5
    inputView.layer.masksToBounds = true
    inputView.distribution = .fillEqually
    inputView.axis = .vertical
    inputView.spacing = 1
    self.view.addSubview(inputView)
    //inputView = centerViewBelow(forView: inputView, whichIsBelow: self.view, increaseWidthBy: 100)
    return inputView
}

func fieldConstraints(subviews: [UIView], superview: UIStackView) {
    for subview in subviews{
        superview.addArrangedSubview(subview)
        subview.clipsToBounds = true
    }
}

Пример снимка экрана текущего приложения

enter image description here

Ответы [ 3 ]

1 голос
/ 01 апреля 2019

Попробуйте указать высоту для

sep?.heightAnchor.constraint(equalToConstant:1.0).isActive = true

также для всех ограничений в fieldConstraints вы забыли

.isActive = true

или используйте NSLayoutConstraint.activate, например

NSLayoutConstraint.activate([
     subview.leftAnchor.constraint(equalTo: superview.leftAnchor),
     subview.rightAnchor.constraint(equalTo: superview.rightAnchor)  
     subview.widthAnchor.constraint(equalTo: superview.widthAnchor),
     subview.heightAnchor.constraint(equalTo: superview.heightAnchor, multiplier: CGFloat(1/len))
])

Этот подход будет работать, но будет лучше использовать вертикальный стек с распределением .fillEqually, и он разделит их и добавит как

 fileds.forEach { stackview.addArrangedSubview($0) }
0 голосов
/ 03 апреля 2019

У вас будут небольшие проблемы с использованием UIStackView. Вы можете встроить его в UIView и дать этому виду скругленные углы, но затем вам нужно добавить отступы к полям в стековом виде, чтобы получить разделительные линии.

Вот еще один подход, который может работать лучше для вас. Это ближе к вашему исходному коду, добавляя поля и представления разделителя к UIView:

extension UIColor {
    convenience init(r:CGFloat, g:CGFloat, b: CGFloat) {
        self.init(red: r/255, green: g/255, blue: b/255, alpha: 1)
    }
}

class SampleViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor(r: 65, g: 92, b: 144)

        let nameField = field(for: "Name")
        let sep1 = fieldSep()
        let emailField = field(for: "Email address")
        let sep2 = fieldSep()
        let passField = field(for: "Password")
        let views = [nameField, sep1, emailField, sep2, passField]
        let inputView = inputDataContainer(with: views)

        view.addSubview(inputView)

        NSLayoutConstraint.activate([
            inputView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20.0),
            inputView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20.0),
            inputView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0.0),
            ])

    }

    func field(for s: String) -> UITextField {
        let f = UITextField()
        f.translatesAutoresizingMaskIntoConstraints = false
        f.placeholder = s
        f.borderStyle = .none
        return f
    }

    func fieldSep() -> UIView {
        let v = UIView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.heightAnchor.constraint(equalToConstant: 1.0).isActive = true
        v.backgroundColor = UIColor(r: 220, g: 220, b: 220)
        return v
    }

    func inputDataContainer(with subviews: [UIView]) -> UIView {

        let horizontalPadding: CGFloat = 8.0
        let verticalSpacing: CGFloat = 8.0

        let containerView = UIView()
        containerView.translatesAutoresizingMaskIntoConstraints = false
        containerView.backgroundColor = .white
        containerView.layer.cornerRadius = 5

        var previousView: UIView?

        for subview in subviews{
            containerView.addSubview(subview)

            // if it's a text field, we want padding on left and right
            if subview is UITextField {
                subview.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: horizontalPadding).isActive = true
                subview.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -horizontalPadding).isActive = true
            } else {
                subview.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 0.0).isActive = true
                subview.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: 0.0).isActive = true
            }

            if subview == subviews.first {
                // if it's the first subview, constrain to top of container
                subview.topAnchor.constraint(equalTo: containerView.topAnchor, constant: verticalSpacing).isActive = true
            } else {
                // unwrap previousView and constrain subview to bottom of previous subview
                if let pv = previousView {
                    subview.topAnchor.constraint(equalTo: pv.bottomAnchor, constant: verticalSpacing).isActive = true
                }
            }
            if subview == subviews.last {
                // if it's the last subview, constrain to bottom of container
                subview.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -verticalSpacing).isActive = true
            }

            // save reference to current subview
            previousView = subview

        }

        return containerView
    }

}

И результат:

enter image description here

0 голосов
/ 02 апреля 2019

используйте UIStackView.это поможет вам сэкономить время на создание сложного интерфейса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...