I'm trying to hide a view after it was tapped. In order to do so, I'm using touchesBegan to detect if the view was tapped and if it was, it should perform an action such as hiding the view and the view on top of it. These two views are defined:
#IBOutlet weak var theDarkView: UIView!
#IBOutlet weak var theFinalView: UIView!
And here is the code that I came up with.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//-- hides the view whenever its touched
if let touch = touches.first {
if touch.view == self.theDarkView {
if theDarkView.isHidden == false || theFinalView.isHidden == false {
theDarkView.isHidden = true
theFinalView.isHidden = true
}
} else {
return
}
}
}
If you could help me out and show me the correct way to go about this and also show me where I messed up with my method, that would be greatly appreciated!
No problem with your code this accomplish the same job also
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
theDarkView.isHidden = touches.first?.view == self.theDarkView
theFinalView.isHidden = theDarkView.isHidden
}
Your code works. When you tap on the theDarkView all the views are setted to hidden.
If in your project it doesn't works, you must connect the IBOutlet on the storyboard.
EDIT:
If the views are embedded in a scrollView it doesn't works because the UIScrollView intercepts these touches events.
The solutions are subclass the UIScrollView or use the UITapGestureRecognizer instead of touchesBegan.
A possible code solution is to add in the viewDidLoad this:
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.tapRecognized))
tapGesture.numberOfTapsRequired = 1
tapGesture.isEnabled = true
tapGesture.cancelsTouchesInView = false
theDarkView.addGestureRecognizer(tapGesture)
to add the tapGesture to your view and then add the method:
#objc func tapRecognized() {
if red.isHidden == false || blue.isHidden == false {
red.isHidden = true
blue.isHidden = true
}
}
Related
I have a view controller where I can add several subviews with a LongPressGesture. For each subview I provide a TapGesture that should open a popover for this view (see picture below).
My problem is, that I can only open the popover for the last subview I added. So why can't I interact with the other subviews anymore?
This is my first App in Swift, so it would be nice if someone could help me.
Some code for you:
This is the LongPressGesture on the root view controller that creates a new subview.
#IBAction func onLongPress(_ gesture : UILongPressGestureRecognizer) {
let position: CGPoint = gesture.location(in: view)
if(gesture.state == .began) {
let subview = MySubview(position: position)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
subview.addGestureRecognizer(tapGesture)
view.addSubview(subview)
}
else if (gesture.state == .ended) {
let subview = self.view.subviews.last
self.openContextMenu(for: subview)
}
}
ViewController with subviews:-
When reacting to an event (long press in your case) only the first responder will handle the event. When adding subviews to a view, all the subviews are added one in front of another. So the last added subview will handle the event - if it is listening for the event. If you need a specific subview to handle the event, you can bring it to front as
parentView.bringSubviewToFront(view: subView)
Alternatively, you can also disable other subviews as
subView.isUserInteractionEnabled = false
Ok, I found a solution for my problem. The good thing is, that it only detects touches in the frames of the subviews.
In my root view controller I added:
var isPanGesture = false
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
isPanGesture = true
if let subview = touches.first!.view as? MySubview {
let position = touches.first!.location(in: self.view)
link.center = position
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if let subview = touches.first!.view as? MySubview {
if(!isPanGesture) {
self.openContextMenu(for: subview)
}
isPanGesture = false
}
}
I have a couple textViews in one cell in a table view controller and I am trying to dismiss the keyboard when you touch anywhere outside the keyboard. I've tried the touches began method but it didn't work. The text views are not transparent and have user interaction enabled.
class RegisterTableViewController: UITableViewController {
override func viewDidLoad() {
// set all text views delegate to self
}
// dismiss keyboard on touch
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touch")
super.touchesBegan(touches, with: event)
view.endEditing(true)
}
}
extension RegisterTableViewController: UITextViewDelegate {
func textViewDidBeginEditing(_ textView: UITextView) {
textView.text = ""
}
}
I'm new to swift and would appreciate any help!
Add touchesBegan code in your UITableViewCell file , which will work if you touch outside TextField but inside cell
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.Your_TextField.endEditing(true)
}
But it won't work outside cell (In UIVIew of another ViewController) , so add UITapGesture to achieve that
override func viewDidLoad() {
super.viewDidLoad()
let tapgest = UITapGestureRecognizer(target: self, action: #selector(taptoend))
self.Your_Table_View.addGestureRecognizer(tapgest)
}
#objc func taptoend()
{
self.Your_Table_View.endEditing(true)
print("Key-Board will be dismissed here")
}
You need to add Tap gesture recognizer inside your cell. Place all you text inputs in a UIView. make outlet of UIView inside cell. and than add this code in your cell.
#IBOutlet weak var myView: UIView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
let tap = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard))
self.myView.addGestureRecognizer(tap)
}
#objc func dismissKeyboard() {
self.endEditing(true)
}
hi Im new to programming I was try to recognize the user touch on the screen and close all textfield but when I add a scrollview I won't be able to do that I read a lot in stack overflow like : tap recognizer but I could not do that anymore after adding the textfield I got confused
tell me how can I do it please?
thanks
for dismiss the keyboard is the subview of UIView, then use
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
for dismiss the keyboard is the subview of UIScrollview, then use in here scroll view observes the userInteraction so "By setting userInteractionEnabled to NO for your scroll view".
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.yourSCrollviewName.endEditing(true)
}
for resign the keyboard in various types, the some other type has already answered in SO
update
for hide the keyboard the create the TapGesture for your scrollview
self.ScrollView.isUserInteractionEnabled = true
// ScrollView.keyboardDismissMode = .onDrag
let tap = UITapGestureRecognizer(target: self, action: #selector(doubleTapped))
tap.numberOfTapsRequired = 1
self.ScrollView.addGestureRecognizer(tap)
and call the action as
func doubleTapped() {
// do something cool here
self.ScrollView.endEditing(true)
}
You have to add tap gesture on ScrollView
Add below code in action of gesture:
self.yourSCrollviewName.endEditing(true)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(keyBoardHideOnTap))
tapGesture.numberOfTapsRequired = 1
self.ScrollView.addGestureRecognizer(tapGesture)
func keyBoardHideOnTap() {
// do something cool here
self.ScrollView.endEditing(true)
}
I'm trying to create a simple function, similar to the touchesBegan, that detects if there's any touch occurring on the screen.
I've hit a brick wall trying it out myself because I'm not comfortable with UITouch class, but I really need some self made function, outside the touchesBegan default one.
I was trying to do something like this 'pseudo-code/swift'
func isTouchingTheScreen() -> Bool {
let someTouchHandleConstant: uitouch ???
if imTouchingTheScreen {
return true
} else {
return false
}
}
Do you have any hints?
PS: I know that code doesn't work, don't call that out, it was just to give you some 'image' of what I was trying to do (:
The idea
You can simply keep track of every touch begun, ended or cancelled by the user.
class GameScene: SKScene {
private var activeTouches = Set<UITouch>()
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
activeTouches.unionInPlace(touches)
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
activeTouches.subtractInPlace(touches)
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
if let touches = touches {
activeTouches.subtractInPlace(touches)
}
}
var isTouchingTheScreen: Bool { return !activeTouches.isEmpty }
}
Keeping activeTouches updated
As you can see I am keeping updated the activeTouches Set.
Every time a touch does begin I add it to activeTouches. And every time a touch does end or is cancelled I remove it from activeTouches.
The isTouchingTheScreen computed variable
This allows me to define the isTouchingTheScreen computed property that simply returns true when the Set contains some element.
You can implement UITapGestureRecognizer as below:
var tapGesture :UITapGestureRecognizer!
override func didMoveToNode() {
// Add UITapGestureRecognizer to view
self.tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.touchedView(_:)))
view.addGestureRecognizer(tapGesture)
}
func touchedView(sender: UITapGestureRecognizer) {
print("view touched")
}
You could implement UITapGestureRecognizer:
// global var
var tapGesture :UITapGestureRecognizer!
override func didMoveToView() {
// Add tap gesture recognizer to view
self.tapGesture = UITapGestureRecognizer(target: self, action: #selector(GameScene.handleTap(_:)))
self.tapGesture.cancelsTouchesInView = false
view.addGestureRecognizer(tapGesture)
}
func handleTap(sender: UITapGestureRecognizer) {
print("GameScene tap")
if sender.state == .Ended {
var positionInScene: CGPoint = sender.locationInView(sender.view)
positionInScene = self.scene!.convertPointFromView(positionInScene)
let touchedNode = self.nodeAtPoint(positionInScene)
if touchedNode.name != "myHero" {
print("The SKSpriteNode myHero was tapped")
}
}
}
You can find more details in Apple docs here.
I'm making a calculator app that has several UIButtons for input of digits etc. I want the user to be able to touch down on one button and, if this was not the intended button, move the finger to another button and touch up inside that one. The button that the user has his/her finger on should change background color to indicate to the user what is happening, much like Apples built in calculator app.
I've tried to do this by using touch drag inside/outside and touch drag enter/exit on the buttons, but it only works for the button where the touch originated. Meaning I can touch down on one button, drag outside, back inside and touch up inside, but I can't touch down, drag outside and touch up inside another button.
Also the area that is recognized as being inside or outside the button is larger than the bounds of the button.
Here's an example of the code I've tried for one of the buttons:
#IBAction func didTouchDownThreeButton(sender: AnyObject) {
threeButton.backgroundColor = blueColor
}
#IBAction func didTouchUpInsideThreeButton(sender: AnyObject) {
inputTextView.text = inputTextView.text + "3"
threeButton.backgroundColor = lightGrayColor
}
#IBAction func didTouchDragExitThreeButton(sender: AnyObject) {
threeButton.backgroundColor = lightGrayColor
}
#IBAction func didTouchDragEnterThreeButton(sender: AnyObject) {
threeButton.backgroundColor = blueColor
}
Any help would be much appreciated!
I managed to create a suitable solution by overriding the functions below and keeping track of which button was touched last and second to last. The last button touched gets highlighted and the second to last gets unhighlighted. Here's my code for a two button test in case anyone should find it useful:
#IBOutlet weak var bottomButton: UIButton!
#IBOutlet weak var topButton: UIButton!
var lastTouchedButton: UIButton? = nil
var secondToLastTouchedButton: UIButton? = nil
override func touchesBegan(touches: Set<UITouch>?, withEvent event: UIEvent?) {
let touch = touches?.first
let location : CGPoint = (touch?.locationInView(self.view))!
if topButton.pointInside(self.view.convertPoint(location, toView: topButton.viewForLastBaselineLayout), withEvent: nil) {
topButton?.backgroundColor = UIColor.redColor()
}
else if bottomButton.pointInside(self.view.convertPoint(location, toView: bottomButton.viewForLastBaselineLayout), withEvent: nil) {
bottomButton?.backgroundColor = UIColor.redColor()
}
super.touchesBegan(touches!, withEvent:event)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let location : CGPoint = (touch?.locationInView(self.view))!
if topButton.pointInside(self.view.convertPoint(location, toView: topButton.viewForLastBaselineLayout), withEvent: nil) {
secondToLastTouchedButton = lastTouchedButton
lastTouchedButton = topButton
lastTouchedButton?.backgroundColor = UIColor.redColor()
}
else if bottomButton.pointInside(self.view.convertPoint(location, toView: bottomButton.viewForLastBaselineLayout), withEvent: nil) {
secondToLastTouchedButton = lastTouchedButton
lastTouchedButton = bottomButton
lastTouchedButton?.backgroundColor = UIColor.redColor()
}
else {
lastTouchedButton?.backgroundColor = UIColor.whiteColor()
}
if secondToLastTouchedButton != lastTouchedButton {
secondToLastTouchedButton?.backgroundColor = UIColor.whiteColor()
}
super.touchesMoved(touches, withEvent: event)
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let location : CGPoint = (touch?.locationInView(self.view))!
if topButton.pointInside(self.view.convertPoint(location, toView: topButton.viewForLastBaselineLayout), withEvent: nil) {
topButton?.backgroundColor = UIColor.whiteColor()
}
else if bottomButton.pointInside(self.view.convertPoint(location, toView: bottomButton.viewForLastBaselineLayout), withEvent: nil) {
bottomButton?.backgroundColor = UIColor.whiteColor()
}
super.touchesEnded(touches, withEvent: event)
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
lastTouchedButton?.backgroundColor = UIColor.whiteColor()
super.touchesCancelled(touches, withEvent: event)
}
I've tried to do this by using touch drag inside/outside and touch drag enter/exit on the buttons, but it only works for the button where the touch originated
Absolutely right. The touch "belongs" to a view, and for as long as you keep dragging, it will still only belong to that view. Thus, the only way something like what you describe can be possible is for the touch detection to take place in the common superview of these button views.