【问题标题】:Changing height of UIView in response to finger drag响应手指拖动改变 UIView 的高度
【发布时间】:2013-08-25 08:17:15
【问题描述】:

我知道标题有点混乱,所以我会尽力解释清楚。我有一个固定宽度为 100 的 UIView 和一个从 0 开始的可变高度。我想要做的是将我的手指从 UIView 的底部拖到屏幕顶部,然后将 UIView改变它的高度/延伸到我手指的位置。如果这仍然很复杂,那就把它想象成从某物下面拉出一条纸条。

如果您能提供帮助,那就太好了。我觉得应该不会太难,但我只是初学者,如果我没有解释清楚,我可以理解!

【问题讨论】:

  • 我会让视图始终全高,但在视图内有一个高度变化的 CALayer。
  • 我该怎么做?
  • 你看过手势识别器吗?

标签: ios objective-c 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));
                   }];
}

当用户手指移动时,这应该会为视图设置动画。希望有帮助!

【讨论】:

  • 行得通,谢谢!你知道我如何为视图的高度添加最大值和最小值吗?
  • 另外,还有一个小问题。该代码有效,但无论您触摸屏幕的哪个位置都有效。这有点问题,因为我将拥有其中的 3 个。有什么办法可以改变它,让它只在你触摸时适用于特定的视图?
  • 最大值和最小值很容易。请注意,唯一重要的是currentPoint.y。确保currentPoint.y 在某个区间内(使用MAXMIN 函数)将为您提供所需的结果。至于你想要它选择的视图,只需查看currentPoint.x,并弄清楚它在哪里。如果它在左侧(小于屏幕宽度的 1/3),则使用第一个视图。如果它在中间,则使用第二个视图等。
  • 我现在已经完成了所有工作,所有三个视图分别工作,我有最小值和最大值。然而,最后一个问题是我已将此应用程序放在 UIScrollView 上。这意味着当我尝试向左或向右滑动以转到下一页时,它认为我正在更改条形。我怎样才能让它只识别向上滑动而不是横向滑动?
  • 查看手势的速度:CGPoint velocity = [gestureRecognizer velocityInView:yourView];,您应该能够确定它正在朝哪个方向移动。
【解决方案2】:

使用 UIPanGestureRecognizer 的 Swift 版本

使用从 Storyboard 添加到 UIView 的 PanGesture 并将委托设置为 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.
    }
}

【讨论】:

  • 谢谢@Alex。您的解决方案对我帮助很大。
猜你喜欢
  • 2013-01-18
  • 1970-01-01
  • 2017-03-19
  • 2016-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多