UIView subviews updating visually but interact as though in previous state - ios

I'm creating a UIViewController that houses some of RosyWriter's functionality, which I'm reworking to create a video recorder. The screen contains a title, a clipped-to-bounds subview that contains the AVCaptureVideoPreviewLayer (so the sublayer CALayer of the video content is added into that subview, so I think it's quite deep-nested), and two buttons acting like a toggle button - in the form of Start and Stop buttons placed in the Storyboard for the UIViewController.
The Start button works fine, even though the video's preview layer is on screen and showing the camera. When I start recording, though, I switch the buttons round, making the Start button hidden and the Stop button hidden=false.
The start button works - this is pressed when the video preview is on-screen and updating, but the actual recording (grabbing samples in buffers and writing them to a file - nothing UIKit related as far as I can see) has not started.
When the video recording is active, with the Stop button showing and the Start button hidden, the visible stop button isn't pressable, but the hidden start button can still be pressed.
I've tried moving the Stop button above the UIView containing the video, in case the CALayer or something else stretches outwith the clipped UIView bounds. This doesn't help. The stop button always acts as though it's not enabled - but it is enabled, and nothing appears to overlap the button. The button works fine if the UIView containing the video (which, I'll reiterate, is lower than the broken button) is never shown.
Can anyone think why this'd happen? I immediately thought about setNeedsLayout and setNeedsDisplay and tried just throwing some of those in, because it's almost as though the view had updated with my request to hide or show buttons, but an interaction layer hadn't updated.
Thanks

I now think this is due to my ignorant use (or misuse) of dispatch queues. I'm still not sure how I was able to interact with buttons that aren't showing - perhaps it's because their own state change responds in part, immediately, and the rest can't take place except on the main queue (the visual refresh, for example).
So I solved the problem, in a sense, by forcing a particular asynchronous delegate method to be called on the main queue. This doesn't affect the operation of this particular step in my recording process.

Related

Button images which are part of a Container View appear before that view is supposed to animate in

