Swift playground on iOS is good IDE for new programmers , and apple provide a virtual keyboard for programming , we can swipe the single button to input multi characters ,including “, ; : / “ …. , I want to realize the feature in my programme . How to implement this functionality? Using UIGestureRecognizerDelegate ? pan ? how to realized the animation that appeared in button when swipping ?
here is my code:
import UIKit
class myViewController: UIViewController, UIGestureRecognizerDelegate {
#IBOutlet weak var mybutton1: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(buttonPressed(_:)))
let moveRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(moved(_:)))
let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(pan(_:)))
let longgestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longLabelPressed(_:)))
longgestureRecognizer.minimumPressDuration = 1 //.001
mybutton1.isUserInteractionEnabled = true;
mybutton1.addGestureRecognizer(gestureRecognizer)
mybutton1.addGestureRecognizer(moveRecognizer)
mybutton1.addGestureRecognizer(panRecognizer)
mybutton1.addGestureRecognizer(longgestureRecognizer)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func moved(_ recognizer:UILongPressGestureRecognizer){
print("moved !!!!")
}
func pan(_ recognizer:UILongPressGestureRecognizer){
print("pan !!!!")
}
func longLabelPressed(_ recognizer:UILongPressGestureRecognizer){
// if let label = recognizer.view as? UIButton {
if recognizer.state == .began {
//label.textColor = UIColor.red
print("longlabelPressed begin !")
}
if recognizer.state == .ended {
//label.textColor = UIColor.black
print("longlabelPressed end !")
}
}
func buttonPressed(_ recognizer:UITapGestureRecognizer) {
print("labelPressed !")
}
}
//=============
Related
I created a separate class for View.
I left all the functions in the Controller.
But when I add a click on the picture, it doesn't work for some reason.
import UIKit
class APOTDView: UIView {
var imageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(APOTDViewController.imageTapped(_:)))
imageView.addGestureRecognizer(tap)
return imageView
}()
}
import UIKit
class APOTDViewController: UIViewController {
let av = APOTDView()
override func viewDidLoad() {
super.viewDidLoad()
// ... add subview and constraint
}
#objc func imageTapped(_ sender: UITapGestureRecognizer) {
print("good job")
}
}
What's the matter? Please help me figure it out
Your selector in the UITapGestureRecognizer is wrong. You can not call the APOTDViewController directly.
APOTDViewController.imageTapped would be a static function, which is not available.
You can use a delegate instead.
Delegate Protocol and View.
protocol APOTDViewDelegate: AnyObject {
func viewDidTapImage()
}
class APOTDView: UIView {
weak var delegate: APOTDViewDelegate?
var imageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
imageView.addGestureRecognizer(tap)
return imageView
}()
#objc func imageTapped() {
delegate?.viewDidTapImage()
}
}
ViewController:
class APOTDViewController: UIViewController, APOTDViewDelegate {
let av = APOTDView()
override func viewDidLoad() {
super.viewDidLoad()
av.delegate = self
// ... add subview and constraint
}
#objc func viewDidTapImage() {
print("good job")
}
}
This will not work, because you are calling the UIViewController method directly without any class reference or object. The solution is to use protocol or clouser to get action from view to class.
class
class APOTDView: UIView {
#objc var imageViewAction: ((UITapGestureRecognizer) -> Void)? = nil
lazy var imageView: UIImageView = {
let imageView = UIImageView()
imageView.backgroundColor = .blue
imageView.translatesAutoresizingMaskIntoConstraints = true
imageView.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector((imageTapped(_:))))
imageView.addGestureRecognizer(tap)
return imageView
}()
#objc private func imageTapped(_ sender: UITapGestureRecognizer) {
self.imageViewAction?(sender)
}
}
ViewController
class APOTDViewController: UIViewController {
let av = APOTDView()
override func viewDidLoad() {
super.viewDidLoad()
av.imageViewAction = { sender in
print("good job")
}
}
}
my code works in iOS 12 last version but after iOS 13 this code can't call the selector
I used UIGestureRecognizerDelegate for iOS 13
here is my code
let panGest = UIPanGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
panGest.delegate = self
txtVw.addGestureRecognizer(panGest)
here is my let txtVw = subVws as! UITextView , txtVw = subVws as! UITextView
I used this code:
let panGest = UIPanGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
self.view.addGestureRecognizer(panGest)
its work but I have one subview and for subview isn't work & call !!
isn't call self.handleTap or gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:)
Is this what you want?
class ViewController: UIViewController, UIGestureRecognizerDelegate {
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
gestureRecognizer.delegate = self
textView.addGestureRecognizer(gestureRecognizer)
textView.isUserInteractionEnabled = true
textView.isMultipleTouchEnabled = true
}
#objc func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
let translation = gestureRecognizer.translation(in: self.view)
//make sure the view is not nil
gestureRecognizer.view!.center = CGPoint(x: gestureRecognizer.view!.center.x + translation.x, y: gestureRecognizer.view!.center.y + translation.y)
gestureRecognizer.setTranslation(CGPoint.zero, in: self.view)
}
}
}
I had to create a new thread bcoz it's driving me crazy and all the other answers online are exactly the same. I have done this countless of times but I cannot see what I am missing for the life of me. I am using a "test" view controller just to get the tap gesture working but it isn't working at all... I am fairly certain that I am setting this up correctly, as this is how I've always implemented it in the past: (yes, I have checked the box for isUserInteractionEnabled). I am even implementing this on a different viewcontroller this exact way and it is working...
class TestViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.addGestureRecognizer(tap)
}
let tap = UITapGestureRecognizer(target: self, action: #selector(wasTapped))
#objc func wasTapped() {
print("tapped")
}
}
I have also tried adding the parameters to wasTapped:
#objc func wasTapped(gestureRecognizer: UITapGestureRecognizer) {
print("tapped")
}
You are saying:
override func viewDidLoad() {
super.viewDidLoad()
view.addGestureRecognizer(tap)
}
let tap = UITapGestureRecognizer(target: self, action: #selector(wasTapped))
The problem is the last line:
let tap = UITapGestureRecognizer(target: self, action: #selector(wasTapped))
You cannot just say let tap like that in the middle of nowhere. You are implicitly making an instance property. But you cannot initialize an instance property with a target of self, because self does not exist at the time an instance property is initialized. (I regard the fact that that code even compiles as a bug, and have reported it as such.)
Move that line to the start of viewDidLoad, like this:
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(wasTapped))
view.addGestureRecognizer(tap)
}
Try something like this
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(wasTapped(sender:)))
tap.numberOfTapsRequired = 1 // Default value
view.isUserInteractionEnabled = true
view.addGestureRecognizer(tap)
}
#objc func wasTapped(sender: UITapGestureRecognizer) {
print("tapped")
}
You have to enable interaction if you want to use gesture recognizers for standard UIView's
Add view.isUserInteractionEnabled = true in your viewDidLoad.
var tapGesture = UITapGestureRecognizer()
take a view and set IBOutlet like:
#IBOutlet weak var viewTap: UIView!
Write pretty code on viewDidLoad() like:
tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.myviewTapped(_:)))
tapGesture.numberOfTapsRequired = 1
tapGesture.numberOfTouchesRequired = 1
viewTap.addGestureRecognizer(tapGesture)
viewTap.isUserInteractionEnabled = true
this method is calling when tap gesture recognized:
#objc func myviewTapped(_ sender: UITapGestureRecognizer) {
if self.viewTap.backgroundColor == UIColor.yellow {
self.viewTap.backgroundColor = UIColor.green
}else{
self.viewTap.backgroundColor = UIColor.yellow
}
}
I would like to make a UILabel clickable.
I have tried this, but it doesn't work:
class DetailViewController: UIViewController {
#IBOutlet weak var tripDetails: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
...
let tap = UITapGestureRecognizer(target: self, action: Selector("tapFunction:"))
tripDetails.addGestureRecognizer(tap)
}
func tapFunction(sender:UITapGestureRecognizer) {
print("tap working")
}
}
Have you tried to set isUserInteractionEnabled to true on the tripDetails label? This should work.
Swift 3 Update
Replace
Selector("tapFunction:")
with
#selector(DetailViewController.tapFunction)
Example:
class DetailViewController: UIViewController {
#IBOutlet weak var tripDetails: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
...
let tap = UITapGestureRecognizer(target: self, action: #selector(DetailViewController.tapFunction))
tripDetails.isUserInteractionEnabled = true
tripDetails.addGestureRecognizer(tap)
}
#objc
func tapFunction(sender:UITapGestureRecognizer) {
print("tap working")
}
}
SWIFT 4 Update
#IBOutlet weak var tripDetails: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(GameViewController.tapFunction))
tripDetails.isUserInteractionEnabled = true
tripDetails.addGestureRecognizer(tap)
}
#objc func tapFunction(sender:UITapGestureRecognizer) {
print("tap working")
}
Swift 5
Similar to #liorco, but need to replace #objc with #IBAction.
class DetailViewController: UIViewController {
#IBOutlet weak var tripDetails: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
...
let tap = UITapGestureRecognizer(target: self, action: #selector(DetailViewController.tapFunction))
tripDetails.isUserInteractionEnabled = true
tripDetails.addGestureRecognizer(tap)
}
#IBAction func tapFunction(sender: UITapGestureRecognizer) {
print("tap working")
}
}
This is working on Xcode 10.2.
Swift 3 Update
yourLabel.isUserInteractionEnabled = true
Good and convenient solution:
In your ViewController:
#IBOutlet weak var label: LabelButton!
override func viewDidLoad() {
super.viewDidLoad()
self.label.onClick = {
// TODO
}
}
You can place this in your ViewController or in another .swift file(e.g. CustomView.swift):
#IBDesignable class LabelButton: UILabel {
var onClick: () -> Void = {}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
onClick()
}
}
In Storyboard select Label and on right pane in "Identity Inspector" in field class select LabelButton.
Don't forget to enable in Label Attribute Inspector "User Interaction Enabled"
You need to enable the user interaction of that label.....
For e.g
yourLabel.userInteractionEnabled = true
For swift 3.0 You can also change gesture long press time duration
label.isUserInteractionEnabled = true
let longPress:UILongPressGestureRecognizer = UILongPressGestureRecognizer.init(target: self, action: #selector(userDragged(gesture:)))
longPress.minimumPressDuration = 0.2
label.addGestureRecognizer(longPress)
Pretty easy to overlook like I did, but don't forget to use UITapGestureRecognizer rather than UIGestureRecognizer.
Thanks researcher
Here's my solution for programmatic user interface using UIKit.
I've tried it only on Swift 5. And It worked.
Fun fact is you don't have to set isUserInteractionEnabled = true explicitly.
import UIKit
open class LabelButon: UILabel {
var onClick: () -> Void = {}
public override init(frame: CGRect) {
super.init(frame: frame)
isUserInteractionEnabled = true
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
}
public convenience init() {
self.init(frame: .zero)
}
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
onClick()
}
}
Uses:
override func viewDidLoad() {
super.viewDidLoad()
let label = LabelButton()
label.text = "Label"
label.onClick = {
// TODO
}
}
Don't forget to set constraints. Otherwise it won't appear on view.
On top of all of the other answers, this depends on where the label is, it might be behind some subviews. You might think you tap on the label but maybe click the top view. To solve this you can bring the label view to the front with the following line.
self.view.bringSubviewToFront(lblView)
As described in the above solution
you should enable the user interaction first and add the tap gesture
this code has been tested using
Swift4 - Xcode 9.2
yourlabel.isUserInteractionEnabled = true
yourlabel.addGestureRecognizer(UITapGestureRecognizer(){
//TODO
})
So when ever I long press on a button, it recognizes the long press, but "test" gets called twice. How do I prevent that from happening?
#IBOutlet weak var button2: UIButton!
func longPressMe(){
print("test")
}
func longPressGes(){
let longpress = UILongPressGestureRecognizer(target: self, action: "longPressMe")
longpress.minimumPressDuration = 1
button2.addGestureRecognizer(longpress)
}
override func viewDidLoad() {
super.viewDidLoad()
longPressGes()
}
You have to check the state of the gesture recognizer. Change longPressMe() to something like this:
func longPressMe(recognizer: UILongPressGestureRecognizer) {
guard recognizer.state == .Began else { return }
// do stuff here
}
Have a try, here is how to use #selector:
func longPressMe(recognizer: UILongPressGestureRecognizer) {
// do stuff here
}
func longPressGes(){
let longpress = UILongPressGestureRecognizer(target: self, action: #selector(yourViewController.longPressMe(_:)))
longpress.minimumPressDuration = 1
button2.addGestureRecognizer(longpress)
}