TL; DR :
Применение визуальных эффектов к содержимому ScrollView
вызывает тысячи запросов на одно и то же (неизменное) изображение для каждого жеста перетаскивания. Могу ли я уменьшить это? (В моем реальном приложении у меня есть 50 с лишним изображений в представлении, и прокрутка соответственно sluggi sh.)
Суть
Чтобы дать немного Жизнь для прокрутки HStack
изображений, я применил несколько преобразований для кругового эффекта "карусели". (Советы по созданию примера кода из Джона М. и Пола Хадсона )
Код можно запускать путем копирования-вставки, как указано. (Вам необходимо предоставить изображение.) Без двух строк, помеченных /* 1 */
и /* 2 */
, объект Slide
сообщает о шести запросах изображения, независимо от того, сколько вы перетаскиваете и прокручиваете. Включите две строки и наблюдайте за увеличением числа запросов до 1000 одним движением пальца.
Замечания
SwiftUI основан на недорогом перерисовывании легкий Views
в зависимости от текущего состояния. Неосторожное управление зависимостью от состояния может неправильно сделать недействительными части дерева представления. И в этом случае постоянное вращение и масштабирование во время прокрутки заставляет среду выполнения повторно визуализировать содержимое.
Но ... должно ли это обязательно потребовать постоянного повторного получения изображений stati c? Случайное перетаскивание моего мизинца вперед и назад вызовет десятки тысяч запросов изображений. Это кажется чрезмерным. Есть ли способ уменьшить накладные расходы в этом примере?
Конечно, это примитивный дизайн, который выкладывает все свое содержимое все время, вместо того, чтобы использовать подход повторного использования ячеек, скажем, UITableView
. Можно подумать о применении преобразований только к трем видимым в настоящее время представлениям. есть некоторые обсуждения об этом в сети, но в моих попытках компилятор не смог сделать вывод типа.
Код
import SwiftUI
// Comment out lines marked 1 & 2 and watch the request count go down.
struct ContentView: View {
var body: some View {
GeometryReader { outerGeo in
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(Slide.all) { slide in
GeometryReader { innerGeo in
Image(uiImage: slide.image).resizable().scaledToFit()
/* 1 */ .rotation3DEffect(.degrees(Double(innerGeo.localOffset(in: outerGeo).width) / 10), axis: (x: 0, y: 1, z: 0))
/* 2 */ .scaleEffect(1.0 - abs(innerGeo.localOffset(in: outerGeo).width) / 800.0)
}
.frame(width:200)
}
}
}
}
.clipped()
.border(Color.red, width: 4)
.frame(width: 400, height: 200)
}
}
// Provides images for the ScrollView. Tracks and reports image requests.
struct Slide : Identifiable {
let id: Int
static let all = (1...6).map(Self.init)
static var requestCount = 0
var image: UIImage {
Self.requestCount += 1
print("Request # \(Self.requestCount)")
return UIImage(named: "blueSquare")! // Or whatever image
}
}
// Handy extension for finding local coords.
extension GeometryProxy {
func localOffset(in outerGeo: GeometryProxy) -> CGSize {
let innerFrame = self.frame(in: .global)
let outerFrame = outerGeo.frame(in: .global)
return CGSize(
width : innerFrame.midX - outerFrame.midX,
height: innerFrame.midY - outerFrame.midY
)
}
}