Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/102.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 使用嵌套堆栈视图确定视图间距_Ios_Swift_Autolayout_Uikit_Uistackview - Fatal编程技术网

Ios 使用嵌套堆栈视图确定视图间距

Ios 使用嵌套堆栈视图确定视图间距,ios,swift,autolayout,uikit,uistackview,Ios,Swift,Autolayout,Uikit,Uistackview,按照Apple的指南(我是通过编程实现的),我创建了3个嵌套在垂直堆栈视图中的水平堆栈视图。为了使文本字段对齐,它们也都位于水平堆栈视图中 是否有方法快速浏览文本字段堆栈视图,以便查看3个字符的占位符文本?我尝试过.fill,.fill按比例,以及其他方法,但水平堆栈视图的标签比例为50/50 我不熟悉自动布局,所以我把它作为一个学习练习。必须有更好的方法来做到这一点,对吗 类似于此(1/4-1/3空间用于标签,2/3-3/4空间用于文本字段) 您可以在标签和textfieldsStackvi

按照Apple的指南(我是通过编程实现的),我创建了3个嵌套在垂直堆栈视图中的水平堆栈视图。为了使文本字段对齐,它们也都位于水平堆栈视图中

是否有方法快速浏览文本字段堆栈视图,以便查看3个字符的占位符文本?我尝试过
.fill
.fill按比例
,以及其他方法,但水平堆栈视图的标签比例为50/50

我不熟悉自动布局,所以我把它作为一个学习练习。必须有更好的方法来做到这一点,对吗

类似于此(1/4-1/3空间用于标签,2/3-3/4空间用于文本字段)


您可以在标签和textfieldsStackview之间添加一个透明的UIView(所谓的间隔视图),并向其添加宽度约束。容器stackview(包含所有三个视图)的分布应为
.fill

[UILabel][UIView][UIStackView]
[UILabel][UIView][UIStackView] 
[UILabel][UIView][UIStackView]

使用包含具有自动布局约束的常规UIView的垂直堆栈视图,然后让每个UIView包含一个UILabel和另一个水平UIStackView(或文本视图,用于第2行)可能更容易。这样,您可以轻松控制标签和子视图的大小和间距。

创建“列”可能有点棘手

根据您的图片和描述,我猜您希望将此(或至少接近此)作为最终结果:

要做到这一点,有两件事:

  • 将水平“行”堆栈视图上的分布设置为
    。填充
  • 将水平“field:field:field”堆栈视图上的分布设置为
    。填充
  • 使用
    .multiplier
    为每个“标题”标签指定一个
    widthAnchor
    等于其堆栈视图百分比的值(为每个“行”指定相同的百分比值)
  • 将“冒号”标签的拥抱设置为
    。必需
  • 将“最小”和“秒”字段宽度约束设置为“小时”字段宽度
这是您的代码,修改后生成我的屏幕截图。我试图只改变必要的内容,我想我包括了足够多的评论来说明:

class RunningPaceCalculatorViewController: UIViewController {
    
    // percent of overall width for Time/Distance/Pace "column" of labels
    private let labelWidth: CGFloat = 0.33
    
    private lazy var timeDistancePaceStackView: UIStackView = {
        // added titleWidth parameter -- percent of width of stack view
        let timeStackView = UIStackView.textFieldsStackView("Time", titleWidth: labelWidth)
        let distanceStackView = UIStackView.distanceStackView(labelWidth)
        let paceStackView = UIStackView.textFieldsStackView("Pace", titleWidth: labelWidth)
        // include setting distribution parameter
        return UIStackView.customStackView(.vertical, distribution: .fillEqually, backgroundColor: .systemTeal, subviews: [timeStackView, distanceStackView, paceStackView])
    }()
    
    private lazy var buttonStackView: UIStackView = {
        return UIStackView.buttonStackView()
    }()
    
