Closed niklasgrewe closed 3 years ago
what I also noticed is the fact that the CalendarViewController is displayed correctly when I put it in a UIViewControllerRepresentable
like this:
// CalendarDayView.swift
import SwiftUI
import CalendarKit
import EventKit
struct CalendarDayView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> CalendarViewController {
let dayView = CalendarViewController()
var style = CalendarStyle()
style.header.backgroundColor = .white
dayView.updateStyle(style)
return dayView
}
func updateUIViewController(_ dayView: CalendarViewController, context: Context) {
}
typealias UIViewControllerType = CalendarViewController
}
inside my SceneDelegate
let primaryViewController = UIHostingController(rootView: CalendarDayView())
The result looks like this
I have lost my NavigationBarStyles and also the NavigationTitle is not displayed, but the layout fits. I don't understand why this works with UIHostingController and not before....
Hi, looks like there are some layout inconsistencies. Please, debug the following line: https://github.com/richardtop/CalendarKit/blob/master/Source/DayView.swift#L126
I think there are some issues in the way the layout code is called in one example versus another. Finding that inconsistency is the key to resolving your issue.
Regarding the Stackoverflow post, I don't see the connection between this issue and the compact/regular layout. If there were one, we'd see iPad layout for the calendar which we clearly don't see.
compact/regular switching code: https://github.com/richardtop/CalendarKit/blob/master/Source/Header/DaySelector/DaySelector.swift#L150
Initialize header views (1,2,3,4,5 // mon,tue,wed...): https://github.com/richardtop/CalendarKit/blob/master/Source/Header/DaySelector/DaySelector.swift#L82
So I'm quite certain that there is some inconsistency in the layout / framing / autoresizing masks code.
If you're planning to debug this issue, please post your findings here, as I'm also interested in the solution.
@richardtop thank you very much for your detailed answer. I absolutely agree with you that the error is most likely in the layout and not in the size classes.
I would love to find this inconsistency. As you already described, I would have to change this part in the code:
https://github.com/richardtop/CalendarKit/blob/master/Source/DayView.swift#L126
Frankly, I wouldn't know what to change in the code. After all, the layout problems occur exclusively in the sidebar. I just can't understand why the problems don't occur when i wrapped in a UIHostingController . What does it do differently than if I use the CalendarViewController directly?
I would appreciate your help and support because I don't really know how can i solve this, without using a UIHostingController instead....
after same research i found this on a medium blog post.
After choosing the doubleColumn style in Interface Builder and running my app I noticed that for some reason the whole master view controller was clipped. The layout of the main menu view controller was created years ago when Safe Area layout guides were not present. Hence, the collection view was constrained to its superview, instead of Safe Area, which caused this weird clipping. After enabling Safe Area layout guides in File inspector everything went back to normal.
https://medium.com/swlh/ios-14-uisplitviewcontroller-5-issues-that-you-may-run-into-65b09601b3fb - Clipped master view controller’s view
could this be related?
Yeah, this could be related. Please try debugging this issue by putting a breakpoint / print statements to the layout code and comparing 'frame' values when CK is ran without and with hosting view controller. This might give us some insights.
as I suspected... the frame values look like this:
let primaryViewController = UINavigationController(rootViewController: CalendarViewController())
// result: dayHeaderView Frame: (0.0, 0.0, 420.0, 88.0)
// result: timelinePagerView Frame: (0.0, 88.0, 420.0, 672.0)
let primaryViewController = UIHostingController(rootView: CalendarView())
// result: dayHeaderView Frame: (0.0, 0.0, 320.0, 88.0)
// result: timelinePagerView Frame: (0.0, 88.0, 320.0, 652.0)
As it seems the UIHostingController sets some layout contraints, so the width is at 320.0
and not at 420.0
. It is interesting that all values are correct, except for the width and the height, only for timelinePagerView. The only question is... how do we manage - just like the UIHostingController - to manually set these layout contraints. Would you have any idea?
Test-Repo: https://github.com/niklasgrewe/CalendarKit-iPadOS
Apparently the bug also has something in common with the new SplitViewController that was added in iOS 14...
In my app (Adaptivity) I deliberately want to be able to show the user how the Classic style split view controller behaves because it is different. For example, in a double/triple column split view the primary view controller is actually wider than what appears on screen (420 points instead of 320) with a leading margin which is 100 points larger than the trailing margin to cancel out the effect.
Using classic style of UISplitViewController in Xcode 12 - https://developer.apple.com/forums/thread/655195?answerId=622814022#622814022
i also found this:
The primary view controller is wider than what is visible on screen to provide extra content when over-scrolling during a swipe action. It is 420 points wide, but 320 points is visible. So content that is aligned with the leading edge instead of the leading margin (or safe area, as you noted), will be partially off-screen.
So is there a way to fix it maybe? If yes, what we need to change?
Try taking a look at both cases with View Hierarchy debugger and make sure to show clipped views as well. Then we'll be able to see what's going on: https://developer.apple.com/library/archive/documentation/ToolsLanguages/Conceptual/Xcode_Overview/ExaminingtheViewHierarchy.html
after some try and error i found a solution to fix the layout issues using UISplitViewController
in the DayView.swift
file i changed the layoutSubviews()
function as follows:
override public func layoutSubviews() {
super.layoutSubviews()
if #available(iOS 11.0, *) {
dayHeaderView.translatesAutoresizingMaskIntoConstraints = false
timelinePagerView.translatesAutoresizingMaskIntoConstraints = false
dayHeaderView.leadingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leadingAnchor).isActive = true
dayHeaderView.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor).isActive = true
dayHeaderView.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor).isActive = true
dayHeaderView.heightAnchor.constraint(equalToConstant: headerHeight).isActive = true
timelinePagerView.leadingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.leadingAnchor).isActive = true
timelinePagerView.trailingAnchor.constraint(equalTo: self.safeAreaLayoutGuide.trailingAnchor).isActive = true
timelinePagerView.topAnchor.constraint(equalTo: dayHeaderView.bottomAnchor).isActive = true
timelinePagerView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
self.transitionToHorizontalSizeClass(traitCollection.horizontalSizeClass)
}
}
The key is to use safe area layouts instead of frames. The transitionToHorizontalSizeClass()
function is also needed at this point so that the layout it also updated correctly in SplitView (two apps side by side in different sizes).
If you want, I'm happy to create a PR so others can benefit from it as well. Otherwise, I can leave the changes on my end.
That's all I've found out so far and I hope you can do something with it. Thanks for your help and tips
Thanks for the solution. Btw, SafeAreaInsets are available in the frame-based layout too. The only problem in your solution is that it's being executed on layoutSubviews
, while the constraints installation should happen once during (this) view life cycle. I'll take a look and a bit more and fix this issue.
Frame-based layout is a legacy of the initial implementation of the CalendarKit, your solution is definitely a better one.
Hi, as i descriped on stackoverflow, i can't using CalendarKit inside
UISplitViewController
When i set theCalendarViewController
as primary viewcontroller, the result looks like this:As you can see, the CalendarViewController fits the iPhone Screen, but not the primary column on the iPad (SplitView). How can i solve this issue?
I am using the CalendarKitApp Template and modified the SceneDelegate like this: