I am adding UIScrollView in UITableViewCell, but when I am click on scroll view did select method is not getting called.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
I am adding the scroll view on contentView of cell, still its not calling did select method.
[cell.contentView addSubview:scrollView];
The reason your table cell is not being able to detect the touches is because the scrollView on your cell is intercepting the touches and is not conveying it to the table cell so that the tableView delegate function can be called.
A simpler fix is just create a subclass of UIScrollView and set the scrollView on your cell to this subclass.
override these methods on the scrollview subclass
-(void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
if (!self.dragging)
[self.superview touchesCancelled: touches withEvent:event];
else
[super touchesCancelled: touches withEvent: event];
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if (!self.dragging)
[self.superview touchesMoved: touches withEvent:event];
else
[super touchesMoved: touches withEvent: event];
}
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (!self.dragging)
[self.superview touchesBegan: touches withEvent:event];
else
[super touchesBegan: touches withEvent: event];
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if (!self.dragging)
[self.superview touchesEnded: touches withEvent:event];
else
[super touchesEnded: touches withEvent: event];
}
Which basically checks whether the scroll view is being dragged , and if its not it passes all the touch events to its superview , in this case the cell content view.
This fixed a similar problem for me , hope this helps.
Cheers.
Because scrollView overlapped on Cell... Best way is add tap Gesture on UIScrollView such like,
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(gestureAction:)];
[recognizer setNumberOfTapsRequired:1];
MYScrollView.userInteractionEnabled = YES;
[MYScrollView addGestureRecognizer:recognizer];
Add above code in cellForRowAtIndexPath method and Write gesture action method such like
-(void)gestureAction:(UITapGestureRecognizer *) sender
{
CGPoint touchLocation = [sender locationOfTouch:0 inView:self.YourTableViewName];
NSIndexPath *indexPath = [self.YourTableViewName indexPathForRowAtPoint:touchLocation];
NSLog(#"%d", indexPath.row);
}
Here in above gesture (action) method you can get indexPath as same as didSelectRowAtIndexPath.
Swift 2
class UIScrollViewSuperTaps: UIScrollView {
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if self.dragging {
super.touchesBegan(touches, withEvent: event)
} else {
self.superview?.touchesBegan(touches, withEvent: event)
}
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
if self.dragging {
super.touchesCancelled(touches, withEvent: event)
} else {
self.superview?.touchesCancelled(touches, withEvent: event)
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
if self.dragging {
super.touchesEnded(touches, withEvent: event)
} else {
self.superview?.touchesEnded(touches, withEvent: event)
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
if self.dragging {
super.touchesMoved(touches, withEvent: event)
} else {
self.superview?.touchesMoved(touches, withEvent: event)
}
}
}
Swift 3
class UIScrollViewSuperTaps: UIScrollView {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if self.isDragging {
super.touchesBegan(touches, with: event)
} else {
self.superview?.touchesBegan(touches, with: event)
}
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
if self.isDragging {
super.touchesCancelled(touches, with: event)
} else {
self.superview?.touchesCancelled(touches, with: event)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if self.isDragging {
super.touchesEnded(touches, with: event)
} else {
self.superview?.touchesEnded(touches, with: event)
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if self.isDragging {
super.touchesMoved(touches, with: event)
} else {
self.superview?.touchesMoved(touches, with: event)
}
}
}
Don't forget to assign class UIScrollViewSuperTaps to your scroll view in storyboard or in code depending on how you created it.
Related
I want to get values from touches began and touches move. I have this code but this is only use for moving not getting value.
override func touchesMoved(touches: Set, withEvent event: UIEvent) {
super.touchesMoved(touches, withEvent: event)
let touch: UITouch = touches.first as! UITouch
if touch.view == btn1 {
println("touchesMoved")
} else {
println("touchesMoved This is not an ImageView")
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let touch = touches.first {
if touch.view == self.button {
// Do whatever
// get button tag => button.tag
// get button titleLabel => button.titleLabel.text
// get button image => button.imageView.image
} else {
return
}
}
}
Use this.
I've got a UICollectionView in my UIViewController and I want it to respond to gestures inside AND outside of the UICollectionView. By default the UICollectionView only responds to the gestures inside its own view but how can I make it respond to swipes outside of its view?
Thanks.
I wrote a view subclass that accomplishes just this:
#import <UIKit/UIKit.h>
#interface TouchForwardingView : UIView
#property (nonatomic, weak) IBOutlet UIResponder *forwardingTarget;
- (instancetype)initWithForwardingTarget:(UIResponder *)forwardingTarget;
#end
#import "TouchForwardingView.h"
#implementation TouchForwardingView
- (instancetype)initWithForwardingTarget:(UIResponder *)forwardingTarget
{
self = [super init];
if (self)
{
self.forwardingTarget = forwardingTarget;
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
[self.forwardingTarget touchesBegan:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
[self.forwardingTarget touchesEnded:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
[self.forwardingTarget touchesCancelled:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
[self.forwardingTarget touchesMoved:touches withEvent:event];
}
#end
In interface builder, set the subview of the containing view to TouchForwardingView, then assign the collection view to the forwardingTarget property.
Swift version of Nailer's anwer, this will forward all gestures done on the viewcontroller to the collectionview
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
collectionView.touchesBegan(touches, withEvent: event)
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
collectionView.touchesEnded(touches, withEvent: event)
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
collectionView.touchesCancelled(touches, withEvent: event)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
collectionView.touchesMoved(touches, withEvent: event)
}
Steven B's answer for with Swift 4 :)
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
collectionView.touchesBegan(touches, with: event)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
collectionView.touchesEnded(touches, with: event)
}
override func touchesCancelled(_ touches: Set<UITouch>?, with event: UIEvent?) {
collectionView.touchesCancelled(touches!, with: event)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
collectionView.touchesMoved(touches, with: event)
}
I am currently developing an iOS app using swift. I used override to write my own tocuhesBegan and tochesEnded functions. Now when I use self.button.
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
super.touchesBegan(touches, withEvent: event)
for touch in touches {
var tap = touch as? UITouch
var touchPoint: CGPoint = tap!.locationInView(self)
self.touchDown(touchPoint)
}
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
super.touchesEnded(touches, withEvent: event)
self.releaseTouch()
}
override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {
super.touchesCancelled(touches, withEvent: event)
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
super.touchesMoved(touches, withEvent: event)
}
func touchDown(point: CGPoint){
if rippleEffect == true {
touchView.frame = touchViewInitFrame
self.addSubview(touchView)
var touchViewFrameXPosition: CGFloat = point.x - (frame.size.width) / 2
println("X position = \(touchViewFrameXPosition)")
var touchViewFrameYPosition: CGFloat = -(self.frame.size.width - self.frame.size.height) / 2
touchViewFrame = CGRectMake(touchViewFrameXPosition, touchViewFrameYPosition, frame.size.width, frame.size.width)
UIView.animateWithDuration(0.25, delay: 0.0, options: .CurveEaseInOut, animations: {
self.touchView.frame = self.touchViewFrame
}, completion: nil)
}
}
func releaseTouch(){
if rippleEffect == true {
UIView.animateWithDuration(0.0, delay: 0.0, options: .CurveEaseInOut, animations: {
self.touchView.removeFromSuperview()
}, completion: nil)
}
}
it doesn't go to the function I specified in the selector. Is anyone else having this issue or does anyone know what's going on?
Here is the code that I used where I am having the issue. It is a subclass of UIButton.
If you override any of the touches methods, you are supposed to override all four and call super.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesBegan:touches withEvent:event];
//your code
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesEnded:touches withEvent:event];
//your code
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesMoved:touches withEvent:event];
//your code
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesCancelled:touches withEvent:event];
//your code
}
You probably have two different handles for your view and your button, to prove that try to touch anywhere else in the screen and your touch will be detected, however while pressing the button the touch is handle and never pass to the other handlers. You have to options, intercept all messages and handle if it should be passed or not for the original handles before/after you do what you need to do, or implement the button handler and make it pass the message up the chain:
From the apple documentation:
Overriding hit-testing ensures that the superview receives all touches
because, by setting itself as the hit-test view, the superview
intercepts and receives touches that are normally passed to the
subview first. If a superview does not override hitTest:withEvent:,
touch events are associated with the subviews where they first
occurred and are never sent to the superview.
Basically I need to create a UIScrollView in my SpriteKit project but i'm having a lot of problem adding SKButtons (custom SKNode class for button management). So I proceeded to create a scrollable SKNode with touch gesture but, obviously, this bar won't have the native UIScrollView acceleration: the feature I was looking for.
So tried to overtake this problem by adding a native UIScrollView and catch every change of position, like this:
using this code:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[blueNode setPosition:CGPointMake(blueNode.position.x, scrollerUI.contentOffset)];
}
This works right but foolishly I forgot that if I add buttons, the touch gesture won't recognize the button's touch event! (The UIScrollView has the priority).
Maybe is just a stupid question but I don't really know how to figure it out. Maybe programming my own acceleration methods?
I think I came up with a solution to handle touches. Since the UIScrollView eats all the touches to allow it to scroll you need to pass them to the SKScene. You can do that by subclassing UIScrollView:
class SpriteScrollView: UIScrollView {
var scene: SKScene?
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
scene?.touchesBegan(touches, withEvent: event)
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
scene?.touchesMoved(touches, withEvent: event)
}
override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {
scene?.touchesCancelled(touches, withEvent: event)
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
scene?.touchesEnded(touches, withEvent: event)
}
}
Then your scene needs to see if the touch hits any nodes and appropriately send the touches to those nodes. So in your SKScene add this:
var nodesTouched: [AnyObject] = []
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
super.touchesBegan(touches, withEvent: event)
let location = (touches.first as! UITouch).locationInNode(self)
nodesTouched = nodesAtPoint(location)
for node in nodesTouched as! [SKNode] {
node.touchesBegan(touches, withEvent: event)
}
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
super.touchesMoved(touches, withEvent: event)
for node in nodesTouched as! [SKNode] {
node.touchesMoved(touches, withEvent: event)
}
}
override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {
super.touchesCancelled(touches, withEvent: event)
for node in nodesTouched as! [SKNode] {
node.touchesCancelled(touches, withEvent: event)
}
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
super.touchesEnded(touches, withEvent: event)
for node in nodesTouched as! [SKNode] {
node.touchesEnded(touches, withEvent: event)
}
}
Note this is for single touches and does not handle errors well, you'll need to wrap some of the forced down casting in if statements if you want to do this properly
I hope this helps someone even though the question is months old.
One possible solution would be to add tap gesture to scene:
override func didMoveToView(view: SKView) {
let tap : UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: Selector("tapped:"))
view.addGestureRecognizer(tap)
}
func tapped(tap : UITapGestureRecognizer) {
let viewLocation = tap.locationInView(tap.view)
let location = convertPointFromView(viewLocation)
let node = nodeAtPoint(location)
if node.name == "lvlButton" {
var button = node as! SKButton
button.touchBegan(location)
}
}
How can I implement it in the new language of Apple:
Objective-C code:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UIView *view in self.view.subviews)
[view resignFirstResponder];
}
I have tried to do so. But the keyboard does not disappear:
Swift code:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
super.touchesBegan(touches, withEvent: event)
self.view.resignFirstResponder()
}
You could probably go with:
self.view.endEditing(true)
Try this
self.view.endEditing(true)