You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

已实现Uber式侧边菜单,求实现类Twitter侧边导航抽屉(Side Menu),不依赖第三方库

Hey there! Since you’ve already built an Uber-style overlay navigation drawer, switching to Twitter’s slide-out-main-content version is totally doable without any third-party libraries or CocoaPods. Let’s walk through the exact steps to replicate that Twitter feel.

Implementing Twitter-Style Navigation Drawer (No Third-Party Tools)

The core difference between Twitter’s and Uber’s drawer is:

Twitter slides the main view controller off-screen to reveal the menu behind it, while Uber slides the menu over the top of the main view controller.

We’ll use a container view controller to manage both the main and menu views—this keeps your code clean and gives full control over animations.

1. Set Up the Container Controller

First, create a container controller to act as your app’s root. It will hold both the menu and main view controllers.

class DrawerContainerViewController: UIViewController {
    // Replace these with your actual menu and main view controllers
    private let menuViewController = YourMenuViewController()
    private let mainViewController = YourMainViewController()
    private var isMenuOpen = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupChildViewControllers()
        addPanGestureToMainView()
    }
    
    private func setupChildViewControllers() {
        // Add menu first (it sits behind the main view)
        addChild(menuViewController)
        view.addSubview(menuViewController.view)
        menuViewController.view.frame = view.bounds
        menuViewController.didMove(toParent: self)
        
        // Add main view on top of the menu
        addChild(mainViewController)
        view.addSubview(mainViewController.view)
        mainViewController.view.frame = view.bounds
        mainViewController.didMove(toParent: self)
    }
    
    private func addPanGestureToMainView() {
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:)))
        mainViewController.view.addGestureRecognizer(panGesture)
    }
}

2. Handle Pan Gesture & Core Animations

This is where the Twitter-style magic happens. We’ll translate the main view with the user’s pan, and auto-complete the open/close animation when the gesture ends.

@objc private func handlePanGesture(_ gesture: UIPanGestureRecognizer) {
    let translation = gesture.translation(in: view)
    let progress = translation.x / view.bounds.width
    let maxSlideDistance = view.bounds.width * 0.7 // Adjust based on your desired menu width
    
    switch gesture.state {
    case .began:
        mainViewController.view.layer.removeAllAnimations() // Clear any pending animations
    case .changed:
        // Move main view with the gesture, cap it at max slide distance
        let newMainViewX = max(0, min(translation.x, maxSlideDistance))
        mainViewController.view.frame.origin.x = newMainViewX
        
        // Add subtle menu scaling/opacity for depth (Twitter-like polish)
        let menuScale = 1 - (progress * 0.1)
        menuViewController.view.transform = CGAffineTransform(scaleX: menuScale, y: menuScale)
        menuViewController.view.alpha = 0.8 + (progress * 0.2)
    case .ended, .cancelled:
        // Decide to open or close based on a threshold
        let openThreshold = view.bounds.width * 0.3
        if mainViewController.view.frame.origin.x > openThreshold {
            openMenu()
        } else {
            closeMenu()
        }
    default:
        break
    }
}

private func openMenu() {
    let targetX = view.bounds.width * 0.7
    UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.5) {
        self.mainViewController.view.frame.origin.x = targetX
        self.menuViewController.view.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
        self.menuViewController.view.alpha = 1.0
    } completion: { _ in
        self.isMenuOpen = true
    }
}

private func closeMenu() {
    UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.5) {
        self.mainViewController.view.frame.origin.x = 0
        self.menuViewController.view.transform = .identity
        self.menuViewController.view.alpha = 0.8
    } completion: { _ in
        self.isMenuOpen = false
    }
}

3. Polish for Twitter’s Exact Feel

  • Navigation Bar Handling: If your main view has a navigation bar, make sure it moves with the main view. Avoid using a standalone UINavigationController—instead, embed the navigation bar directly in your main view controller.
  • Menu Item Actions: Add a method in the container to close the menu when a menu item is tapped. Call this from your menu view controller (you can use a delegate or closure to communicate between them).
  • Screen Rotation: Update the frames of both views in viewWillTransition(to size:with coordinator:) to keep the drawer working correctly on rotation.
  • Status Bar Adjustments: If needed, override preferredStatusBarStyle in the container to match the menu/open state.

内容的提问来源于stack exchange,提问作者Hasnain Kanji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:42:55