响应手指拖动改变UIView高度

12

我知道这个标题有点令人困惑,所以我会尽力解释清楚。我有一个UIView,它的宽度固定为100,高度可变且从0开始。我想能够从UIView底部向屏幕顶部拖动手指,使UIView的高度/延伸到手指的位置。如果还是太复杂了,就把它想象成从某个东西下面拉出来的纸条。

如果您能帮忙,那真的太好了。我不认为这应该太难,但我只是一个初学者,如果我没有解释清楚,我可以理解!


我想让视图始终具有全高度,但是视图中有一个CALayer,其高度会发生变化。 - Abhi Beckert
我该如何着手做这件事? - user2397282
你看过手势识别器吗? - Wain
3个回答

15

使用UIPanGestureRecognizer和一些简单的数学计算,这应该是直接的。要将视图更改为正确的框架(我使用名称_viewToChange,稍后将其替换为您的视图),只需添加:

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

init方法添加到你的超级视图中,并定义该方法:

Translated:

Add the init method to your super view, and define the method:

- (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));
                   }];
}

这应该会在用户手指移动时使视图向上动画。希望有所帮助!


可以,谢谢!你知道我怎么能在视图的高度上添加最大值和最小值吗? - user2397282
还有一个小问题。代码可以运行,但是无论您在屏幕的哪个位置触摸它,它都会起作用。这是一个问题,因为我将拥有3个这样的视图。您是否有办法更改它,使其仅在触摸特定视图时才起作用? - user2397282
最大值和最小值很容易确定。请注意,唯一重要的点是 currentPoint.y。确保 currentPoint.y 在某个区间内(使用 MAXMIN 函数)将给您所需的结果。至于您想要选择的视图,只需查看 currentPoint.x 并找出它在哪里。如果它在左侧(小于屏幕宽度的 1/3),则使用第一个视图。如果在中间,则使用第二个视图,以此类推。 - msgambel
现在我已经使所有三个视图单独工作并且我有了最小和最大值。然而,最后一个问题是我将这个应用程序放在一个UIScrollView上。这意味着当我尝试向左或向右滑动以转到下一页时,它会认为我正在更改栏。我如何让它只识别向上滑动,而不是横向滑动? - user2397282
检查手势速度:CGPoint velocity = [gestureRecognizer velocityInView:yourView];,你应该能够确定它移动的方向。 - msgambel

10

使用UIPanGestureRecognizer的Swift版本

从Storyboard中添加PanGesture到UIView,并将delegate设置为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
    }
  }
}

如果我的视图附加到屏幕顶部,我想将高度增加到底部,则在此代码中我需要更改什么。 - Birju

5
这是我的 Swift 解决方案,使用自动布局和对要调整大小的视图设置高度约束,同时根据安全区域设置顶部和底部限制。
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.
    }
}

谢谢@Alex。你的解决方案帮了我很多。 - Birju
detailsContainerViewHeight是什么? - Mumtaz Hussain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接