UIScrollView с динамически изменяемым содержимым - PullRequest
0 голосов
/ 19 января 2020

(Xcode 11, Swift)

Будучи новичком ie до iOS и Autolayout, я борюсь с реализацией довольно простого (IMHO) представления, которое отображает [вертикальный] список элементов , Единственная проблема заключается в том, что элементы определяются динамически, и каждый из них может быть либо текстом, либо изображением (где любой из них может быть достаточно большим, поэтому потребуется прокрутка). WebView не является опцией, поэтому он должен быть реализован изначально.

Вот как я понимаю процесс:

  • Сделайте в IB UIScrollView и измените его размер до размера внешний фрейм.
  • Создайте вид контейнера как подпредставление UIScrollView (снова в IB) и измените его размер.
  • Установите ограничение на равную ширину обоих
  • В во время выполнения, заполните представление контейнера UILabels / UIImageViews, а также установите программные ограничения для обеспечения правильной компоновки.
  • «Расскажите» прокручиваемое представление о высоте подпредставления, чтобы оно могло управлять его прокруткой.

Это правильный подход? Кажется, это не работает для меня (для игрушечного примера динамического добавления очень высокого изображения в представление контейнера - я не могу заставить прокрутку работать). Что было бы правильным способом сделать последний шаг в вышеописанном процессе - просто принудительно задайте для contentSize scrollview размер представления заполненного контейнера (мне кажется, это не работает). Любая помощь будет оценена.

Ответы [ 2 ]

3 голосов
/ 20 января 2020

При добавлении нескольких элементов в представление прокрутки во время выполнения может оказаться гораздо проще использовать UIStackView ... при правильной настройке он будет автоматически увеличиваться по высоте с каждым добавленным объектом.

В качестве простого примера ...

1) Начните с добавления UIScrollView (я выделил синий фон, чтобы его было легче увидеть). Ограничьте его нулем со всех четырех сторон:

enter image description here

Обратите внимание, что мы видим «красный круг», указывающий на отсутствующие / конфликтующие ограничения. Пока проигнорируйте это.

2) Добавьте UIView в качестве «представления содержимого» к представлению прокрутки (я дал ему системный желтый фон, чтобы его было легче видеть). Ограничьте его нулем со всех 4 сторон до Руководства по макету содержимого - это (в конечном итоге) определит размер содержимого представления прокрутки. Также ограничьте его равной шириной и высотой для Руководства по компоновке рамы :

enter image description here

Важный шаг: Выберите ограничение высоты и на панели Size Inspector установите флажок Placeholder - Remove at build time. Это удовлетворит автоматической компоновке в IB во время разработки, но позволит высоте этого вида уменьшаться / увеличиваться по мере необходимости.

3) Добавьте Вертикаль UIStackView к «представлению содержимого». Ограничить его до нуля со всех 4 сторон. Настройте его свойства для Fill / Fill / 8 (как показано ниже):

enter image description here

4) Добавьте соединение @IBOutlet в представление стека в вашем контроллере представления учебный класс. Теперь, во время выполнения, когда вы добавляете элементы пользовательского интерфейса в представление стека, вся ваша «прокручиваемость» будет обрабатываться автоматическим макетом.

Вот пример класса:

class DynaScrollViewController: UIViewController {

    @IBOutlet var theStackView: UIStackView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // local var so we can reuse it
        var theLabel = UILabel()
        var theImageView = UIImageView()

        // create a new label
        theLabel = UILabel()
        // this gets set to false when the label is added to a stack view,
        // but good to get in the habit of setting it
        theLabel.translatesAutoresizingMaskIntoConstraints = false
        // multi-line
        theLabel.numberOfLines = 0
        // cyan background to make it easy to see
        theLabel.backgroundColor = .cyan
        // add 9 lines of text to the label
        theLabel.text = (1...9).map({ "Line \($0)" }).joined(separator: "\n")

        // add it to the stack view
        theStackView.addArrangedSubview(theLabel)

        // add another label
        theLabel = UILabel()
        // multi-line
        theLabel.numberOfLines = 0
        // yellow background to make it easy to see
        theLabel.backgroundColor = .yellow
        // add 5 lines of text to the label
        theLabel.text = (1...5).map({ "Line \($0)" }).joined(separator: "\n")

