QQ個人中心的側滑功能(通常稱為"抽屜式導航")可以通過以下幾種方式在iOS中實現:
主要實現方案
- 使用第三方庫
最快速的方式是使用成熟的第三方庫:
- SWRevealViewController:最流行的側滑菜單庫
- MMDrawerController:另一個功能豐富的抽屜式導航庫
- KYDrawerController:輕量級的實現
示例代碼(SWRevealViewController):
// 初始化
let revealViewController = SWRevealViewController(rearViewController: MenuViewController(), frontViewController: MainViewController())// 設置為主窗口根視圖
window?.rootViewController = revealViewController// 添加手勢
revealViewController?.tapGestureRecognizer()
revealViewController?.panGestureRecognizer()
- 自定義實現
如果需要完全自定義,可以自己實現:
class DrawerController: UIViewController {private var mainViewController: UIViewController!private var menuViewController: UIViewController!private var isMenuOpen = false private let menuWidth: CGFloat = 300init(mainViewController: UIViewController, menuViewController: UIViewController) {self.mainViewController = mainViewController self.menuViewController = menuViewControllersuper.init(nibName: nil, bundle: nil)}override func viewDidLoad() {super.viewDidLoad()addChild(mainViewController)view.addSubview(mainViewController.view)mainViewController.didMove(toParent: self)addChild(menuViewController)view.insertSubview(menuViewController.view, at: 0)menuViewController.didMove(toParent: self)menuViewController.view.frame = CGRect(x: -menuWidth, y: 0, width: menuWidth, height: view.bounds.height)let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:)))view.addGestureRecognizer(panGesture)}@objc private func handlePanGesture(_ recognizer: UIPanGestureRecognizer) {let translation = recognizer.translation(in: view)switch recognizer.state {case .changed:let newX = mainViewController.view.frame.origin.x + translation.x if newX >= 0 && newX <= menuWidth {mainViewController.view.frame.origin.x = newX menuViewController.view.frame.origin.x = newX - menuWidth }recognizer.setTranslation(.zero, in: view)case .ended:let velocity = recognizer.velocity(in: view)if velocity.x > 0 {openMenu()} else {closeMenu()}default: break}}func openMenu() {UIView.animate(withDuration: 0.3) {self.mainViewController.view.frame.origin.x = self.menuWidthself.menuViewController.view.frame.origin.x = 0}isMenuOpen = true }func closeMenu() {UIView.animate(withDuration: 0.3) {self.mainViewController.view.frame.origin.x = 0self.menuViewController.view.frame.origin.x = -self.menuWidth }isMenuOpen = false}
}
實現要點
- 視圖層級:主視圖在上,菜單視圖在下
- 手勢處理:需要處理滑動手勢(UIPanGestureRecognizer)
- 動畫效果:使用UIView.animate實現平滑過渡
- 邊緣手勢:可以添加UIScreenEdgePanGestureRecognizer實現從邊緣滑出的效果
- 遮罩效果:QQ通常會在主視圖上添加半透明黑色遮罩
高級優化
- 性能優化:使用UIViewPropertyAnimator實現更流暢的交互
- 陰影效果:為主視圖添加陰影增加層次感
- 狀態保存:記住菜單的打開/關閉狀態
- 交互阻斷:菜單打開時阻斷主視圖的交互
SwiftUI實現
如果你使用SwiftUI,可以這樣實現:
struct ContentView: View {@State private var offset: CGFloat = 0 @State private var lastOffset: CGFloat = 0@GestureState private var dragOffset: CGFloat = 0var body: some View {let drag = DragGesture().updating($dragOffset) { value, state, _ instate = value.translation.width}.onEnded { value in withAnimation {if value.translation.width > 100 {offset = 300} else if value.translation.width < -100 {offset = 0 } else {offset = lastOffset }}lastOffset = offset }return ZStack(alignment: .leading) {MenuView().frame(width: 300)MainView().offset(x: max(0, offset + dragOffset)).gesture(drag)}}
}
選擇哪種實現方式取決于你的項目需求和技術棧。第三方庫可以快速實現,自定義實現則更加靈活可控。