Анимации переходов между представлениями (view transition) были доступны с самой первой версии фреймворка SwiftUI. Фреймворк позволяет указать определенную анимацию перехода, которая будет применяться всякий раз, когда представление удаляется или добавляется в иерархию представлений. С недавних пор фреймворк SwiftUI предлагает нам еще один тип анимаций перехода — анимации переходов для содержимого (content transition). Суть та же, что и раньше. Фреймворк теперь позволяет нам указывать определенную анимацию перехода для содержимого представления, которая будет проигрываться всякий раз, когда оно изменяется. На этой неделе мы с вами разберемся, как использовать новый API для анимирования переходов содержимого в SwiftUI.

В предыдущих версиях SwiftUI мы не могли применять переходы (transition) к содержимому представления. И если вы запустите этот пример на iOS 15, то никакой анимации перехода вы не увидите.

struct ContentView: View {
    @State private var flag = false
    
    var body: some View {
        VStack {
            Text(verbatim: "1000")
                .fontWeight(flag ? .black : .light)
                .foregroundColor(flag ? .yellow : .red)
        }
        .onTapGesture {
            withAnimation(.default.speed(0.1)) {
                flag.toggle()
            }
        }
    }
}

Предыдущая версия SwiftUI не поддерживает никаких переходов для содержимого представления Text и сразу же применяет изменения без какого-либо визуального эффекта. К счастью, последняя итерация SwiftUI позволяет нам указать анимацию перехода для содержимого представления Text с помощью модификатора представления contentTransition:

struct ContentView: View {
    @State private var flag = false
    
    var body: some View {
        VStack {
            Text(verbatim: "1000")
                .fontWeight(flag ? .black : .light)
                .foregroundColor(flag ? .yellow : .red)
        }
        .contentTransition(.opacity)
        .onTapGesture {
            withAnimation(.default.speed(0.1)) {
                flag.toggle()
            }
        }
    }
}

Как видно из приведенного выше примера, единственная строка кода, которую мы добавили, — это модификатор представления contentTransition. Он принимает инстанс выбранной нами анимации перехода, который SwiftUI применяет к представлению при каждом изменении его содержимого. В данном случае поскольку мы используем интерполяцию (interpolate), анимация перехода влияет на размер и цвет текста.

struct ContentView: View {
    @State private var flag = false
    
    var body: some View {
        VStack {
            Text(verbatim: "1000")
                .fontWeight(flag ? .black : .light)
                .foregroundColor(flag ? .yellow : .red)
        }
        .contentTransition(.opacity)
        .onTapGesture {
            withAnimation(.default.speed(0.1)) {
                flag.toggle()
            }
        }
    }
}

В этом примере мы используем другой инстанс ContentTransition называемый opacity. В этом случае SwiftUI будет анимировать постепенное появление/исчезновение текста при каждом его изменении.

В SwiftUI есть еще один тип ContentTransition, который работает только с числовым текстом (numericText). Он понимает, как изменилось число, и создает приятный визуальный эффект, изменяющий только часть представления Text, которая представляет число.

struct TextContentView: View {
    @State private var number = "99"
    
    var body: some View {
        Text(verbatim: number)
            .font(.system(size: 36))
            .contentTransition(.numericText())
            .onTapGesture {
                withAnimation(.default.speed(0.2)) {
                    number = "98"
                }
            }
    }
}

Чтобы узнать больше о других вариациях анимации изменений в тексте, читайте статью “AnimatableModifier в SwiftUI”.

Модификатор представления contentTransition передает предоставленный ему инстанс ContentTransition через среду SwiftUI, что позволяет нам получить к нему доступ по определенному EnvironmentKey.

struct MySuperCustomTextView: View {
    let text: String
    
    @Environment(\.contentTransition) private var transition
    
    var body: some View {
        switch transition {
        case .opacity:
            drawWithOpacity()
        case .interpolate:
            drawWithInterpolation()
        default:
            draw()
        }
    }
    
    // ...
}

Здесь мы наблюдаем супер кастомизированное текстовое представление, которое использует среду SwiftUI, чтобы определить, какую технику отрисовки переданного текста следует использовать, на основе используемой анимация перехода.

Существует еще один EnvironmentKey, связанный с анимацией перехода содержимого, который позволяет нам решать, когда мы хотим использовать усиленный GPU рендеринг, оборачивая содержимое с анимацией перехода в drawingGroup.

struct ContentView: View {
    @State private var flag = false
    
    var body: some View {
        VStack {
            Text(verbatim: "1000")
                .fontWeight(flag ? .black : .light)
                .foregroundColor(flag ? .yellow : .red)
        }
        .environment(\.contentTransitionAddsDrawingGroup, true)
        .contentTransition(.interpolate)
        .onTapGesture {
            withAnimation(.default.speed(0.1)) {
                flag.toggle()
            }
        }
    }
}

Сегодня мы с вами разобрали новые техники анимации переходов для содержимого в SwiftUI. В настоящее время их поддерживает не так много представлений, но их количество скорее всего изменится в будущем. Попробуйте поддержать эту фичу в своих представлениях, добавив новые API, которые мы рассмотрели сегодня.

Перевод материала подготовлен в рамках специализации iOS Developer.

Комментарии (1)


  1. nikita_dol
    09.11.2022 16:00
    +2

    Было бы очень неплохо увидеть картинки

    А в случае с переходами анимированные картинки