UIWebView overriding touch events in my UITableViewCell subclass - ios

I have a UIWebView in a UIView subclass stored in a UITableViewCell subclass. I've noticed that I lose touch events in my view controller. How can I get around this?
I've tried
- (BOOL) canResignFirstResponder {
return YES;
}
in my custom UIView. I want the UIWebView to receive touch input when the one div is selected. I thought about making the div 100% high but that causes other problems. I was thinking of allowing the UIView subclass to resign first responder status so that tableView:didSelectRowAtIndexPath would be called but doesn't seem to work.
Any suggestions?

Have you tried using the gesture recognizer delegate method gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:? You can read about it here: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIGestureRecognizerDelegate_Protocol/Reference/Reference.html

Related

Why a UIButton on UITableViewCell only drawn darker when touch gesture continued for a short time

Pressing the button quickly and not holding for a short time, will not highlight the button.
Different from a UIButton on a common UIView.
Like the head photo in official Twitter client got same issue.
Instagram client seems solved this, all buttons works fine.
Find same question here:
Why doesn't UIButton showsTouchWhenHighlighted work when the button is on a UITableViewCell?
But I still don't know how to fix it.
Well... a UITableView is a subclass of UIScrollView and the UIScrollView class is known to eat touches for it's own purpose.
When it realizes the touch was not meant for it, it passes it to it's immediate subview.
This feature is the delaysContentTouches property (which by default is YES).
Which is why, the UIButton shows it's highlighted state only after a extended touch because the touch event was with the UITableView for a short while until it determined whether the touch was meant for scrolling or swiping the cell and on realizing the touch was for neither, it immediately passes the touch event to the subView directly below it.
In case of a quick-tap, the button's highlighted state is bypassed due to this delay and the target selector method is called directly.
To show the highlighted state of the button in a UITableView (just as it would on a UIView) do:
For iOS7+:
In -viewDidLoad or anywhere appropriate do:
[yourTableViewObject setDelaysContentTouches:NO];
Also... The cell.subviews has a class UITableViewCellScrollView which apparently is another scrollView and we need to disable the delaysContentTouches property of this class as well.
So... in the -cellForRowAtIndexPath: method (just before return cell;) do:
NSArray *test = cell.subviews;
for (UIView *currentView in cell.subviews) {
if ([NSStringFromClass([currentView class]) isEqualToString:#"UITableViewCellScrollView"]) {
UIScrollView *svTemp = (UIScrollView *) currentView;
[svTemp setDelaysContentTouches:NO];
break;
}
}
For iOS 6-:
In iOS6, the cell.subviews has a UITableViewCellContentView class which is not a scrollView subclass and so all it takes is setting one parameter for the tableView alone.
So, in -viewDidLoad or anywhere appropriate, this is all that you need:
[yourTableViewObject setDelaysContentTouches:NO];
PS: By doing this, it will mess up with the scrolling of the tableView so use your better judgement.

UITapGestureRecognizer on UIView and Its Subview Respond Together When Subview Is Tapped

UITapGestureRecognizer is applied to both UIImageView and its subview (UITextView). However, when I tap on subview, the receiver becomes subview and its parent view (i.e. UIImageView + UITextView). It should however be only subview because that was the one I tapped. I was assuming nested gestures would react first but apparently parent receives the fist tap and then it goes to child.
So, there are different solutions out there for various scenarios (not similar to mine but rather buttons inside scroll view conflict). How can I easily fix my issue without possible subclassing and for iOS 6+ support? I tried delaying touch on start for UIGestureRecognizer on UIImageView and I tried setting cancelsTouchesInView to NO - all with no luck.
Try the following code:
conform the <UIGestureRecognizerDelegate> to your class.
set yourGesture.delegate = self;
then add this delegate Method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
// return YES (the default) to allow the gesture recognizer to examine the touch object, NO to prevent the gesture recognizer from seeing this touch object.
if([touch.view isKindOfClass: [UITextView class]] == YES)] {
return YES;
}
else {
return NO;
}
}
Hope it will solve your issue. Enjoy Coding..!!!!
That's exactly what is it supposed to do.
View hierarchy is like a tree structure and its traversal during a touch gesture starts from the root node. It is very likely for your parent view to receive gesture first and then its subviews. The traversal skips the nodes for which
userInteractionEnabled = NO.
since, you don't have any code I can't help you to play with this flag. A more general solution is to always set gesture only for your parentView and in the gesture delegates check the coordinates if it belongs to any one of the subview and if yes then call your gesture method for your subview.
Not a clean approach but works. !!
you should implement the UIGestureRecognizer delegate methods and apply the correct policy to the gesture, when multiple gesture are recognized

Check If a method Has Been Called and Do Not Call It Again

