SwiftUI: Хитрые макеты с пиннингом и соседями? - PullRequest
1 голос
/ 30 марта 2020

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

enter image description here

Здесь показаны 3 варианта одного и того же представления. В представлении есть 3 текстовых детей. Слева, по центру и справа со следующими свойствами:

  • Виды слева и справа, закрепленные в начале и в конце суперпредставления, вид по центру всегда остается в центре суперпредставления (1)
  • Вид по центру остается в центре, если какой-либо вид сбоку отсутствует или является пустым (2)
  • Вид по центру увеличивается, пока не достигнет любого вида сбоку, а затем обрезает его содержимое (3)

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

Как этого добиться с помощью макета SwiftUI?

import SwiftUI

struct MyExample: View {

    let leftText:String
    let mainText:String
    let rightText:String

    var body: some View {
        HStack{
            HStack {
                Text(self.leftText)
                    .modifier(MyBigFont())

                Spacer()
            }

            Text(self.mainText)
                .modifier(MyBigFont())
                .layoutPriority(1.0)

            HStack {
                Spacer()
                Text(self.rightText)
                    .modifier(MyBigFont())

            }
        }
    }

}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        VStack {
            MyExample(leftText:"ABC", mainText:"1234", rightText:"XYZ").padding()
            MyExample(leftText:"", mainText:"1234", rightText:"XYZ").padding()
            MyExample(leftText:"ABC", mainText:"1234567890", rightText:"XYZ").padding()
            Spacer()
        }
    }
}

struct MyBigFont: ViewModifier {
    func body(content: Content) -> some View {
        content
            .lineLimit(1)
            .font(Font.system(size: 42).bold())
    }
}

Вывод:

enter image description here

1 Ответ

2 голосов
/ 30 марта 2020

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

var body: some View {
    HStack{
        HStack {
            Text(self.leftText)
                .modifier(MyBigFont())
                .fixedSize()   // <====

            Spacer()
        }

        Text(self.mainText)
            .modifier(MyBigFont())
            .padding(.horizontal)
            .layoutPriority(1.0)


        HStack {
            Spacer()
            Text(self.rightText)
                .modifier(MyBigFont())
                .fixedSize()    // <====
        }
    }
}

enter image description here


Ваш вопрос в комментарии действительно хорош, и отличный повод объяснить, как это работает. Здесь нет ничего сложного IMO, так что это хорошо понять.

Из документов layoutPriority: «Родительский макет должен предлагать дочерним элементам с наивысшим приоритетом макета все пространство, предлагаемое родителю, за вычетом минимальное пространство, необходимое для всех дочерних элементов с более низким приоритетом и т. д. для каждого значения с более низким приоритетом. " (выделение мое) Разве это не означает, что SwiftUI должен придавать боковым текстам минимальный размер, чтобы соответствовать их содержимому?

SwiftUI равен , давая боковым текстам минимальный размер, чтобы соответствовать их тексту. содержание. Размер минимум для текста с усечением хвоста - это пространство, необходимое для рисования одного символа и многоточия. идеальный (горизонтальный) размер - это размер, необходимый для рисования всего текста на одной строке без переноса.

Таким образом, внешний HStack сначала запрашивает у двух внутренних HStack их минимальные размеры. Они, в свою очередь, спрашивают свой текст о его минимальном размере (первый символ плюс многоточие), а минимум спейсера равен нулю.

Затем внешний HStack берет эти два минимума и вычитает их из общей суммы и предлагает их текст по центру.

Когда вы добавляете fixedSize, это говорит тексту, чтобы он сообщал свой минимальный размер как размер, необходимый для рисования всей строки в одной строке, так что теперь каждый внутренний HStack имеет это как минимум, и центральному тексту предлагается меньше места.

В обоих случаях центральный текст затем сообщает внешнему HStack, сколько места он будет использовать, урезая при необходимости (так как у него нет fixedSize).

Внешний HStack вычитает это пространство и затем рассматривает двух других потомков. Они одинаково гибки (поскольку оба включают Spacer), поэтому он предлагает половину пространства слева. Левый получает именно то, что ему было предложено (*), и поэтому другая половина предлагается правому, который также берет все это.

(*) В большинстве случаев, о которых мы говорим Вот. В достаточно узком контейнере, возможно, минимальный требуемый размер будет больше, чем то, что доступно. В этом случае ребенок будет брать больше, чем ему предлагают, и все будет выходить за пределы.

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