SA0702 — Погружение в SwiftUI
Содержание страницы
Декларативный стиль SwiftUI позволяет легко реализовать привлекательный дизайн. В этой главе вы будете использовать модификаторы SwiftUI, чтобы придать RGBullsEye новый дизайн с помощью neumorphism, последней тенденции дизайна.
Виды и модификаторы
В файле contentView с открытым холстом нажмите кнопку + или нажмите Command-Shift-L, чтобы открыть библиотеку:

Библиотека примитивных представлений и модификаторов
Примечание: Чтобы сэкономить место, я переключился на просмотр значков и скрыл детали.
Представление SwiftUI-это часть вашего пользовательского интерфейса: вы объединяете небольшие представления для создания больших представлений. Существует множество примитивных представлений , таких как Text
иColor
, которые вы можете использовать в качестве основных строительных блоков для ваших пользовательских представлений.
На первой вкладке перечислены примитивные виды, сгруппированные как элементы управления, макет, краска и другие виды. Многие из них, особенно элементы управления, знакомы вам как элементы UIKit, но некоторые из них уникальны для SwiftUI. Вы узнаете, как их использовать, в следующих главах.
На второй вкладке перечислены модификаторы элементов управления, эффектов, макета, текста, изображения и многого другого. Модификатор-это метод, который создает новое представление из существующего. Вы можете связать модификаторы в цепочку, как конвейер, чтобы настроить любое представление.
SwiftUI рекомендует создавать небольшие повторно используемые представления, а затем настраивать их с помощью модификаторов для конкретного контекста, в котором вы их используете. И не волнуйтесь, SwiftUI сворачивает измененное представление в эффективную структуру данных, так что вы получаете все это удобство без видимого снижения производительности.
Многие из этих модификаторов можно применить к любому типу представления. А иногда порядок имеет значение, как ты скоро увидишь.
Нейморфизм
Нейморфизм-это новый скеуоморфизм, отказ от суперплоского минимального пользовательского интерфейса. Неуморфный элемент пользовательского интерфейса, по-видимому, выдвигается из-под своего фона, создавая плоский 3D-эффект.
Представьте, что элемент немного выступает из экрана, а солнце садится к северо-западу от элемента. Это приводит к выделению верхнего левого края и тени нижнего правого края. Или солнце встает к юго-востоку от элемента, так что подсветка находится на правом нижнем краю, а тень-на левом верхнем:

Северо-запад и юго-восток блики и тени
Вам нужно три цвета, чтобы создать эти блики и тени:
- Нейтральный цвет для фона и поверхности элемента.
- Более светлый цвет для подсветки.
- Более темный цвет для тени.
В этом примере используются цвета, которые создают высокую контрастность, просто чтобы сделать его действительно видимым. В вашем проекте вы будете использовать цвета, которые создают более тонкий эффект.
Вы добавите блики и тени к цветовым кругам, меткам и кнопкам в RGBullsEye, чтобы реализовать этот дизайн Figma:

