ios - UICollectionViewLayout - invalidateLayout() 仅在屏幕旋转后有效

标签 ios swift uicollectionviewlayout

我对 UICollectionViewLayout 进行了子类化以创建日历。我想让用户能够更改一些设置,例如屏幕上显示的天数(默认为 7)。 enter image description here

我将daysToShow保存在UserDefaults中。每当 UIStepper 值发生更改时,它都会调用此方法:

func stepperValueChanged(sender:UIStepper){
        stepperValue = String(Int(sender.value))
        valueLabel.text =  String(Int(sender.value))
        UserDefaults.standard.set(String(Int(sender.value)), forKey: "daysToShow")
        NotificationCenter.default.post(name: Notification.Name(rawValue: "calendarSettingsChanged"), object: nil, userInfo: nil)
 }

因此,在将新值保存到 UserDefault 中后,我发布一条通知,然后调用 reloadForSettingsChange (实际上,当我在此处设置断点时会调用该通知):

override func viewDidLoad() {
        super.viewDidLoad()

        NotificationCenter.default.addObserver(self, selector: #selector(reloadForSettingsChange(notification:)), name: NSNotification.Name(rawValue: "calendarSettingsChanged"), object: nil)

             // other code.....
}

func reloadForSettingsChange(notification:NSNotification){
        // here I save the user setting in a variable declared in my custom UICollectionViewLayout
        self.calendarView.daysToShow = Int(UserDefaults.standard.string(forKey: "daysToShow")!)
        self.calendarView.daysToShowOnScreen  = Int(UserDefaults.standard.string(forKey: "daysToShow")!)
        self.calendarView.forceReload(reloadEvent: true)

}

func forceReload(reloadEvent:Bool){
    DispatchQueue.main.async {
        if reloadEvent{
            self.groupEventsByDays()
            self.weekFlowLayout?.invalidateCacheLayout()
            self.collectionView.reloadData()
        }
    }
}
func invalidateCacheLayout(){

    self.needsToPopulateAttributesForAllSections  = true
    self.cachedDayDateComponents?.removeAllObjects()
    self.cachedStartTimeDateComponents?.removeAllObjects()
    self.cachedEndTimeDateComponents?.removeAllObjects()
    self.cachedCurrentDateComponents?.removeAllObjects()
    self.cachedEarliestHour = Int.max
    self.cachedLatestHour = Int.min
    self.cachedMaxColumnHeight = CGFloat.leastNormalMagnitude
    self.cachedColumnHeights?.removeAllObjects()
    self.cachedEarliestHours?.removeAllObjects()
    self.cachedLatestHours?.removeAllObjects()
    self.itemAttributes?.removeAllObjects()
    self.allAttributes?.removeAllObjects()
    _layoutAttributes.removeAll()
    self.invalidateLayout()
}

问题是,在我旋转屏幕设备(即从横向到纵向)之前,布局不会更新(无效?)。我用于旋转的函数调用的方法与我在 reloadForSettingsChange 中调用的方法完全相同,因此我不明白为什么它在旋转屏幕时起作用,而不是在旋转屏幕之前起作用:

 func rotated() {
        switch UIDevice.current.orientation {
        case .landscapeLeft, .landscapeRight:
            calendarView.forceReload(reloadEvent: true)
        default:
            calendarView.forceReload(reloadEvent: true)
        }
    }

最佳答案

我找到了解决方案:我现在正在调用 setNeedsLayout():

func reloadForSettingsChange(notification:NSNotification){
        self.calendarView.daysToShow = Int(UserDefaults.standard.string(forKey: "daysToShow")!)
        self.calendarView.daysToShowOnScreen  = Int(UserDefaults.standard.string(forKey: "daysToShow")!)
        self.calendarView.forceReload(reloadEvent: true)
        self.calendarView.setNeedsLayout() // this line has been added 
}

我最初使用了 layoutSubviews() ,它有效,但是 Apple Documentation说:

You should not call this method directly. If you want to force a layout update, call the setNeedsLayout() method instead to do so prior to the next drawing update. If you want to update the layout of your views immediately, call the layoutIfNeeded() method.

我尝试了 setNeedsLayout() 这似乎是调用的正确方法(?!?),但由于它不起作用,我使用了 setNeedsLayout():

Call this method on your application’s main thread when you want to adjust the layout of a view’s subviews. This method makes a note of the request and returns immediately. Because this method does not force an immediate update, but instead waits for the next update cycle, you can use it to invalidate the layout of multiple views before any of those views are updated. This behavior allows you to consolidate all of your layout updates to one update cycle, which is usually better for performance.

关于ios - UICollectionViewLayout - invalidateLayout() 仅在屏幕旋转后有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41575304/

相关文章:

ios - 在基于ARC的APP中释放内存?

ios - 设置自定义数据集值 - 图表 3.0.4 和使用 Swift 4.0

ios - CSV 格式不正确

ios - 如何制作一个确认某个协议(protocol)并具有不同父类的对象数组?

swift - 'requestReview()' 在 iOS 14.0 中被弃用

ios - 什么是 fence-hang/handling fence/blown-fence 错误?

ios - Storyboard中的 Xcode 6 UIVisualEffectView

ios - UICollectionView swift 中的一个自定义单元格

ios - UICollectionView indexPath.row 或项目,项目不稳定,跳来跳去

ios - 动画 UICollectionView 框架时的布局和单元格问题