I've implemented a custom dialog box in a game (showing options when the game is paused) by using a Container View in the main game's ViewController.
That Container View has a constraint to be centered vertically and I'm using that constraint to animate this custom dialog box.
The dialog box itself is an image of a wooden board on a pole with 4 buttons, each being an image I prepared. These buttons are arranged in a vertical Stack View which contains 2 horizontal Stack Views, each with 2 buttons, so they will be laid out nicely symmetrical.
All of the above is done in Interface Builder. So a segue was automatically added from the game's main ViewController to the new Pause Dialog View Controller.
In my game's main ViewController I move the Container View out of view by adding the following to my viewDidLoad():
dialogBoxYConstraint.constant -= (view.bounds.height)
Then when the user clicks on a PAUSE button which should show this dialog, the following code is running:
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: .curveEaseInOut) {
self.dialogBoxYConstraint.constant += (self.view.bounds.height)
self.view.layoutIfNeeded()
}
}
So this code will bring the constraint's constant back to its original location and it will show the dialog box that I put inside the Container View.
When the user clicks on the PAUSE button all of this indeed happens and there's a nice animation with the wooden board and all 4 buttons fall into place and all buttons are clickable. Here's an image (disregard the small white buttons, these are temporary work-in-progress):
But, before that, before I click on the PAUSE button, I always see part of the buttons all the way on top. I see the lower 2 buttons completely and a bit of those above as in the following image:
As you can see, the wooden board isn't here, only the buttons, and when I do press the PAUSE button everything together correctly animates to the right place as in the 1st image.
(It's an AR app so you basically see my walls in the background, but that's irrelevant for this question).
Moreover, when the buttons are on top, they are not clickable.
Also, it doesn't matter if I change the constraint's constant to be even higher, say I do this:
dialogBoxYConstraint.constant -= (view.bounds.height + 500)
the buttons will always show at the same place.
And if I try to put this line in viewDidAppear then I can see the whole board with the buttons as in the first image for a second on a black background and then I get what you see in the 2nd image, which makes sense.
The above happens whether or not I've implemented the prepare(for segue: )
The segue itself is actually happening immediately as the main view is loaded, which is why I had to initially move it out of view.
As a test, I tried to set one button's isHidden to true in the Pause Dialog View Controller and then set it to false in the prepare(for segue: ), thinking that maybe that would do something, but the button remained hidden all the time.
(Side question: how should I perform such changes in this child View Controller only after the user presses the PAUSE button? Since the segue happens already from the start, I don't understand how to control such changes only later on by user action?)
I'm not sure what I'm doing wrong. Looks like a glitch, but, as always, I guess it's something I did.
I had assumed that moving the view's constraint should always move all of its contents together.
Anyone has any idea why the buttons are always there at the top?
I saw that there is a present(_:animated:completion:) method to present VC's. Should I be looking into this instead of animating the constraint as I did???
Posting this as an answer, as per the OP's comments...
It can be very difficult to debug layouts when UI element are "clear." Giving them background colors allows you to easily see the framing at run-time.
Also, Debug View Hierarchy can be very helpful, because you can inspect constraints (and even see hidden or out-of-bounds elements). Note that you may need to temporarily disable certain features - such as playing video or an active AR scene.

How to manually controll animation progress in iOS app?

I am planing a "tutorial/demo app" that should show the user how to control other apps/software by presenting a screenshot walkthrough, e.g.
Show in Screenshot1
Fade in a label above the Screenshot that tells the user "Touch this button"
Run som click/touch animation above the button
Fade in Sceenshot2
Zoom in to some area of the Screenshot
...
Creating this using basic UIView animation is not a big deal:
Start animation to show the lable
Run click/touch animation with some delay
...
However the user should be able to manually control the progress of this animation, move forward and backward, pause, etc. Just as if the presentation would be a movie that can be controlled using the timeline.
If the user does not do anything, the animation simply runs and some view (e.g. a UISlider) shows the progress. But if the user touches the slider the animation stops. By moving the slider back or forth, the user can rewind or fast forward the presentation.
How can this be done?
Stopping the animation at is no problem, but UIView animation do not have any properties to control the progress, do they?
You can try to use this framework https://github.com/IFTTT/RazzleDazzle

How do I make the elements in my UIView responsive?

My goal is to create an alert that has three text fields, one taller than the others, and an image that, when tapped, allows the user to choose a picture to replace a set default one.
After unsuccessfully searching for a library for this, I decided to create my own alert by placing a UIView off the screen and, when prompted by a button, would zoom onto the screen; it consists of all the elements I require.
When I run the application, the view pops up correctly, but none of the elements on the view are responding to touch. I've checked that isUserInteractionEnabled for everything is turned on.
What's also odd is that when I keep the view on the screen (instead of placing it some distance away on Storyboard), all the elements work fine.
I'm assuming it had something to do with the animation. I tested it with a fade in instead of a displacement, and the result was the same - the elements were unresponsive.
In order for your elements to be responsive you have to link the action of you clicking them to your view's code. You can do this in a non-programmatic manner by ctrl-clicking your element on story-views and then dragging to the view controller. Then choose action instead of outlet, and choose when the action you want will be triggered (bottom part). Then insert your code in the viewController.
So I figured it out. I used the debug view hierarchy and saw that the alert was behind the elements behind it, even though it was still being shown (for some reason). I changed the zIndex of the UIView and it worked!

iOS UISlider not moving when I swipe, even though other UI elements are fine

I've created a simple xib file with three buttons and a UISlider.
When I start the app on my phone I'm able to tap the buttons no problem, but the UISlider is locked and doesn't move..
However if I keep trying to move it with my finger it eventually scrolls left and right fine, but only after about a minute of furious screen swiping..
I thought it might be because it was hidden behind something onscreen (not that there's anything for it to hide behind) so I did 'arrange -> send to front', but this doesn't help.
Does anyone know why it might be doing this?

UIWebView freezes when text is selected

My app, on very rare occasions, freezes when I select text in a UIWebView. Here's how it happens:
Tap and hold to select text
Text gets selected
Whole app freezes, unresponsive to touch, but I can still see operatings running
May freeze for around 10s. After that the UIMenuController appears. If I try to scroll while it is freezing, the scrolling happens after the app is responsive again
If the text is still selected, it freezes again if I scroll. Happens again and again
If I managed to scroll the selected text out of the view, scrolling the rest of the webview is fine, until I scroll the selected text back
If I get out of the UIViewController containing the UIWebView, I can confirm that they are both deallocated. Go back into a new UIViewController with UIWebView and it happens again.
This continues to happen with new instances of UIWebView, and even when I close and resume the app. Only stops if I force a restart of the app.
Does anyone have any clue how I can debug this? I've never seen this in simulator. Only happens very rarely on device.
I suspect you either have set up your view hierarchy improperly, or have modified it on a thread not the main thread. So tell us exactly where the UIWebView resides (super views), and take a good look at code that modifies sub view arrays.
For instance, you don't add the web view to a UINavigationController's sub views directly, but to its view controllers array etc.
All else fails create a demo project that also displays the problem and upload it to DropBox where we can run it ourselves.

Resources