Переход с matchedGeometryEffect корректно работает только в одном направлении.

Попытка сделать сегментированную анимацию управления с изменением цвета опций. В одном направлении все работает хорошо, а в другом фон выше контента. Я хочу сделать это без GeometryReader.

Анимация хорошо работает в одном направлении: https://stackru.com/images/6c5397e3288ffe90042f5e3c8951bd470a354e4b.gif

Но вот как это работает в другом направлении: https://stackru.com/images/9800e1cf288892f268845f1c65808c0ddf19c6e5.gif

Код подборщика:

      struct CustomPicker<Option: CustomPickerOption>: View {

    // MARK: - Properties

    @Binding var selection: Option
    let options: [Option]

    @Namespace private var namespaceID
    private let buttonBackgroundID: String = "buttonOverlayID"
    private let buttonOverlayID: String = "buttonOverlayID"

    // MARK: - UI

    var body: some View {
        HStack(spacing: 0) {
            ForEach(options) { option in
                Segment(
                    title: option.title,
                    isSelected: selection == option,
                    backgroundID: buttonBackgroundID,
                    overlayID: buttonOverlayID,
                    namespaceID: namespaceID,
                    action: { selection = option }
                )
            }
        }
        .padding(4)
        .background(Color.blue)
        .clipShape(Capsule())
    }

}

Код сегмента:

      private struct Segment: View {

        // MARK: - Properties

        let title: String
        let isSelected: Bool
        let backgroundID: String
        let overlayID: String
        let namespaceID: Namespace.ID
        let action: () -> Void

        @State private var isPressed: Bool = false

        // MARK: - UI

        var body: some View {
            Button(action: action) {
                titleView
                    .blendMode(.difference)
                    .overlay(
                        titleView
                            .blendMode(.hue)
                    )
                    .overlay(
                        titleView
                            .foregroundColor(.black)
                            .blendMode(.overlay)
                    )
                    .background {
                        if isSelected {
                            background
                                .matchedGeometryEffect(id: backgroundID, in: namespaceID)
                                .transition(.offset())
                        }
                    }
            }
            .buttonStyle(.customHighlighted(isPressed: $isPressed))
        }

        private var background: some View {
            Color.white
                .clipShape(Capsule())
        }

        private var titleView: some View {
            Text(title)
                .font(\.semibold)
                .foregroundColor(.white)
                .padding(.horizontal, 12)
                .padding(.vertical, 10)
        }

    }

Я пытался заменить.transition(.offset)и используйте другие переходы, добавьте.frame(maxWidth: .infinity, maxHeight: .infinity), но ничего не работает. Есть ли другие решения этой проблемы?.animation(.default, value: isSelected)добавляет эффект затухания, так что это не лучшее решение.

Обновлять:zIndex(selection == option ? 1 : 0)помогает нормализовать переход. Честно говоря, я не понимаю, почему. Если можете, пожалуйста, объясните этот странный хак.

0 ответов

Другие вопросы по тегам