UIButton not receiving IBAction - ios

I have what should be a very simple thing to do. I'm working on someone else's code, and I want to enlarge a UIButton because it's too small for users. I made it bigger in the storyboard, but when I run the app, the associated IBAction only gets hit when touching where the original rectangle was before I changed it. The button is still visibly larger, but only a portion of it receives touch events. Does anyone know what else might be at play here?
Note: there are no views on top of the new area that the button occupies, so I don't think the touches get picked up by a view on top.

Something to check is whether the UIButton has an ancestor view (i.e. a view in its superview chain) that is the smaller size. Hit-tests only pass down the view hierarchy if the touch is contained within the view so a smaller superview will stop the touches outside its bounds, even if the touch is inside the button.

Is the IBAction hooked up to "touch up inside" in Interface Builder/Storyboard? I've made mistakes where I hook it up with a different kind of event, which exhibits behaviours like you're experiencing.

Found the issue. There was a view being programmatically added on top of the button. It's origin.x was being hardcoded to where the buttons width use to end.

Related

XCUITests: Can't tap element on scrollview while views are stack on each other

Sample Project
This is a sample project that showing the issue. It's storyboard based, but method of building interface doesn't matter. It's UIViewController with UIScrollView for entire screen and 128 pts height view that is on top of this UIScrollView.
Inside scroll view there is an UIView that has 2000 pts height and UIButton in the center.
Initial State
After light scroll
At the bottom of UIScrollView
Link here: https://github.com/JakubMazur/UITestsDemo
Problem
I'm trying to tap this green button with XCUITest using app.buttons["Tap Me!"].tap()
XCUITest get identifiers from elements on screen for entire scroll view that works fine.
According to this reply on a thread on Apple Developer Forum written by Apple Framework Engineer I shouldn't scroll manually to get to the button and yes, this is partially true.
What is happening when code from (1) is executed is that button is scrolled just enough to be visible on screen but it's still not hittable, because other (purple view) is on top of UIScrollView
What is working
If I run a test written like this:
func testThatDoWorkButItsSlow() {
app.scrollViews.firstMatch.swipeUp()
app.buttons[buttonLabel].tap()
}
that is scrolling up and then looks for a button this will work, but it's slow and so inaccurate that is hardly usable.
What I cannot do
Disabling userInteractions on purple view. In real example I still need touches for this (purple) view.
Questions
Is there a way to use precise scrolling in XCTest for this case?
Or is there a way to set contentOffset scrollview to other value that will make this button more centered on a screen compared to action of tap()?
Or there is a way to fast scroll to the bottom (without animations) and maybe moving only up for each element?
My recommendation here would be to use the XCUICoordinate.press(forDuration:thenDragTo:) method to scroll.
https://developer.apple.com/documentation/xctest/xcuicoordinate/1615003-press
You can create a XCUICoordinate for the yellow view, then drag it slightly upwards to expose the button and make it hittable.
In most cases, the automatic scroll should work, but it seems like in this case a manual scroll/drag is necessary.
The UI Testing should replicate human interactions. You cannot expect from a human being to scroll "153px", you can just expect to "scroll until".
You can try something like :
while (!app.buttons["Tap Me!"].isHittable) {
app.swipeUp()
}
NB: You may also want to add a condition to leave the while loop if you can't find the button after a reasonable amount of attempts

The event can be triggered after change the frame of superview

1.Show a popup when tap a button(KLCPopup)
2.Change the height of contentView(KLCpopup) when tap the 'change frame' button,and change the height successfully
3. Tap 'change frame' button again, I want change the height again, but it does not work.
the source is in https://github.com/leogeng/LabProject.git
Who can fix it?
I can fix it but it is best you do it. Let this answer be a bit more about how to debug your application.
After a very short analysis I put a breakpoint in your button action method and found out it is only called once. So it does not resize the second time because the button is not working at all.
What the candidates for that are is the button is being tempered with in ways such as interactions disabled, it is over-layed with another view which prevents the touch events, or its superviews are not correctly sized to detect touches.
After using the view debugger (there is an icon you may use in runtime which displays the view hierarchy) I can see the black button on the blue background which is on some transparent background whose size is too small and the blue view is out of bounds.
It seems you need to resize the superview of the blue view as well.

