How can a UIViewController inside a UIPageController get touch events? - objective-c

It seems that the button simply doesn't get pressed.
I tried:
UIPageViewController Gesture recognizers
However, here is the catch
if page transition of UIPageViewController is UIPageViewControllerTransitionStyleScroll then
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
NSLog(#"%#",self.pageViewController.gestureRecognizers.description);
NSLog(#"%#",self.pageViewController.gestureRecognizers.description);
will simply be empty.
I tried adding my own gestureRecoqnizers instead of button into the UIViewControllers's subview. It still doesn't work.
So I have a UIPageViewController that display a UIViewController whose view has some button. How do I get that button pressed?
I also tried both solutions here:
http://emlyn.net/posts/stopping-gesture-recognizers-in-their-tracks
None works. First of all I cannot disable gesture recoqnizers of the UIPageViewController because there is no such thing. In scrollView mode, UIPageViewController doesn't have gesture recoqnizers.
I tried to add my own gesture recoqnizers to my own button but those are never called.
I want the UIPageViewController to still handle swipe though. But not tap.
I can't access the gesture recoqnizers of UIPageViewControllers because self.pageViewController.gestureRecognizers is empty. The UIPageViewController seems to just "absorb" all tap events. So my button doesn't get it.
I can add button in front of UIPageViewController but that button will absorb the swiping action which I want UIPageVIewController to still handle.
By the way if we uses the template from IOS (Create a page based app, and change the transition to scroll the pageviewcontroller.gesturerecoqnizers will be empty
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Configure the page view controller and add it as a child view controller.
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];//Turn this to scroll view
self.pageViewController.delegate = self;
SDDataViewController *startingViewController = [self.modelController viewControllerAtIndex:0 storyboard:self.storyboard];
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];
self.pageViewController.dataSource = self.modelController;
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
// Set the page view controller's bounds using an inset rect so that self's view is visible around the edges of the pages.
CGRect pageViewRect = self.view.bounds;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
pageViewRect = CGRectInset(pageViewRect, 40.0, 40.0);
}
self.pageViewController.view.frame = pageViewRect;
[self.pageViewController didMoveToParentViewController:self];
// Add the page view controller's gesture recognizers to the book view controller's view so that the gestures are started more easily.
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
NSLog(#"%#",self.pageViewController.gestureRecognizers.description); //This is empty
while (false);
}

Maybe you can set up a custom gesture recognizer in your UIPageViewController. This way, you will be able to filter through UITouch Events, by implementing this in your gesture recognizer delegate (the one for your UIPageViewController) :
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gesture shouldReceiveTouch:(UITouch *)touch {
if (touch.tapCount > 1) { // It will ignore touch with less than two finger
return YES;
}
return NO;
}
This, you will tell the UIPageViewController gestureRecognizer to not care about touch with one finger. You'll have to try it, but i think it might do the trick. The problem here is you have to ask your user for a two-finger swipe...
Check here for an other answer

Related

Objective c stop animations of UIImageView on UINavigationController segue

I have some strange animations when transitioning between views with UINavigationController. The images start with different frame properties and animate to the ones that i have set each time i segue with UINavigationController. I can't find anything to make that animation go away. Does it have something to do with ViewWillAppear implementation?
- (void)viewDidLoad
{
LoadingView* loadingView;
// adding a loading view
loadingView = [self setViewLoading];
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]
initWithTitle:#"≡"
style:UIBarButtonSystemItemDone
target:self.revealViewController
action:#selector(rightRevealToggle:)];
// pan gesture for side menu (Facebook style)
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
self.navigationItem.title = #"Brands";
[self.navigationController setNavigationBarHidden:NO];
self.menusDataArray = self.menusData[TAG_MENUS];
// removing loading view.
[self setViewNotLoading:loadingView];
}
- (void)viewWillAppear:(BOOL)animated
{
// if I don't do this, the swipe gesture for the Facebook stile side menu won't be recognised after pressing back on navigation controller bar
[super viewWillAppear:animated];
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
}

Presenting a modal view controller with cross-disolve isn't showing views added in code

