你好,歡迎來到IOS教程網

 Ios教程網 >> IOS使用技巧 >> IOS7技巧 >> Swift側滑菜單實現仿QQ,菜單帶縮放效果

Swift側滑菜單實現仿QQ,菜單帶縮放效果

編輯:IOS7技巧
側滑菜單各位可能見到的不少了如果使用QQ的肯定知道側滑菜單是什麼效果了,下面我們來看一個Swift側滑菜單實現仿QQ,菜單帶縮放效果的例子。

前面我寫了一篇文章介紹如何實現側滑菜單:Swift - 側滑菜單的實現(樣例1:主頁向右滑動,露出下方菜單頁)

其實現方式是,通過手勢拖動主頁面移動,從而露出下面的菜單頁(其實後面的菜單頁是固定不動的)。

下面演示另一種樣式的實現(模仿手機QQ的側滑菜單),主頁面滑動停靠的過程中會逐漸縮小,同時菜單頁也會逐漸移動放大,浮現出來。

(注:本文樣例是基於前面文章的demo修改的,如果沒閱讀前文的話可以先去看下。為便於理解,下面將效果分兩步實現。)

原文:Swift - 側滑菜單的功能實現(樣例2:仿QQ,菜單帶縮放效果)

1,主頁停靠側邊時尺寸逐漸縮小

(1)定義了新屬性 minProportion,表示停靠時的縮小比例。在滑動時,再根據頁面的位置實時計算出當前的縮放比例。
(2)在主頁面與菜單頁之間添加了個黑色遮罩層(blackCover), 初始化時是不透明的。隨著菜單的展開透明度逐漸變為0。這樣側滑菜單有逐漸顯示出來的效果。 
原文:Swift - 側滑菜單的功能實現(樣例2:仿QQ,菜單帶縮放效果)   原文:Swift - 側滑菜單的功能實現(樣例2:仿QQ,菜單帶縮放效果)   原文:Swift - 側滑菜單的功能實現(樣例2:仿QQ,菜單帶縮放效果)

ViewController.swift 代碼如下(高亮處為修改過的地方):


import UIKit
 
class ViewController: UIViewController {
    // 主頁導航控制器
    var mainNavigationController:UINavigationController!
    
    // 主頁面控制器
    var mainViewController:MainViewController!
    
    // 菜單頁控制器
    var menuViewController:MenuViewController?
    
    // 菜單頁當前狀態
    var currentState = MenuState.Collapsed {
        didSet {
            //菜單展開的時候,給主頁面邊緣添加陰影
            let shouldShowShadow = currentState != .Collapsed
            showShadowForMainViewController(shouldShowShadow)
        }
    }
    
    // 菜單打開後主頁在屏幕右側露出部分的寬度
    let menuViewExpandedOffset: CGFloat = 60
    
    // 側滑菜單黑色半透明遮罩層
    var blackCover: UIView?
    
    // 最小縮放比例
    let minProportion: CGFloat = 0.77
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //狀態欄文字改成白色
        UIApplication.sharedApplication().statusBarStyle = .LightContent;
        
        // 給根容器設置背景
        let imageView = UIImageView(image: UIImage(named: "back"))
        imageView.frame = UIScreen.mainScreen().bounds
        self.view.addSubview(imageView)
        
        //初始化主視圖
        mainNavigationController = UIStoryboard(name: "Main", bundle: nil)
            .instantiateViewControllerWithIdentifier("mainNavigaiton")
            as! UINavigationController
        view.addSubview(mainNavigationController.view)
        
        //指定Navigation Bar左側按鈕的事件
        mainViewController = mainNavigationController.viewControllers.first
            as! MainViewController
        mainViewController.navigationItem.leftBarButtonItem?.action = Selector("showMenu")
        
        //添加拖動手勢
        let panGestureRecognizer = UIPanGestureRecognizer(target: self,
            action: "handlePanGesture:")
        mainNavigationController.view.addGestureRecognizer(panGestureRecognizer)
        
