如何在SwiftUI中实现无限可滑动的周视图?

huangapple go评论67阅读模式
英文:

How to implement infinite swipable week view in SwiftUI?

问题

我目前正在开发一个课程表应用。我需要实现一个可滑动的周视图,就像苹果的“日历”应用中一样。在SwiftUI中没有内置的解决方案(也许我没有找到),所以我使用了SwiftUIPager库。它有点可行,但我必须提供一个元素数组给它。然后Pager使用这些元素来创建页面。这不适合我,所以我决定在接近其边界时动态添加数组的元素。

问题是,当我向数组的开头添加元素时,Pager会丢失当前页面并跳转到左侧的下一页。

我尝试在索引中添加一个额外的页面,但它没有起作用。

也许有一个更简单的解决方案,不需要提供一个数组吗?我希望Pager只提供给我从第一个加载的页面的偏移量。

英文:

I am currently working on an app with class schedule. I need to implement a swipable week view just like in Apple's "Calendar" app. There is no built-in solution for this in SwiftUI (Maybe I didn't find it), so I used SwiftUIPager library. It kinda works, but I have to provide it an array of elements. Then Pager use this elements to create pages. This does not suit me, so I decided to dynamically add elements of the array when I approach its border.

struct WeekObserverView: View {
	
    let vm: WeekObserverViewModel = WeekObserverViewModel()
    let OnDayChanged: (Date)->Any
	
    @State private var selectedDay = Date()
    @State private var currentPage = Page.withIndex(2)
    @State private var data = Array(-2..<3)
    @State private var disableButtons = false
    
    var body: some View {
        VStack(spacing: 0){
            VStack(alignment: .center, spacing: 0){
                Pager(page: currentPage,
                      data: data,
                      id: \.self) {
                    self.generateWeekView($0)
                }
                      .singlePagination(ratio: 0.5, sensitivity: .high)
                      .onPageWillChange({ (page) in
                          withAnimation {
    			  //Moving forward or backward a week
                              selectedDay = selectedDay + TimeInterval(604800) * Double((page - currentPage.index))
                          }
                          _ = OnDayChanged(selectedDay)
                      })
					  .onPageChanged({
						  page in
                                                  //Adding new weeks when we approach the boundaries of the array
						  if page == 1 {
							  let newData = (1...5).map { data.first! - $0 }.reversed()
							  withAnimation {
								  currentPage.update(.move(increment: newData.count))
								  data.insert(contentsOf: newData, at: 0)
							  }
						  } else if page == self.data.count - 2 {
							  guard let last = self.data.last else { return }
							  let newData = (1...5).map { last + $0 }
							  withAnimation {
								  data.append(contentsOf: newData)
							  }
						  }
						  disableButtons = false
					  })
                      .onDraggingBegan({
                          disableButtons = true
                      })
                      .pagingPriority(.simultaneous)
                      .frame(height: 48)
                Capsule()
                    .frame(width: 32, height: 6)
                    .foregroundColor(Color("TransparetPurple"))
                    .padding(4)
            }
            .frame(maxWidth: .infinity)
            .background(Color("AccentBlue"))
            //Spacer()
        }
    }

The problem is when I adding element to the front of array Pager loses current page and goes to the next page on the left.

I tried to add one extra page to the index, but it didn't work

currentPage.update(.move(increment: newData.count + 1))

Maybe there is a more simple solution without providing an array? I want Pager to just give me the offset from first loaded page.

答案1

得分: 0

我查看了这个并检查了SwiftUIPager项目中包含的名为InfiniteExampleView的示例。

我注意到他们如何能够在当前项目前后动态添加项目。

我无法完全测试您的代码,因为存在一些缺失的部分,以使其以您的方式运行,但似乎当他们在当前项目之前插入项目时,他们还更新了页面索引,而我在您的代码中没有看到您这样做。

这是示例中的代码:

if page == 1 {
   let newData = (1...5).map { data1.first! - $0 }.reversed()
   withAnimation {
       page1.index += newData.count //<-- 这一行
       data1.insert(contentsOf: newData, at: 0)
       isPresented.toggle()
   }
}

这是if语句下的您的代码的一部分,位于withAnimation部分,page==1

currentPage.update(.move(increment: newData.count))
data.insert(contentsOf: newData, at: 0)

也许添加一行来更改索引有助于修复这个问题。如果不行,请提供一个更完整的示例以便更容易进行调试。

英文:

I looked into this and checked an example called InfiniteExampleView included in the git project for SwiftUIPager.

I noticed how they are able to add items to the array dynamically both in front of the current items and behind them.

I can't test your code completely since there are some missing parts to make it run the way you run it, but it seems when they insert in front of current items they update the page index as well and I don't see you do that in your code.

This is the code from the example:

if page == 1 {
   let newData = (1...5).map { data1.first! - $0 }.reversed()
   withAnimation {
       page1.index += newData.count //<-- this line
       data1.insert(contentsOf: newData, at: 0)
       isPresented.toggle()
   }
} 

this is your code under the withAnimation part of if statement page==1:

currentPage.update(.move(increment: newData.count))
data.insert(contentsOf: newData, at: 0)

So maybe adding a line to change the index helps fix this. If not, please provide a more complete example to make it possible to debug it more easily.

huangapple
  • 本文由 发表于 2023年2月8日 20:08:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/75385580.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定