Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios UICollectionView动态数据源项添加到集合视图的开头_Ios_Swift_Uiscrollview_Uicollectionview_Uicollectionviewlayout - Fatal编程技术网

Ios UICollectionView动态数据源项添加到集合视图的开头

Ios UICollectionView动态数据源项添加到集合视图的开头,ios,swift,uiscrollview,uicollectionview,uicollectionviewlayout,Ios,Swift,Uiscrollview,Uicollectionview,Uicollectionviewlayout,我正在使用动态内容加载功能创建集合视图。就我而言,我在做日历。当前日期将显示在可见部分(加载后)。如果向上滚动,则会显示较旧的日期,如果向下滚动,则会看到下一个日期 我的集合视图使用标准流布局。我一行有7个单元格,4个可见行 我在添加较旧日期时遇到问题(例如,向上滚动时出现的单元格)。我正在做的是:首先,我实现了用于检测滚动事件的滚动视图方法。 startOffsetY是在viewDidLoad中设置的contentOffset.y值。它不等于0,因为我设置了contentInsetupd只是一

我正在使用动态内容加载功能创建集合视图。就我而言,我在做日历。当前日期将显示在可见部分(加载后)。如果向上滚动,则会显示较旧的日期,如果向下滚动,则会看到下一个日期

我的集合视图使用标准流布局。我一行有7个单元格,4个可见行

我在添加较旧日期时遇到问题(例如,向上滚动时出现的单元格)。我正在做的是:首先,我实现了用于检测滚动事件的滚动视图方法。
startOffsetY
是在viewDidLoad中设置的contentOffset.y值。它不等于0,因为我设置了
contentInset
upd
只是一个标志,表示可以开始新的更新

func scrollViewDidScroll(scrollView: UIScrollView) {
   if scrollView.contentOffset.y <= startOffsetY - 20 && upd {
      calendar.updateDataSource()
   }
}
但是,当添加行和滚动正在进行时,我有明显的延迟

我尝试了不同的策略:我使用了
reloadData()。从这一点上,我发现,插入项目的动画可能是问题所在。我试图将
performBatchUpdates
包装到
ui视图中。perform没有动画
块,但也没有运气

我真的在寻找一些帮助,我不寻找现成的解决方案,除非它们能像我描述的那样工作(上下滚动并加载内容),我可以看看它是如何工作的。再一次,滚动已经加载的项目不是问题,问题是在我的数据数组中添加内容时出现滞后

编辑 Swift中@teamnorge提供的代码

