SwiftUI:在 CarouselView 中实现定时器

Posted

技术标签:

【中文标题】SwiftUI:在 CarouselView 中实现定时器【英文标题】:SwiftUI: Implementing Timer into CarouselView 【发布时间】:2020-03-30 14:56:21 【问题描述】:

我遵循了这个教程..https://www.youtube.com/watch?v=fB5MzDD1PZI&list=WL&index=32&t=0s

我正在尝试将计时器添加到它,因为它会自动转到下一张图像。有什么建议吗?谢谢。

这是我当前的代码,缺少一些代码,我不知道下一步该做什么。

 import SwiftUI

struct ContentView: View 

    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    @State var Counter = 0

    var body: some View 
        ZStack 
            VStack 
                Text("HELLOWORLD")
                VStack
                    CarouselView(itemHeight: 400, views: [
                        AnyView(Text("1")),
                        AnyView(Text("2")),
                        AnyView(Text("3")),
                        AnyView(Text("4")),
                        AnyView(Text("5")),
                        AnyView(Text("6")),
                    ]).onReceive(timer)  _ in
                        if self.Counter > 0 
                          self.Counter -= 1
                          //missing some code to move index of carousel to i+1
                        
                      
                

                Button(action: 
                  self.Counter = 10
                  ) 
                    Text("RUN")
                  
            
        
    

    

struct CarouselView: View 

    @GestureState private var dragState = DragState.inactive
    @State var carouselLocation = 0

    var itemHeight:CGFloat
    var views:[AnyView]


    private func onDragEnded(drag: DragGesture.Value) 
        print("drag ended")
        let dragThreshold:CGFloat = 200
        if drag.predictedEndTranslation.width > dragThreshold || drag.translation.width > dragThreshold
            carouselLocation =  carouselLocation - 1
         else if (drag.predictedEndTranslation.width) < (-1 * dragThreshold) || (drag.translation.width) < (-1 * dragThreshold)
        
            carouselLocation =  carouselLocation + 1
        
    



    var body: some View 
        ZStack
            VStack

                ZStack
                    ForEach(0..<views.count)i in
                        VStack
                            Spacer()
                            self.views[i]
                                //Text("\(i)")

                            .frame(width:300, height: self.getHeight(i))
                            .animation(.interpolatingSpring(stiffness: 300.0, damping: 30.0, initialVelocity: 10.0))
                                .background(Color.white)
                            .cornerRadius(10)
                            .shadow(radius: 3)


                            .opacity(self.getOpacity(i))
                            .animation(.interpolatingSpring(stiffness: 300.0, damping: 30.0, initialVelocity: 10.0))
                            .offset(x: self.getOffset(i))
                            .animation(.interpolatingSpring(stiffness: 300.0, damping: 30.0, initialVelocity: 10.0))
                            Spacer()
                        
                    

                .gesture(

                    DragGesture()
                        .updating($dragState)  drag, state, transaction in
                            state = .dragging(translation: drag.translation)
                    
                    .onEnded(onDragEnded)

                )

                Spacer()
            
            VStack
                Spacer()
                Spacer().frame(height:itemHeight + 50)
                Text("\(relativeLoc() + 1)/\(views.count)").padding()
                Spacer()
            
        
    

    func relativeLoc() -> Int
        return ((views.count * 10000) + carouselLocation) % views.count
    

    func getHeight(_ i:Int) -> CGFloat
        if i == relativeLoc()
            return itemHeight
         else 
            return itemHeight - 100
        
    


    func getOpacity(_ i:Int) -> Double

        if i == relativeLoc()
            || i + 1 == relativeLoc()
            || i - 1 == relativeLoc()
            || i + 2 == relativeLoc()
            || i - 2 == relativeLoc()
            || (i + 1) - views.count == relativeLoc()
            || (i - 1) + views.count == relativeLoc()
            || (i + 2) - views.count == relativeLoc()
            || (i - 2) + views.count == relativeLoc()
        
            return 1
         else 
            return 0
        
    

    func getOffset(_ i:Int) -> CGFloat

        //This sets up the central offset
        if (i) == relativeLoc()
        
            //Set offset of cental
            return self.dragState.translation.width
        
            //These set up the offset +/- 1
        else if
            (i) == relativeLoc() + 1
                ||
                (relativeLoc() == views.count - 1 && i == 0)
        
            //Set offset +1
            return self.dragState.translation.width + (300 + 20)
        
        else if
            (i) == relativeLoc() - 1
                ||
                (relativeLoc() == 0 && (i) == views.count - 1)
        
            //Set offset -1
            return self.dragState.translation.width - (300 + 20)
        
            //These set up the offset +/- 2
        else if
            (i) == relativeLoc() + 2
                ||
                (relativeLoc() == views.count-1 && i == 1)
                ||
                (relativeLoc() == views.count-2 && i == 0)
        
            return self.dragState.translation.width + (2*(300 + 20))
        
        else if
            (i) == relativeLoc() - 2
                ||
                (relativeLoc() == 1 && i == views.count-1)
                ||
                (relativeLoc() == 0 && i == views.count-2)
        
            //Set offset -2
            return self.dragState.translation.width - (2*(300 + 20))
        
            //These set up the offset +/- 3
        else if
            (i) == relativeLoc() + 3
                ||
                (relativeLoc() == views.count-1 && i == 2)
                ||
                (relativeLoc() == views.count-2 && i == 1)
                ||
                (relativeLoc() == views.count-3 && i == 0)
        
            return self.dragState.translation.width + (3*(300 + 20))
        
        else if
            (i) == relativeLoc() - 3
                ||
                (relativeLoc() == 2 && i == views.count-1)
                ||
                (relativeLoc() == 1 && i == views.count-2)
                ||
                (relativeLoc() == 0 && i == views.count-3)
        
            //Set offset -2
            return self.dragState.translation.width - (3*(300 + 20))
        
            //This is the remainder
        else 
            return 10000
        
    





