overtake / TelegramSwift

Source code of Telegram for macos on Swift 5.0
https://macos.telegram.org
GNU General Public License v2.0
5.01k stars 849 forks source link

Issues encountered with NavigationViewController while studying Telegram source code. #1105

Closed xiky closed 5 months ago

xiky commented 5 months ago

Hello, as a developer who is just learning macOS development, I chose to learn from the source code of the great project Telegram. I encountered the following problem when reading the source code:

let a = AController(barHeight: 0)
let b = BController(barHeight: 50)
let c = AController(barHeight: 0)
let rightController: MajorNavigationController

The way I test entering 'a' (rightController.push(a, false, style: ViewControllerStyle.none)) or (rightController.push(a, true, style: ViewControllerStyle.push)) does not affect 'b'.

When pushing from a controller 'a' with bar = .init(height: 0) to a controller 'b' with bar = .init(height: 50) (navigationController?.push(b)), and then from 'b' pushing to a controller 'c' with bar = .init(height: 0) (navigationController?.push(c)), the navigation bar on 'c' appears.

Also, when returning to 'b', 'c's bar will cover 'b' (phenomenon is: the text in 'b's titleBarView displays 'b's defaultBarTitle, the reason being that pushing 'c' will set centerBarView = getCenterBarViewOnce() in loadView).

I noticed that in NavigationViewController, push calls the func show(_ controller: ViewController, _ style: ViewControllerStyle) -> Void {}, In the show method, there are a few lines of code like this:

func show(_ controller: ViewController, _ style: ViewControllerStyle) -> Void {
    // ...
    let animatePosBar: Bool = controller.bar.height != previous.bar.height && style != .none
    self.navigationBar.frame = NSMakeRect(point.x, barInset, size.width, animatePosBar && controller.bar.height == 0 ? previous.bar.height : controller.bar.height)
    // I tried to modify to self.navigationBar.frame = NSMakeRect(point.x, barInset, size.width, controller.bar.height), but it did not solve the problem

    // ...

    switch style {
    case .push:
        // ...
        if animatePosBar {
            navigationBar.layer?.animatePosition(from: NSMakePoint(nfrom, navigationBar.frame.minY), to: NSMakePoint(nto, barInset), duration: previous.animationStyle.duration, timingFunction: previous.animationStyle.function)
            navigationBar.frame = NSMakeRect(point.x, barInset, size.width, controller.bar.height) // I added this line of code, and it's working
        }
    case .pop:
        // ...
        if animatePosBar {
            // ...
            navigationBar.frame = NSMakeRect(point.x, barInset, size.width, controller.bar.height) // I added this line of code
        }
}

After adding my modifications, 'b' pushing 'c' could be done without displaying the navigation, but when 'c' pops to 'b', it still covers the content of 'b's titleBarView.

So, how should I modify the code in NavigationViewController to solve this problem?

Would you be willing to help me out with the problem I encountered while learning? I would be so grateful for your help.

Thank you for your time, sincerely appreciate it.

xiky commented 5 months ago

Today, in the func show(...) method, I came across the logic if !animatePosBar || (animatePosBar && style == .push) {}. I changed it to (animatePosBar && style != .none), which temporarily resolved the issue of the navigationBar displaying the centerBarView text of c's defaultBarTitle when returning from c to b.

However, the animation flickers during the return process. I hope there is a more correct method to modify this.

If there is a better way, I hope to receive your assistance. Thank you sincerely once again.