func scrollViewDidScroll(scrollView: UIScrollView) {

    let currentOffset = scrollView.contentOffset.y
    let contentHeight = scrollView.contentSize.height
    var offset : CGFloat!

    println(currentOffset)

    /*  0.125 - 1/8,  0.5 - 1/2  */
    if currentOffset < contentHeight * 0.125 {

        offset = contentHeight * 0.125 - currentOffset


        // reload content here

        scrollView.contentOffset = CGPoint(x: 0, y: currentOffset + contentHeight * 0.5 + offset - CGFloat(cellHeight))

    }


    /*  0.75 - 6/8,  0.5 - 1/2  */
    if currentOffset > contentHeight * 0.75 {

        offset = currentOffset - contentHeight * 0.75

        // reload content here


        scrollView.contentOffset = CGPoint(x: 0, y: currentOffset - contentHeight * 0.5 - offset + CGFloat(cellHeight))

 }

我认为布局的失效导致了这些滞后。那么,我可能需要定制流程布局?如果是的话,你能给出什么建议。

这实际上是一个非常有趣的话题。我将尝试解释我在开发另一个日历应用程序时提出的想法

在我的例子中,它不是日历视图,而是日视图,从上到下列出了小时数00:00-24:00,因此我有
UITableView
而不是
UICollectionView
,但在这种情况下它并不重要

使用的语言不是Swift,而是Objective-C,所以我只是尝试翻译代码示例

我用固定数量的行创建了
UITableView
,而不是使用数据源进行操作,在我的情况下,只存储两天(48行,每行两天24小时)。您可以选择在两个全屏中包含的行数

重要的是行的总数必须是8的倍数。

然后需要一个公式,根据第一行中的内容计算每个特定单元格的天数

其思想是,
UICollectionView
实际上是
UIScrollView
,因此当我们向下或向上滚动时,我们可以处理相应的事件并计算可见偏移量

为了模拟无限滚动,我们处理
scrollViewDidScroll
并检查您是否刚刚通过
UIScrollView
高度滚动的
1/8
,将
UIScrollView
移动到高度加上精确偏移的
1/2
,使其平滑地移动到“第二屏”。如果向下滚动时传递了
UIScrollView
高度的
6/8
,请将
UIScrollView
向上移动到其高度减去偏移量的
1/2

当您这样做时,您会看到滚动指示器上下跳跃,这非常混乱,因此我们必须将其隐藏,只需将其放置在
viewDidLoad
中的某个位置:

calendarView.showsHorizontalScrollIndicator = false
calendarView.showsVerticalScrollIndicator = false
其中,
calendarView
是您的
UICollectionView
实例名称

以下是代码(此处翻译自Objective-C,未在实际项目中试用):

func scrollViewDidScroll(scrollView_:UIScrollView) {  
    if !enableScrollingHandling {return}
    var currentOffsetX:CGFloat = scrollView_.contentOffset.x  
    var currentOffSetY:CGFloat = scrollView_.contentOffset.y  
    var contentHeight:CGFloat = scrollView_.contentSize.height  
    var offset:CGFloat  

    /*  0.125 - 1/8,  0.5 - 1/2  */
    if currentOffSetY < (contentHeight * 0.125)  {
        enableScrollingHandling = false  
        offset = (contentHeight * 0.125) - currentOffSetY    

        // @todo: your code, specify which days are listed in the first row (2nd screen)

        scrollView_.contentOffset = CGPoint(x: currentOffsetX, y: currentOffset + 
        contentHeight * 0.5 + offset - CGFloat(kRowHeight))

        enableScrollingHandling = true
        return
    }  

    /*  0.75 - 6/8,  0.5 - 1/2  */
    if currentOffSetY > (contentHeight * 0.75)  {  
        enableScrollingHandling = false  
        offset = currentOffSetY - (contentHeight * 0.75)    

        // @todo: your code, specify which days are listed in the first row (1st screen)

        scrollView_.contentOffset = CGPoint(x: currentOffsetX, y: currentOffset - 
        contentHeight * 0.5 - offset + CGFloat(kRowHeight))
        enableScrollingHandling = true
        return
    }  
}  
func scrollViewDidScroll(scrollView\uUiScrollView){
如果!启用滚动处理{return}
var currentOffsetX:CGFloat=scrollView\uView.contentOffset.x
var currentOffset:CGFloat=scrollView\uView.contentOffset.y
var contentHeight:CGFloat=scrollView\ux.contentSize.height
var偏移量:CGFloat
/*  0.125 - 1/8,  0.5 - 1/2  */
如果currentOffSetY<(内容高度*0.125){
enableScrollingHandling=false
偏移量=(内容高度*0.125)-currentOffSetY
//@todo:您的代码,指定第一行(第二屏)列出的日期
scrollView_u2;.contentOffset=CGPoint(x:currentOffsetX,y:currentOffset+
contentHeight*0.5+偏移量-CGFloat(kroweight))
enableScrollingHandling=true
返回
}  
/*  0.75 - 6/8,  0.5 - 1/2  */
如果currentOffSetY>(内容高度*0.75){
enableScrollingHandling=false
偏移量=当前偏移量-(内容高度*0.75)
//@todo:您的代码,指定第一行(第一屏)中列出的日期
scrollView.contentOffset=CGPoint(x:currentOffsetX,y:currentOffset-
contentHeight*0.5-偏移量+CGFloat(克朗)
enableScrollingHandling=true
返回
}  
}  
然后,在您的
collectionView:cellForItemAtIndexPath:
中,根据第一行的内容(这是第一个屏幕的内容还是第二个屏幕的内容)以及当前可见天数(公式),您只需更新单元格内容

这个公式也可能是一个棘手的部分,可能需要一些变通方法,特别是如果您决定在两个月之间输入月份名称。我也有一些关于如何组织的想法,所以如果你遇到任何问题,我们可以在这里讨论

但这种模拟“两屏循环并在两屏之间跳跃”的不定式滚动的方法真的很有魅力,在老式手机上也测试过非常平滑的滚动行为

PS:kroweight只是一个常数
calendarView.showsHorizontalScrollIndicator = false
calendarView.showsVerticalScrollIndicator = false
func scrollViewDidScroll(scrollView_:UIScrollView) {  
    if !enableScrollingHandling {return}
    var currentOffsetX:CGFloat = scrollView_.contentOffset.x  
    var currentOffSetY:CGFloat = scrollView_.contentOffset.y  
    var contentHeight:CGFloat = scrollView_.contentSize.height  
    var offset:CGFloat  

    /*  0.125 - 1/8,  0.5 - 1/2  */
    if currentOffSetY < (contentHeight * 0.125)  {
        enableScrollingHandling = false  
        offset = (contentHeight * 0.125) - currentOffSetY    

        // @todo: your code, specify which days are listed in the first row (2nd screen)

        scrollView_.contentOffset = CGPoint(x: currentOffsetX, y: currentOffset + 
        contentHeight * 0.5 + offset - CGFloat(kRowHeight))

        enableScrollingHandling = true
        return
    }  

    /*  0.75 - 6/8,  0.5 - 1/2  */
    if currentOffSetY > (contentHeight * 0.75)  {  
        enableScrollingHandling = false  
        offset = currentOffSetY - (contentHeight * 0.75)    

        // @todo: your code, specify which days are listed in the first row (1st screen)

        scrollView_.contentOffset = CGPoint(x: currentOffsetX, y: currentOffset - 
        contentHeight * 0.5 - offset + CGFloat(kRowHeight))
        enableScrollingHandling = true
        return
    }  
}