轮播视图 SwiftUI
Carousel view SwiftUI
如何实现swift的iCarousel框架中的旋转式Carousel。以下是我想用 SwiftUI
实现的
我检查了很多教程和现有的框架,但我无法实现如上图所示
这是一个通用的方法:所有项目都绘制在彼此上方 ZStack
,然后它们的位置和不透明度根据到最前面元素的“距离”而改变。
演示中的项目具有固定大小,但可以轻松调整。根据您的意愿更改 opacity
和 scaleEffect
中的值。
struct Item: Identifiable {
var id: Int
var title: String
var color: Color
}
class Store: ObservableObject {
@Published var items: [Item]
let colors: [Color] = [.red, .orange, .blue, .teal, .mint, .green, .gray, .indigo, .black]
// dummy data
init() {
items = []
for i in 0...7 {
let new = Item(id: i, title: "Item \(i)", color: colors[i])
items.append(new)
}
}
}
struct ContentView: View {
@StateObject var store = Store()
@State private var snappedItem = 0.0
@State private var draggingItem = 0.0
var body: some View {
ZStack {
ForEach(store.items) { item in
// article view
ZStack {
RoundedRectangle(cornerRadius: 18)
.fill(item.color)
Text(item.title)
.padding()
}
.frame(width: 200, height: 200)
.scaleEffect(1.0 - abs(distance(item.id)) * 0.2 )
.opacity(1.0 - abs(distance(item.id)) * 0.3 )
.offset(x: myXOffset(item.id), y: 0)
.zIndex(1.0 - abs(distance(item.id)) * 0.1)
}
}
.gesture(
DragGesture()
.onChanged { value in
draggingItem = snappedItem + value.translation.width / 100
}
.onEnded { value in
withAnimation {
draggingItem = snappedItem + value.predictedEndTranslation.width / 100
draggingItem = round(draggingItem).remainder(dividingBy: Double(store.items.count))
snappedItem = draggingItem
}
}
)
}
func distance(_ item: Int) -> Double {
return (draggingItem - Double(item)).remainder(dividingBy: Double(store.items.count))
}
func myXOffset(_ item: Int) -> Double {
let angle = Double.pi * 2 / Double(store.items.count) * distance(item)
return sin(angle) * 200
}
}
如何实现swift的iCarousel框架中的旋转式Carousel。以下是我想用 SwiftUI
实现的我检查了很多教程和现有的框架,但我无法实现如上图所示
这是一个通用的方法:所有项目都绘制在彼此上方 ZStack
,然后它们的位置和不透明度根据到最前面元素的“距离”而改变。
演示中的项目具有固定大小,但可以轻松调整。根据您的意愿更改 opacity
和 scaleEffect
中的值。
struct Item: Identifiable {
var id: Int
var title: String
var color: Color
}
class Store: ObservableObject {
@Published var items: [Item]
let colors: [Color] = [.red, .orange, .blue, .teal, .mint, .green, .gray, .indigo, .black]
// dummy data
init() {
items = []
for i in 0...7 {
let new = Item(id: i, title: "Item \(i)", color: colors[i])
items.append(new)
}
}
}
struct ContentView: View {
@StateObject var store = Store()
@State private var snappedItem = 0.0
@State private var draggingItem = 0.0
var body: some View {
ZStack {
ForEach(store.items) { item in
// article view
ZStack {
RoundedRectangle(cornerRadius: 18)
.fill(item.color)
Text(item.title)
.padding()
}
.frame(width: 200, height: 200)
.scaleEffect(1.0 - abs(distance(item.id)) * 0.2 )
.opacity(1.0 - abs(distance(item.id)) * 0.3 )
.offset(x: myXOffset(item.id), y: 0)
.zIndex(1.0 - abs(distance(item.id)) * 0.1)
}
}
.gesture(
DragGesture()
.onChanged { value in
draggingItem = snappedItem + value.translation.width / 100
}
.onEnded { value in
withAnimation {
draggingItem = snappedItem + value.predictedEndTranslation.width / 100
draggingItem = round(draggingItem).remainder(dividingBy: Double(store.items.count))
snappedItem = draggingItem
}
}
)
}
func distance(_ item: Int) -> Double {
return (draggingItem - Double(item)).remainder(dividingBy: Double(store.items.count))
}
func myXOffset(_ item: Int) -> Double {
let angle = Double.pi * 2 / Double(store.items.count) * distance(item)
return sin(angle) * 200
}
}