enum DragState 
    case inactive
    case dragging(translation: CGSize)

    var translation: CGSize 
        switch self 
        case .inactive:
            return .zero
        case .dragging(let translation):
            return translation
        
    

    var isDragging: Bool 
        switch self 
        case .inactive:
            return false
        case .dragging:
            return true
        
    

附言。对不起,误解了规则。我是 *** 和 SwiftUI 的新手。谢谢你。

【问题讨论】:

你试过什么?你遇到了什么问题? 嗨河马,欢迎来到***。请阅读***.com/help/how-to-ask。这不是“我们为您编写代码”的平台,而是“我们帮助您编写代码”的平台。所以向我们展示您尝试过的代码...它应该可以运行并重现您的问题。 请不要破坏您自己的帖子。当您在此处发帖时,您授予 SO 根据 CC-by SA 4.0 分发内容的权利。任何破坏行为都将被撤销。 【参考方案1】:

看看这个:

import SwiftUI

struct ContentView: View 

    @State var location : Int = 0

    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    @State var Counter = 0

    var body: some View 
        ZStack 
            VStack 
                Text("HELLOWORLD")
                VStack
                    CarouselView(carouselLocation: self.$location, itemHeight: 400, views: [
                        AnyView(Text("1")),
                        AnyView(Text("2")),
                        AnyView(Text("3")),
                        AnyView(Text("4")),
                        AnyView(Text("5")),
                        AnyView(Text("6")),
                    ]).onReceive(timer)  _ in
                        if self.Counter > 0 
                            self.Counter -= 1
                            //missing some code to move index of carousel to i+1
                        
                    
                

                Button(action: 
                    self.Counter = 10
                    Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true)  (timer) in
                        self.location += 1

                    
                ) 
                    Text("RUN")
                
            
        
    