        // add it to the stack view
        theStackView.addArrangedSubview(theLabel)

        // create a new UIImageView
        theImageView = UIImageView()
        // this gets set to false when the label is added to a stack view,
        // but good to get in the habit of setting it
        theImageView.translatesAutoresizingMaskIntoConstraints = false
        // load an image for it - I have one named background
        if let img = UIImage(named: "background") {
            theImageView.image = img
        }
        // let's give the image view a 4:3 width:height ratio
        theImageView.widthAnchor.constraint(equalTo: theImageView.heightAnchor, multiplier: 4.0/3.0).isActive = true

        // add it to the stack view
        theStackView.addArrangedSubview(theImageView)

        // add another label
        theLabel = UILabel()
        // multi-line
        theLabel.numberOfLines = 0
        // yellow background to make it easy to see
        theLabel.backgroundColor = .green
        // add 2 lines of text to the label
        theLabel.text = (1...2).map({ "Line \($0)" }).joined(separator: "\n")

        // add it to the stack view
        theStackView.addArrangedSubview(theLabel)

        // add another UIImageView
        theImageView = UIImageView()
        // this gets set to false when the label is added to a stack view,
        // but good to get in the habit of setting it
        theImageView.translatesAutoresizingMaskIntoConstraints = false
        // load a different image for it - I have one named AquariumBG
        if let img = UIImage(named: "AquariumBG") {
            theImageView.image = img
        }
        // let's give this image view a 1:1 width:height ratio
        theImageView.heightAnchor.constraint(equalTo: theImageView.widthAnchor, multiplier: 1.0).isActive = true

        // add it to the stack view
        theStackView.addArrangedSubview(theImageView)

    }

}

Если шаги были выполнены, вы должны получить следующие выходные данные:

enter image description here

и, после прокрутки вниз:

enter image description here

0 голосов
/ 19 января 2020

Ограничения выравнивания (начальное / конечное / верхнее / нижнее)

Ограничение выравнивания между просмотром прокрутки и представлением содержимого определяет scrollable range of the content. Например, ,

  • Если scrollView.bottom = contentView.bottom, это означает, что представление прокрутки можно прокрутить до нижней части представления содержимого.
  • Если scrollView.bottom = contentView.bottom + 100, нижний конец прокручиваемого представления прокрутки превысит конец представления содержимого на 100 пунктов.
  • Если scrollView.bottom = contentView.bottom - 100, нижняя часть представления содержимого не будет достигнуто, даже если scrollView прокручивается до нижнего края.

То есть (нижний) якорь в представлении прокрутки указывает (нижний) край внешнего кадра, то есть видимую часть представления содержимого. ; (нижняя) привязка в представлении содержимого относится к краю фактического содержимого, которое будет скрыто, если не будет выделено. В отличие от обычных случаев использования, ограничения выравнивания между просмотром прокрутки и представлением содержимого не имеют ничего общего с фактическим размером представления содержимого. Они влияют только на «прокручиваемый диапазон просмотра содержимого», но НЕ на «фактический размер содержимого». Фактический размер представления содержимого должен быть определен дополнительно.

Ограничения размера (ширина / высота)

Чтобы фактически изменить размер представления содержимого, мы можем установить размер представления содержимого до заданной длины c, например, ширина / высота 500. Если ширина / высота превышает ширину / высоту вида прокрутки, для пользователей будет предусмотрена полоса прокрутки. Однако более распространенным случаем будет то, что мы хотим, чтобы представление контента имело ту же ширину (или высоту), что и представление прокрутки. В этом случае у нас будет

contentView.width = scrollView.width

Ширина представления содержимого относится к фактической полной ширине содержимого. С другой стороны, ширина представления прокрутки относится к ширине рамки внешнего контейнера в представлении прокрутки. Конечно, она не обязательно должна быть такой же ширины, но могут быть и другие формы, такие как * scrollView.width + b. И если у нас есть представление содержимого выше (или шире), чем представление прокрутки, появляется полоса прокрутки. Представление содержимого может представлять собой не только одно представление, но и несколько представлений, если они соответствующим образом ограничены с помощью ограничений выравнивания и размера для представления прокрутки.

Подробнее см. В этой статье: Ссылка .

...