【问题标题】:Restrict the movement of subview inside superview bounds限制子视图在父视图范围内的移动
【发布时间】:2018-05-04 23:01:15
【问题描述】:

我有一个 UIView,它是我的 VC 的视图(self.view),我在其中添加了另一个 UIView 作为子视图,它们看起来都像一个正方形。我想限制子视图在父视图内的移动。基本上子视图不应超出父视图范围。
我确实实现了

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 
// i check if point of touch is inside my superview i set the center i.e
UITouch *touch = [[UITouch allObjects] firstObject];
if (CGRectContainsPoint(subview.frame, [touch locationInView:self.view])) {
// set the center here... i.e
subview.center = [touch locationInView:self.view];
}

这可行,子视图正在移动,但它也移动到父视图之外;如何仅限制超级视图内的移动?

我什至尝试过类似 .

if (CGRectContainsRect(self.view.bounds, subview.frame)) {
// this condition works but i don't know why my subview sticks to the sides of superview if i try to drag it through the bounds of superview
}

我没有在 touchesBegan、touchesCancelled 中做任何事情,在 touchesEnd 中也没有任何相关内容。

【问题讨论】:

    标签: ios objective-c cocoa-touch uiview


    【解决方案1】:

    您需要检查您正在移动的视图的“新框架”,并将其边缘与其父视图的边界进行比较:

    @implementation DraggableView
    
    - (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
    {
        // restrict to superview bounds
        CGRect parentFrame = [self.superview bounds];
        
        UITouch *aTouch = [touches anyObject];
        CGPoint location = [aTouch locationInView:self];
        CGPoint previousLocation = [aTouch previousLocationInView:self];
        
        // new frame for this "draggable" subview, based on touch offset when moving
        CGRect newFrame = CGRectOffset(self.frame, (location.x - previousLocation.x), (location.y - previousLocation.y));
        
        if (newFrame.origin.x < 0) {
    
            // if the new left edge would be outside the superview (dragging left),
            // set the new origin.x to Zero
            newFrame.origin.x = 0;
            
        } else if (newFrame.origin.x + newFrame.size.width > parentFrame.size.width) {
            
            // if the right edge would be outside the superview (dragging right),
            // set the new origin.x to the width of the superview - the width of this view
            newFrame.origin.x = parentFrame.size.width - self.frame.size.width;
            
        }
        
        if (newFrame.origin.y < 0) {
    
            // if the new top edge would be outside the superview (dragging up),
            // set the new origin.y to Zero
            newFrame.origin.y = 0;
            
        } else if (newFrame.origin.y + newFrame.size.height > parentFrame.size.height) {
            
            // if the new bottom edge would be outside the superview (dragging down),
            // set the new origin.y to the height of the superview - the height of this view
            newFrame.origin.y = parentFrame.size.height - self.frame.size.height;
            
        }
        
        // update this view's frame
        self.frame = newFrame;
    }
    
    @end
    

    这也使用了触摸的偏移,而不是使视图在触摸上居中(因此当您开始拖动时它不会“跳到您的手指”)。

    编辑澄清:在这张图片中,蓝色视图类是DraggableView...它不能被拖到它的超级视图(红色视图)之外。


    编辑

    Swift 版本,带有示例视图控制器:

    class DraggableView: UIView {
        
        override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
            
            // unwrap superview and touch
            guard let sv = superview,
                let touch = touches.first
            else { return }
            
            let parentFrame = sv.bounds
            
            let location = touch.location(in: self)
            let previousLocation = touch.previousLocation(in: self)
            
            // new frame for this "draggable" subview, based on touch offset when moving
            var newFrame = self.frame.offsetBy(dx: location.x - previousLocation.x, dy: location.y - previousLocation.y)
            
            // make sure Left edge is not past Left edge of superview
            newFrame.origin.x = max(newFrame.origin.x, 0.0)
            // make sure Right edge is not past Right edge of superview
            newFrame.origin.x = min(newFrame.origin.x, parentFrame.size.width - newFrame.size.width)
    
            // make sure Top edge is not past Top edge of superview
            newFrame.origin.y = max(newFrame.origin.y, 0.0)
            // make sure Bottom edge is not past Bottom edge of superview
            newFrame.origin.y = min(newFrame.origin.y, parentFrame.size.height - newFrame.size.height)
            
            self.frame = newFrame
            
        }
    
    }
    class DraggableTestViewController: UIViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            let dragView = DraggableView()
            dragView.backgroundColor = .cyan
            dragView.frame = CGRect(x: 20, y: 20, width: 50, height: 50)
            
            let containerView = UIView()
            containerView.translatesAutoresizingMaskIntoConstraints = false
            containerView.backgroundColor = .red
            
            containerView.addSubview(dragView)
            
            view.addSubview(containerView)
            
            let g = view.safeAreaLayoutGuide
    
            NSLayoutConstraint.activate([
                containerView.widthAnchor.constraint(equalToConstant: 300.0),
                containerView.heightAnchor.constraint(equalTo: containerView.widthAnchor),
                containerView.centerXAnchor.constraint(equalTo: g.centerXAnchor),
                containerView.centerYAnchor.constraint(equalTo: g.centerYAnchor),
            ])
    
        }
        
    }
    

    【讨论】:

    • Bingo @DonMag :)..... 1 澄清,仅仅是由于这种触摸偏移,我的解决方案无法正常工作吗??
    • 我在这里看到了 1 个问题,当我沿着我的超级视图拖动时,我猜想子视图也被拖动了,因为 touchesBegan 也在为它工作(超级视图)。我怎样才能避免这种情况??
    • @user2606782 - 不太清楚你在问什么......在我的回答中查看带有屏幕帽的编辑 - 也许这会有所帮助?
    • 实际上我的可拖动视图不是一个单独的类,因此 superView 和它的子视图都调用了 touchesMoved。我希望你明白。有什么办法可以避免这种情况?其他然后为 subView 创建一个单独的 draggableView 类??
    • @EmreDeğirmenci - 请参阅我的答案底部的编辑
    猜你喜欢
    • 2012-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多