    private lazy var constainerStackView: UIStackView = {
        // include setting distribution parameter
        return UIStackView.customStackView(.vertical, distribution: .fillEqually, backgroundColor: .gray, subviews: [timeDistancePaceStackView, buttonStackView])
    }()
    
    override func viewDidLoad() {
        setUpView()
    }
    
    func setUpView() {
        view.backgroundColor = .orange
        view.addSubview(constainerStackView)
        
        NSLayoutConstraint.activate([
            constainerStackView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.55),
            // we're setting Leading and Trailing, so we don't need centerX
            //constainerStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            constainerStackView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            constainerStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
            constainerStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10)
        ])
    }
}

private extension UITextField {
    static func customTextField(_ placeholder: String) -> UITextField {
        let textField = UITextField()
        textField.placeholder = placeholder
        textField.backgroundColor = .white
        return textField
    }
}

private extension UIStackView {
    static func customStackView(_ orientation: NSLayoutConstraint.Axis, distribution: UIStackView.Distribution = UIStackView.Distribution.fill, backgroundColor: UIColor, subviews: [UIView]) -> UIStackView {
        let stackView = UIStackView(arrangedSubviews: subviews)
        stackView.axis = orientation
        
        // use distribution parameter, not hard-coded .fillEqually
        //stackView.distribution = .fillEqually
        stackView.distribution = distribution
        
        stackView.backgroundColor = backgroundColor
        stackView.spacing = 5.0
        stackView.directionalLayoutMargins = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2)
        stackView.isLayoutMarginsRelativeArrangement = true
        stackView.translatesAutoresizingMaskIntoConstraints = false
        return stackView
    }
    
    static func textFieldsStackView(_ title: String, titleWidth: CGFloat) -> UIStackView {
        let COLON = ":"
        let label = UILabel.customLabel(title)
        let paceTextField1 = UITextField.customTextField("Hrs")
        let colonLabel1 = UILabel.customLabel(COLON)
        let paceTextField2 = UITextField.customTextField("Min")
        let colonLabel2 = UILabel.customLabel(COLON)
        let paceTextField3 = UITextField.customTextField("Sec")
        // include setting distribution parameter
        let textFieldContainerStackView = UIStackView.customStackView(.horizontal, distribution: .fill, backgroundColor: .systemPink, subviews: [paceTextField1, colonLabel1, paceTextField2, colonLabel2, paceTextField3])
        
        // create the stack view to return
        let retStack = UIStackView.customStackView(.horizontal, distribution: .fill, backgroundColor: .systemBlue, subviews: [label, textFieldContainerStackView])
        // colon labels should HUG their content
        colonLabel1.setContentHuggingPriority(.required, for: .horizontal)
        colonLabel2.setContentHuggingPriority(.required, for: .horizontal)
        NSLayoutConstraint.activate([
            // constrain "title label" width to percentage of stack view width
            label.widthAnchor.constraint(equalTo: retStack.widthAnchor, multiplier: titleWidth),
            // constrain text field widths to each other
            paceTextField2.widthAnchor.constraint(equalTo: paceTextField1.widthAnchor),
            paceTextField3.widthAnchor.constraint(equalTo: paceTextField1.widthAnchor),
        ])
        return retStack
    }
    
    static func distanceStackView(_ titleWidth: CGFloat) -> UIStackView {
        let DISTANCE = "Distance"
        let label = UILabel.customLabel(DISTANCE)
        let distanceTextField = UITextField.customTextField(DISTANCE)

        // create the stack view to return
        let retStack = UIStackView.customStackView(.horizontal, distribution: .fill, backgroundColor: .systemGray, subviews: [label, distanceTextField])
        NSLayoutConstraint.activate([
            // constrain "title label" width to percentage of stack view width
            label.widthAnchor.constraint(equalTo: retStack.widthAnchor, multiplier: titleWidth),
        ])
        return retStack
    }
    
    static func buttonStackView() -> UIStackView {
        let calculateButton = UIButton.customButton("Calculate")
        let resetButton = UIButton.customButton("Reset")
        // include setting distribution parameter
        return UIStackView.customStackView(.horizontal, distribution: .fillEqually, backgroundColor: .green, subviews: [calculateButton, resetButton])
    }
}

