2017-01-10 8 views
0

캘린더를 만들려면 서브 클래스가 UICollectionViewLayout입니다. 사용자에게 화면에 표시 할 일수와 같은 일부 설정을 변경할 수있는 권한을 부여하고 싶습니다 (기본적으로 7). enter image description hereUICollectionViewLayout - 화면 회전 후에 만 ​​invalidateLayout()이 작동합니다.

나는 UserDefaults에 저장합니다. daysToShow

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를 호출 알림을 게시하십시오 UIStepper 값이 변경 될 때마다이 메소드를 호출합니다 :

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() 
} 

문제는 레이아웃이 업데이트되지 않는 것입니다 (무효?) I (즉 풍경에서에 세로) 화면 장치를 회전 할 때까지.

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

답변

0
나는 해결책을 발견

: : 지금 전화하고 내가 회전에 사용하는 기능은 I 화면과 이전하지 회전 할 때 작동 왜 그렇게 이해가 안 나는 reloadForSettingsChange에 전화를 정확하게 같은 메소드를 호출 setNeedsLayout() : 내가 처음 일 layoutSubviews()하지만 Apple Documentation을 사용했다

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 
} 

는 말한다 : 당신은이 메소드를 직접 호출해서는 안

. 레이아웃 업데이트를 강제 실행하려면다음 드로잉 업데이트에 앞서 setNeedsLayout() 메서드를 호출하십시오. 즉시 보기의 레이아웃을 업데이트하려면 layoutIfNeeded() 메소드를 호출하십시오. (?!?)

내가 전화를 할 수있는 권리 방법이 될 듯 setNeedsLayout() 시도했지만 작동하지 이후 나는 setNeedsLayout()를 사용 :

전화 응용 프로그램의 주 스레드에서이 방법 때 보기의 하위보기의 레이아웃을 조정하고 싶습니다. 이 메서드는 요청을 기록하고 즉시 반환합니다. 이 방법은 즉시 업데이트를 강제 실행하지 않고 다음 업데이트 주기를 기다리지 않고 여러보기의 레이아웃을 무효화하기 위해이보기를 업데이트하기 전에 을 사용할 수 있습니다. 이 동작을 통해 은 모든 레이아웃 업데이트를 하나의 업데이트 주기로 통합 할 수 있습니다. 이는 일반적으로 성능 향상을 위해 입니다.