When I present a modal view controller over my view storyboard originated root view controller it flashes the story board view, even if it has been altered. My root view controller has a bright green back ground with large white subview across the top that contains a label bound to an IBOutlet. In UIViewController viewDidLoad I am adding a light gray, slightly transparent UIView that covers the entire view as a subview of the viewcontroller's view. I am also setting the label text to be different than that of the Storyboard layout.
When I trigger the modal, either via segue or via presentViewController:completion: what I see is the light gray view over my label then the view added in code seems to become transparent and animate away and the bright green of the storyboard layout shows up and then the modal view cross-dissolves in. When I dismiss the first and present the second in the completion block i see a cross-dissolve to bright green, pop of light as the added view becomes visible again, pop to bright green and the cross-dissolve in of the second view controller's view.
When I dismiss the second view controller then I see cross-dissolve out to the bright green and then the added light gray, semi-transparent view pops back to being visible.
Anyone have any idea how to stop the cross-dissolve from showing the views underneath the view added in code?
This example is made more jarring if you remove the opacity from the overlay view added in viewDidLoad.
https://github.com/jonnolen/ios-cross-disolve-problem
Code snippet and story board layout:
#interface DTViewController (){
BOOL hasShownSegue;
}
#end
#implementation DTViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UIView * view = [UIView new];
view.frame = self.view.bounds;
view.backgroundColor = [UIColor colorWithWhite:.95 alpha:.7];
NSLog(#"View Bounds: %#", NSStringFromCGRect(self.view.bounds));
[self.view addSubview:view];
self.label.text = #"Hello!";
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
if (!hasShownSegue){
[self performSegueWithIdentifier:#"modal.1.segue" sender:self];
hasShownSegue = YES;
}
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
DTCallbackViewController *vc = segue.destinationViewController;
vc.completionCallback = ^{
[self dismissViewControllerAnimated:YES completion:^{
DTCallbackViewController * vc = [self.storyboard instantiateViewControllerWithIdentifier:#"vc.2"];
vc.completionCallback = ^{
[self dismissViewControllerAnimated:YES completion:nil];
};
[self presentViewController:vc animated:YES completion:nil];
}];
};
}
Figured it out, I don't really like it but it works:
I put all of the maskable content into a separate view:
And then hide that view when I need it to be "masked".
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"View Bounds: %#", NSStringFromCGRect(self.view.bounds));
self.label.text = #"Hello!";
self.content.hidden = YES;
}
Then animations behave as expected. However, this only works with an opaque mask (which is what I needed).

Handling Multiple Gestures on a View

Is there any way to detect a single tap vs. a scrolling gesture on a UIWebView?
I have a UIWebView, that contains rich text that many times, scrolls, if there is a lot of text content. I need to add a new feature that will allow the user to tap the UIWebView to get different content.
The problem is, my solution for this was to place a clear custom button on top of the UIWebView, which handles the tap but kills the scrolling feature. How do the cool kids do this type of thing?
Thanks
I solved this with a gesture recognizer. This eliminates the need for the UIButton overlay altogether.
//Handle taps on the UIWebView
self.singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(**tapDetected:**)];
singleTap.numberOfTapsRequired = 1;
singleTap.delegate = self;
[self.readAboutItView addGestureRecognizer:singleTap];
//Set up the event handler
- (IBAction)**tapDetected:**(UIGestureRecognizer *)sender {
//Do something with the content
[self webViewTouched:self];
}
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
return YES;
}
-(BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}

How do I assign a view as the first responder, after touching a tableview cell?

