英文:
Slide Carousel cards on Cards tap in SwiftUI
问题
我在SwiftUI中创建了一个走马灯卡片,它在DragGesture
上正常工作。
我希望在卡片的点击上实现相同的体验,即在.onTapGesture
上,无论哪张卡片被点击,它都应该滑动到屏幕中央,就像附加的视频中所示。
我的当前代码 -
import SwiftUI
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]
// 虚拟数据
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
@State var activeIndex: Int = 0
var body: some View {
ZStack {
ForEach(store.items) { item in
// 文章视图
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(getDragGesture())
.onTapGesture {
// 将卡片移动到中心
}
}
private func getDragGesture() -> some 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
// 获取活动项目的索引
self.activeIndex = store.items.count + Int(draggingItem)
if self.activeIndex > store.items.count || Int(draggingItem) >= 0 {
self.activeIndex = Int(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
}
}
注意:在.onTapGesture
中,您需要编写逻辑来将卡片移动到屏幕中央,但此处的代码未提供相关逻辑。
英文:
I have created a carousel cards in SwiftUI, it is working on the DragGesture
I want to achieve same experience on the tap of cards i.e. on .onTapGesture
, which ever cards is being tapped it should be slide to centre on the screen like shown in the video attached
My current code -
import SwiftUI
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
@State var activeIndex: Int = 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(getDragGesture())
.onTapGesture {
//move card to centre
}
}
private func getDragGesture() -> some 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
//Get the active Item index
self.activeIndex = store.items.count + Int(draggingItem)
if self.activeIndex > store.items.count || Int(draggingItem) >= 0 {
self.activeIndex = Int(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
}
}
答案1
得分: 1
你需要将.onTapGesture()
修饰符应用于ForEach
内部的单个项目,而不是围绕它。
然后,您只需处理不同的情况,将被点击的项目与当前位于前面的项目进行比较,并相应地更改draggingItem
的值。
这是视图主体内的代码:
ZStack {
ForEach(store.items) { item in
// 文章视图
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)
// 这是修饰符 - 放在项目上,而不是放在 ForEach 上
.onTapGesture {
// 需要使用 withAnimation
withAnimation {
draggingItem = Double(item.id)
}
}
}
}
.gesture(getDragGesture())
英文:
You need to apply the .onTapGesture()
modifier to the single item inside the ForEach
, not around it.
Then, you just need to handle the different cases, comparing the tapped item with the one currently on the front, and change the value of draggingItem
accordingly.
Here's the code inside the view's body:
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)
// Here is the modifier - on the item, not on the ForEach
.onTapGesture {
// withAnimation is necessary
withAnimation {
draggingItem = Double(item.id)
}
}
}
}
.gesture(getDragGesture())
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论