Дизайн Figma
Этот дизайн был разработан для 375×812-точечного экрана (iPhone X или 13 mini). Вы настроите свой дизайн с помощью значений размера из дизайна Figma, а затем измените их на значения, зависящие от размера экрана.
Примечание: Многие разработчики пропускают шаг Figma/Sketch design и просто проектируют непосредственно в SwiftUI — это так просто!
Цвета для неуморфизма
Откройте стартовый проект. Это то же самое, что и проект final challenge из предыдущей главы, но ColorCircle
он находится в собственном файле с size
параметром, а Assets.xcassets содержит цвета элемента, подсветки и тени как для светлого, так и для темного режима:
- Элемент: #F1F3F7; Темный: #292A2D
- Подсветка: #FFFFFF (непрозрачность 20%); Темнота: #3D3E42
- Тень: #BDCDE1; Темнота: #1A1A1A
Файл Model/ColorExtension содержит статические свойства для этих:
static let element = Color("Element") static let highlight = Color("Highlight") static let shadow = Color("Shadow")
Тени для неуморфизма
Во-первых, вы создадите пользовательские модификаторы для северо-западных и юго-восточных теней.
Создайте новый Swift — файл с именем ViewExtension и замените его import Foundation
оператор следующим кодом:
`import SwiftUI
extension View {
func northWestShadow(
radius: CGFloat = 16,
offset: CGFloat = 6
) -> some View {
return self
.shadow(
color: .highlight, radius: radius, x: -offset,
y: -offset)
.shadow(
color: .shadow, radius: radius, x: offset, y: offset)
}
func southEastShadow(
radius: CGFloat = 16,
offset: CGFloat = 6
) -> some View {
return self
.shadow(
color: .shadow, radius: radius, x: -offset, y: -offset)
.shadow(
color: .highlight, radius: radius, x: offset, y: offset)
}
}`
shadow(color:radius:x:y:)
Модификатор добавляет в представление тень указанного color
and radius
(размера), смещенную на (x
, y
). По умолчанию Color
используется черный цвет с непрозрачностью 0.33, а смещение по умолчанию равно (0, 0).
Для модификаторов северо-западной и юго-восточной теней вы применяете тень в левом верхнем углу представления (отрицательные значения смещения) и тень другого цвета в правом нижнем углу (положительные значения смещения). Для северо-западной тени верхний левый цвет равен нулю, highlight
а нижний правыйshadow
-нулю . Вы переключаете эти цвета для юго-восточной тени.
Цветные круги и кнопка используют одни и те же значения радиуса и смещения, поэтому вы устанавливаете их в качестве значений по умолчанию. Позже текстовые метки нуждаются в меньших значениях, которые вы будете передавать в качестве аргументов.
Не имеет значения, в каком порядке вы применяете shadow
модификаторы. Я заказал их сначала в верхнем левом углу, так что легко визуализировать направление неуморфной тени.
Настройка цвета фона
Чтобы эти тени работали, фон представления должен быть того же цвета, что и элементы пользовательского интерфейса. Вернитесь в contentView, чтобы настроить это.
Вы будете использовать aZStack
, чтобы установить цвет фона всего экрана element
. Направление Z перпендикулярно поверхности экрана, поэтому это хороший способ наложения слоев на экран. Элементы, расположенные ниже в ZStack
закрытии, отображаются выше в представлении стека. Думайте об этом как о размещении первого вида вниз на поверхности экрана, затем наложении следующего вида поверх него и так далее.
Итак, вот что вы делаете: вставляете VStack
в aZStack
, а затем добавляете Color.element
перед VStack
.
ZStack { Color.element VStack {...} }
Обновите предварительный просмотр. Вы наложили Color
слой ниже VStack
, но цвет не распространяется на безопасную область. Чтобы исправить это, добавьте этот модификатор вColor.element
:
.ignoresSafeArea()
Примечание: Вы можете добавить этот модификатор to
ZStack
вместо toColor
, но тогдаZStack
он будет свободно распространять свои представления контента в безопасную область, что, вероятно, не то, что вы хотите.
Теперь ваше приложение выглядит так же, как и раньше, за исключением того, что фон не совсем белый. Затем вы придадите цветным кругам рамку, а затем примените к ней подсветку и тень.
Создание неуморфной границы
Самый простой способ создать границу-это наложить RGB
цветной круг поверх element
цветного круга, используя-как вы уже догадались — a ZStack
.
В ColorCircleзамените содержимое body
следующим:
ZStack { Circle() .fill(Color.element) .northWestShadow() Circle() .fill(Color(red: rgb.red, green: rgb.green, blue: rgb.blue)) .padding(20) } .frame(width: size, height: size)
Вы вставляете Circle()
в a ZStack
, добавляете anelement
-colored Circle
перед ним, затем добавляете отступы, чтобы сделать RGB
круг меньше. Чтобы получить эффект тени, вы применяете northWestShadow()
его к пограничному кругу.
Примечание: Модификатор
fill(_:style:)
может быть применен только к фигурам, поэтому изменение порядка модификаторов приводит к ошибке:
Circle() .padding(20) .fill(Color(red: rgb.red, green: rgb.green, blue: rgb.blue))
Наконец, вы устанавливаете и width
то, и height``size
другое .
При необходимости обновите предварительный просмотр, чтобы увидеть, как это выглядит:

