How to scroll UIPageViewController on top of UIPageViewController? - ios

I have this really strange scenario. There's a UIPageViewController on top of UIPageViewController. And then the upper one is on the section where it's clear view, I would like to be able to swipe and use the UIPageViewController that is underneath. Sliding through pages on upper UIPageViewController is done with menu buttons.
It's something like :
[x][x][x][x]
[x][ ][x]
I've tried using
func point(inside point: CGPoint, with event: UIEvent?) -> Bool {}
But I cant seem to differentiate between what to return...
Any ideas, if there's any other way?
EDIT:

Related

Simultaneous gestures across overlapping sibling views

I'm having trouble accepting two gestures simultaneously across my sibling views. The view structure is as follows.
Superview
|
|--> ChildView1 (UITableView)
|
|--> ChildView2 (UIView).. Partially overlaps ChildView1
When I do a pan gesture on ChildView2, I would like that to pass through to ChildView1 so that the UITableView scrolls properly.
However, when I do a LongPress gesture on ChildView2, I would like that to be properly recognized within ChildView2.
The closest question (and answer) I've seen is this. However, unlike that question, where ChildView1 has to handle the passed gesture, I would like the UITableView to handle the gesture and scroll as if it was scrolled directly on the view. Is that possible?
Thanks for any insights.
Create a subclass of UIView and add it as the class for childView2
class customView:UIView
{
override func point(inside point: CGPoint,with event: UIEvent?) -> Bool
{
return false
}
}

How to scroll UICollectionView that is underneath another UICollectionView?

So heres my issue, the 4 orange rectangles you see on the gif are a single vertical UICollectionView = orangeCollectionView.
The Green and Purple "card" views are part of another UICollectionView = overlayCollectionView.
overlayCollectionView has 3 cells, one of which is just a blank UICollectionViewCell, the other 2 are the cards.
When the overlayCollectionView is showing the blank UICollectionViewCell, I want to be able to scroll the orangeCollectionView.
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
guard let superr = superview else { return true}
for view in superr.subviews {
if view.isKind(of: OrangeCollectionView.self) {
view.point(inside: point, with: event)
return false
}
}
return true
}
This allows me to scroll the orangeCollectionView HOWEVER this doesn't actually work to fix my issue. I need to be able to scroll left and right to show the cards, however this blocks all touches becuase the point always falls on the OrangeCollectionView.
How can I check to see if they are scrolling left/right to show the cards? Otherwise if they are on the blank cell, scroll the orangeViewController up and down.
Had this issue as well... Didn't find a nice way to do it, but this works.
First, you need to access the scroll view delegate method scrollViewDidScroll(). There you call:
if scrollView == overlayScrollView {
if scrollView.contentOffset.x == self.view.frame.width { // don't know which coordinate you need
self.overlayScrollView.alpa = 0
}
}
After that, you add a blank view onto of the orange collection view. The view's alpha is 0 (I think, maybe the color is just clear; try it out if it works).
In the code, you then add a UISwipeGestureRecognizer to the view you just created and and detect whether there's a swipe to the left or to the right.
By detecting the direction of that swipe, you can simply change the contentOffset.x axis of your overlayScrollView to 0 or self.view.frame.width * 2.
Sorry I can't provide my working sample code, I'm answering from my mobile. It's not the proper solution, but when I made a food app for a big client it worked perfectly and no one ever complained :)

ScrollView - Gesture Recognizer - Swipe vertically

I have a UIScrollView that works when swiping left or right, however I've reduced the size of the scrollView so, now display area doesn't fully occupy the superview's frame, and swiping works only within the frame of the scroll view.
I would like to be able to scroll vertically even when swiping up and down outside the horizontal bounds of the narrowed scroll view.
It was recommended that I use a gesture recognizer, but that's beyond my current familiarity with iOS and could use more specific advice or a bit more guidance to get started with that.
There is a simpler approach then use a Gesture Recognizer =]
You can setup the superview of the scroll view (which is BIGGER...) to pass the touches to the scroll view. It's working M-A-G-I-C-A-L-Y =]
First, select the view that will pass all it's touches to the scroll view. if your parent view is already ok with that you may use it. otherwise you should consider add a new view in the size that you want that will catch touches.
Now create a new class (I'll use swift for the example)
class TestView: UIView {
#IBOutlet weak var Scroller: UIScrollView!
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let view = super.hitTest(point, with: event)
if (view == self) {
return Scroller
}
return view
}
}
Nice! now as you can see we added an outlet of the scroller. so use interface builder, select the new view and set it's class to "TestView" in the identity inspector (Or to the name that you'll use for your custom class).
After you set the class and your view is still selected go to connections inspector and connect "Scroller" to your scroll view on the storyboard. All connected properly =]
That's it!! no gesture recognizer needed!!
The new view will pass all it's touches to the scroll view and it'll behave just like you pan in it =]
In my answer I used that answer
EDIT: I improved the code now, it wasn't working as expected before, now it catches only when in needs and not every touch in the app as before
Search for a component called SwipeGestureRecognizer :
Grab it and drop it on top of the View (use the hierarchy to make sure
you drop it on it, if you drop it on another element this code will not work):
Select one of the SwipeGestureRecognizer in the hierarchy and go to its attribute page. Change Swipe to Right.
Make sure the other recogniser has the Swipe attribute to Left
Select UIScrollView and uncheck Scrolling enabled
Connect detectSwipe() (see source code below) to both recognizers.
--
#IBAction func detectSwipe (_ sender: UISwipeGestureRecognizer) {
if (currentPage < MAX_PAGE && sender.direction == UISwipeGestureRecognizerDirection.left) {
moveScrollView(direction: 1)
}
if (currentPage > MIN_PAGE && sender.direction == UISwipeGestureRecognizerDirection.right) {
moveScrollView(direction: -1)
}
}
func moveScrollView(direction: Int) {
currentPage = currentPage + direction
let point: CGPoint = CGPoint(x: scrollView.frame.size.width * CGFloat(currentPage), y: 0.0)
scrollView.setContentOffset(point, animated: true)
// Create a animation to increase the actual icon on screen
UIView.animate(withDuration: 0.4) {
self.images[self.currentPage].transform = CGAffineTransform.init(scaleX: 1.4, y: 1.4)
for x in 0 ..< self.images.count {
if (x != self.currentPage) {
self.images[x].transform = CGAffineTransform.identity
}
}
}
}
Refer to https://github.com/alxsnchez/scrollViewSwipeGestureRecognizer for more
I don't have time for detailed answer but:
In storyboard drag a pan gesture recognizer on the scroll view's superview... Connect it's action with your view controller and in this action change the scroll view position by using the properties from the gesture recognizer that you got as parameter
Tip: when connecting the action change parameter type from Any to UIPanGestureRecognizer in the combo box
please don't see this answer as recommendation to use this approach in your problem, I don't know if that's the best way, I'm just helping you to try it