Here's a more info on my sitation...I have a tableview that when you touch a cell within the tableview, it adds a custom view called DraggableView to the window on the exact same position as the tableview row you selected, and the same size.
EDIT: Here's how I added the DraggableView subview to the view. This code is on the custom tableviewcell class:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UIView *topmostView = [[[super superview] superview] superview];
UITableView *parentTableView = (UITableView *)[self superview];
CGPoint draggablePoint = parentTableView.frame.origin;
CGSize draggableSize = parentTableView.frame.size;
draggablePoint.y += indexPath.row * 44;
dragView.frame = CGRectMake(draggablePoint.x, draggablePoint.y, draggableSize.width, 44);
[topmostView addSubview:dragView];
}
This draggable view is made so it is draggable. On it's designated initializer, it adds a UIPanGestureRecognizer to the view so you can pan it around. I do this like so:
- (void) activatePan {
UIPanGestureRecognizer *pan =
[[[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panMove:)] autorelease];
[self addGestureRecognizer:pan];
}
- (void) panMove:(UIPanGestureRecognizer*)recognizer {
CGPoint touchLocation;
if (recognizer.state == UIGestureRecognizerStateBegan) {
currentFrame = self.frame;
touchLocation = [recognizer locationInView:self];
}
CGPoint translatedPoint = [(UIPanGestureRecognizer*)recognizer translationInView:self];
//The object is being moved across the screen
self.frame = CGRectMake(currentFrame.origin.x + translatedPoint.x, currentFrame.origin.y + translatedPoint.y, currentFrame.size.width, currentFrame.size.height);
}
What I need is for this newly created Draggable View to have the user's "focus" when his finger is still on top of the row. This is for the draggable view to be draggable once it's created.
What happens as of now, is that the draggable view is created, but I have to release my finger, and tap the draggable view to pan it around. I wish to skip the step of releasing the finger and touch the view, so I can drag it once it's been created. Any ideas?
From the Apple documentation:
- (BOOL)becomeFirstResponder
"You may call this method to make a responder object such as a view the first responder. However, you should only call it on that view if it is part of a view hierarchy. If the view’s window property holds a UIWindow object, it has been installed in a view hierarchy; if it returns nil, the view is detached from any hierarchy."

UIGestureRecognizer blocking table view scrolling

I'm using a custom UIGestureRecognizer subclass to track gestures on my InfoView class. The InfoView class is a subview of a custom UITableViewCell subclass called InfoCell.
I've added my gesture recognizer to my root view (the parent view of everything else on screen, because the purpose of my custom gesture recognizer is to allow dragging of InfoCell views between tables). Now, everything works as it should except one thing. I'm using the following code in my UIGestureRecognizer subclass to detect touches on the InfoView view:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UIView *touchView = [[touches anyObject] view];
if ([touchView isKindOfClass:[InfoView class]]) {
// Do stuff
}
The problem here is that the touches on the InfoView object are being intercepted, therefore they are not being forwarded to the UITableView which contains the InfoCell, which is the parent view of the InfoView. This means that I can no longer scroll the table view by dragging on the InfoView view, which is an issue because the InfoView covers the entire InfoCell.
Is there any way I can forward the touches onto the table view so that it can scroll? I've tried a bunch of things already:
[super touchesBegan:touches withEvent:event];
[touchView.superview.superview touchesBegan:touches withEvent:event]; (touchView.superview.superview gets a reference to its parent UITableView)
But nothing has worked so far. Also, the cancelsTouchesInView propery of my UIGestureRecognizer is set to NO, so thats not interfering with the touches.
Help is appreciated. Thanks!
Check out the UIGestureRecognizerDelegate method: - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
If this returns YES it will prevent your gesture recognizer from stomping on the one that UIScrollView is using to detect scrolling.
UIGestureRecognizer has a property "cancelsTouchesInView" which is set to YES by default. This means that touches in a UIView are cancelled when a gesture is recognized. Try to set it to NO to allow the UIScrollView to receive further touch events.
I had a line in my touchesBegan method that set the state property of the gesture recognizer to UIGestureRecognizerStateBegan. Removing this line seems to fix the problem.
You can try add this notification
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
if ([gestureRecognizer class] == [UIPanGestureRecognizer class]) {
UIPanGestureRecognizer *panGestureRec = (UIPanGestureRecognizer *)gestureRecognizer;
CGPoint point = [panGestureRec velocityInView:self];
if (fabsf(point.x) > fabsf(point.y) ) {
return YES;
}
}
return NO;
}