限制子视图在父视图范围内的移动
Restrict the movement of subview inside superview bounds
我有一个 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 中也没有做任何相关的事情。
您需要检查正在移动的视图的“新框架”,并将其边缘与其父视图的边界进行比较:
@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
这也使用了触摸的偏移量,而不是使视图在触摸上居中(因此当您开始拖动时它不会“跳到您的手指上”)。
编辑澄清: 在这张图片中,蓝色视图 class 是 DraggableView
...它不能被拖到它的 superView 之外(红色视图)。
编辑
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),
])
}
}
我有一个 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 中也没有做任何相关的事情。
您需要检查正在移动的视图的“新框架”,并将其边缘与其父视图的边界进行比较:
@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
这也使用了触摸的偏移量,而不是使视图在触摸上居中(因此当您开始拖动时它不会“跳到您的手指上”)。
编辑澄清: 在这张图片中,蓝色视图 class 是 DraggableView
...它不能被拖到它的 superView 之外(红色视图)。
编辑
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),
])
}
}