Неуморфный цветной круг на белом фоне
Да, есть тень, но предварительный ColorCircle
просмотр имеет белый фон, поэтому вы не видите полного эффекта тени.
Прокрутите вниз previews
и измените его содержимое на следующее:
ZStack { Color.element ColorCircle(rgb: RGB(), size: 200) } .frame(width: 300, height: 300) .previewLayout(.sizeThatFits)
Вы устанавливаете цвет фона element
так же, как и в ContentView
. Нет никакой безопасной зоны, о которой можно было бы беспокоиться, потому что рамка предварительного просмотра уже установлена достаточно большой, чтобы показать тень.

Неуморфный цветной круг на элементно-цветном фоне
На не совсем белом фоне подсветка на верхнем левом краю выделяется больше, а тень от нижнего правого края кажется менее темной. Закомментируйте и раскомментируйтеColor.element
, previews
чтобы убедиться в этом сами.
Теперь вернитесь в contentView и обновите его предварительный просмотр:

Неуморфный целевой цветной круг
Поздравляю, ваши круги теперь неуморфны!
Порядок модификаторов
Когда вы применяете к представлению несколько модификаторов, иногда порядок имеет значение.
Модификаторы любят padding
и frame
изменяют расположение или положение представления. Модификаторы типа background``border
«Заполнить» или «обернуть» вид. Обычно вы хотите настроить макет и положение представления перед его заполнением или переносом.
Например, в contentViewдобавьте border
модификатор после padding
модификатораText(guess.intString)
:
.padding() .border(Color.purple)

Граница вокруг дополненного текста
Размер по умолчанию padding
окружает текст Text
представления, затем вы border
обводите текст фиолетовым цветом.
Теперь измените порядок:
.border(Color.purple) .padding()

Обводка текста по краям
Если вы примените border
первое, оно обойдет внутреннюю область текста. Если вы выберете padding()
его в редакторе кода, то сможете увидеть, где он находится, но все, что он делает, — это держит соседние элементы на расстоянии.
Удалить.border(Color.purple)
.
Некоторые модификаторы могут быть применены только к определенным видам представлений. Например, эти модификаторы можно применять только к Text
представлениям:

Текстовые модификаторы
Некоторые, но не все эти модификаторы возвращают Text
представление. Например, font
, fontWeight
, bold
и italic
измените Text
представление, чтобы создать другое Text
представление. Таким образом, вы можете применять эти модификаторы в любом порядке.
Но lineLimit
возвращается some View
, так что это указывает на ошибку:
Text(guess.intString) .lineLimit(0) .bold()
И этот заказ в порядке вещей:
Text(guess.intString) .bold() .lineLimit(0)
Подробнее об использовании модификаторов вы узнаете в разделе “Введение в элементы управления: текст и изображение».
Создание неуморфной кнопки
Далее, все еще в contentView, давайте сделаем так, чтобы ваша кнопка Hit Me! попала!
Чтобы отбросить тень, кнопка нуждается в более существенной форме. Добавьте эти модификаторы под действием, передalert
:
.frame(width: 327, height: 48) .background(Capsule())
Вы устанавливаете фон в форме капсулы. Capsule
это a RoundedRectangle
со значением радиуса угла, равным половине длины его более короткой стороны. Он заполняет указанный вами фрейм.
По умолчанию используется цвет заливкиprimary
, который в световом режиме является черным.
Это неуморфная кнопка, поэтому добавьте эти модификаторы Capsule()
, чтобы установить ее цвет заливки element
и применить северо-западную тень:
.fill(Color.element) .northWestShadow()
А вот и твоя неуморфическая кнопка:

