Site icon AppTractor

Сравниваем два View с помощью слайдера в SwiftUI

Когда вам нужно визуально сравнить два изображения, экрана или состояния, слайдер «до и после» часто оказывается наиболее интуитивно понятным решением. В этой статье мы рассмотрим, как создать многоразовое представление сравнения со слайдером полностью на SwiftUI — без использования UIKit или внешних библиотек.

Обзор концепции

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

Компоненты такого типа часто используются для:

Структура представления

Мы определим универсальный контейнер SliderComparisonView<Left: View, Right: View>, который принимает два представления SwiftUI — по одному для каждого слоя.

public var body: some View {
    GeometryReader { geometry in
        ZStack {
            Color.clear
                .overlay {
                    lhs()
                }
            
            Color.clear
                .overlay {
                    rhs()
                }
                .mask {
                    Rectangle()
                        .offset(x: dividerLocation + geometry.size.width / 2)
                }
            
            dividerView()
                .offset(x: dividerLocation)
        }
        .gesture(
            DragGesture()
                .onChanged { gesture in
                    dividerLocation = min(
                        max(gesture.location.x - geometry.size.width / 2, -geometry.size.width / 2),
                        geometry.size.width / 2
                    )
                }
        )
    }
    .ignoresSafeArea()
}

Основная идея проста:

Маскирование правого представления

Маска определяет, какая часть верхнего слоя будет видна.

Color.clear
    .overlay {
        rhs()
    }
    .mask {
        Rectangle()
            .offset(x: dividerLocation + geometry.size.width / 2)
    }

Вот что происходит:

Создание разделителя

Сам разделитель является визуальным и интерактивным. Он указывает место разделения и предоставляет возможность перетаскивания.

private func dividerView() -> some View {
    Rectangle()
        .fill(dividerColor)
        .frame(width: dividerWidth)
        .overlay {
            Circle()
                .fill(indicatorColor)
                .frame(width: indicatorWidth)
                .overlay {
                    indicatorImage
                        .resizable()
                        .scaledToFit()
                        .frame(width: indicatorImageWidth)
                        .foregroundColor(indicatorImageColor)
                }
        }

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

Обработка жестов

Логика жестов обеспечивает плавное горизонтальное перетаскивание в пределах области просмотра:

.onChanged { gesture in
    dividerLocation = min(
        max(gesture.location.x - geometry.size.width / 2, -geometry.size.width / 2),
        geometry.size.width / 2
    )
}

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

Пример использования

Вы можете использовать представление сравнения с любым содержимым SwiftUI, а не только с изображениями:

SliderComparisonView {
    Image(.winter)
} rhs: {
    Image(.spring)
}
 SliderComparisonView(
        lhs: { Text("Some Text").font(.title).fontWeight(.heavy).foregroundColor(.gray) },
        rhs: { Text("Some Text").font(.title).fontWeight(.heavy).foregroundColor(.blue) }
    )

Заключение

Инкапсулировав логику в повторно используемый компонент SliderComparisonView, вы можете добавить этот компонент в любой проект SwiftUI — будь то для визуального сравнения, демонстрации переходов или креативного взаимодействия с пользовательским интерфейсом.

Проект на GitHub: https://github.com/Livsy90/LivsyComparisonSliderView/

Источник

Exit mobile version