Требуется справка по макету ViewController - PullRequest
0 голосов
/ 06 августа 2020

Я использую XCode для создания пользовательского интерфейса для приложения таймера / метронома обратного отсчета. После борьбы с ограничениями компоновки я обнаружил вертикальные и горизонтальные представления стека, которые, как я думал, значительно упростят задачу.

Однако крайние границы представления стека кажутся вне поля зрения устройства. Я удалил все ограничения макета, но это не имело никакого значения.

Вот частичный снимок экрана проекта в XCode:

Границы StackView

Извините, если этот вопрос задавали раньше - я смотрел, но ничего не нашел.

Я профессиональный разработчик программного обеспечения последние 30 лет или около того. Языки, с которыми я работаю ежедневно в течение последних 20 лет, - это Java, C ++ и Fortran. Так что работа с макетом пользовательского интерфейса в IOS, мягко говоря, разочаровывает!

Заранее благодарим за любую помощь!

Изменить: вот скриншот самого верхнего инспектора размера представления стека: размер инспектор

1 Ответ

0 голосов
/ 06 августа 2020

Я хорошо знаю твое разочарование, потому что, когда я начинал, оно было и моим, и я решил помочь тебе. Сделайте весь пользовательский интерфейс программно следующим образом:

в вашем классе Controller построил ваши объекты программно:

let buttonPlay: UIButton = {
    let button = UIButton(type: .system)
    button.backgroundColor = UIColor.yourColor
    let image = UIImage(systemName: "play.fill")
    button.setImage(image, for: .normal)
    button.tintColor = .black
    button.heightAnchor.constraint(equalToConstant: 50).isActive = true
    button.layer.cornerRadius = 25
    button.clipsToBounds = true
    return button
}()

let buttonPause: UIButton = {
    let button = UIButton(type: .system)
    button.backgroundColor = UIColor.yourColor
    let image = UIImage(systemName: "pause.fill")
    button.setImage(image, for: .normal)
    button.tintColor = .black
    button.heightAnchor.constraint(equalToConstant: 50).isActive = true
    button.layer.cornerRadius = 25
    button.clipsToBounds = true
    return button
}()

let buttonStop: UIButton = {
    let button = UIButton(type: .system)
    button.backgroundColor = UIColor.yourColor
    let image = UIImage(systemName: "stop.fill")
    button.setImage(image, for: .normal)
    button.tintColor = .black
    button.heightAnchor.constraint(equalToConstant: 50).isActive = true
    button.layer.cornerRadius = 25
    button.clipsToBounds = true
    return button
}()

let minutesLabel: UILabel = {
    let label = UILabel()
    label.backgroundColor = .white
    label.text = "MM"
    label.textColor = .gray
    label.textAlignment = .center
    label.font = .systemFont(ofSize: 20, weight: .semibold)
    return label
}()

let secondsLabel: UILabel = {
    let label = UILabel()
    label.backgroundColor = .white
    label.text = "SS"
    label.textColor = .gray
    label.textAlignment = .center
    label.font = .systemFont(ofSize: 20, weight: .semibold)
    return label
}()

let separatorLabel: UILabel = {
    let label = UILabel()
    label.backgroundColor = .clear
    label.text = ":"
    label.textColor = .black
    label.textAlignment = .center
    label.font = .systemFont(ofSize: 20, weight: .semibold)
    return label
}()

let titleLabel: UILabel = {
    let label = UILabel()
    label.backgroundColor = UIColor.yourColor
    label.text = "Title label"
    label.textColor = .black
    label.textAlignment = .center
    label.font = .systemFont(ofSize: 20, weight: .semibold)
    label.translatesAutoresizingMaskIntoConstraints = false // this distactive automatic constraints
    return label
}()

let timeLabel: UILabel = {
    let label = UILabel()
    label.backgroundColor = .clear
    label.text = "Tempo:"
    label.textColor = .black
    label.font = .systemFont(ofSize: 20, weight: .regular)
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
}()

let imageViewTime: UIImageView = {
    
    let image = UIImage(named: "yourImage")?.withRenderingMode(.alwaysTemplate)
    let imageView = UIImageView(image: image)
    imageView.tintColor = .white
    imageView.backgroundColor = .purple
    imageView.contentMode = .scaleAspectFit
    imageView.translatesAutoresizingMaskIntoConstraints = false
    return imageView
}()