        //單擊收起菜單手勢
        let tapGestureRecognizer = UITapGestureRecognizer(target: self,
            action: "handlePanGesture")
        mainNavigationController.view.addGestureRecognizer(tapGestureRecognizer)
    }
    
    //導航欄左側按鈕事件響應
    func showMenu() {
        //如果菜單是展開的則會收起,否則就展開
        if currentState == .Expanded {
            animateMainView(false)
        }else {
            addMenuViewController()
            animateMainView(true)
        }
    }
    
    //拖動手勢響應
    func handlePanGesture(recognizer: UIPanGestureRecognizer) {
        
        switch(recognizer.state) {
            // 剛剛開始滑動
        case .Began:
            // 判斷拖動方向
            let dragFromLeftToRight = (recognizer.velocityInView(view).x > 0)
            // 如果剛剛開始滑動的時候還處於主頁面,從左向右滑動加入側面菜單
            if (currentState == .Collapsed && dragFromLeftToRight) {
                currentState = .Expanding
                addMenuViewController()
            }
            
            // 如果是正在滑動,則偏移主視圖的坐標實現跟隨手指位置移動
        case .Changed:
            let screenWidth = view.bounds.size.width
            var centerX = recognizer.view!.center.x +
                recognizer.translationInView(view).x
            //頁面滑到最左側的話就不許要繼續往左移動
            if centerX < screenWidth/2 { centerX = screenWidth/2 }
            
            // 計算縮放比例
            var proportion:CGFloat = (centerX - screenWidth/2) /
                (view.bounds.size.width - menuViewExpandedOffset)
            proportion = 1 - (1 - minProportion) * proportion
        
            // 執行視差特效
            blackCover?.alpha = (proportion - minProportion) / (1 - minProportion)
            
            //主頁面滑到最左側的話就不許要繼續往左移動
            recognizer.view!.center.x = centerX
            recognizer.setTranslation(CGPointZero, inView: view)
            //縮放主頁面
            recognizer.view!.transform =
                CGAffineTransformScale(CGAffineTransformIdentity, proportion, proportion)
            
            // 如果滑動結束
        case .Ended:
            //根據頁面滑動是否過半,判斷後面是自動展開還是收縮
            let hasMovedhanHalfway = recognizer.view!.center.x > view.bounds.size.width
            animateMainView(hasMovedhanHalfway)
        default:
            break
        }
    }
    
    //單擊手勢響應
    func handlePanGesture() {
        //如果菜單是展開的點擊主頁部分則會收起
        if currentState == .Expanded {
            animateMainView(false)
        }
    }
    
    // 添加菜單頁
    func addMenuViewController() {
        if (menuViewController == nil) {
            menuViewController = UIStoryboard(name: "Main", bundle: nil)
                .instantiateViewControllerWithIdentifier("menuView") as? MenuViewController
            
            // 插入當前視圖並置頂
            view.insertSubview(menuViewController!.view,
                belowSubview: mainNavigationController.view)
            
            // 建立父子關系
            addChildViewController(menuViewController!)
            menuViewController!.didMoveToParentViewController(self)
            
            // 在側滑菜單之上增加黑色遮罩層,目的是實現視差特效
            blackCover = UIView(frame: CGRectOffset(self.view.frame, 0, 0))
            blackCover!.backgroundColor = UIColor.blackColor()
            self.view.insertSubview(blackCover!,
                belowSubview: mainNavigationController.view)
        }
    }
    
    //主頁自動展開、收起動畫
    func animateMainView(shouldExpand: Bool) {
        // 如果是用來展開
        if (shouldExpand) {
            // 更新當前狀態
            currentState = .Expanded
            // 動畫
            let mainPosition = view.bounds.size.width * (1+minProportion/2)
                - menuViewExpandedOffset
            doTheAnimate(mainPosition, mainProportion: minProportion, blackCoverAlpha: 0)
        }
            // 如果是用於隱藏
        else {
            // 動畫
            doTheAnimate(view.bounds.size.width/2, mainProportion: 1, blackCoverAlpha: 1) {
                finished in
                // 動畫結束之後更新狀態
                self.currentState = .Collapsed
                // 移除左側視圖
                self.menuViewController?.view.removeFromSuperview()
                // 釋放內存
                self.menuViewController = nil;
                // 移除黑色遮罩層
                self.blackCover?.removeFromSuperview()
                // 釋放內存
                self.blackCover = nil;
            }
        }
    }
    
    //主頁移動動畫、黑色遮罩層動畫
    func doTheAnimate(mainPosition: CGFloat, mainProportion: CGFloat,
        blackCoverAlpha: CGFloat, completion: ((Bool) -> Void)! = nil) {
            //usingSpringWithDamping:1.0表示沒有彈簧震動動畫
            UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 1.0,
                initialSpringVelocity: 0, options: .CurveEaseInOut, animations: {
                    self.mainNavigationController.view.center.x = mainPosition
                    self.blackCover?.alpha = blackCoverAlpha
                    // 縮放主頁面
                    self.mainNavigationController.view.transform =
                        CGAffineTransformScale(CGAffineTransformIdentity,
                            mainProportion, mainProportion)
                }, completion: completion)
    }
    
    //給主頁面邊緣添加、取消陰影
    func showShadowForMainViewController(shouldShowShadow: Bool) {
        if (shouldShowShadow) {
            mainNavigationController.view.layer.shadowOpacity = 0.8
        } else {
            mainNavigationController.view.layer.shadowOpacity = 0.0
        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}
 
// 菜單狀態枚舉
enum MenuState {
    case Collapsed  // 未顯示(收起)
    case Expanding   // 展開中
    case Expanded   // 展開
}

源碼下載:hangge_1035.zip

2,側滑展開時,菜單頁逐漸放大
(1)菜單頁的背景是透明的,背景圖(大海背景)是添加在容器頁(ViewController)裡面的。
(2)菜單頁的移動縮放原理和上面一樣,也是根據滑動時,主頁面的位置實時計算出菜單頁的尺寸和位置。
(3)由於側滑菜單打開時是從屏幕外滑入的,新增屬性 menuViewStartOffset 表示它的起始位置(超出屏幕多少距離)。

原文:Swift - 側滑菜單的功能實現(樣例2:仿QQ,菜單帶縮放效果)   原文:Swift - 側滑菜單的功能實現(樣例2:仿QQ,菜單帶縮放效果)   原文:Swift - 側滑菜單的功能實現(樣例2:仿QQ,菜單帶縮放效果)


ViewController.swift 代碼如下(高亮處為修改過的地方):


import UIKit
 
class ViewController: UIViewController {
    // 主頁導航控制器
    var mainNavigationController:UINavigationController!
    
    // 主頁面控制器
    var mainViewController:MainViewController!
    
    // 菜單頁控制器
    var menuViewController:MenuViewController?
    
    // 菜單頁當前狀態
    var currentState = MenuState.Collapsed {
        didSet {
            //菜單展開的時候,給主頁面邊緣添加陰影
            let shouldShowShadow = currentState != .Collapsed
            showShadowForMainViewController(shouldShowShadow)
        }
    }
    
    // 菜單打開後主頁在屏幕右側露出部分的寬度
    let menuViewExpandedOffset: CGFloat = 60
    
    // 側滑開始時,菜單視圖起始的偏移量
    let menuViewStartOffset: CGFloat = 70
    
    // 側滑菜單黑色半透明遮罩層
    var blackCover: UIView?
    
    // 最小縮放比例
    let minProportion: CGFloat = 0.77
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //狀態欄文字改成白色
        UIApplication.sharedApplication().statusBarStyle = .LightContent;
        
        // 給根容器設置背景
        let imageView = UIImageView(image: UIImage(named: "back"))
        imageView.frame = UIScreen.mainScreen().bounds
        self.view.addSubview(imageView)
        
        //初始化主視圖
        mainNavigationController = UIStoryboard(name: "Main", bundle: nil)
            .instantiateViewControllerWithIdentifier("mainNavigaiton")
            as! UINavigationController
        view.addSubview(mainNavigationController.view)
        
        //指定Navigation Bar左側按鈕的事件
        mainViewController = mainNavigationController.viewControllers.first
            as! MainViewController
        mainViewController.navigationItem.leftBarButtonItem?.action = Selector("showMenu")
        
        //添加拖動手勢
        let panGestureRecognizer = UIPanGestureRecognizer(target: self,
            action: "handlePanGesture:")
        mainNavigationController.view.addGestureRecognizer(panGestureRecognizer)
        
        //單擊收起菜單手勢
        let tapGestureRecognizer = UITapGestureRecognizer(target: self,
            action: "handlePanGesture")
        mainNavigationController.view.addGestureRecognizer(tapGestureRecognizer)
    }
    
    //導航欄左側按鈕事件響應
    func showMenu() {
        //如果菜單是展開的則會收起,否則就展開
        if currentState == .Expanded {
            animateMainView(false)
        }else {
            addMenuViewController()
            animateMainView(true)
        }
    }
    
    //拖動手勢響應
    func handlePanGesture(recognizer: UIPanGestureRecognizer) {
        
        switch(recognizer.state) {
            // 剛剛開始滑動
        case .Began:
            // 判斷拖動方向
            let dragFromLeftToRight = (recognizer.velocityInView(view).x > 0)
            // 如果剛剛開始滑動的時候還處於主頁面,從左向右滑動加入側面菜單
            if (currentState == .Collapsed && dragFromLeftToRight) {
                currentState = .Expanding
                addMenuViewController()
            }
            
            // 如果是正在滑動,則偏移主視圖的坐標實現跟隨手指位置移動
        case .Changed:
            let screenWidth = view.bounds.size.width
            var centerX = recognizer.view!.center.x +
                recognizer.translationInView(view).x
            //頁面滑到最左側的話就不許要繼續往左移動
            if centerX < screenWidth/2 { centerX = screenWidth/2 }
            
            // 計算縮放比例
            let percent:CGFloat = (centerX - screenWidth/2) /
                (view.bounds.size.width - menuViewExpandedOffset)
            let proportion = 1 - (1 - minProportion) * percent
        
            // 執行視差特效
            blackCover?.alpha = (proportion - minProportion) / (1 - minProportion)
            
            recognizer.view!.center.x = centerX
            recognizer.setTranslation(CGPointZero, inView: view)
            //縮放主頁面
            recognizer.view!.transform =
                CGAffineTransformScale(CGAffineTransformIdentity, proportion, proportion)
            
            //菜單視圖移動
            menuViewController?.view.center.x = screenWidth/2 -
                menuViewStartOffset * (1 - percent)
            //菜單視圖縮放
            let menuProportion = (1 + minProportion) - proportion
            menuViewController?.view.transform = CGAffineTransformScale(
                CGAffineTransformIdentity, menuProportion, menuProportion)
            
            // 如果滑動結束
        case .Ended:
            //根據頁面滑動是否過半,判斷後面是自動展開還是收縮
            let hasMovedhanHalfway = recognizer.view!.center.x > view.bounds.size.width
            animateMainView(hasMovedhanHalfway)
        default:
            break
        }
    }
    
    //單擊手勢響應
    func handlePanGesture() {
        //如果菜單是展開的點擊主頁部分則會收起
        if currentState == .Expanded {
            animateMainView(false)
        }
    }
    
    // 添加菜單頁
    func addMenuViewController() {
        if (menuViewController == nil) {
            menuViewController = UIStoryboard(name: "Main", bundle: nil)
                .instantiateViewControllerWithIdentifier("menuView") as? MenuViewController
            
            menuViewController!.view.center.x = view.bounds.size.width/2
                * (1-(1-minProportion)/2) - menuViewStartOffset
            menuViewController!.view.transform = CGAffineTransformScale(
                CGAffineTransformIdentity, minProportion, minProportion)
            
            // 插入當前視圖並置頂
            view.insertSubview(menuViewController!.view,
                belowSubview: mainNavigationController.view)
            
            // 建立父子關系
            addChildViewController(menuViewController!)
            menuViewController!.didMoveToParentViewController(self)
            
            // 在側滑菜單之上增加黑色遮罩層,目的是實現視差特效
            blackCover = UIView(frame: CGRectOffset(self.view.frame, 0, 0))
            blackCover!.backgroundColor = UIColor.blackColor()
            self.view.insertSubview(blackCover!,
                belowSubview: mainNavigationController.view)
        }
    }
    
    //主頁自動展開、收起動畫
    func animateMainView(shouldExpand: Bool) {
        // 如果是用來展開
        if (shouldExpand) {
            // 更新當前狀態
            currentState = .Expanded
            // 動畫
            let mainPosition = view.bounds.size.width * (1+minProportion/2)
                - menuViewExpandedOffset
            doTheAnimate(mainPosition, mainProportion: minProportion,
                menuPosition: view.bounds.size.width/2, menuProportion: 1,
                blackCoverAlpha: 0)
        }
            // 如果是用於隱藏
        else {
            // 動畫
            let menuPosition = view.bounds.size.width/2 * (1-(1-minProportion)/2)
                - menuViewStartOffset
            doTheAnimate(view.bounds.size.width/2, mainProportion: 1,
                menuPosition: menuPosition, menuProportion: minProportion,
                blackCoverAlpha: 1) { finished in
                // 動畫結束之後更新狀態
                self.currentState = .Collapsed
                // 移除左側視圖
                self.menuViewController?.view.removeFromSuperview()
                // 釋放內存
                self.menuViewController = nil;
                // 移除黑色遮罩層
                self.blackCover?.removeFromSuperview()
                // 釋放內存
                self.blackCover = nil;
            }
        }
    }
    
    //主頁移動動畫、黑色遮罩層動畫、菜單頁移動動畫
    func doTheAnimate(mainPosition: CGFloat, mainProportion: CGFloat,
        menuPosition: CGFloat, menuProportion: CGFloat,
        blackCoverAlpha: CGFloat, completion: ((Bool) -> Void)! = nil) {
            //usingSpringWithDamping:1.0表示沒有彈簧震動動畫
            UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 1.0,
                initialSpringVelocity: 0, options: .CurveEaseInOut, animations: {
                    self.mainNavigationController.view.center.x = mainPosition
                    self.blackCover?.alpha = blackCoverAlpha
                    // 縮放主頁面
                    self.mainNavigationController.view.transform =
                        CGAffineTransformScale(CGAffineTransformIdentity,
                            mainProportion, mainProportion)
                    
                    // 菜單頁移動
                    self.menuViewController?.view.center.x = menuPosition
                    // 菜單頁縮放
                    self.menuViewController?.view.transform =
                        CGAffineTransformScale(CGAffineTransformIdentity,
                            menuProportion, menuProportion)
                    
                }, completion: completion)
    }
    
    //給主頁面邊緣添加、取消陰影
    func showShadowForMainViewController(shouldShowShadow: Bool) {
        if (shouldShowShadow) {
            mainNavigationController.view.layer.shadowOpacity = 0.8
        } else {
            mainNavigationController.view.layer.shadowOpacity = 0.0
        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}
 
// 菜單狀態枚舉
enum MenuState {
    case Collapsed  // 未顯示(收起)
    case Expanding   // 展開中
    case Expanded   // 展開
}

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved