I'm using a UIScrollView whose content is a simple UIView subclass whose size is set using auto layout and which uses drawRect: to render its content rather than having subviews of its own.
If the content (and the size) of the UIView changes then everything works as intended. The new content instantly appears and the scrollability of the UIScrollView enables/disables if the size of the content now needs / no longer needs scrolling.
However, if there's an animation going on somewhere else on the screen things no longer work as intended.
In that case the change to the UIView is animated along with that other animation.
So if that other animation takes say, 2 seconds, the new UIView content is instantly redrawn but at a scale so that it fits in the old content's size. Then it animates the content, growing (or shrinking) over a period of 2 seconds so that at the end of the animation its size is what it should be.
The "interfering" animator in question is owned by a ViewController quite a bit further up in the food chain and the UIScrollView and its content UIView are never told about the UIViewPropertyAnimator.
The problem only happens if the content change overlaps the animation. If that other animation has completed (or hasn't started yet) the content in the scroll view is updated instantly.
Does anyone have insight into this, or perhaps could suggest a way to force UIScrollView and/or its content view to always do their own thing and not tag along for the ride if some unrelated UIViewPropertyAnimator is chugging along elsewhere?
EDIT: A bit of extra info
The animation code is older and originally made use of UIView.Animate and some swipe gestures were triggering the animation. In that case even if the animation and the content size change overlap (using the exact same repro scenario), the new (scrolled content) size appears immediately and doesn't get linked to the UIView.Animate animation. Swapping in UIViewPropertyAnimator code (and without any gesture recognizers getting involved) the problem is triggered and content size change becomes animated.
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.
I'm trying to recreate the passbook UI using a collection view with a custom layout.
So far so good, but there's this thing I can't seem to find a solution for.
Problem: When I click on a cell I want it to move up to the top of the screen (content offset of the cv). Most of the cells don't have a problem with this and they perform as such. However, when the selected cell is near the bottom of the screen, there's no moving at all... just a fade-out and fade-in.
To achieve this animation, I embedded the layout subclass' invalidateLayout in an animation block to be performed by UIView. No matter how high or low I set the time interval, the duration is still the same, and so no effect on the fade-in fade-out behaviour.
I'll paste here the methods that I believe to need to be modified and also a link to a video on youtube. Hopefully, someone can find a solution for this >_<".
YT: https://www.youtube.com/watch?v=3xIL-fFUcJo
Code: http://pastebin.com/QKLKGwdN
Scenario:
Horizontally scrolling UIScrollView with reused page views (so that there are only few page viewcontrollers which are being reused similar way like UITableView cells). So that they are able to be updated with new content and reused I need to know exact position of UIScrollView's content view (offset). This works great.
Now I need to implement custom scrolling animation - I mean to programatically move the content view, so that user touches some buttons, and the scroll view scrolls to desired position with this custom animation. The movement can be very quick and very far. I can not use Core Animation for this, as I could not track position during animation (CA reports you only start and end of the movement). So I decided to use CADisplayLink, and calculate each UIScrollView content for each position. This works great too.
The only problem is, that sometimes I see stroboscopic effect - say I am moving the content to the right, and it looks like it is moving to left. If I look at builtin animation within UISCrollView using setContentOffset:animated:, the animation is smooth and nice. Does anyone know, how to get rid of this stroboscopic effect?
Most likely your issue is that timestamp is a double and you're assigning it to a float
Floats have 7 digits while Doubles have 15-16 digits.
So in other words you're experiencing data loss. By using double you should see a silky smooth animation.
Seems like a very simple problem! But I'm having great difficulty.
My ideas and attempts so far:
scrollView.backgroundColor = [UIColor colorWithPatternImage:myImage]]
Doesn't scroll with contents
Create UIView the size of contentSize (actually, larger due to elastic bounces on scroll view), and use pattern as above on this sub view of UIScrollView.
Causes massive memory hit (and crash) when UIView gets too large. See also: Large UIScrollView with background pattern fails
Similar to (2), exept I only create a UIView the size of the maximum number of repetitions of the background image that will be seen, and cleverly move the view to wherever is needed to show the correct background repetitions.
Causes this background view to shift left and right unexpectedly when animating the scroll.
Create UIView subclass and override drawRect. Use various Core Graphics techniques to draw content by hand.
Not animatable. Implementing my own contentOffset property isn't a standard Core Animation property.
Overriding drawRect on UIScrollView doesn't respect the content offset, and doesn't get called multiple times as it scrolls/animates. The rect parameter is always simply the bounds of the UIScrollView.
As with (4), except I set the bounds.origin of my UIView subclass in my setContentOffset implementation, since it's an animatable property.
drawRect doesn't seem to get called every frame.
Use CATiledLayer, as suggested in this answer: Large UIScrollView with background pattern fails. Implementation details here: http://www.cimgf.com/2011/03/01/subduing-catiledlayer/.
I really don't want the ugliness of seeing tiles asynchronously being drawn as user scrolls. It's just a simple background pattern!
This seems like the simplest thing! Why is it so hard!?
Maybe the sample code:ScollViewSuit->3_Tiling can help you. You can search it in the official docset.
This works like CATiledLayer but only use UIKit, the tile was loaded on the main thread.
And I really don't think this is a good solution.
I have two views that flip based on a button press within the view. The view has two CAGradientLayers as sublayers. If I flip immediately after the action method fires, the button is in the process of changing the opacity of the gradients and so you see stuttering (the UIVIew flip animation is having to accommodate the button that is itself changing.)
I can hack a solution by doing a performWithSelection:withObject:afterDelay:0.1f, but it feels like such a hack. I tried setting the layer's needsDisplay property and testing for when it was clears, but probably this is insufficient to tell me the screen itself has redrawn.
Dav
In the end this has no solution. I have since found that when animating a view there are severe performance implication if you also try to animate the super views. You can see this in many iOS apps where the app animates an image in a scrolling list - the scrolling stumbles.
So what I learned is either animate something, or it's view, but not both!