+4

Tự làm một slide menu đơn giản với Swift

Xin chào mọi người, đến hẹn lại lên Viblo 😃 , để thay đổi không khí với mấy bài phỏng vấn khô khan trước đó, hôm nay mình xin phép custom một cái slide menu đơn giản, đủ để có thể áp dụng vào công việc mà không cần đến thư viện.

Bắt đầu thôi 😃

1. Ý tưởng

Trên mạng có rất nhiều thư viện về Sliding và đa số là dùng navigation để xử lý, nên mình sẽ đi theo một hướng khác, không dùng UINavigationController làm root để điều khiển mà là sẽ dùng window để add subview. Chức năng thì giống nhau nhưng sẽ có 1 số khác biệt nhỏ.

2. Bắt đầu

a. Tạo 1 class CustomSlideViewController kế thừa UIViewController

Cái chức năng quan trọng nhất của 1 sliding đó là có thể tự đóng, mở và kéo qua kéo lại được.

Đóng/Mở: Vì là add subview và màn hình sliding sẽ di chuyển qua lại theo chiều ngang nên cách đơn giản nhất là chúng ta sẽ xử lý toạ độ x của nó, vì vậy ta đơn giản sẽ hình dung được ngay khi đóng thì x = -width và mở thì x = 0 Minh hoạ:

    //đây là đóng
    public func close() {
        var frame = view.frame
        frame.origin.x = -frame.size.width
        UIView.animate(withDuration: animatedTime,
                       delay: 0.0,
                       options: .transitionFlipFromRight,
                       animations: {[unowned self] in
            self.view.frame = frame
            }, completion: nil)
    }
    
    //còn đây là mở
        public func expand() {
        var frame = view.frame
        frame.origin.x = 0
        UIView.animate(withDuration: animatedTime,
                       delay: 0.0,
                       options: .transitionFlipFromLeft,
                       animations: {[unowned self] in
            self.view.frame = frame
            }, completion: nil)
    }

Kế tiếp, cái này quan trọng cho việc nó có "thật sự" là slide hay không chính là nó có khả năng kéo, thả hay không. Kéo thả: Trong ios muốn tương tác trực tiếp đến UIView thì ta phải add 1 gesture, cụ thể trường hợp của sliding này thì view của nó sẽ add 1 thể hiện của class UIPanGestureRecognizer. Nhớ là "Pan" chứ không phải "Tap". Code:

    fileprivate func addGesture() {
        let panGesture = UIPanGestureRecognizer(target: self,
                                                action: #selector(CustomSlideViewController.panInSelf(_ :)))
        panGesture.maximumNumberOfTouches = 1
        view.addGestureRecognizer(panGesture)
    }

Sau khi add gesture xong thì phải tới bước khó khắn hơn đó là xử lý khi mà mình "pan" nó 😃) Okay, phân tích một chút. Ở cái panGesture này thì nó có một cái property là "state", nó giúp ta detect được trạng thái của nó, nó có đến 6 loại trạng thái, nhưng ta chỉ cần detect 3 cái là đủ rồi.

  • changed: cái này là đang moving đấy. Nếu đang ở trạng thái này thì ta chỉ cần biết là nó dịch chuyển 1 đoạn bao nhiêu sau đó cập nhật là toạ độ ứng với đoạn đó là xong (dùng translation(in: UIVIewUIVIew?) để biết), sẽ thấy được cái sliding nó di chuyển theo ngón tay ta di chuyển, tất nhiên trong bài này là theo chiều ngang nhé
  • ended/cancelled: gặp trạng thái này là lúc mình bỏ tay ra khỏi màn hình, thì lúc này mình xem xét thử, nếu như là nó hiển thị hơn 1 nữa cái độ rộng của chính nó thì mình cho nó tự động mở ra, còn nếu nó hiển thị bằng 1 nữa hoặc ít hơn thì tự close đi, cho nó giống slide, chứ để khơi khơi thì nó rất thô. Code đây:
    func panInSelf(_ gesture: UIPanGestureRecognizer) {
        if gesture.state == .changed { //moving
            var center = view.center
            let translation = gesture.translation(in: view)
            let x = center.x + translation.x
            if x > maxExpandCenter {
                center.x = maxExpandCenter
            } else {
                center.x = x
            }
            gesture.view?.center = center
            gesture.setTranslation(CGPoint.zero, in: view)
        }
        
        if gesture.state == .ended || gesture.state == .cancelled {
            let center = view.center
            if center.x > 0 {
                expand(false)
            } else {
                close(false)
            }
        }
        
    }

Đó là xong phần chính của một cái sliding nên có,còn lại thì 1 chút vụn vặt như có shadow hay không, có thì màu gì, độ rộng như nào, ... thì đơn giản sẽ có đầy đủ trong source trên github, đừng nghĩ nhiều về nó.

Bây giờ thì ta đã có một sliding viewcontroller rồi, muốn dùng nó thì tạo 1 lass viewcontroller bất kỳ rồi kế thừa lại nó là xong.

Vậy là xong phần sliding nhé. Bây giờ qua 1 chút màn hình Main

b. MainViewController

Ở main thì chúng ta init cái sliding ở viewDidLoad() là được

Code: minh hoạ với 1 vài thông số tuỳ thích

    fileprivate func initProfileViewController() {
        let leftVC = LeftViewController(nibName: "LeftViewController", bundle: nil)
        if let frame = UIApplication.shared.windows.last?.frame {
            leftVC.resetWidth(parentWidth: frame.width)
            leftVC.shadowColor = UIColor(red: 46.0/255, green: 24.0/255, blue: 82.0/255, alpha: 0.7)
            leftVC.hasShadow = true
            UIApplication.shared.windows.last?.addSubview(leftVC.view)
        }
        self.leftVC = leftVC
    }
    

Có 1 điều lưu ý nhỏ ở đây là, khi làm sliding menu thì nó hay để hở 1 khoảng trống chứ ít khi che hết bên dưới nó, nên mình làm luôn 1 cái action nhỏ là tap vào khoảng trống thì close đi, tất nhiên không bắt buộc phải thế, tuỳ thích mà thôi

Code:

    fileprivate func addGesture() {
        let gesture = UITapGestureRecognizer(target: self, action: #selector(self.tapInSelf))
        self.view.addGestureRecognizer(gesture)
    }
    
    func tapInSelf() {
        leftVC?.close()
    }

3. Kết

Okay, trên đây là mình đã giải thích về cái sliding tự custom của mình, thấy cũng hay hay nên share cho mọi người, tất nhiên đem so sánh với những thư viện đã có thì nó chẳng là gì, nhưng cái mình muốn nói ở đây là nếu không có cần thiết phải sử dụng 1 cái sliding phức tạp thì mình nên tự làm lấy 1 cái mà dùng, củng cố kỹ năng cũng như khuyến khích tinh thần tự nghiên cứu mày mò học tập. Kya, hành trình chém gió đến đây kết thúc, xin cảm ơn (bow). Source code link: GitHub


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí