ios - 限制 subview 在父 View 范围内的移动

标签 ios objective-c cocoa-touch uiview

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

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

这有效, subview 正在移动,但它也移动到父 View 之外;如何限制父 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 中也没有做任何相关的事情。

最佳答案

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

@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

这也使用触摸的偏移量,而不是将 View 以触摸为中心(因此当您开始拖动时它不会“跳到您的手指”)。

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

enter image description here


编辑

Swift 版本,带有示例 View Controller :

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),
        ])

    }
    
}

关于ios - 限制 subview 在父 View 范围内的移动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47413817/

相关文章:

ios - Fabric SDK 崩溃 [ANSAnswersController logCrashEvent :]

ios - 如何将 CodingKeys 用于符合 Codable 协议(protocol)的枚举?

ios - Core Graphics 的图形效果库?

iphone - 访问 ipad 相册中的图像

ios - 在 Swift 中创建 JSON 参数

ios - 在 AES 中使用 base32 key 加密

ios - 点击时清除横幅通知

iphone - UITableViewController 不使用 NSMutableArray 填充 TableView

objective-c - 数组上的这个操作如何实现?

ios - Swiffy输出透明背景