I usually use this function to hide the keyboard once any point in screen is touched
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
}
But when I use it with scroll view it doesn't work.
How I can hide the keyboard once any point of scroll view is touched ?
Try set keyboardDismissMode of UIScrollView to OnDrag or Interactive, it's default to UIScrollViewKeyboardDismissModeNone
The manner in which the keyboard is dismissed when a drag begins in the scroll view.
Add tap gesture recognizer to scrollView object.
let touch = UITapGestureRecognizer(target: self, action: "singleTapGestureCaptured:")
scrollView.addGestureRecognizer(touch)
and receive the touch event and hide keyboard.
func singleTapGestureCaptured(gesture: UITapGestureRecognizer){
self.view.endEditing(true)
}
There is delegate function for scrollview - "scrollview did scroll" you can dismiss the keyboard there.
Related
How do I allow my tableView to be selectable by overriding hitTest?
I have a tableview that lives outside of bounds of its superview so I need to override hitTest of the view containing the superview. However, when I pass the tableview's hittest I can only scroll and not tap on a row.
public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let pointInTableview = tableView.convert(point, from: self)
guard tableView.bounds.contains(pointInTableview) else {
return super.hitTest(point, with: event)
}
return tableView.hitTest(pointInTableview, with: event)
}
The datasource and delegates are set. If I manually call tableview.selectRowAt(..) I am able to receive the delegate callback.
Gif of demo
The VC View is the view that is overriding hitTest. We are trying to pass the touches to the tableview because the tableview is outside the bounds of the view it lives in.
The problem wasn't the hitTest.
My VC View had a tap gesture to close keyboards. This tap gesture was cancelling the tableview's tap gesture.
Ref: https://kakubei.github.io/2016/02/24/Tap-Gesture-and-TableView/
I have a custom button and it's added to a static cell. Somehow whenever I tap the button, it doesn't react immediately like when the button is added to a plain normal view.
When tapped, it registers the tap right away but the background color has a slight delay before changing.
To change the color I have the following code in my subclass of UIButton:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesBegan(touches, withEvent: event)
border.fillColor = .redColor() // border is a CAShapeLayer
print("began") // This prints right when the button is clicked
}
This button is added in a subclass of UITableViewCell and the button is reacting, except changing the color has a delay. How can I fix this?
Answer (by Jelly):
The answer of Jelly helped me a lot and made the button react a bit better. Knowing what the problem is also made it easier to research the problem and found out to make the button react just as it would in a normal view I have to disable both delaysContentTouches in the table view and it's subviews:
tableView.delaysContentTouches = false
tableView.subviews.forEach { ($0 as? UIScrollView)?.delaysContentTouches = false }
Set delaysContentTouches = false on your tableView.
In Messages.app you can dismiss the keyboard down by scrolling the list view. To be clear, it isn't simply responding to a scrollViewDidScroll event. The keyboard tracks with your finger as you swipe down. Any idea how this is done?
Since iOS 7, you can use
scrollView.keyboardDismissMode = .Interactive
From the documentation:
UIScrollViewKeyboardDismissModeInteractive
The keyboard follows the
dragging touch offscreen, and can be pulled upward again to cancel the
dismiss.
In the XCode, attributes inspector, the scrollView has a Keyboard attribute. It has 3 options.
Do not dismiss
Dismiss on drag
Dismiss interactive.
If you're using a tableView and Swift 3 or Swift 4, it works by using:
tableView.keyboardDismissMode = .onDrag
Since iOS7, UIScrollView and all classes that inherit from it (including UITableView) have a keyboardDismissMode property. With Swift 5 and iOS 12, keyboardDismissMode has the following declaration:
var keyboardDismissMode: UIScrollView.KeyboardDismissMode { get set }
The manner in which the keyboard is dismissed when a drag begins in the scroll view.
Note that UIScrollView.KeyboardDismissMode is an enum that has none, interactive and onDrag cases.
#1. Set keyboardDismissMode programmatically
The code snippet below shows a possible implementation of keyboardDismissMode:
override func viewDidLoad() {
super.viewDidLoad()
// Dismiss keyboard when scrolling the tableView
tableView.keyboardDismissMode = UIScrollView.KeyboardDismissMode.interactive
/* ... */
}
#2. Set keyboardDismissMode in storyboard
As an alternative to the programmatic approach above, you can set the keyboardDismissMode value for your UIScrollView/UITableView in the storyboard.
Select your UIScrollView / UITableView instance,
Select the Attributes Inspector,
Set the correct value for Keyboard.
Without tableview - yes it not a swipe but it doesn't the trick
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
}
I cannot find a way to replace the default UIPanGestureRecognizer of theUIScrollView. However I need to adjust the gesture that causes the UIScrollView to scroll.
I only want to recognize pans with higher velocity. In addition, the velocity of a finger is to be measured after it has moved certain distance (to be sure it is not the initial slow motion). To my knowledge this cannot be achieved with UScrollView's default UIPanGestureRecognizer.
How can I replace it with my own recognizer?
Changing the underlying gesture recognizer is the wrong way to go. What you want to do can probably be accomplished by implementing the gestureRecognizer(_:shouldReceiveTouch:) method of UIGestureRecognizerDelegate.
So long as the scroll view you want to customize isn't a part of a UICollectionView, UITableView, or a similar class then you'll be able to set the delegate of the gesture recognizer. Within the delegate you can then use the velocityInView(_:) method of UIPanGestureRecognizer to decide if you want to allow the gesture recognizer to trigger scrolling.
You could implement the touchesMoved method in here as well. You could do a comparison between touches to check velocity. something like this but it is pseudo code
global firstpoint;
global secondpoint
override func touchesBegan(touches: NSSet, withEvent event: UIEvent){
for touch: AnyObject in touches {
let firstpoint = (touch as UITouch).locationInNode(self);
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let secondpoint = (touch as UITouch).locationInNode(self);
}
let diffx = secondpoint - firstpoint;
if diffx > "some value you choose for velocity"{
"do some action that you want";
}
else {
firstpoint = secondpoint;
}
}
This will give you some velocity for the movement that you could use to supply a further action.
You could try placing a clear UIView over the scrollView, and could then add a UIPanGestureRecognizer to it. You would then be able to set a selector for that GestureRecognizer that could then tell the scrollView to scroll. But then you will be responsible for determining the distance to scroll for each high velocity pan.
I have a custom subclass of UIView, designed in IB that contains a few labels and a button.
There is an action for touchUpInside event on the button and the target is the custom view.
I am attaching this custom view to a self.tableView.tableHeaderView for a tableview in my UI.
The strange thing is this custom view is not responding to touches. I can see it nicely with all the labels and the button in side the table view, that means the table view handles and shows it correctly, however it is not responding to touches.
I checked the whole view hierarchy and all the views involved have userInteractionEnabled as YES.
If i drag some other controls into that custom view for example a switch, segmented control..they do not respond as well. It is like these controls in custom view are not registering touches.
It doesn't make any sense. I am out of ideas. Can you help to allow the touch event on the button to arrive to its parent view?
What is a "headerTableView"? Do you mean a UITableViewHeaderFooterView? Have you tried setting userInteractionEnabled on the root UITableViewHeaderFooterView?
This is a hack that will detect a button touch and trigger touchUpInside programmatically:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
super.touchesBegan(touches, with: event)
if let touch = touches.first, button.bounds.contains(touch.location(in: button)) {
button.sendActions(for: UIControl.Event.touchUpInside)
}
}
I don’t know what your real problem is because that button should work without this.