Custom views with UIPanrecognizer unintendetly locks UITableViewController - swift

I would like to place custom views (created from nib) inside UITableViewCells. That works without issues, unless the custom view declares it's own single touch UIPanrecognizer. In those cases my custom view responds to the pan events, but that pretty much disables the ability to scroll the cells inside the table view. I tried registering the UIPanRecognizer with both the cell and the custom view, but that ability seems to be not allowed any more since IOS 9 (seems like this is also not how Apple wants touch events to be handled, I read somewhere that touch events should just be handled by one view)
I also failed to find a way to scroll the table view programmatically, which would also seem a little hacky.
What are my options when it comes to wanting to preserve the pan behaviour of the UITableView while still being able to respond to a pan event inside my custom view?
My use case is as follows: I want to reuse a custom view that can sideways-scroll that I created for another part of my app. My table view is set to only react to downward pans. Therefore the two pan actions are not interfering.
Two ways I have this solved currently are as follows:
The sideways scroll reacts to two-finger pans. This is super awkward and unintuitive.
All gestures on the custom view (except taps) get sent to its superview. A tap on the custom view disables the rerouting, which locks the table view and enables sideways scrolling by letting the custom view react to the sideways pan. Another tap restores the initial behavior. This is awkward since it asks the user to perform three separate actions for what should be just one.
I know that I can enable sideways panning for table views, but that doesn't solve my problem of wanting to reuse my custom view inside the cell.
Does anyone know a solution to this dilemma?

The solution was to create a custom UIGestureRecognizer.
I followed this tutorial, created a custom SidewaysPanGestureRecognizer, registered that instead and passed all gestures but SidewaysPanGestureRecognizer to the superview by implementing the UIGestureRecognizerDelegate method responsible for deciding if the view should handle the gesture:
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer,
shouldReceiveTouch touch: UITouch) -> Bool {
return gestureRecognizer is SidewaysPanGestureRecognizer
}

Related

Is Selecting Multiple Items with a Two-Finger Pan Gesture only possible with UITableViewController?

I tried implementing the selecting multiple items with a two-finger pan gesture. However, the checkmarks didn't always appear and disappear when tapping edit to start the process, or tapping done when finished.
I later discovered that it works fine when using a UITableViewController after choosing the different controller from cocoa touch menu, instead of the UIViewController and UITableView I was using before.
So my question is: is it correct for me to now assume that these gestures when used in a table are really meant for a dedicated table view controller (with all the extra functionality you only get from it)?
Without any example code, I can't really see what might be going wrong. Have a look at the documentation to see if you are implementing it correctly.
https://developer.apple.com/documentation/uikit/uitableviewdelegate/selecting_multiple_items_with_a_two-finger_pan_gesture

Avoiding touch gesture conflicts between two different views

Let me emphasize that there are two views that overlap and I want handle the touch gestures of the view on top.
The UIGestureRecognizeDelegate methods work for conflicting gestures within one view not two views from what I have read. Please don't link me to those threads without explaining.
This issue is occurring between the toolbar items and an image view with gestures attached to it.
In the image above the bar buttons cannot be touched.
Other apps handle this case without issues. If I touch a bar button it would work and if I drag the view on the non-overlapped parts I would be able to drag it.
How can I achieve this ?
Currently the image view has gestures attached to it (one for testing, its a pan).
Update
As requested here is a Gif.
Notice how the buttons are not responding when there is a view under the toolbar.
The issue was that I was using view.layer.zPosition, apparently changing the zPosition does not change the position of view is the subview hierarchy (which was something that I assumed).
Source: https://stackoverflow.com/a/15807250/3366784

How to make a table view based selector control accessible for VoiceOver?

I have a selector control in my app based on UITableView. The user can scroll the table view and a marker in the center shows selected item. Every selectable item is a table view cell.
Example
Now I want to make my app VoiceOver compatible for a friend. But this control, I have trouble make it work.
With VoiceOver on, I can't scroll the table view to select other elements. I looked at picker view in clocks app. It does not scroll too. But when you flick up or down it jumps to the next or previous value. It says
"swipe up or down with one finger to adjust the value".
I read Matt Gammell's VoiceOver guide where he sais the hint must say what the control does not what you should do.
So I infer this is a special trait they use for things that can swipe up or down to adjust value. But I cant find such trait.
Since UIPickerView is based on UITableViews how did Apple make it work with VoiceOver? Must I use gesture recognizer for flick?
Edit
I am setting the adjustable trait on the UITableView subclass like this:
self.isAccessibilityElement = YES;
self.accessibilityLabel = #"Start date.";
self.accessibilityTraits = UIAccessibilityTraitAdjustable;
The table view implements
- (void)accessibilityIncrement {
NSLog(#"accessibilityIncrement");
}
- (void)accessibilityDecrement {
NSLog(#"accessibilityDecrement");
}
Now I can drag across cells and VoiceOver will read their labels and mark them with the black rectangle. But table view does not scroll and the methods above don't get called.
The cells themselves are isAccessibilityElement = NO; and don't implement accessibility action methods.
You are looking for the adjustable trait: UIAccessibilityTraitAdjustable.
If you specify this trait on your view/cell you must also implement accessibilityIncrement and accessibilityDecrement in that view/cell. These are the two methods that get called when the user swipes up and down with one finger.
There is no need to implement any gesture recognizers yourself. Setting the trait is enough to get that behavior (it will also add the "swipe up or down with one finger ..." description)
You add the UIAccessibilityTraitAdjustable to the element's traits. Then you implement the -(void)accessibilityIncrement and -(void)accessibilityDecrement actions. In the case of the date picker, you should do this for each component (year, month, date) - each of these is an element (which the user can move the VoiceOver cursor to by flicking left and right) and each is adjustable (by flicking up/down while the VoiceOver cursor is on it).

Alternative to UIScrollVIew

I have a quick question. I am trying to implement an application where the user can navigate between the screens via swipe gestures. So I am using gesture recognisers to push and pop views, the problem with that is that I don't want the transition animation to apply to the entire screen as there are certain similar components and it looks weird.
I considered using a scroll view, however I don't want to load all the controllers at the same time.
Any suggestions?
I'd suggest looking into UIGestureRecognizer and setting the UIScrollView property delaysContentTouches to NO to prevent the scroll view from consuming touch events before your gesture recognizer has the change to process the input, if you'd prefer that approach.
Don't forget that UIGestureRecognizer offers you quite a lot of information when the gesture fires.
I would suggest using a scroll view and load only the visible controller. You can then look for this delegate method, and load the other controller lazily
- (void)scrollViewDidScroll:(UIScrollView *)scrollView

UIScrollView event handling

I'm trying to make my own custom UIScrollView for some reason. The question is, is it possible to exactly mimic the event handling behavior of UIScrollView including 'delayed content touches' and 'cancellable content touches'? That is, the custom scroll view should delay handling the event until it can determine if scrolling is the intent, and it should also be able to cancel its subviews' touches later. The problem is as follows:
1) hitTest: should return immediately so I can't delay the determination of the touch owner.
2) We can't cancel a touch event later programmatically. There's no such api.
3) I tried to override the sendEvent: method, but it didn't help. Having to call [super sendEvent:] will send events to unintended views. Moreover, hit test has been already done when sendEvent: was called and we can't alter the value of UITouch.view later.
So again the question is, is it possible to make a custom UIScrollView including it's touch handling behavior without using UIScrollView?
Thanks in advance!
One thing to keep in mind is that the gestureRecognizers (Pan and Zoom) that are used for regular UIScrollViews are private properties until iOS 5.0 comes out. I suppose when they are public you could transfer them to your own scroll view.