let slider: UISlider = {
    let s = UISlider()
    s.maximumValue = 0
    s.maximumValue = 100
    s.isContinuous = true
    s.tintColor = .black
    s.addTarget(self, action: #selector(sliderInAction), for: .valueChanged) // call the function below to show slider value
    s.translatesAutoresizingMaskIntoConstraints = false
    
    return s
}()

let sliderLabel: UILabel = {
    let label = UILabel()
    label.backgroundColor = .clear
    label.text = "2"
    label.textAlignment = .center
    label.textColor = .black
    label.font = .systemFont(ofSize: 16, weight: .regular)
    label.widthAnchor.constraint(equalToConstant: 30).isActive = true
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
}()

let containerSlider: UIView = {
    let v = UIView()
    v.backgroundColor = UIColor.yourColor
    v.translatesAutoresizingMaskIntoConstraints = false
    return v
}()

В viewDidLoad установите цвет фона и вызовите функцию для настройки программных ограничений:

override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = UIColor.yourColor
    setupConstraints()
}

теперь устанавливаем ограничения с помощью автозапуска:

fileprivate func setupConstraints() {
    let stackViewTime = UIStackView(arrangedSubviews: [minutesLabel, separatorLabel, secondsLabel])
    stackViewTime.distribution = .fillProportionally
    stackViewTime.spacing = 4
    stackViewTime.translatesAutoresizingMaskIntoConstraints = false
    
    view.addSubview(stackViewTime)
    stackViewTime.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10).isActive = true
    stackViewTime.heightAnchor.constraint(equalToConstant: 50).isActive = true
    stackViewTime.widthAnchor.constraint(equalToConstant: 148).isActive = true
    stackViewTime.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    
    let stackViewPlayer = UIStackView(arrangedSubviews: [buttonPlay, buttonPause, buttonStop])
    stackViewPlayer.distribution = .fillEqually
    stackViewPlayer.spacing = 10
    stackViewPlayer.translatesAutoresizingMaskIntoConstraints = false
    
    view.addSubview(stackViewPlayer)
    stackViewPlayer.widthAnchor.constraint(equalToConstant: 170).isActive = true
    stackViewPlayer.heightAnchor.constraint(equalToConstant: 50).isActive = true
    stackViewPlayer.centerXAnchor.constraint(equalTo: stackViewTime.centerXAnchor).isActive = true
    stackViewPlayer.topAnchor.constraint(equalTo: stackViewTime.bottomAnchor, constant: 20).isActive = true
    
    view.addSubview(imageViewTime)
    imageViewTime.topAnchor.constraint(equalTo: stackViewPlayer.bottomAnchor, constant: 20).isActive = true
    imageViewTime.heightAnchor.constraint(equalToConstant: 80).isActive = true
    imageViewTime.widthAnchor.constraint(equalToConstant: 60).isActive = true
    imageViewTime.centerXAnchor.constraint(equalTo: stackViewTime.centerXAnchor).isActive = true
    
    view.addSubview(titleLabel)
    titleLabel.topAnchor.constraint(equalTo: imageViewTime.bottomAnchor, constant: 20).isActive = true
    titleLabel.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 30).isActive = true
    titleLabel.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -30).isActive = true
    titleLabel.heightAnchor.constraint(equalToConstant: 50).isActive = true
    
    view.addSubview(timeLabel)
    timeLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 10).isActive = true
    timeLabel.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 10).isActive = true
    timeLabel.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -10).isActive = true
    timeLabel.heightAnchor.constraint(equalToConstant: 50).isActive = true
    
    let stackSlider = UIStackView(arrangedSubviews: [sliderLabel, slider])
    stackSlider.distribution = .fill
    stackSlider.spacing = 10
    stackSlider.translatesAutoresizingMaskIntoConstraints = false
    
    
    view.addSubview(containerSlider)
    containerSlider.topAnchor.constraint(equalTo: timeLabel.bottomAnchor, constant: 0).isActive = true
    containerSlider.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 10).isActive = true
    containerSlider.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -10).isActive = true
    containerSlider.heightAnchor.constraint(equalToConstant: 30).isActive = true
    
    containerSlider.addSubview(stackSlider)
    stackSlider.topAnchor.constraint(equalTo: containerSlider.topAnchor).isActive = true
    stackSlider.bottomAnchor.constraint(equalTo: containerSlider.bottomAnchor).isActive = true
    stackSlider.leadingAnchor.constraint(equalTo: containerSlider.leadingAnchor, constant: 10).isActive = true
    stackSlider.trailingAnchor.constraint(equalTo: containerSlider.trailingAnchor, constant: -10).isActive = true
}

последний шаг устанавливает функцию для отображения значения ползунка в ярлыке ползунка при его перемещении:

@objc fileprivate func sliderInAction() {
    sliderLabel.text = "\(Int(slider.value))"
}

Это результат:

введите описание изображения здесь

Поиграйте с этим кодом, опытный разработчик, как и вы, должен потратить немного времени на написание кода.

...