struct CarouselView: View 

    @GestureState private var dragState = DragState.inactive
    @Binding var carouselLocation : Int

    var itemHeight:CGFloat
    var views:[AnyView]


    private func onDragEnded(drag: DragGesture.Value) 
        print("drag ended")
        let dragThreshold:CGFloat = 200
        if drag.predictedEndTranslation.width > dragThreshold || drag.translation.width > dragThreshold
            carouselLocation =  carouselLocation - 1
         else if (drag.predictedEndTranslation.width) < (-1 * dragThreshold) || (drag.translation.width) < (-1 * dragThreshold)
        
            carouselLocation =  carouselLocation + 1
        
    



    var body: some View 
        ZStack
            VStack

                ZStack
                    ForEach(0..<views.count)i in
                        VStack
                            Spacer()
                            self.views[i]
                                //Text("\(i)")

                                .frame(width:300, height: self.getHeight(i))
                                .animation(.interpolatingSpring(stiffness: 300.0, damping: 30.0, initialVelocity: 10.0))
                                .background(Color.white)
                                .cornerRadius(10)
                                .shadow(radius: 3)


                                .opacity(self.getOpacity(i))
                                .animation(.interpolatingSpring(stiffness: 300.0, damping: 30.0, initialVelocity: 10.0))
                                .offset(x: self.getOffset(i))
                                .animation(.interpolatingSpring(stiffness: 300.0, damping: 30.0, initialVelocity: 10.0))
                            Spacer()
                        
                    

                .gesture(

                    DragGesture()
                        .updating($dragState)  drag, state, transaction in
                            state = .dragging(translation: drag.translation)
                    
                    .onEnded(onDragEnded)

                )

                Spacer()
            
            VStack
                Spacer()
                Spacer().frame(height:itemHeight + 50)
                Text("\(relativeLoc() + 1)/\(views.count)").padding()
                Spacer()
            
        
    

    func relativeLoc() -> Int
        return ((views.count * 10000) + carouselLocation) % views.count
    

    func getHeight(_ i:Int) -> CGFloat
        if i == relativeLoc()
            return itemHeight
         else 
            return itemHeight - 100
        
    


    func getOpacity(_ i:Int) -> Double

        if i == relativeLoc()
            || i + 1 == relativeLoc()
            || i - 1 == relativeLoc()
            || i + 2 == relativeLoc()
            || i - 2 == relativeLoc()
            || (i + 1) - views.count == relativeLoc()
            || (i - 1) + views.count == relativeLoc()
            || (i + 2) - views.count == relativeLoc()
            || (i - 2) + views.count == relativeLoc()
        
            return 1
         else 
            return 0
        
    

    func getOffset(_ i:Int) -> CGFloat

        //This sets up the central offset
        if (i) == relativeLoc()
        
            //Set offset of cental
            return self.dragState.translation.width
        
            //These set up the offset +/- 1
        else if
            (i) == relativeLoc() + 1
                ||
                (relativeLoc() == views.count - 1 && i == 0)
        
            //Set offset +1
            return self.dragState.translation.width + (300 + 20)
        
        else if
            (i) == relativeLoc() - 1
                ||
                (relativeLoc() == 0 && (i) == views.count - 1)
        
            //Set offset -1
            return self.dragState.translation.width - (300 + 20)
        
            //These set up the offset +/- 2
        else if
            (i) == relativeLoc() + 2
                ||
                (relativeLoc() == views.count-1 && i == 1)
                ||
                (relativeLoc() == views.count-2 && i == 0)
        
            return self.dragState.translation.width + (2*(300 + 20))
        
        else if
            (i) == relativeLoc() - 2
                ||
                (relativeLoc() == 1 && i == views.count-1)
                ||
                (relativeLoc() == 0 && i == views.count-2)
        
            //Set offset -2
            return self.dragState.translation.width - (2*(300 + 20))
        
            //These set up the offset +/- 3
        else if
            (i) == relativeLoc() + 3
                ||
                (relativeLoc() == views.count-1 && i == 2)
                ||
                (relativeLoc() == views.count-2 && i == 1)
                ||
                (relativeLoc() == views.count-3 && i == 0)
        
            return self.dragState.translation.width + (3*(300 + 20))
        
        else if
            (i) == relativeLoc() - 3
                ||
                (relativeLoc() == 2 && i == views.count-1)
                ||
                (relativeLoc() == 1 && i == views.count-2)
                ||
                (relativeLoc() == 0 && i == views.count-3)
        
            //Set offset -2
            return self.dragState.translation.width - (3*(300 + 20))
        
            //This is the remainder
        else 
            return 10000
        
    





enum DragState 
    case inactive
    case dragging(translation: CGSize)

    var translation: CGSize 
        switch self 
        case .inactive:
            return .zero
        case .dragging(let translation):
            return translation
        
    

    var isDragging: Bool 
        switch self 
        case .inactive:
            return false
        case .dragging:
            return true
        
    


struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        ContentView()
    

【讨论】:

以上是关于SwiftUI:在 CarouselView 中实现定时器的主要内容,如果未能解决你的问题,请参考以下文章

可以在另一个 CarouselView 中放置一个 CarouselView 吗?

在 SwiftUI 中实现昂贵的派生属性的最佳方法是啥?

如何在 SwiftUI 的视图控制器中实现数据绑定?

在 SwiftUI 中实现多个标题

SwiftUI:如何在 macOS 应用程序中实现编辑菜单

如何在 SwiftUI 中实现 MVVM 模式?视图不会重新渲染