Неуморфическая кнопка
Создание пользовательского стиля кнопок
Когда вы начинаете настраивать кнопку, рекомендуется создать собственный стиль кнопки. Даже если вы не планируете повторно использовать его в этом приложении, ваш код будет менее загроможден. Особенно если вы решите добавить больше опций к этому стилю кнопок.
Поэтому создайте новый Swift — файл с именем NeuButtonStyle и import Foundation
замените его следующим кодом:
`import SwiftUI
struct NeuButtonStyle: ButtonStyle {
let width: CGFloat
let height: CGFloat
func makeBody(configuration: Self.Configuration)
-> some View {
configuration.label
// Move frame and background modifiers here
}
}`
ButtonStyle
это протокол, который предоставляет a ButtonStyleConfiguration
два свойства: кнопку label
и логическое значение, true
когда пользователь нажимает кнопку.
Вы будете реализовыватьmakeBody(configuration:)
, чтобы изменить label
.
Вы уже поняли , как вы хотите изменитьButton
, поэтому вырежьте модификаторы frame
и background
из Button
contentView и вставьте их ниже configuration.label``NeuButtonStyle
.
Затем замените фреймы width
и height
значения соответствующими свойствами NeuButtonStyle
.
Ваш код стиля кнопки теперь выглядит следующим образом:
`struct NeuButtonStyle: ButtonStyle {
let width: CGFloat
let height: CGFloat
func makeBody(configuration: Self.Configuration)
-> some View {
configuration.label
.frame(width: width, height: height)
.background(
Capsule()
.fill(Color.element)
.northWestShadow()
)
}
}`
Вернувшись в contentView, измените Button
его с помощью этой строки кода:
.buttonStyle(NeuButtonStyle(width: 327, height: 48))
Это значение ширины работает для таких iPhone, как 13 Pro. Чтобы поддерживать меньшие или большие iPhone, вы узнаете, как передавать подходящие значения позже.
Теперь обновите предварительный просмотр. Он должен выглядеть так же, как и раньше:

Neumorphic button с использованием NeuButtonStyle
Но… это не одно и то же. Этикетка кнопки теперь черная, а не синяя!
Исправление проблем со стилем кнопок
При создании пользовательского стиля кнопки вы теряете цвет метки по умолчанию и визуальную обратную связь по умолчанию, когда пользователь нажимает на кнопку.
Цвет этикетки не является проблемой, если вы уже используете пользовательский цвет. Если нет, то вы просто добавите этот модификатор configuration.label
в NeuButtonStyle
структуру:
.foregroundColor(Color(UIColor.systemBlue))
Однако текст кнопки Figma design черный, так что это не проблема.
Теперь перейдем к проблеме визуальной обратной связи.
Создание стиля кнопки фактически возлагает на вас ответственность за определение того, что происходит, когда пользователь нажимает на кнопку. На самом деле описание метки конфигурации — это “представление, описывающее эффект нажатия кнопки”.
Live-предварительный просмотр ContentView
и нажатие на кнопку: внешний вид кнопки не меняется при нажатии на нее. Это не очень хороший пользовательский опыт. К счастью, легко восстановить поведение по умолчанию.
Прежде чем покинуть файл contentView, нажмите кнопку pin-код в левом нижнем углу холста:

