Взгляд на проблемы выравнивания на основе вопроса SO

Летом 2020 года я написал статью об использовании выравниваний в SwiftUI и подумал, что было бы неплохо вернуться к ней, поскольку она по сути основана на SwiftUI 1.0. Пересмотрите тему, используя вопросы SO, чтобы найти реальную проблему и решение. В связи с чем вот вопрос.



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

Давайте работать над проблемой. У меня есть несколько представлений, некоторые модификаторы текста и некоторые метки. Все они разной длины и должны быть выровнены. Но тут загвоздка, они не в одном контейнере, мне нужно не только метки выровнять, но и контейнеры.

Начнем с текста. Теперь это разумно прямо вперед. Выравнивание текстового представления управляется фреймом, в котором оно находится. Но — есть подвох. В SwiftUI текстовый объект занимает не больше места, чем ему действительно нужно для текста по умолчанию. Так что, если вы попытаетесь изменить выравнивание, это ничего не изменит. Если вы хотите изменить выравнивание, вам нужно сделать рамку, содержащую текстовый объект, больше, чем нужно. Насколько большой, конечно, зависит от ваших требований.

В качестве примера возьмем два поля в вопросе SO. Здесь мы добавили фреймы в оба текстовых поля, первый фрейм имеет ширину 128, второй — 32. Затем мы устанавливаем выравнивание первого фрейма как замыкающее, а второго — как ведущее.

HStack {
  Text("65")
    .background(Color.red)
    .frame(width: 128, height: 32, alignment: .trailing)
  Text("Final")
    .background(Color.red)
    .frame(width: 32, height: 32, alignment: .leading)
}

Net net это будет выглядеть так. Зеленый прямоугольник — это контейнер, HStack.

Далее давайте подробнее рассмотрим Label, новый модификатор, который появился в SwiftUI 2.0. В этом я использовал labelStyle для настройки того, как текст и изображение будут выровнены друг с другом.

HStack {
  Label {
    Text("Team 1")
    .font(.system(size: 16, weight: .semibold, design: .rounded))
} icon: {
  Image(systemName:"seal")
    .resizable()
    .scaledToFit()
    .frame(width: 30)
  }.labelStyle(HorizontalLabelStyle())
}

Используемый нами код labelStyle выглядит следующим образом.

struct HorizontalLabelStyle: LabelStyle {
  func makeBody(configuration: Configuration) -> some View {
    HStack(alignment: .center, spacing: 8) {
      configuration.icon
      configuration.title
    }
  }
}

В рамках этого определения я в основном сказал, что значок находится перед заголовком и выровнен по горизонтали. С расстоянием между изображением и текстом около 8 пунктов. Чистая сеть выглядит так.

Мы делаем то же самое для другого текста/меток, чтобы они также были правильно выровнены друг с другом. Поскольку мы планируем выровнять все вместе, очевидно, ширина меток тоже должна совпадать.

Теперь все, о чем нам нужно беспокоиться, это выравнивание контейнеров друг с другом. Мы делаем это, добавляя оба контейнера в ZStack, на котором мы будем использовать выравниваниеGuide, это руководство. Руководство я назвал «Выравнивание».

Чтобы использовать «theAlignment», мне нужно назвать его в ZStack и пометить HStack с помощью viewModifier, чтобы связать его.

private var zeroX: CGFloat = 160
ZStack(alignment: .theAlignment) {
  HStack {
  ....
}.alignmentGuide(.theHorizontalAlignment, computeValue: {d in zeroX})

Это говорит о том, что HStack необходимо выровнять с ZStack с помощью функции HorizontalAlignment, которая возвращает .leading и вычисленное значение 160 точек. Объяснение, которое, я надеюсь, немного понятнее, глядя на это изображение.

Синее поле — это UILabel, его рамка переменного размера, размер текстовой метки внутри него. В зеленом поле два модификатора просмотра текста, один из которых на 128 пунктов, один на 48 пунктов. Число «65» установлено в конце текстового объекта. Слово «final» устанавливается на переднем крае текстового объекта. Теперь контейнеры, синюю коробку и зеленую нужно выровнять друг с другом. Итак, я настраиваю выравнивание, которое говорит, что передний край синего прямоугольника должен располагаться на расстоянии 160 пунктов от переднего края зеленого прямоугольника. Это как раз то, о чем я только что упомянул.

Я применяю то же правило ко второму набору контейнеров, поэтому передний край красного прямоугольника будет установлен на расстоянии 160 пунктов от оранжевого, независимо от размера контейнера.

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

Вот статья прошлым летом, в которой рассказывается об этой и других техниках. Пожалуйста, дайте мне хлопок, если вы нашли это полезным. И поделитесь комментарием или двумя, если вы найдете ошибку, другое мнение или проблему, которую вы хотите, чтобы я решил. А пока я надеюсь, что вам понравилось читать это так же, как мне писать. Подпишитесь на меня на medium.com, чтобы получить больше того же самого.



Сохраняйте спокойствие, продолжайте кодировать