Изменение высоты UIView в ответ на перетаскивание пальца

Я понимаю, что название немного запутанно, поэтому я постараюсь объяснить это хорошо. У меня есть UIView с фиксированной шириной 100 и переменной высотой, начинающейся с 0. То, что я хочу сделать, это перетащить мой палец из базы UIView, в верхнюю часть экрана и UIView изменяет его высоту/простирается до положения моего пальца. Если это еще сложно, просто представьте себе, как из-под чего вытаскивается полоска бумаги.

Если вы можете помочь, это будет действительно здорово. Я не думаю, что это должно быть слишком сложно, но я всего лишь новичок, и я могу понять, если я не объяснил это хорошо!

Ответ 1

Это должно быть прямолинейно с UIPanGestureRecognizer и небольшой математикой. Чтобы изменить представление на правильный фрейм (я использую имя _viewToChange, поэтому замените его на свой взгляд позже), просто добавьте:

UIPanGestureRecognizer * pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
pan.maximumNumberOfTouches = pan.minimumNumberOfTouches = 1;
[self addGestureRecognizer:pan];

к вашему методу init для супер-представления и определите метод:

- (void)pan:(UIPanGestureRecognizer *)aPan; {
  CGPoint currentPoint = [aPan locationInView:self];

  [UIView animateWithDuration:0.01f
                   animations:^{
                     CGRect oldFrame = _viewToChange.frame;
                     _viewToChange.frame = CGRectMake(oldFrame.origin.x, currentPoint.y, oldFrame.size.width, ([UIScreen mainScreen].bounds.size.height - currentPoint.y));
                   }];
}

Это должно анимировать представление вверх по мере перемещения пальца пользователя. Надеюсь, что это поможет!

Ответ 2

Swift версия с использованием UIPanGestureRecognizer

Использование PanGesture добавлено в UIView из раскадровки и делегат установлен на self. UIView прикреплен к нижней части экрана.

class ViewController: UIViewController {
var translation: CGPoint!
var startPosition: CGPoint! //Start position for the gesture transition
var originalHeight: CGFloat = 0 // Initial Height for the UIView
var difference: CGFloat!

override func viewDidLoad() {
    super.viewDidLoad()
    originalHeight = dragView.frame.height
}

@IBOutlet weak var dragView: UIView! // UIView with UIPanGestureRecognizer

@IBOutlet var gestureRecognizer: UIPanGestureRecognizer!

@IBAction func viewDidDragged(_ sender: UIPanGestureRecognizer) {

    if sender.state == .began {
        startPosition = gestureRecognizer.location(in: dragView) // the postion at which PanGestue Started
    }

    if sender.state == .began || sender.state == .changed {
        translation = sender.translation(in: self.view)
        sender.setTranslation(CGPoint(x: 0.0, y: 0.0), in: self.view)
        let endPosition = sender.location(in: dragView) // the posiion at which PanGesture Ended
        difference = endPosition.y - startPosition.y
        var newFrame = dragView.frame
        newFrame.origin.x = dragView.frame.origin.x
        newFrame.origin.y = dragView.frame.origin.y + difference //Gesture Moving Upward will produce a negative value for difference
        newFrame.size.width = dragView.frame.size.width
        newFrame.size.height = dragView.frame.size.height - difference //Gesture Moving Upward will produce a negative value for difference
        dragView.frame = newFrame
    }

    if sender.state == .ended || sender.state == .cancelled {
        //Do Something
    }
  }
}

Ответ 3

Это моё быстрое решение, использующее автоматическое расположение и ограничение высоты для вида, размер которого вы хотите изменить, при этом устанавливая верхний и нижний пределы в зависимости от безопасных областей.

private var startPosition: CGPoint!
private var originalHeight: CGFloat = 0

override func viewDidLoad() {
    super.viewDidLoad()

    let panGesture = UIPanGestureRecognizer(target: self, action: #selector(viewDidDrag(_:)))
    resizableView.addGestureRecognizer(panGesture)
}

@objc private func viewDidDrag(_ sender: UIPanGestureRecognizer) {
    if sender.state == .began  {
        startPosition = sender.location(in: self.view)
        originalHeight = detailsContainerViewHeight.constant
    }

    if sender.state == .changed {
        let endPosition = sender.location(in: self.view)
        let difference = endPosition.y - startPosition.y
        var newHeight = originalHeight - difference

        if view.bounds.height - newHeight < topSafeArea + backButtonSafeArea {
            newHeight = view.bounds.height - topSafeArea - backButtonSafeArea
        } else if newHeight < routeDetailsHeaderView.bounds.height + bottomSafeArea {
            newHeight = routeDetailsHeaderView.bounds.height
        }

        resizableView.constant = newHeight
    }

    if sender.state == .ended || sender.state == .cancelled {
        //Do Something if interested when dragging ended.
    }
}