Slide finger across 3 buttons - Xcode & Swift - ios

I have 3 buttons in my UI that ultimately will perform similar to keys on a piano. Either of the 3 buttons may get tapped to perform that particular buttons actions, but the user can 'slide' their finger off onto the next button to perform button 2's action.
I did some searching and it looks like a touchesBegan method detecting the location of the tap is best. My attempt is below:
#IBOutlet weak var button1: UIButton!
#IBOutlet weak var button2: UIButton!
#IBOutlet weak var button3: UIButton!
(I don't have any action events tied to the 3 buttons, because I thought touchesBegan will cover that.)
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
var touch: UITouch = event!.allTouches()!.first!
var location: CGPoint = touch.locationInView(touch.view!)
if CGRectContainsPoint(button1.frame, location){
print("button 1")
}
else if CGRectContainsPoint(button2.frame, location) {
print("button 2")
}
else if CGRectContainsPoint(button3.frame, location) {
print("button 3")
}
}
Nothing prints to the console when I test this. I tested both tapping and swiping across buttons. Should I be using UIViews instead of UIButtons? Should I be using actions on the buttons? This is for Swift 2.0. Thank you.
EDIT
I have a working prototype much closer to how I envisioned this functioning. This thread here: Using iOS pan gesture to highlight buttons in grid pointed me in the direction of using a pangesture on the buttons superview.
var touchPoint = CGPoint()
var myGesture = UIPanGestureRecognizer()
viewDidLoad:
myGesture = UIPanGestureRecognizer(target: self, action: Selector("panDetected:"))
myGesture.maximumNumberOfTouches = 1
view.addGestureRecognizer(myGesture)
.
func panDetected(sender : UIPanGestureRecognizer) {
touchPoint = sender.locationInView(self.view)
if CGRectContainsPoint(button1.frame, touchPoint) {
button1Func()
}
else if CGRectContainsPoint(button2.frame, touchPoint) {
button2Func()
}
else if CGRectContainsPoint(button3.frame, touchPoint) {
button3Func()
}
The above DOES work, however, button1Func / button2Func / button3Func all contain an animation block. When the finger is dragged within the buttons, it fires the method every time a movement is detected. I just need for this to happen once. I tried adding this to a state == .Began statement, but that prevents any functionality once the finger leaves the first tapped button.
Is there any way I can fire those methods (button1Func / button2Func / button3Func) just ONCE inside the pan gesture once the finger is inside the bounds of each of the 3 buttons? I will be happy to clarify this if it's confusing. THANKS.

There are a whole bunch of control events you can tie to IBActions. Take a look at the UIControlEvents enum. You probably want to add actions for UIControlEventTouchDragInside, UIControlEventTouchDragEnter and a few others.

Related

How to clearly differentiate gesture?

First of all, I'm pretty new to swift.
I'm doing an app where I have to recognize a lot of gesture (swipe up, down, left, right, single tap, double tap, single tap with 2 fingers, double tap with 2 fingers, rotations etc etc).
I'm able to recognize each gesture, but my problem occurs when I'm doing a double tap.
The app recognizes a single tap before the double tap (looks logical...), but as each gesture is dedicated to one action it's a problem: it sends the action linked to the single tap before the action linked to the double tap...
Do you have an idea how I can get rid of this ?
I clearly have no idea here :/
Thank you.
Have a nice day.
// SINGLE TAP
#IBOutlet var oneFingerTap: UITapGestureRecognizer!
#IBOutlet var twoFingersTap: UITapGestureRecognizer!
// DOUBLE TAP
#IBOutlet var doubleTapOneFinger: UITapGestureRecognizer!
#IBOutlet var doubleTapTwoFinger: UITapGestureRecognizer!
// SINGLE TAP
#IBAction func oneFingerTap(_ sender: UITapGestureRecognizer) {
statusLabel.text = "single Tap"
}
#IBAction func twoFingersTap(_ sender: UITapGestureRecognizer) {
statusLabel.text = "Two fingers Tap"
}
// DOUBLE TAP
#IBAction func doubleTapOneFinger(_ sender: UITapGestureRecognizer) {
statusLabel.text = "Double Tap 1 finger"
}
#IBAction func doubleTapTwoFingers(_ sender: UITapGestureRecognizer) {
statusLabel.text = "Double Tap 2 fingers"
}
EDIT :
I tried what's on [UITapGestureRecognizer - single tap and double tap
]1 but nothing's working.
Here is what I tried :
doubleTapOneFinger.require(toFail: oneFingerTap);
Doing this throw me an error "fatal error: unexpectedly found nil while unwrapping an Optional value", so I changed how I was declaring my variables to avoid using optional variables like this :
let oneFingerTap = UITapGestureRecognizer(target: self, action: #selector(self.oneFingerTap))
oneFingerTap.numberOfTapsRequired = 1
oneFingerTap.numberOfTouchesRequired = 1
self.view.addGestureRecognizer(oneFingerTap)
let twoFingerTap = UITapGestureRecognizer(target: self, action: #selector(self.twoFingersTap))
twoFingerTap.numberOfTapsRequired = 1;
twoFingerTap.numberOfTouchesRequired = 2;
self.view.addGestureRecognizer(twoFingerTap)
No more error, but nothing's happening... Do you have any idea what I can do ?

How to triggered different function when user drag into element area in swift for ios

I'm sure that answer is near.
I'm new in swift and want to create simple app for iOS.
I have created view and add different elements on this view. Also added pan recognized for this view. I want to do different actions when user drag his finger over different element. For example when finger entered in button area to write in console, when dragged into label area - change labels's text. Also With this type realized swipe method of input text from keyboard. It must do in one touch that's why I use pan recognizer. But when I run my app, I can get finger position, but don't know how triggered function when need.
Hope for yours help
Thanx
class ViewController: UIViewController {
#IBOutlet var mainView: UIView!
#IBOutlet var gest: UIPanGestureRecognizer!
#IBOutlet var tap: UITapGestureRecognizer!
#IBOutlet weak var btn: UIButton!
#IBOutlet weak var btn2: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.view.addGestureRecognizer(self.gest)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func drAG(_ sender: UIPanGestureRecognizer) {
print(sender.location(in: self.view))
}
Looks like you have most everything you need. Now, just use the hitTest() method of any view's layer:
func moveEye(_ recognizer:UIPanGestureRecognizer) {
let p = recognizer.location(in: self)
if btn.layer.hitTest(p) != nil {
// finger panned over btn
}
}
I use hitTest() alot in a few apps. But beware - I usually see it associated with the tap gesture. (I use the pan gesture to move a subview.) I do not know how things will behave if you have two overlapping subviews that the user pans over.

Remove custom UIView(s) dynamically on user selection/highlighed in ios swift

I am new to swift, please kindly advise the best way to achieve this.
Let say if there are 3 to 4 (custom) UIView(s) added under a parent view
when user select/highlighted a particular one (e.g. the 2nd UIView), and this will get removed and the whole layout will re-render immediately. Any idea?
Connect all views to one IBOutletCollection, add gesture recognizer for tap and in recognizer callback just get the touch point and check if the point is contained in one of the views from the outlet collection.
#IBOutlet var views: [UIView]!
override func viewDidLoad() {
super.viewDidLoad()
let tapGesture = UITapGestureRecognizer(target: self, action: Selector("viewTapped:"))
self.view.addGestureRecognizer(tapGesture)
}
func viewTapped(tapGesture: UITapGestureRecognizer) {
let locationInView = tapGesture.locationInView(view)
for v in views {
if CGRectContainsPoint(v.frame, locationInView) {
v.removeFromSuperview()
}
}
}
Make sure you have your autolayout setup for the state in which each of the view is not there.

xcode swift: how to drag a button?

I am working with xcode to create a view that allows users to drag buttons. with the code below, I can move the button to the touch and drag from there, but I cant click the button and drag.
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
for obj in touches {
let touch = obj as! UITouch
let location = touch.locationInView(self.view)
word1Button.center = location
}
}
Buttons respond to touch events, so when the user touches down within the bounds of a button the view underneath will not receive those touch events. You can get around this by using a gesture recogniser on your button instead of relying on the lower level touch delivery methods. A long press gesture recognizer would probably work best:
// Where you create your button:
let longPress = UILongPressGestureRecognizer(target: self, action: "handleLongPress:")
word1Button.addGestureRecognizer(longPress)
//...
func handleLongPress(longPress: UILongPressGestureRecognizer) {
switch longPress.state {
case .Changed:
let point = longPress.locationInView(view)
button.center = point
default:
break
}
}
Note that by default, the UILongPressGestureRecognizer needs the user to hold down for 0.5 seconds before the gesture starts recognizing (and therefore starts dragging). You can change this with the minimumPressDuration property of UILongPressGestureRecognizer. Be careful not to make it too short though - as soon as the gesture recognizes it will cancel other touches to the button, preventing the button action from being fired when the touch is lifted.

Tap gesture with finger movement

As far as i observed, Tap gestures cancels event when finger moves. Here a screenShot from Event Handling Guide:
I have already done some tests with the following code. Nope, it cancels...
#IBAction func dosomething(sender: UITapGestureRecognizer) {
//called by gesture recognizer
}
#IBOutlet var red: UIView!
#IBOutlet var green: UIView!
#IBOutlet var yellow: UIView!
#IBOutlet var white: UIView!
//setting delegate when outlet get set.
#IBOutlet var tapGesture: UITapGestureRecognizer! { didSet { outlet.delegate = self
}}
//delegate func shouldReceiveTouch
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if touch.view == red {
println("ez")
return true
}else if touch.view == green{
println("bp")
return false
}else { view.backgroundColor = UIColor.clearColor()
return true}
}
So if I'm right, when touchesMoved: called, tapGestureRecognizer must have failed, but according to figure it does not. What I'm missing here?
When a user taps or drags their finger across a screen in an iPhone application, two things happen:
The view receives a UITouch object(s)
A UIGestureRecognizer may grab the UITouch object(s) and try to infer what the user is doing (pan in/out, scroll up/down, swipe between pages in a browser, etc.)
A UIGestureRecognizer will not know what the user is doing unless the user has finished tapping the screen. The iPhone will know when the user is done when the UITouch object(s) are no longer apart of the current view.
The thing is, UIGestureRecognizer doesn't "fail", but rather it has no value or meaning until the user's touches are "cancelled" or not apart of the view. This can be seen by the fourth column to the right of Figure 1-6. Another problem is that a tap is not what you think it is. It's just a single touch. The touch ends as soon as it begins. If you're trying to swipe or drag something across a screen, you need a different UIGestureRecognizer object such as UIPanGestureRecognizer, UILongPressGestureRecognizer, UISwipeGestureRecognizer, etc.
If you want to see this in action, try doing the following in an iOS Single View Application:
Make a ViewController.swift file.
Class your ViewController as a subclass of UIViewController.
Add a UIGestureRecognizerDelegate protocol.
Add some UITapGestureRecognizer objects and UITouch objects and link them to a single view in your storyboard.
Set the UIGestureRecognizer object's delegate to the UIViewController or self.
Check when a touch begins and ends by adding some println statements in the touchesBegan:withEvent:, touchesMoved:withEvent:, touchesEnded:withEvent, and touchesCancelled:withEvent methods.
You can learn more about how these methods work in the iOS Developer Library directly.

Resources