Issue with horizontal scrollview inside a vertical scrollview in ios swift

My layout is currently like this:
View
-- View
-- Vertical ScrollView
------ View
--------- Horizontal Paginated ScrollView
--------- View
------------- Horizontal ScrollView -- not working properly
See this image for view hierarchy screenshot from xcode:
Using Swift.
I am adding subviews dynamically to this "Size Select Scroll View"
Two Issues:
After adding views, there is no margin between the subviews. Each subview's coord. are like this: (10.0, 0.0, 44.0, 44.0), (54.0, 0.0, 44.0, 44.0), (98.0, 0.0, 44.0, 44.0), (142.0, 0.0, 44.0, 44.0) etc.
But the appearance is like this without the 10 points gap between each subview: http://i.stack.imgur.com/mCGRW.png
Scrolling horizontally is a pain. It only works on maybe 1/4 height from top of the scrollview area and very difficult to scroll. How do i layout subviews so that this scrollview is properly scrollable?
Note: I am explicitly setting content size of size scrollview to more than required so that i can see the scrolling.
I found out the issue. According to the Apple Docs the touch events will be passed to a subview only if it lies entirely in its parent.
In my case, the scrollview was going out of bounds of its parent view ( Details View), because of which touch events were weird. I increased the parent view's size to fit the scrollview and it works fine now.
From the docs (https://developer.apple.com/library/content/qa/qa2013/qa1812.html):
The most common cause of this problem is because your view is located outside the bounds of its parent view. When your application receives a touch event, a hit-testing process is initiated to determine which view should receive the event. The process starts with the root of the view hierarchy, typically the application's window, and searches through the subviews in front to back order until it finds the frontmost view under the touch. That view becomes the hit-test view and receives the touch event. Each view involved in this process first tests if the event location is within its bounds. Only after the test is successful, does the view pass the event to the subviews for further hit-testing. So if your view is under the touch but located outside its parent view's bounds, the parent view will fail to test the event location and won't pass the touch event to your view.
This is always a challenge in iOS.
There are various solutions which unfortunately depend on the exact situation.
Here's a drop-in solution which is often the right solution.
/*
So, PASS any touch to the NEXT view, BUT ALSO if any of OUR
subviews are buttons, etc, then THOSE should ALSO work normally. :/
*/
import UIKit
class Passthrough: UIView {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return subviews.contains(where: {
!$0.isHidden
&& $0.isUserInteractionEnabled
&& $0.point(inside: self.convert(point, to: $0), with: event)
})
}
}
(Of course, you can also just drop the call in to some class, eg
class SomeListOrWhatever: UICollectionView, .. {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
print("MIGHT AS WELL TRY THIS")
return subviews.contains(where: {
!$0.isHidden
&& $0.isUserInteractionEnabled
&& $0.point(inside: self.convert(point, to: $0), with: event)
})
}
Even if you "don't totally understand what the problem is", this is "one of" the solutions!
For example, this is (usually!) the precise solution to the exact issue quoted from the doco by #kishorer747
It's definitely a real nuisance in iOS.

Any way to change the clipping rect of the current context in UIView.drawRect?

I have a custom class which overrides the point(inside point: CGPoint, with event: UIEvent?) -> Bool function so that small buttons can have a touchable area greater than their frame. I thought it would be convenient if I could draw this touchable area around the button when working in Interface Builder. I overrode drawRect to fill the touchable area, but it seems that drawRect clips to the view's frame. Is there any way to change the clipping area to something bigger? I'd rather not add a child view for something like this.

Resources