How to display a UITableViewController as a scroll gesture in front of another ViewController?

I am trying to get something like this to work. This is an Uber app. If the user can scroll up another view, in front of the background view.

enter image description here

The background view is quite simple, it is already done. The view to be scrolled from above will be a UITableView. I want the user to be able to see only the small top at first, when the application starts, and then when it swings a little, it should stop in the middle, and then after a full turn, it should go all the way to the top, replacing the background view.

The structures I was looking at are an amazing view for iOS. But he is too old and does not receive pleasant animations. I also looked at the SWRevealViewController, but I can't figure out how to scroll from the bottom.

I also tried using a button, so when the user clicks on it, the table view controller looks modal, spanning the vertical, but this is not what I want. He must recognize the gesture.

Any help is appreciated. Thank.

EDIT: I'm going to not accept my answer and keep it open if anyone has a much better way to implement it in the future. Although my answer works, it can be improved. Also, this is not the same as the Uber app, which was my initial question.

+5
source share
4 answers

: , , Pulley. , , !

:

Rikh, Tj3n . - , , Uber, .

UIViewController. UIPanGestureRecognizer , . , , , , .

UIViewController, .

enter image description here

MainViewController :

class MainViewController: UIViewController {

// This image will be dragged up or down.
@IBOutlet var imageView: UIImageView!

// Gesture recognizer, will be added to image below.
var swipedOnImage = UIPanGestureRecognizer()

// This is the view controller that will be dragged with the image. In my case it a UITableViewController.
var vc = UIViewController()

override func viewDidLoad() {
    super.viewDidLoad()

    // I'm using a storyboard.
    let sb = UIStoryboard(name: "Main", bundle: nil)

    // I have identified the view inside my storyboard.
    vc = sb.instantiateViewController(withIdentifier: "TableVC")

    // These values can be played around with, depending on how much you want the view to show up when it starts.
    vc.view.frame = CGRect(x: 0, y: self.view.frame.height, width: self.view.frame.width, height: -300)


    self.addChildViewController(vc)
    self.view.addSubview(vc.view)
    vc.didMove(toParentViewController: self)

    swipedOnImage = UIPanGestureRecognizer(target: self, action: #selector(self.swipedOnViewAction))
    imageView.addGestureRecognizer(swipedOnImage)

    imageView.isUserInteractionEnabled = true

}

// This function handles resizing of the tableview.
func swipedOnViewAction() {

    let yLocationTouched = swipedOnImage.location(in: self.view).y

    imageView.frame.origin.y = yLocationTouched

    // These values can be played around with if required. 
    vc.view.frame =  CGRect(x: 0, y: yLocationTouched, width: UIScreen.main.bounds.width, height: (UIScreen.main.bounds.height) - (yLocationTouched))
    vc.view.frame.origin.y = yLocationTouched + 50

}

enter image description here

, , iOS, , .

+3

, ( hittest), ( ),

,

, .

+1

Tj3n, UISwipeGesture UITableView. , ( ), :

UIViewController , UITableView. UITableView , UITableView. UIViewController UITableView, UITableView UIViewController ( , UITableView ). ( , , ). , :

topSpaceToViewControllerConstraint.constant = -mainTableViewHeightConstraint.constant

 UIView.animate(withDuration: 0.3) { 

     view.layoutIfNeeded()
 };

, UITableView (.. , ), UIPanGestureRecognizer autoLayout UITableView ( view.layoutIfNeeded . - , , , - ).

func handlePan(sender: UIPanGestureRecognizer) {

        if sender.state == .Changed {
               //update y origin value here based on the pan amount
        }
    }

, UITableViewController

, , UITableViewController, , , UINavigationControllerDelegate , UIPercentDrivenInteractiveTransition UITableViewController , UIPanGestureRecognizer, , . UISwipeGestureRecognizer, UITableViewController, , "" .

+1

, 2 , - :

, UIViewPropertyAnimator. : http://www.swiftkickmobile.com/building-better-app-animations-swift-uiviewpropertyanimator/

:

, UIViewPropertyAnimator, GIF:

Github: https://github.com/Luigi123/UIViewPropertyAnimatorExample

UIViewController s, ViewController BottomSheetViewController. UIPanGestureRecognizer , 3 ( ):

① , ,
② ,
③ , . Notification, notification.userInfo.

, ①, , , 500 100- , , 20% . - , fractionComplete UIViewPropertyAnimator.

⚠️ , , "" .

, , , , , , , github. , , , 100 .

, , ViewController:

import UIKit
import MapKit
import NotificationCenter

class ViewController: UIViewController {
    @IBOutlet weak var someView: UIView!
    @IBOutlet weak var blackView: UIView!

    var animator: UIViewPropertyAnimator?

    func createBottomView() {
        guard let sub = storyboard!.instantiateViewController(withIdentifier: "BottomSheetViewController") as? BottomSheetViewController else { return }
        self.addChild(sub)
        self.view.addSubview(sub.view)
        sub.didMove(toParent: self)
        sub.view.frame = CGRect(x: 0, y: view.frame.maxY - 100, width: view.frame.width, height: view.frame.height)
    }

    func subViewGotPanned(_ percentage: Int) {
        guard let propAnimator = animator else {
            animator = UIViewPropertyAnimator(duration: 3, curve: .linear, animations: {
                self.blackView.alpha = 1
                self.someView.transform = CGAffineTransform(scaleX: 0.8, y: 0.8).concatenating(CGAffineTransform(translationX: 0, y: -20))
            })
            animator?.startAnimation()
            animator?.pauseAnimation()
            return
        }
        propAnimator.fractionComplete = CGFloat(percentage) / 100
    }

    func receiveNotification(_ notification: Notification) {
        guard let percentage = notification.userInfo?["percentage"] as? Int else { return }
        subViewGotPanned(percentage)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        createBottomView()

        let name = NSNotification.Name(rawValue: "BottomViewMoved")
        NotificationCenter.default.addObserver(forName: name, object: nil, queue: nil, using: receiveNotification(_:))
    }
}

(BottomSheetViewController):

import UIKit
import NotificationCenter

class BottomSheetViewController: UIViewController, UIGestureRecognizerDelegate {
    @IBOutlet weak var navBarView: UIView!

    var panGestureRecognizer: UIPanGestureRecognizer?
    var animator: UIViewPropertyAnimator?

    override func viewDidLoad() {
        gotPanned(0)
        super.viewDidLoad()

        let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(respondToPanGesture))
        view.addGestureRecognizer(gestureRecognizer)
        gestureRecognizer.delegate = self
        panGestureRecognizer = gestureRecognizer
    }

    func gotPanned(_ percentage: Int) {
        if animator == nil {
            animator = UIViewPropertyAnimator(duration: 1, curve: .linear, animations: {
                let scaleTransform = CGAffineTransform(scaleX: 1, y: 5).concatenating(CGAffineTransform(translationX: 0, y: 240))
                self.navBarView.transform = scaleTransform
                self.navBarView.alpha = 0
            })
            animator?.isReversed = true
            animator?.startAnimation()
            animator?.pauseAnimation()
        }
        animator?.fractionComplete = CGFloat(percentage) / 100
    }

    // MARK: methods to make the view draggable

    @objc func respondToPanGesture(recognizer: UIPanGestureRecognizer) {
        let translation = recognizer.translation(in: self.view)
        moveToY(self.view.frame.minY + translation.y)
        recognizer.setTranslation(.zero, in: self.view)
    }

    private func moveToY(_ position: CGFloat) {
        view.frame = CGRect(x: 0, y: position, width: view.frame.width, height: view.frame.height)
        let maxHeight = view.frame.height - 100
        let percentage = Int(100 - ((position * 100) / maxHeight))
        gotPanned(percentage)
        let name = NSNotification.Name(rawValue: "BottomViewMoved")
        NotificationCenter.default.post(name: name, object: nil, userInfo: ["percentage": percentage])
    }
}
+1

Source: https://habr.com/ru/post/1661656/


All Articles