Placing a control over a mapview iOS 7 using storyboards

I'm trying to place a button over a mapview. In storyboard I have it as the last control in the view hierarchy, the map view still covers it up. I've tried adding this line in my viewDidLoad method to bring my button view to the front but it doesnt seem to work either
[self.view bringSubviewToFront:self.flagButton];
anyone have any idea why this wouldnt be working? the map view covers most of the screen, and I want to place a few buttons on top of the map, but so far can't get them to show up, they are under it every time.
I was able to do this by making my view as subview of map view.
first,
self.view = self.gmsMapView;
then,
[self.gmsMapView addSubview:_myBtnView];
I know this is an old post, but I'm answering for the sake of someone facing the same problem.
I was having the same issue, then I found a solution, and is as follows:
First, open your project and go to your StoryBoard then click on "Show Document Outline" switch that is on bottom left very small switch. After that select your "Scene" that you are having problems with then click "View". Find your MKMapView object and drag it up until you reach the first row. This will make your MKMapView object (or any other) "the first in a layer" so to speak.
I hope someone will find this helpful.
E
I was using storyboards and was not seeing the button. I had to set the MKMapView to hidden until the button was displayed and in position. Then I set the MKMapView to visible.
Here are the steps I had to take in the interface builder to get my button to show
Create a UIViewController which contains a view
Add an MKMapView and set constraints
Add UIButton in the same view as the MKMapView, set the image and text, whatever is applicable. If MKMapView disappear when you try to resize or move the button, the map view has just set its width and height to zero. Enter new values in the Size Inspector for the map view and it will resize back. Or you can move the button elsewhere off the MKMapView and then move the button back to where you want it.
The important part is to set constraints for the UIButton. I also had to set the MKMapView hidden until I got the size and placement right and then set it back to visible.
Here's how it looks in the simulator
You can't add a subview to an MKMapView via the storyboard. Add it as a sibling view instead.
Edit: Your map view should also be a subview of the root view (i.e. self.view) for this to work.
I was having similar issues and I did the following:
Made sure both the map view and the button are at the same level in the view hierarchy, I accomplished this by creating a View that both the map view and button were children of.
Made sure the button is dragged below the map view in the left gutter of the storyboard (so it is actually rendered on top).
Made sure there were valid constraints for the button.
The only thing new that hasn't already been mentioned was double-checking the constraints, and that appeared to resolve it for me. Hope that helps.

Set "Touchable" area of UIScrollView

I have a main menu with a list of buttons. On the bottom I have a bar that the user can flick up to the top via a scrollview. Whats underneath that bar however is a uiwebview. So when the user tries to scroll in the uiwebview, the bar and webview just snaps back down. Also, the uibuttons won't work when the bar is down because the scrollview is sitting over them. How do i make the scroll only work when the user touches the bar and make the buttons on my menu work when the bar is down?
Thanks in Advance!
Where you want the scrollView to "work" (maybe when user flicks the bar up) have the following code:
scrollView.userInteractionEnabled = YES;
and wherever you don't want the scrollView to register any user actions (like when the bar is down) just do the opposite and set it to NO.
So if I understand correctly, you want the UIScrollView to respond to touches in only a certain part of the frame (the bar)?
I would suggest taking a look at one of my previous answers to a similar problem, here.
In particular, see:
This answer to the SO question Touch and pull down a view. It uses the hitTest:withEvent: method to determine whether the scrollview responds to a touch or leaves it for the view under it to respond to.
This answer to the question Drag Down UIView in iOS 5 works in a similar way, using pointInside:withEvent: to make the UIScrollView only respond to touches in a given area.
This answer to the question Event handling for iOS - how hitTest:withEvent: and pointInside:withEvent: are related? gives a good overview of how hitTest:withEvent: and pointInside:withEvent: work together.

Propagate dragging touch to UIScrollView superview

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.

Resources