So I'm trying to let the user two-finger scroll a SKView that they can paint on. I'm using a PanGestureRecognizer that is set with a minimum number of fingers as 2. I have the selector it calls shift the offset of the UIScrollView to which the SKView has been added. It scrolls the SKView perfectly... the problem is any SKNodes that have been added to that view don't scroll with it. Since a picture is worth a thousand words hopeful these will help(Thanks for any help you can give! I'm sure there is a simple solution. I just haven't found it ^^; ):
Initial state
After Scrolling the view up
After Scrolling the view down
UPDATE:
I added a contentOffset variable to the "GameScene" that, moved all SKNodes to a "root" node and then have this in the update run root.position = self.contentOffset and this does in fact get the nodes scrolling as well... however, if I start off with a screen that looks like this:
If I then scroll up and down a bit and then add a new node by touching at the very top edge in the center then I get a screen that looks like this:
So as you can see when I scroll the nodes will "slide" a bit and this also shifts the way the touches are registered as well. Also, it doesn't seem to "slide" again after that.
It may help at this point to know that I add a physicsbody to each of the added SKNodes so that I can hit them with touches but set the dynamic = false so theoretically should only be moved if explicitly told to. So any ideas on this?
Related
I am struggling with aligning a screen to a certain Views inside a UIScrollView. I would like to have same behaviour as paging (same fast and smooth deceleration) but with alignment to a custom views instead of stoping on multiples of the scroll view’s bounds. I have implemented delegate method scrollViewWillEndDragging(_:withVelocity:targetContentOffset:) in order to define my own scroll view’s bounds location. I have also set decelerationRate to UIScrollViewDecelerationRateFast.
It work mostly as desired except the cases when alignment animation is very slow. To be more precise, sometimes, after the dragging is finished, the scrolling animation decelerates to final point very slowly. It finally reach the correct point but after a longer while. I am not able to track down the cases when it happens. I am able to say that everything works fine when final velocity of dragging is zero. Thus, it happens only in some cases when dragging is finished with nonzero velocity.
I wonder if somebody had same problem since I wasn't able to google anything useful. Can you help me please?
I have solved this problem by implementing delegate methods scrollViewDidEndDragging and scrollViewWillBeginDecelerating. Then by using information from scroll view’s pan gesture I found out about translation and I determined final scroll view’s bounds location using setContentOffset method on scroll view.
So I want to add a PanGestureRecognizer to a UIView class that I have made. Everything is working well, however: when I drag the view, it's subviews are also moving/updating etc.
-I am using SnapKit for my view's constraints
-I tried setting translatesAutoresizingMask to false, no result
-I tried to set constant constraints on the subviews,not result
Here is a gif of what it looks like:
https://media.giphy.com/media/oI0Wf5T6B0jIY/giphy.gif
Thanks for the help everyone.
This is expected and is how UIKit (and essentially all 2D/3D scene graphs) are designed to work. The geometry of a view is relative to its parent view. If the parent view moves, so do its decedents.
If you do not want a view to be dependent on the position of the view being moved, it probably should not be a subview of that view in the first place. It's possible to apply the inverse movement to the subviews to make it appear that they're not moving, but that is most likely a lot more work than just not making them subviews in the first place.
In my iOS swift app I have an instance where I am making a circle with SKShapeNode(circleOfRadius: 15) but it makes a skinny ellipse instead, the width is only half of what it should be to make a circle.
Also, when I try to put something in the middle of the screen by setting the position.x of the object to view.bounds.width/2 it puts it in the middle of the left half of the screen instead of the middle of the whole screen. When I try to put it on the far right of the screen by using position.x to view.bounds.width it then goes to the middle instead of the right bound of the screen.
Has anyone ever seen this and know what the issue is?
Check the size of the view which you are adding the SKShapeNode to. It may be that your scene was created to half of the screen size.
Theres a few things you can checkout here first.
i didnt add the view's view controller as a child view controller before loading the view. That fixed this issue for me.
Check the frame of the superview before you're adding the view as its subview, when i seen the frame isnt what i thoguht it was number one solved my problem
the last thing i can think of is add this code to layout subviews. Layout Subviews is called once all the on screen view's bounds and frames have been updated.
If all three doesnt work. Then smoewhere in your code your not doing something right. Displaying some code that you have wrote can dramatically help us help you. Good Speed my friend God Speed.
I have been looking to all the other similar topics here, using UIGestureRecognizers, using hitTest:withEvent, pointInside:withEvent: etc. but nothing seems to be ok for what I need to achieve.
Basically I have a main view (self.view of a common UIViewController) and a small rectangular UIScrollView attached onto it at the bottom: the scrollView is filled with some UIImageViews and the user can scroll it as usual.
But the user should also be able to drag one UIImageView (or a copy of it) from the UIScrollView to the main view, and, this is what I am finding really difficult, with the SAME dragging gesture, hence I need a way to:
1) Distinguish between normal horizontal scrolling gesture, which should be handled by the UIScrollView the usual way and a dragging gesture over the image view.
2) Once identified a dragging gesture, should propagate the touch to the superview, which will host a copy of the UIImageView and WITH the SAME dragging gesture continue the dragging over the main view even out of the bounds of the UIScrollView.
Please note that I know that if the UIScrollView has userInteractionEnabled = NO the touch is propagated to the subviews, but 1) I want to propagate it to the superview not the subviews, 2) the userInteractionEnabled property apparently becomes active only once the initial gesture is terminated, while I need to use a single dragging gesture.
Thank you very much for any help.
So, so far I have ended up implementing the touchesShouldBegin:withEvent:inContentView: method of my UIScrollView subclass but with delayContentTouches set to YES (default) instead of NO as #nhahtdh was suggesting.
Strangely enough even only implementing the method was sufficient for my subviews to intercept the dragging, and still my scrollview is scrolling properly, while with delayContentTouches set to NO I was not able to scroll it as all the subviews were starting to move around.
Really the credit for this is #nhahtdh, so man, if you post an answer I will accept it, thank you very much for your help.
I'm trying to create some sort of timeline view like in video editors: media elements in a row, which are UIView's. I can successfully drag these views inside currently visible part of scroll view using UIScrollView touch events like touchesBegan and touchesMoved. I want to scroll the scroll view once subview is dragged to one of the scroll view edges. The best I can think of now is to create a timer that will scroll the view while user holds the subview with the finger near scroll view edge.
There's a lot of questions here on the same topic, but I was unable to find one that covers scrolling.
Is there a good way to do this? Should I use gesture recognizers instead?
Thank you in advance.
Actually what you want IS a timed event. As soon, as the user is at the edge of the scrollview, you start a timer, which regularly increases the contentOffset. If you don't like your animation results (i guess you're using setContentOffset:animated:?), just try another timing and distance of animation.. I guess you have to try some different settings. What I would try first is 1px at a time. Perhaps every 0.3 second?
If that doesn't work you could also try another "extreme". Start a single animation, when the user reaches the edge, which animates the contentOffset until the end of the contentSize. But over a large timespan so the movement is slow. If the user stops dragging, or moves out of the edge, stop the animation at the current position. That would even be a solution without a timer, because the animation would be your timer itself.
I seriously doubt gesture recognizers would part of a good solution to this since they tend to be most helpful with discreet gestures.
I don't think I can improve on your general direction based on the assumption, implied above, that you are looking for continuous/gradual scrolling.
What I suggest instead is that you consider designing this to use a paged scrolling approach. When your user drags the object to the edge of the scrollview, cause the scrollview to move one page in that direction (by setting the contentOffset to move in that direction according to the bounds of the scrollview). When that even occurs, move the object slightly out of the "hot zone" at the edge of the scrollview so that the user is forced to explicitly express that they want to move another page, or something along those lines - that is, since the design approach depends on this "paging events" you need to implement some sort of gestural system for the user to keep paging.
I suppose you could use a timer in that same situation, so that if the user maintains the position and touch for another second, you would page again.