private extension UIButton {
    static func customButton(_ title: String) -> UIButton {
        let button = UIButton()
        button.setTitle(title, for: .normal)
        return button
    }
}

private extension UILabel {
    static func customLabel(_ text: String) -> UILabel {
        let timeLabel = UILabel()
        timeLabel.text = text
        return timeLabel
    }
}

你能举个例子吗?当我将分布设置为
.fill
并添加一个间隔视图和一个约束,如
间隔视图.widthAnchor.constraint(equalToConstant:1)或1000000
,它会使标签和文本之间的间距变大fields@h.and.h查看更新后的答案。在界面生成器中做任何事情都要容易得多。为什么会被否决?
import UIKit

class RunningPaceCalculatorViewController: UIViewController {

    private lazy var timeDistancePaceStackView: UIStackView = {
        let timeStackView = UIStackView.textFieldsStackView("Time")
        let distanceStackView = UIStackView.distanceStackView()
        let paceStackView = UIStackView.textFieldsStackView("Pace")
        return UIStackView.customStackView(.vertical, backgroundColor: .systemTeal, subviews: [timeStackView, distanceStackView, paceStackView])
    }()

    private lazy var buttonStackView: UIStackView = {
        return UIStackView.buttonStackView()
    }()

    private lazy var constainerStackView: UIStackView = {
        return UIStackView.customStackView(.vertical, backgroundColor: .gray, subviews: [timeDistancePaceStackView, buttonStackView])
    }()

    override func viewDidLoad() {
        setUpView()
    }

    func setUpView() {
        view.backgroundColor = .orange
        view.addSubview(constainerStackView)

        NSLayoutConstraint.activate([
            constainerStackView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.55),
            constainerStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            constainerStackView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            constainerStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
            constainerStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10)
        ])
    }
}

private extension UITextField {
    static func customTextField(_ placeholder: String) -> UITextField {
        let textField = UITextField()
        textField.placeholder = placeholder
        textField.backgroundColor = .white
        return textField
    }
}

