Restrict the movement of subview inside superview bounds

后端 未结 1 1960
一个人的身影
一个人的身影 2020-12-20 09:32

I have a UIView which is my VC\'s view(self.view) inside which I have another UIView added as subview both looks like a square. I would like to limit the movement of subview

相关标签:
1条回答
  • 2020-12-20 10:23

    You need to check the "new frame" of the view you are moving, and compare its edges to the bounds of its superview:

    @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
    

    This also uses the offset of the touch, instead of centering the view on the touch (so it doesn't "jump to your finger" when you start dragging).

    Edit for clarification: In this image, the Blue view class is DraggableView... It cannot be dragged outside of its superView (the Red view).


    Edit

    Swift version, with example 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),
            ])
    
        }
        
    }
    
    0 讨论(0)
提交回复
热议问题