#ios #swift #animation #swiftui
#iOS #swift #Анимация #swiftui
Вопрос:
Я хотел бы добиться анимации слайдов с подчеркиванием, перемещающимся с одной вкладки на другую, когда пользователь выбирает другую
Я использую matchedGeometryEffect следующим образом:
HStack(spacing: 15) {
ForEach(categories, id: .self) { category in
let isSelected = selectedVal == category
Button {
withAnimation {
selectedVal = category
}
} label: {
VStack(spacing: 4) {
Text(category)
.frame(width: 100)
if isSelected {
RoundedRectangle(cornerRadius: 5)
.frame(width: 50, height: 2)
.matchedGeometryEffect(id: "Category", in: animation, isSource: isSelected)
}
}
}
}
}
Этот подход работает с предупреждением о Multiple inserted views in matched geometry group Pair<String, ID>(first: "Category", second: SwiftUI.Namespace.ID(id: 10)) have isSource: true, results are undefined.
Когда я извлекаю RoundedRectangle
из Button
, предупреждение исчезает:
HStack(spacing: 15) {
ForEach(categories, id: .self) { category in
let isSelected = selectedVal == category
VStack(spacing: 4) {
Button(category) {
withAnimation {
selectedVal = category
}
}
if isSelected {
RoundedRectangle(cornerRadius: 5)
.frame(width: 50, height: 2)
.matchedGeometryEffect(id: "Category", in: animation, isSource: isSelected)
}
}
}
}
Я подозреваю, что это как-то связано с Button
тем, что он не был удален из иерархии представлений в первом решении и, следовательно, все еще содержит ссылку на RoundedRectangle
, что сбивает с толку matchedGeometry, поскольку вы не можете видеть исходный вид «видимым», но я бы isSource
хотел, чтобы установка в выбранное состояние решила эту проблему. Есть ли объяснение, почему я получаю предупреждение в первом сценарии?
Комментарии:
1. Что касается меня, это похоже на ошибку SwiftUI.
2. Я обнаружил, что установка продолжительности анимации на более быстрое время может помочь избежать столкновений, когда пользователь может нажать кнопку в неподходящее время во время настройки. Почему это должно привести к сбою программы, а не просто к отказу, мне непонятно.
Ответ №1:
Проблема в том, что вы можете установить matchedgeometryeffect с одним и тем же пространством имен только для одного представления одновременно. чтобы SwiftUI мог определить, какой объект нужно анимировать. и вот вы устанавливаете геометрический эффект для всех трех представлений с одним и тем же пространством имен, поэтому SwiftUI не может понять, как анимировать и компоновать все представления.
struct ContentView: View {
enum Tab: String {
case one
case two
case three
}
@State private var selected: Tab = .one
@Namespace private var tabNameSpace
var body: some View {
ZStack {
HStack(spacing: 32) {
ZStack {
if selected == .one {
Color.red
.frame(width: 100, height: 50)
.matchedGeometryEffect(id: "namespace", in: tabNameSpace)
}
Text(Tab.one.rawValue)
.frame(width: 100, height: 50)
.onTapGesture {
withAnimation(.spring()) {
selected = .one
}
}
}
ZStack {
if selected == .two {
Color.red
.frame(width: 100, height: 50)
.matchedGeometryEffect(id: "namespace", in: tabNameSpace)
}
Text(Tab.two.rawValue)
.frame(width: 100, height: 50)
.onTapGesture {
withAnimation(.spring()) {
selected = .two
}
}
}
ZStack {
if selected == .three {
Color.red
.frame(width: 100, height: 50)
.matchedGeometryEffect(id: "namespace", in: tabNameSpace)
}
Text(Tab.three.rawValue)
.frame(width: 100, height: 50)
.onTapGesture {
withAnimation(.spring()) {
selected = .three
}
}
}
}
}
}
}