private extension UIStackView {
    static func customStackView(_ orientation: NSLayoutConstraint.Axis, distribution: UIStackView.Distribution = UIStackView.Distribution.fill, backgroundColor: UIColor, subviews: [UIView]) -> UIStackView {
        let stackView = UIStackView(arrangedSubviews: subviews)
        stackView.axis = orientation
        stackView.distribution = .fillEqually
        stackView.backgroundColor = backgroundColor
        stackView.spacing = 5.0
        stackView.directionalLayoutMargins = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2)
        stackView.isLayoutMarginsRelativeArrangement = true
        stackView.translatesAutoresizingMaskIntoConstraints = false
        return stackView
    }

    static func textFieldsStackView(_ title: String) -> UIStackView {
        let COLON = ":"
        let label = UILabel.customLabel(title)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.setContentHuggingPriority(.defaultHigh + 1, for: .horizontal)
        label.setContentHuggingPriority(.defaultHigh + 1, for: .vertical)

        let spacerView = UIView()
        spacerView.backgroundColor = .clear
        spacerView.translatesAutoresizingMaskIntoConstraints = false
        spacerView.widthAnchor.constraint(equalToConstant: 10).isActive = true

        let paceTextField1 = UITextField.customTextField("Hrs")
        paceTextField1.translatesAutoresizingMaskIntoConstraints = false
        let colonLabel1 = UILabel.customLabel(COLON)
        colonLabel1.translatesAutoresizingMaskIntoConstraints = false
        colonLabel1.widthAnchor.constraint(equalToConstant: 20).isActive = true

        let paceTextField2 = UITextField.customTextField("Min")
        paceTextField2.translatesAutoresizingMaskIntoConstraints = false
        let colonLabel2 = UILabel.customLabel(COLON)
        colonLabel2.translatesAutoresizingMaskIntoConstraints = false
        colonLabel2.widthAnchor.constraint(equalToConstant: 20).isActive = true

        let paceTextField3 = UITextField.customTextField("Sec")
        paceTextField3.translatesAutoresizingMaskIntoConstraints = false

        let textFieldContainerStackView = UIStackView.customStackView(.horizontal, backgroundColor: .systemPink, subviews: [paceTextField1, colonLabel1, paceTextField2, colonLabel2, paceTextField3])
        textFieldContainerStackView.setContentHuggingPriority(.defaultLow - 50, for: .horizontal)
        textFieldContainerStackView.setContentCompressionResistancePriority(.defaultLow - 1, for: .horizontal)
        textFieldContainerStackView.distribution = .fill

        paceTextField1.widthAnchor.constraint(equalTo: paceTextField2.widthAnchor).isActive = true
        paceTextField2.widthAnchor.constraint(equalTo: paceTextField3.widthAnchor).isActive = true

        let stackView = UIStackView.customStackView(.horizontal, distribution: .fill, backgroundColor: .systemBlue, subviews: [label, spacerView, textFieldContainerStackView])
        stackView.distribution = .fill
        return stackView
    }

    static func distanceStackView() -> UIStackView {
        let DISTANCE = "Distance"
        let label = UILabel.customLabel(DISTANCE)
        let distanceTextField = UITextField.customTextField(DISTANCE)
        return UIStackView.customStackView(.horizontal, distribution: .equalCentering, backgroundColor: .systemGray, subviews: [label, distanceTextField])
    }

    static func buttonStackView() -> UIStackView {
        let calculateButton = UIButton.customButton("Calculate")
        let resetButton = UIButton.customButton("Reset")
        return UIStackView.customStackView(.horizontal, backgroundColor: .green, subviews: [calculateButton, resetButton])
    }
}

private extension UIButton {
    static func customButton(_ title: String) -> UIButton {
        let button = UIButton()
        button.setTitle(title, for: .normal)
        return button
    }
}

private extension UILabel {
    static func customLabel(_ text: String) -> UILabel {
        let timeLabel = UILabel()
        timeLabel.text = text
        return timeLabel
    }
}
class RunningPaceCalculatorViewController: UIViewController {
    
    // percent of overall width for Time/Distance/Pace "column" of labels
    private let labelWidth: CGFloat = 0.33
    
    private lazy var timeDistancePaceStackView: UIStackView = {
        // added titleWidth parameter -- percent of width of stack view
        let timeStackView = UIStackView.textFieldsStackView("Time", titleWidth: labelWidth)
        let distanceStackView = UIStackView.distanceStackView(labelWidth)
        let paceStackView = UIStackView.textFieldsStackView("Pace", titleWidth: labelWidth)
        // include setting distribution parameter
        return UIStackView.customStackView(.vertical, distribution: .fillEqually, backgroundColor: .systemTeal, subviews: [timeStackView, distanceStackView, paceStackView])
    }()
    
    private lazy var buttonStackView: UIStackView = {
        return UIStackView.buttonStackView()
    }()
    
    private lazy var constainerStackView: UIStackView = {
        // include setting distribution parameter
        return UIStackView.customStackView(.vertical, distribution: .fillEqually, backgroundColor: .gray, subviews: [timeDistancePaceStackView, buttonStackView])
    }()
    
    override func viewDidLoad() {
        setUpView()
    }
    
    func setUpView() {
        view.backgroundColor = .orange
        view.addSubview(constainerStackView)
        
        NSLayoutConstraint.activate([
            constainerStackView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.55),
            // we're setting Leading and Trailing, so we don't need centerX
            //constainerStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            constainerStackView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            constainerStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
            constainerStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10)
        ])
    }
}

