iOS View Controller is only accepting touches in a certain portion of the window - ios

I have a relatively simple dialog/popup style UIViewController that isn't behaving correctly. I have many others just like it (though each with a unique button layout) that work just fine. For some reason that I cannot figure out, this controller is only accepting touches within (approximately) the green shaded area.
Note that none of these colors are the actual colors, just placeholders. Same goes for the text.
Tapping in the "Search..." text field does nothing. Tapping on the "Cancel" button does nothing. No UI reaction whatsoever.
The tableview will scroll just fine (there are over 100 rows) if it's touched inside (approximately) the green region. Touching the tableview below the green results in no response. Same thing for the "Cats" button. It reacts when touched in approximately the top half, but nothing in the bottom half.
I've banged my head against the wall for the requisite "several hours" and am getting nowhere.

It seems that part of your view controller's view is overlapped with some "harmful" view/views. Maybe this view is created programmatically and is not visible in IB. You should start with checking your views hierarchy. Put breakpoint in your view controller's code. Somewhere, where you are sure all views (normal and harmful) are already created and type in debug area
po [self.view recursiveDescription]
you should receive something like
Now try to find harmful views. Temporarily delete some "normal" views could be a good idea.

I found my solution. I have a method that launches a dialog controller given the dialog to launch and the parent (up until this point, always a full-screen view controller). The parent gets darkened and the dialog gets launched on the center of the screen.
This one wasn't working because I was launching it from an existing dialog; I was telling the dialog launcher that the new dialog's parent was the current dialog, not the whole screen. This means that the new dialog (which is bigger than the first one) launches at the correct size, but only accepts input inside the area of the "parent" dialog, which is the smaller one underneath it.
Fix: Launch the new dialog using the current dialog's parent (which is full screen) and it works fine. The green zone on my image is the approximate size of the dialog that was being used as the parent, which is why input was only being accepted in that area.

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 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!

buttons appear on screen before SCNView

In storyboard, I have buttons attached to main view as siblings to SCNView(both buttons and SCNView are subviews of main view). At launch time, the buttons appear on screen before the SCNView does. This is quite unfortunate. Do you have any idea how to fix this?
//edit: added button programatically in viedDidLoad: as a subview of SCNView..Still the same problem.
SettingsButton and View appear before SceneView. This happens on iPhone 5,5c and lower and on iPads.(3 for sure, don't know for others)
Code for adding view programatically:
let uv = UIView(frame:myFrame)
uv.backgroundColor = UIColor.blackColor
sceneView.addSubview(uv)// scene view from storyboard
Thats it. How can iOS take 5-10s to load an app, but than rushes with adding views to the screen in an unpredictable order.. Couldn't it just take 0.2s more and present view properly? Really stupid problem
I imagine if you check via debugger breakpoints or logging in viewDidLoad, you'll find that the SCNView instance is indeed in the view hierarchy immediately.
What you're seeing is that said view's SceneKit content does not appear immediately. Depending on what you're doing with SceneKit, it may take some time to load content and prepare for rendering, and during that time the rest of the view hierarchy remains visible. That delay is probably unavoidable — you might be able to minimize it by optimizing asset formats, reducing the amount of stuff in your scene, etc. So it sounds like the key issue here is getting your app launch experience to look the way you want while accounting for the delay.
A good way to do that might be to show a splash image of some sort until SceneKit is ready to display. You could put a UIImageView in your storyboard, set up to obscure everything with a splash screen (possibly the same launch image iOS displays before your app takes over), then hide that image view (with a fade out even?) when SceneKit starts rendering.
To find out when SceneKit starts rendering, make one of your objects the scene renderer delegate and implement renderer:didRenderScene:atTime:. That method gets called on every frame, so you can use it to catch when the first frame has been rendered (and then ignore it for subsequent frames).

Preventing Sliding When Top View is Off Screen

So I've been playing around with the examples included with ECSlidingView.
In the BasicMenu Example: I've placed 20 rows in the Settings table view. When I open the menu, the table view in settings continues to slide if I touch it.
In the TransitionFun Example, the table views are not slide-able when they're not full screen.
I've looked through the code and don't see what's causing this difference. Can someone point it out to me? I have an app that pretty much started as BasicMenu and I sometimes have trouble using the pan gesture to close the menu, because I end up accidentally sliding the mostly off screen table view instead.
Thanks!
Look at setting:
slidingController.topViewAnchoredGesture = ECSlidingViewControllerAnchoredGesturePanning | ECSlidingViewControllerAnchoredGestureTapping;
such that, when the top view is anchored, tapping and panning it will both result in sliding. This eliminates the ability to otherwise interact with the top view controller contents.

clearButton not working in UITextEditField

This is one of those "it was working a while ago" troubleshooting efforts.
I'm working on the document preview view controller, in which is a scroll view, which itself contains subclasses of UIView that represent each document. I'm modeling this pretty closely to how Keynote handles its document preview, except I build my scroll view horizontally and with paging. But the standard user experience is present: Long press on a document icon causes all document icons to start jiggling, nab bar has + button and Edit button, etc.
The issue at hand is that when you tap on the name of a document, I hide all the others, move the one being edited front and center, build a new text edit field, add it as a subview atop the real name label, and set it as first responder; but the
[editNameTextField setClearButtonMode:UITextFieldViewModeWhileEditing];
while correctly showing in the edit field is not taking any action when the user taps on the clear button.
I can't figure out what I may have done to cause this to not work -- it had been!
My first thought was that somehow my instance of this subclass is no longer the delegate for this text edit field. To try and confirm/deny that, I usurped a tap on the image view of the document preview to compare the delegate property to self, and it passes.
if (editNameTextField) {
NSLog(#"editNameTextField is still active");
if ([editNameTextField.delegate isEqual:self]) {
NSLog(#"we're still the delegate for the editNameTextField");
}
}
Editing the text within the edit field works fine. Pressing the Return/Done key correctly sends the delegate message textFieldShouldReturn:
While investigating this I implemented the delegate method textFieldShouldClear: just to write a log message if the method gets called (and return YES of course). It never gets called.
My next thought was that perhaps a subview had covered up the area where the clear button sits. So I implemented textFieldShouldBeginEditing: and used the opportunity to bring my the text field to the front. That didn't change anything either. I set a debugger breakpoint there to play a sound when it was called, and it got called, so I know my text edit field is frontmost.
I have only one troubleshooting strategy remaining: Go backwards through snap shots until it starts working again. Before doing that I thought I'd see if any of the more experienced folks out here have any suggestions of what to try next.
Where are you adding the textfield? As a subview of the scrollView? If you added the textfield and it is out of bounds of its parent view it won't receive any touches.
You can try and not call becomeFirstResponder and see if clicking it will show keyboard. Another possible error might be that the parent view of the UITextField has userInteractionEnabled = NO.
Without seeing more code I'm afraid I can not offer more solutions.

Resources