I have a UISlider in my table view's reusable cell. As soon as the value changes, a custom method valueChanged() gets called, which triggers the table view's reloadData() method.
The reloadData() calls cellForRowAtIndexPath and as soon as the cell in which the slider was changed gets loaded, it animates two constraints which should make it look as if a button is sliding in from the right of the cell.
Basically, the effect I'm trying to create is that as soon as the user starts sliding the UISlider the animation takes place and the button appears. Here's the catch though: the UISlider's isContinious property is set to true to make sure the animation happens right away, and doesn't get delayed until the user takes his finger of the slider. Setting isContinious to true, however, makes it that reloadData() (which was inside my custom valueChanged()) gets called A LOT OF TIMES with every little slide the user commits. After doing some research, and trying out a lot of debugging tactics, I now know that as soon as reloadData() gets called, any running animations (which are still animating at the time reloadData() gets called) get interrupted and just move to the state it's supposed to be in after the animation is done.
So to recap the scenario:
1) slider moves, 2) valueChanged() triggers reloadData(), 3) animation starts to update layout, 4) reloadData() immediately gets called again ruining the animation which started in step 3.
Everything is happening so fast when isContinious is set to true, so the animation doesn't get the time it needs to complete before reloadData() gets called again. This ruins the animation and makes it look as if the button is just appearing on the screen without animation, even though I know UIView.animate(withDuration:) DOES get called and does its job normally. I was wondering if there's a way to refresh a table without calling reloadData(), so basically an alternative to this method (I've already tried reloadCellAtIndexPath and this has the exact same effect). If not, is there a way to make absolutely sure that an animation finishes without being interrupted by any other layout updating method?
If the problem is the refresh kills the animation you can defer the reloadRowsAtIndexPaths call until the animation has finished executing. Normally I would say call it in the completion handler of your animation block but it seems like your value changed may be firing off more than one animation. Instead when you start the animation also start a timer that will run a block to execute the reload. If you start a new animation, invalidate the old timer and make a new one. the reload will only execute when the final animation is done.
var timer = Timer()
func valueChanged() {
timer.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: animationDuration, repeats: false) { _ in
//Call reload here
}
//Animate here
}
Related
This question is brief and I don't believe it requires showing code, but I'd like to learn why my app is doing this.
In my ViewController, I have a countdown Timer that fires every second and updates a label in the view with seconds -= 1 (for example). Everything's working perfectly as it should... no big deal.
But, I also have a UIButton in this same view that I can drag around. The problem occurs every time my Timer() fires (every second)... My PanGesture (dragging the UIButton) is cancelled and the UIButton is dropped.
Is there a certain property that I need to set on either the UIButton or the Timer to prevent this from happening?
Many thanks for your advice!
Even though I haven't been able to discover the reasoning behind it, here's what's I've learned:
If you are in the middle of a UIPanGesture (dragging a UIView around) and you try to update the text on a label (ie. update the UI), your UIPanGesture will cancel and .ended will be called. This was happening for me every second when my timer was updating the text on the label.
In my application, the label showing the countdown value is originally hidden (alpha = 0) in my view even when I am performing the text updates on it, and my UIButton to drag around is only visible when my countdown label isn't.
So my workaround was to only update the text on the label when it's actually visible. That way, my UIPanGesture isn't affected while I can drag it around, but when the label becomes visible and my UIButton isn't, then I can update the text on the label as desired without worrying about dragging the UIButton around.
I know it's a very custom fix that works for me, but if anyone knows what causes the issue, please do share :)
In my viewController.view, I have some work done in viewWillLayoutSubviews that organizes which subviews are visible, which to bring to the front, which to hide, etc, if the orientation changes.
But I have buttons on my view that somehow cause viewWillLayoutSubviews to get called every time they are pressed. Why would this be? According to the Apple docs, viewWillLayoutSubviews is only called if your view's bounds change.
The result is that my views are getting re-arranged just from pressing a button, but I'm not rotating the device at all nor am I manipulating view.bounds or view.frame in any way.
You better do one thing andrews take a bool and set it TRUE on button press and check it on layoutSubviews and operate whether it is true or false. You get it what i am trying to do.
Its weird , I wrote a demo just 2 methods , one for button's action and one is - (void)viewWillLayoutSubviews, when I pressed the button, - (void)viewWillLayoutSubviews is not called.Maybe some mistake in your code?
Is there anyway to get the setContentOffset animation to happen immediately instead of waiting until the app returns to the main run loop? I tried setting the animation property to NO and nesting inside of an animation block but it still waits until returning to the main run loop. I've also tried using a sub method to perform the animation. My problem is I perform some heavy work after setting the contentOffset so the scroll view waits until this work is complete to animate the setting of the content offset so it appears to lag for a second.
I moved the heavy work to scrollViewDidEndAnimation and it resolved my issue. The timer didn't work because my heavy work relies on the content offset position after the scrolling animation is finished and using the timer couldn't assure an accurate offset.
No drawing will happen until the run loop gets time. If your heavy work does not need to be on the main thread then kick off another thread, otherwise schedule a timer with a time interval of 0 to perform the heavy work after the scroll view draws.
I need to handle a touch event on my custom uiviewcotroller. I have a sub controller within the view that already handle touch event (it's a plot that handle zooming and scrolling).
I want to make a tabbar disappear when I tap the screen once. Actually it only works (even tought the tabbar doesn fade away but simply is no visible) in the areas in which the subcontrol is not present but I need it to work everywhere still handling the subcontrol events.
Make sure you're calling the superclass's event handler method in your event handler method to continue propagation of the event up the responder chain.
Also make sure the subcontrol's exclusiveTouch property is set to NO.
You might want to have a look at the event handling documentation.
Try to set userInteractionEnabled = NO in subcontrol view.
UPD: Try to add transparent button to subcontrol.
I have an animation in a EAGLView which is itself in a UITableViewCell. How can I pause the animation in the EAGLView when the view is not visible?
Normally, I would simply use the responsible UIViewController and listen to viewDidDisappear. But how do I do that if the EAGLView is in a table?
I don't think that this is a task to implement at all.
Once your cell is scrolled out of view, it will be deallocated instantly.
So if you have a Custom Cell, the animation will have to be stopped in -dealloc anyhow.
EDIT 1:
Actually, I was not really precise: I wrote "instantly", but of course, this depends on the OS and Apple and may be changed in future versions. Actually, the cell is deallocated whenever the OS garbage collector wants. Currently, Apple deallocates one cell whenever it needs a new one. Usually, scrolling a table implies that one row disappears and a new one appears, so that's why deallocation seems to happen instantly.
If the view, that is switched on, contains a table view, than you will see the same instant deallocation.