private extension UITextField {
    static func customTextField(_ placeholder: String) -> UITextField {
        let textField = UITextField()
        textField.placeholder = placeholder
        textField.backgroundColor = .white
        return textField
    }
}

private extension UIStackView {
    static func customStackView(_ orientation: NSLayoutConstraint.Axis, distribution: UIStackView.Distribution = UIStackView.Distribution.fill, backgroundColor: UIColor, subviews: [UIView]) -> UIStackView {
        let stackView = UIStackView(arrangedSubviews: subviews)
        stackView.axis = orientation
        
        // use distribution parameter, not hard-coded .fillEqually
        //stackView.distribution = .fillEqually
        stackView.distribution = distribution
        
        stackView.backgroundColor = backgroundColor
        stackView.spacing = 5.0
        stackView.directionalLayoutMargins = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2)
        stackView.isLayoutMarginsRelativeArrangement = true
        stackView.translatesAutoresizingMaskIntoConstraints = false
        return stackView
    }
    
    static func textFieldsStackView(_ title: String, titleWidth: CGFloat) -> UIStackView {
        let COLON = ":"
        let label = UILabel.customLabel(title)
        let paceTextField1 = UITextField.customTextField("Hrs")
        let colonLabel1 = UILabel.customLabel(COLON)
        let paceTextField2 = UITextField.customTextField("Min")
        let colonLabel2 = UILabel.customLabel(COLON)
        let paceTextField3 = UITextField.customTextField("Sec")
        // include setting distribution parameter
        let textFieldContainerStackView = UIStackView.customStackView(.horizontal, distribution: .fill, backgroundColor: .systemPink, subviews: [paceTextField1, colonLabel1, paceTextField2, colonLabel2, paceTextField3])
        
        // create the stack view to return
        let retStack = UIStackView.customStackView(.horizontal, distribution: .fill, backgroundColor: .systemBlue, subviews: [label, textFieldContainerStackView])
        // colon labels should HUG their content
        colonLabel1.setContentHuggingPriority(.required, for: .horizontal)
        colonLabel2.setContentHuggingPriority(.required, for: .horizontal)
        NSLayoutConstraint.activate([
            // constrain "title label" width to percentage of stack view width
            label.widthAnchor.constraint(equalTo: retStack.widthAnchor, multiplier: titleWidth),
            // constrain text field widths to each other
            paceTextField2.widthAnchor.constraint(equalTo: paceTextField1.widthAnchor),
            paceTextField3.widthAnchor.constraint(equalTo: paceTextField1.widthAnchor),
        ])
        return retStack
    }
    
    static func distanceStackView(_ titleWidth: CGFloat) -> UIStackView {
        let DISTANCE = "Distance"
        let label = UILabel.customLabel(DISTANCE)
        let distanceTextField = UITextField.customTextField(DISTANCE)

        // create the stack view to return
        let retStack = UIStackView.customStackView(.horizontal, distribution: .fill, backgroundColor: .systemGray, subviews: [label, distanceTextField])
        NSLayoutConstraint.activate([
            // constrain "title label" width to percentage of stack view width
            label.widthAnchor.constraint(equalTo: retStack.widthAnchor, multiplier: titleWidth),
        ])
        return retStack
    }
    
    static func buttonStackView() -> UIStackView {
        let calculateButton = UIButton.customButton("Calculate")
        let resetButton = UIButton.customButton("Reset")
        // include setting distribution parameter
        return UIStackView.customStackView(.horizontal, distribution: .fillEqually, backgroundColor: .green, subviews: [calculateButton, resetButton])
    }
}

private extension UIButton {
    static func customButton(_ title: String) -> UIButton {
        let button = UIButton()
        button.setTitle(title, for: .normal)
        return button
    }
}

private extension UILabel {
    static func customLabel(_ text: String) -> UILabel {
        let timeLabel = UILabel()
        timeLabel.text = text
        return timeLabel
    }
}