Touchesbegan, Touchesended, Touchesmoved for Moving Uiview

touchesBegan, touchesEnded, touchesMoved for moving UIView

There's something a bit strange in your code.

You ask for the location in self, some UIView which presumably contains the UILabel you want to check. This begs the question as to why you do not add the touchesXXX to some UILabel subclass of yours.

This cancels out as you're using the label.frame which is defined in terms of its superview.bounds (your parent UIView you asked the touch location with respect to), but this doesn't make for the most straightforward way to follow what's going on.

Animated UIView object jumps when touchesBegan is invoked

You need to remove/reset the animation after you change the location of the label. The animation does not know you updated the values and is trying to stay in the same range of byValue from the beginning. Here is a working example of updating the animation.

import UIKit

class ViewController: UIViewController {

var optOneLbl = UILabel()

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

optOneLbl = UILabel(frame: CGRect(x: 20, y: 50, width: self.view.bounds.width - 40, height: 40))
optOneLbl.textAlignment = .center
optOneLbl.text = "I Will Be Moving Up and Down"
optOneLbl.textColor = .white
optOneLbl.backgroundColor = .blue
self.view.addSubview(optOneLbl)

//starts it in the beginnning with a y
fireAnimation(toY: self.view.bounds.midY*1.1)

}

func fireAnimation(toY:CGFloat) {
UIView.animate(withDuration: 12.0, delay: 0.0, options: [ .allowUserInteraction, .curveLinear, .autoreverse, .repeat ], animations: {
self.optOneLbl.center = CGPoint(x: self.optOneLbl.center.x, y:toY)
})
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
let touchLocation = touch!.location(in: self.view)

if self.optOneLbl.layer.presentation()!.hitTest(touchLocation) != nil {
//re
optOneLbl.layer.removeAllAnimations()
optOneLbl.center = touchLocation
}
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
let touchLocation = touch!.location(in: self.view)
var sender: UILabel

if self.optOneLbl.layer.presentation()!.hitTest(touchLocation) != nil {
self.optOneLbl.center = touchLocation
sender = self.optOneLbl
}
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
//restart animation after finished and change the Y if you want.
// you could change duration or whatever
fireAnimation(toY: self.view.bounds.height - optOneLbl.bounds.height)
}

}

touchesMoved touches.first!.view remains the same, if I move a finger out of view

Answer based on Rob's comment above

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
if let touch = touches.first {
if ( !self.grayUIView.frame.contains(touch.location(in: self.grayUIView)) ){
return

}else {
//still in current view - process with your logic

}
}
}

Move UIView with relation to touch

Modify the touchesBegan and touchesMoved methods to be like the following.

float oldX, oldY;
BOOL dragging;

The touchesBegan:withEvent: method.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];

if (CGRectContainsPoint(window.frame, touchLocation)) {

dragging = YES;
oldX = touchLocation.x;
oldY = touchLocation.y;
}
}

The touchesMoved:withEvent: method.

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];

if (dragging) {

CGRect frame = window.frame;
frame.origin.x = window.frame.origin.x + touchLocation.x - oldX;
frame.origin.y = window.frame.origin.y + touchLocation.y - oldY;
window.frame = frame;
}
}

The touchesEnded:withEvent: method.

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

dragging = NO;
}

Using touchesbegan, touchesmoved and touchesended is not animating the dragging smoothly

Finally I figured out where my problem was:

I didn't track the movement of the object in the superview, but of the touchpoint on the object.

This is the adjusted code which works fine with smooth dragging:

- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
UITouch *touch = [touches anyObject];
if (touch.view == _topCard) {
translation = [touch locationInView:_topCard.superview];
}

}

- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent *)event {
UITouch* touch = [touches anyObject];

if (touch.view == _topCard) {
CGPoint newTranslation = [touch locationInView:_topCard.superview];
_topCard.frame = CGRectOffset(_topCard.frame, newTranslation.x - translation.x, newTranslation.y - translation.y);
translation = newTranslation;

}
}

touchesBegan and touchesMoved not getting triggered on UIView

I don't know why you are setting your default view to UILabel(), but your default isUserInteractionEnabled of your view is false. Set it to true

override func loadView() {
view = UILabel()
view.isUserInteractionEnabled = true
}

How to handle touches by an UIView on top of a UIScrollView and the UIScrollView both at the same time

Following this answer worked for me, though with some slight changes. Do note that for this solution, the UIScrollView is on top of the UIView. Firstly, you need to create a subclass of UIScrollView and override the touch methods.

protocol CustomScrollViewDelegate {
func scrollViewTouchBegan(_ touches: Set<UITouch>, with event: UIEvent?)
func scrollViewTouchMoved(_ touches: Set<UITouch>, with event: UIEvent?)
func scrollViewTouchEnded(_ touches: Set<UITouch>, with event: UIEvent?)
}

class CustomScrollView: UIScrollView {

var customDelegate: CustomScrollViewDelegate?

override func awakeFromNib() {
super.awakeFromNib()

for gesture in self.gestureRecognizers ?? [] {
gesture.cancelsTouchesInView = false
gesture.delaysTouchesBegan = false
gesture.delaysTouchesEnded = false
}
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
customDelegate?.scrollViewTouchBegan(touches, with: event)
super.touchesBegan(touches, with: event)
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
customDelegate?.scrollViewTouchMoved(touches, with: event)
super.touchesMoved(touches, with: event)
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
customDelegate?.scrollViewTouchEnded(touches, with: event)
super.touchesEnded(touches, with: event)
}
}

Take note of the code in awakeFromNib(). UIScrollView has its own set of gestures. So for each gesture, delaysTouchesBegan and delaysTouchesEnded needs to be false to prevent delays for the touch events.

Finally, just assign the delegate to your ViewController and implement the methods like so.

class ViewController: UIViewController {

@IBOutlet weak var scrollView: CustomScrollView!
@IBOutlet weak var touchView: UIView!

override func viewDidLoad() {
super.viewDidLoad()
scrollView.customDelegate = self
}
}

extension ViewController: CustomScrollViewDelegate {
func scrollViewTouchBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// Check if touch location is within the bounds of the UIView
if let touch = touches.first {
let position = touch.location(in: view)
if touchView.bounds.contains(position) {
print("Began")
}
}
}

func scrollViewTouchMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
// Check if touch location is within the bounds of the UIView
if let touch = touches.first {
let position = touch.location(in: view)
if touchView.bounds.contains(position) {
print("Moved")
}
}
}

func scrollViewTouchEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// Check if touch location is within the bounds of the UIView
if let touch = touches.first {
let position = touch.location(in: view)
if touchView.bounds.contains(position) {
print("Ended")
}
}
}
}

Listen for a UIView's touchesBegan/touchesEnded within an NSObject

For custom touch handling logic you should subclass UIGestureRecognizer. You can then add it to any view.

Check out the documentation for gesture recognizers and the guide.



Related Topics



Leave a reply



Submit