In touchesBegan I call a method [self animateWindow]; when I touch a UILabel. It animates and brings the window from top. When I touch that UILabel again, I don't want that method [self animateWindow]; to be called again because it animates and brings the window again which is already being displayed. How do I do this? Any help? I tried searching all over, couldn't find the exact answer.
Just create an instance variable which is a BOOL as use it as a flag:
#property (assign, monatomic) BOOL hasAnimated;
- (void) touchesBegan...
{
if (!self.hasAnimated) {
[self animateWindow];
self.hasAnimated = YES;
}
}
Based on your expanded description in the comments, you're going to need to add some more logic which checks which label is actually being touch. A better solution may be to use gesture recognisers on each of the labels. Then you have direct access to the view of the gesture recognizer to check which label it was (perhaps using the tag) and you can add and remove gestures depending on what state you're in (only some labels should respond to touches and they should show or hide).

UITableView didSelectRowAtIndexPath Not Selected on UIPageViewController

I have a UIViewController that has UIPageViewController's view added to it. That UIPageViewController has a page with a subview that has a UITableView added as a subview. I am using iOS 6 and the method didSelectRowAtIndexPath is not being called when I click on the cell. There is a weird "bug" though... If I turn the page halfway and then come back to the page I was on (without completing the page turn), I'm then able to select the cell. I assume this has something to do with gesture recognizers, but I can't figure it out. I tried removing the gesture recognizers from the instantiation of the UIPageViewController, but was unable to get that to work.
I remove the tap gesture recognizers from the UIPageViewController like so, but still the buggy behavior exists...
for (UIGestureRecognizer *recognizer in pageViewController.gestureRecognizers) {
if ([recognizer isKindOfClass:[UITapGestureRecognizer class]]) {
recognizer.enabled = NO;
}
}
Any suggestions?
Subclass UIView with UITableView. let say myUIView.
Implement the UITableView delegates in myUIView.
Add myUIView as a subview of UIPageControl.
UITableView delegates in myUIView will trigger.
It turned out to be something very simple. On my UIViewController I had the autoresizingMask set to FlexibleHeight. Changing it to None for some reason fixed my problem.
// self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
// Changed to :
self.contentView.autoresizingMask = UIViewAutoresizingNone;
If anyone can shed some light onto the reasons why this is the case, I'd appreciate it.

touches methods not getting called on UIView placed inside a UIScrollView

I have a Custom Scroll View, subclassing UIScrollView. I have added a scroll view in my viewcontroller nib file and changed its class to CustomScrollView. Now, this custom scroll view (made from xib) is added as a subview on self.view.
In this scroll view, I have 3 text fields and 1 UIImageView(named signImageView) added from xib. On clicking UIImageView (added a TapGestureRecogniser), a UIView named signView is added on the custom scroll view. I want to allow User to sign on this view, So I have created a class Signature.m and .h, subclassing UIView and implemented the touches methods (touchesBegan, touchesMoved and touchesEnded) and initialised the signView as follows:
signView = [[Signature alloc]initWithFrame:signImageView.frame];
[customScrollView addSubview:signView];
But when I start signing on the signView, the view gets scrolled and hence the touches methods don't get called.
I have tried adding signView on self.view instead of custom scroll view, but in that case the view remains glued to a fixed position when I start scrolling. (Its frame remains fixed in this case)
Try setting canCancelContentTouches of the scrollView to NO and delaysContentTouches to YES.
EDIT:
I see that similiar question was answered here Drag & sweep with Cocoa on iPhone (the answer is exactly the same).
If the user tap-n-holds the signView (for about 0.3-0.5 seconds) then view's touchesBegan: method gets fired and all events from that moment on go to the signView until touchesEnded: is called.
If user quickly swipes trough the signView then UIScrollView takes over.
Since you already have UIView subclassed with touchesBegan: method implemented maybe you could somehow indicate to user that your app is prepared for him to sign ('green light' equivalent).
You could also use touchesEnded: to turn off this green light.
It might be better if you add signImageView as as subView of signView (instead of to customScrollView) and hide it when touchesBegan: is fired). You would add signView to customScrollview at the same place where you add signImageView in existing code instead.
With this you achieve that there is effectively only one subView on that place (for better touch-passing efficiency. And you could achieve that green light effect by un-hiding signImageView in touchesBegan:/touchesEnded:
If this app-behaviour (0.3-0.5s delay) is unacceptable then you'd also need to subclass UIScrollView. There Vignesh's method of overriding UIScrollView's touchesShouldBegin: could come to the rescue. There you could possibly detect if the touch accoured in signView and pass it to that view immediately.
When ever you add a scrollview in your view hierarchy it swallows all touches.Hence you are not getting the touches began. So to get the touches in your signon view you will have to pass the touches to signon view. This is how you do it.
We achieved this with a UIScrollView subclass that disables the pan gesture recogniser for a list of views that you provide.
class PanGestureSelectiveScrollView: UIScrollView {
var disablePanOnViews: [UIView]?
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
guard let disablePanOnViews = disablePanOnViews else {
return super.gestureRecognizerShouldBegin(gestureRecognizer)
}
let touchPoint = gestureRecognizer.location(in: self)
let isTouchingAnyDisablingView = disablePanOnViews.first { $0.frame.contains(touchPoint) } != nil
if gestureRecognizer === panGestureRecognizer && isTouchingAnyDisablingView {
return false
}
return true
}
}

Resources