Закрепите предварительный просмотр contentView
Вы будете работать в файле NeuButtonStyle, внося изменения, которые влияют на contentView. Закрепление его предварительного просмотра означает, что вы сможете увидеть эффект ваших изменений без необходимости переходить от одного файла к другому.
Теперь в NeuButtonStyleдобавьте эту строку над frame
модификатором:
.opacity(configuration.isPressed ? 0.2 : 1)
Когда пользователь нажимает на кнопку, вы уменьшаете непрозрачность этикетки, создавая стандартный эффект затемнения.
Обновите предварительный просмотр в реальном ContentView
времени и проверьте это.
Если вы хотите воспользоваться преимуществами своей неуморфной кнопки, вы можете отключить или переключить направление тени, когда пользователь нажимает на кнопку.
В NeuButtonStyle
, замените содержимое background
на это:
Group { if configuration.isPressed { Capsule() .fill(Color.element) } else { Capsule() .fill(Color.element) .northWestShadow() } }
Group
это еще один контейнер SwiftUI. Он не делает никакой разметки. Это просто полезно, когда вам нужно обернуть код, который сложнее, чем одно представление.
Если пользователь нажимает кнопку, вы показываете плоскую кнопку. В противном случае вы покажете затененную кнопку.
Обновите предварительный просмотр в реальном времени, а затем нажмите на кнопку. Удерживайте нажатой кнопку, чтобы увидеть, как тень исчезнет.
Вариация на этот счет заключается в том, чтобы применятьsouthEastShadow()``isPressed
, когдаtrue
:
Group { if configuration.isPressed { Capsule() .fill(Color.element) .southEastShadow() // Add this line } else { Capsule() .fill(Color.element) .northWestShadow() } }
Выключите предварительный просмотр в реальном времени.
Создание скошенной кромки
Затем вы создадите новый внешний вид меток цветных кругов. Вы будете использовать Capsule
его снова, чтобы унифицировать дизайн. Но вы создадите эффект скошенного края, чтобы отличить его от кнопки.
Создайте новый файл представления SwiftUI и назовите его BevelText.
Замените содержимое BevelText
структуры следующим:
`let text: String
let width: CGFloat
let height: CGFloat
var body: some View {
Text(text)
}`
Вернувшись в contentView, замените Text
представления и их padding
на BevelText
представления:
if !showScore { BevelText( text: "R: ??? G: ??? B: ???", width: 200, height: 48) } else { BevelText( text: game.target.intString, width: 200, height: 48) } ColorCircle(rgb: guess, size: 200) BevelText(text: guess.intString, width: 200, height: 48)
BevelText
виды не нужныpadding
, потому что их высота кадра составляет 48 точек.
Теперь открутите предварительный ContentView
просмотр, чтобы вы могли сосредоточиться BevelText
.
Вернувшись в BevelText, замените содержимое previews
следующим:
ZStack { Color.element BevelText( text: "R: ??? G: ??? B: ???", width: 200, height: 48) } .frame(width: 300, height: 100) .previewLayout(.sizeThatFits)
Вы накладываете слой BevelText
поверх element
цветного фона. Это ваша отправная точка для создания капсулы со скошенным краем.

BevelText: Начало работы
В разделе body
of BevelText
добавьте эти два модификатора вText
:
.frame(width: width, height: height) .background( Capsule() .fill(Color.element) .northWestShadow(radius: 3, offset: 1) )
Обновите предварительный просмотр. Это внешняя форма капсулы. Это просто уменьшенная версияNeuButtonStyle
:

Наружная капсула с северо-западной тенью
Теперь вставьте это в aZStack
, чтобы вы могли Capsule
наложить на него еще один слой, вставленный на 3 точки:
ZStack { Capsule() .fill(Color.element) .northWestShadow(radius: 3, offset: 1) Capsule() .inset(by: 3) .fill(Color.element) .southEastShadow(radius: 1, offset: 1) }
Представьте, что солнце садится на северо-западе: оно освещает внешний верхний левый край и внутренний нижний правый край и отбрасывает тени от внутреннего верхнего левого края и внешнего нижнего правого края.
Чтобы получить этот эффект, вы наносите юго-восточную тень на внутреннюю Capsule
.

BevelText: Готово
Примечание: Спасибо Кэролайн Бегби за эту элегантную простую реализацию.
А теперь вернемся к contentView, чтобы насладиться результатами:

Нейморфизм завершен!
“Отладка” темного режима
Помните, что наборы цветов в активах имеют значения темного режима. Как выглядит этот дизайн в темном режиме?
Его легко просматривать в темном режиме. Если live-preview включен, выключите его, затем откройте инспектор предварительного просмотра и выберите Dark color scheme:

Установите цветовую схему предварительного просмотра на темную.
Благодаря магии цветовых наборов вы получаете темный режим теней бесплатно!

Нейморфизм: Темный режим
Однако, похоже, есть одна проблема. Снова запустите Live preview и нажмите Hit Me!. Цветовая схема оповещения не темная?!

Цветовая гамма Alert не темная?!
Я потратил много времени, пытаясь найти способ обойти эту проблему. Но это прекрасный пример того, почему вы не должны полностью полагаться на предварительный просмотр.
Создайте и запустите приложение на симуляторе iPhone 13 Pro. Первое, что вы замечаете, — темная цветовая схема предварительного просмотра не влияет на симулятор.
Не проблема: Нажмите кнопку Переопределения среды на панели инструментов отладки и включите внешний вид ▸ Темный:

Переопределение цветовой схемы во время работы в симуляторе.
Примечание: Вы можете найти список встроенных
EnvironmentValues
в apple.co/2yJJk7T. Многие из них соответствуют пользовательским настройкам устройства, таким как доступность, языковой стандарт, календарь и цветовая схема.
Теперь симулятор отображает приложение в темном режиме. Тап Ударил меня!:

Симулятор: Цветовая схема оповещения темная.
Темный режим, темная тревога, как и должно быть!
Поэтому, если предварительный просмотр не показывает того, что вы ожидаете увидеть, попробуйте запустить его на моделируемом или реальном устройстве, прежде чем тратить время на устранение фантомной проблемы.
Остановите симулятор и прямой просмотр.
Удалите или закомментируйте эту строку, вставленную инспектором предварительного просмотра в contentView previews
:
.preferredColorScheme(.dark)
Изменение шрифта
Вам нужно еще кое-что, чтобы внести последний штрих в дизайн Figma: весь текст должен быть немного больше и немного смелее.
В contentViewдобавьте этот модификатор к VStack
тому, что содержит все элементы пользовательского интерфейса:
.font(.headline)
Вы устанавливаете значение среды уровня представления для VStack
объекта, которое влияет на все его дочерние представления. Так что теперь весь текст использует размер шрифта заголовка:

Размер шрифта заголовка применяется ко всему тексту.
Вы можете переопределить этот общий Text
модификатор. Например, добавьте этот модификатор HStack
в ColorSlider
структуру:
.font(.subheadline)
Теперь ползунковые метки используют меньший, не полужирный шрифт:

Ползунковые метки используют размер шрифта подзаголовка.
Адаптация к размеру экрана устройства
Хорошо, пришло время посмотреть, как этот дизайн выглядит на меньшем экране. Чтобы проверить, как ваш дизайн вписывается в меньший экран, укажите previewDevice
for previews
. Добавьте этот модификатор вContentView(guess: RGB())
:
.previewDevice("iPhone 8")

Устройство предварительного просмотра: iPhone 8
Высота экрана iPhone 8 составляет всего 667 точек, поэтому кнопка не видна. Вы можете решить эту проблему, сделав цветные круги меньше. Но на сколько?
Еще один способ проверить свой дизайн в других размерах экрана-выбрать симулятор в меню назначения запуска.
Удалите previewDevice(_:)
модификатор и измените пункт назначения запуска на iPhone 13 Pro Max. Предварительный просмотр обновлений для использования этого симулятора:

Пункт назначения запуска: iPhone 13 Pro Max
Высота этого экрана составляет 926 точек, так что пустого места больше. Здесь вы можете сделать круги больше. Но на сколько?
В contentViewдобавьте эти свойства ниже @State
свойств:
let circleSize: CGFloat = 0.275 let labelHeight: CGFloat = 0.06 let labelWidth: CGFloat = 0.53 let buttonWidth: CGFloat = 0.87
Я разработал эти пропорции из оригинального дизайна Figma 375×812, убедившись, что высота безопасной зоны iPhone 13 mini составляет 728 точек. Эти дроби дают значения, близкие к тем, которые вы жестко встроили в свой код: circleSize
* 728 = 200.2, labelHeight
* 728 = 43.68, labelWidth
* 375 = 198.75, buttonWidth
* 375 = 326.25.
Высота кнопки тоже labelHeight
есть .
Теперь, если ваш код может определить высоту и ширину размера экрана, он может вычислить правильные размеры для этих элементов.
Получение размера экрана из GeometryReader
Вот что вы сделаете: встроите ZStack
в aGeometryReader
, чтобы получить доступ к его size
значениям и frame
значениям.
Примечание: Подробнее об
GeometryReader
этом читайте в разделе “Глава 18: Рисование и пользовательская графика».
В меню Command-click есть удобный пункт catch-all Embedded…:

Встраивайте ZStack … какой-то контейнер.
В contentViewвстроите верхний уровень ZStack
в этот универсальный Container
файл, а затем измените Container
его наGeometryReader
:
GeometryReader { proxy in ZStack {
GeometryReader
предоставляет вам GeometryProxy
объект, который имеет frame
метод size
и safeAreaInset
свойства. Вы называете этот объект proxy
.
В двух ColorCircle
инициализаторах замените size: 200
на
size: proxy.size.height * circleSize
В трех BevelText
инициализаторах замените width: 200, height: 48
на
width: proxy.size.width * labelWidth, height: proxy.size.height * labelHeight
Заменить (NeuButtonStyle(...))
на
(NeuButtonStyle( width: proxy.size.width * buttonWidth, height: proxy.size.height * labelHeight))
Измените пункт назначения запуска обратно на iPhone 13 Pro и обновите предварительный просмотр, чтобы убедиться, что он выглядит так же, как и раньше.
Предварительный просмотр различных устройств
Чтобы увидеть все три размера экрана одновременно, вы можете создать и запустить приложение на двух симуляторах. Вместо этого вы добавите предварительные просмотры в ContentView_Previews
.
Нажмите кнопку Дублировать предварительный просмотр на панели инструментов предварительного просмотра:

Дубликат-кнопка предварительного просмотра
Другой ContentPreview
появляется в предварительном просмотре холста, а теперь еще Group
и в редакторе кода.
Group { ContentView(guess: RGB()) ContentView(guess: RGB()) }
Добавьте этот модификатор к первому ContentView
в списке.Group
:
.previewDevice("iPhone 8")
Имя устройства должно совпадать с одним из тех, что указаны в меню назначения запуска. Например, “iPhone SE” не работает, потому что в меню есть “iPhone SE (2-е поколение)”.
Теперь на холсте показаны iPhone 8 и iPhone 13 Pro (пункт назначения вашего запуска).:

Предварительный просмотр iPhone 8 и iPhone 13 Pro
На меньшем iPhone он сидит плотнее, но все видно.
Скопируйте и вставьте код “iPhone 8” и измените имя устройства следующим образом::
.previewDevice("iPhone 13 Pro Max")
А теперь их стало трое. И элементы дизайна изменились по размеру.
Ключевые моменты
- Представления и модификаторы SwiftUI помогут вам быстро реализовать ваши дизайнерские идеи.
- Библиотека содержит список примитивных представлений и список методов — модификаторов. Вы можете легко создавать собственные представления, стили кнопок и модификаторы.
- Нейморфизм-это новый скеуморфизм. Это легко реализовать с помощью цветовых наборов и
shadow
модификатора SwiftUI. - Вы можете использовать
ZStack
его для наложения слоев на элементы пользовательского интерфейса. Например, установите цвет фона и расширьте его до безопасной области, а затем наложите на него остальную часть пользовательского интерфейса. - Обычно вы хотите применить модификатор, который изменяет макет или положение представления, прежде чем заполнить его или обернуть рамку вокруг него.
- Некоторые модификаторы могут быть применены ко всем типам представлений, в то время как другие могут быть применены только к определенным типам представлений, таким как
Text
фигуры или фигуры. Не всеText
модификаторы возвращаютText
представление. - Создайте пользователь
ButtonStyle
, реализовав егоmakeBody(configuration:)
метод. Вы потеряете некоторые стандартные свойства, такие как цвет этикетки и затемнение при нажатии. - Если предварительный просмотр не показывает того, что вы ожидаете увидеть, попробуйте запустить его на моделируемом или реальном устройстве, прежде чем тратить время на устранение фантомной проблемы.
- Используется
GeometryReader
для доступа к свойствам кадра и размера устройства.