UIImageView transform loses swipe gesture - swift

I have an image that I want to rotate every time the user swipes on it. It works the first time, and first time only! How is it that the view is losing the swipe gesture recognizer?
myCircle = UIImageView( ... )
myCircle.isUserInteractionEnabled = true
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(swiping(sender:)))
swipeLeft.direction = .left
myCircle.addGestureRecognizer(swipeLeft)
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(swiping(sender:)))
swipeRight.direction = .right
myCircle.addGestureRecognizer(swipeRight)
}
#objc func swiping(sender: UISwipeGestureRecognizer) {
// this function only called the first time!
if sender.direction == UISwipeGestureRecognizer.Direction.left {
myCircleRotation -= CGFloat(Double.pi/2)
} else if sender.direction == UISwipeGestureRecognizer.Direction.right {
myCircleRotation += CGFloat(Double.pi/2)
}
// if I comment out this next line, function is called (correctly) every swipe!
myCircle.transform = CGAffineTransform(rotationAngle: myCircleRotation)
}

You can add a UIView as a container view to your hierarchy, and then add the UIGestureRecognizers to the container view instead of to the UIImageView. This would allow your image to be rotated without impact to the gestures.
import UIKit
class ImageViewController: UIViewController {
#IBOutlet weak var myCircleView: UIImageView!
#IBOutlet weak var containerView: UIView!
var myCircleRotation:CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
setupImage()
}
private func setupImage() {
let image = UIImage(named: "your-image")
myCircleView.image = image
myCircleView.isUserInteractionEnabled = true
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(swiping(sender:)))
swipeLeft.direction = .left
containerView.addGestureRecognizer(swipeLeft)
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(swiping(sender:)))
swipeRight.direction = .right
containerView.addGestureRecognizer(swipeRight)
}
#objc func swiping(sender: UISwipeGestureRecognizer) {
// this function only called the first time!
if sender.direction == UISwipeGestureRecognizer.Direction.left {
myCircleRotation -= CGFloat(Double.pi/2)
} else if sender.direction == UISwipeGestureRecognizer.Direction.right {
myCircleRotation += CGFloat(Double.pi/2)
}
UIView.animate(withDuration: 0.5) {
self.myCircleView.transform = CGAffineTransform(rotationAngle: self.myCircleRotation)
}
}
}

Related

UITapGestureRecognizer not attaching action

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")
}
}
}

can not call selector and gesture delegate iOS 13.2

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)
}
}
}

how to realize iOS swift playgrounds virtual keyboard feature .

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 !")
}
}
//=============

UILongPressGesture gets called twice

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)
}

UIVisualEffectView creating unwanted shadow while presenting new view

In my custom presentation transition I've created a new view controller which will pre presented on top of the current active view controller (see screenshot). Somehow there's a shadow behind the blue view controller and I have no idea where it's coming from. Is there a way to stop getting that shadow?
The project is completely empty and has only 2 empty view controllers.
This is the code I'm using:
class ViewController: UIViewController {
let transitionDelegate = TransitionManager()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellowColor()
let button = UIButton(type: .System)
button.frame = CGRectMake(10, 10, 50, 50)
button.addTarget(self, action: "test:", forControlEvents: .TouchUpInside)
button.backgroundColor = UIColor.redColor()
view.addSubview(button)
}
func test(sender: UIButton) {
let destination = UIViewController()
destination.view.backgroundColor = .blueColor()
destination.transitioningDelegate = transitionDelegate
destination.modalPresentationStyle = .Custom
presentViewController(destination, animated: true, completion: nil)
}
}
The code for presenting the view:
class PresentingTransition: NSObject, UIViewControllerAnimatedTransitioning {
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return 0.3
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
let presented = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
let container = transitionContext.containerView()!
let durations = transitionDuration(transitionContext)
presented.view.alpha = 0
container.addSubview(presented.view)
UIView.animateWithDuration(durations, animations: { presented.view.alpha = 1 }) { transitionContext.completeTransition($0) }
}
}
The code for handling the presenting view controller:
class PresentationController: UIPresentationController {
var background: UIView!
override init(presentedViewController: UIViewController, presentingViewController: UIViewController) {
super.init(presentedViewController: presentedViewController, presentingViewController: presentingViewController)
prepareBackground()
}
func prepareBackground() {
self.background = UIView(frame: presentingViewController.view.bounds)
let blur = UIVisualEffectView(effect: UIBlurEffect(style: .Light))
blur.frame = background.bounds
blur.autoresizingMask = [.FlexibleHeight, .FlexibleWidth]
background.addSubview(blur)
let tapRecognizer = UITapGestureRecognizer(target: self, action: "backgroundTapped:")
background.addGestureRecognizer(tapRecognizer)
}
func backgroundTapped(tapRecognizer: UITapGestureRecognizer) {
presentingViewController.dismissViewControllerAnimated(true, completion: nil)
}
override func presentationTransitionWillBegin() {
let container = containerView!
background.frame = container.bounds
background.alpha = 0.0
container.insertSubview(background, atIndex: 0)
presentedViewController.transitionCoordinator()?.animateAlongsideTransition({ _ in self.background.alpha = 1.0 }, completion: nil)
}
override func dismissalTransitionWillBegin() {
presentedViewController.transitionCoordinator()?.animateAlongsideTransition({ _ in self.background.alpha = 0.0 }, completion: nil)
}
override func frameOfPresentedViewInContainerView() -> CGRect {
return containerView!.bounds.insetBy(dx: 100, dy: 100)
}
override func containerViewWillLayoutSubviews() {
background.frame = containerView!.bounds
presentedView()!.frame = frameOfPresentedViewInContainerView()
}
}