i have a game with like 48 buttons that i have in a 6 x 8 grid. the games kind of like a chess game in the layout, so its kind of important to have all those buttons. well if you can imagine a chess game that the layouts so big that i may need a vertical scroll view so that the user can scroll up and down to play the game fully. And, when i scroll i obviously don't want my navigational buttons at the top scrolling too (menu button for example). So, what i did was i made a view controller, i added a UIView, then inside the UIView i added a scroll view, and inside that scroll view i added first all my 48 buttons for my chess-like game and then my bg for that game, so that the when the user vertically scrolled not only the bg would scroll but also all the buttons too. I did all the code and everything to make my scroll view work, and then lastly i put my navigational buttons (menu, pause etc..) inside my first view i made underneath the scroll view (so that it was layered correctly)
well, after i did this my scrolling worked fine, except there was a lag when i tried to press one of my 48 buttons. This was a lag that i did not experience before i put all my buttons inside a scroll view. Before this my buttons performed fantastically, but now that they were in a scroll view, they lagged a very little bit. Like when you touch the button it takes the button about a fifth of a second to change instead of instantaneous. Its a small lag, but definitely noticeable. Yet, when i try and touch my navigational buttons (that are not embedded in a scroll view) there is no lag at all,
Did i do anything wrong by putting my buttons in a scroll view? If so, what else can i do to get my buttons to scroll without my navigational buttons scrolling.
ANY HELP IS APPRECIATED!
EDIT: I'm running this on the simulator if that makes a difference
I believe that this is something to do with responder, and the fact that both your UIButton and the UIScrollView need to know what to do with your touch.
If you put your finger on the UIButton, the UIScrollView will also see this touch. The UIScrollView is interested to know if this touch is going to turn into a drag, therefore waits to see if you move your finger. Perhaps this is blocking your UIButton from firing.
Related
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
I have created a horizontal scrollview in swift with 3 view controllers and it almost works fine except for one thing. When I scroll between view controllers, it is possible for half of one view controller to take up one half of the screen and the next view controller in the other half. I was wondering if there was any way to prevent this so that the view controllers do not get "stuck" halfway and that there will always be only one view controller displaying on the screen.
-Also on a side note I have one left and one right swipe gesture within one of the viewcontrollers in this scrollview, and I noticed that after about 7-10 swipes, the screen no longer responds to the swipe gestures(left, right). Any clues as to what could be solving this?
If anyone could answer or attempt to steer me in the right direction for solving one or both of these questions, it would be greatly appreciated.
First, you need to enable pageing for your scrollview. You should be using something like
scorllView.isPagingEnabled = true
Then most importantly, you to make this paging work, each "page" in your scroll view must has equal width with your scroll view.
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.
I'm using the great iOS control iCarousel's Wheel type and I want all of the buttons it contains to be usable / selectable at any time (i.e. I can tap any of them, no matter which one is currently at the top of the wheel). The user can still scroll the wheel as normal, but no matter which button they tap, it should register.
The current behavior seems inconsistent: if I tap one of the buttons directly next to the center one (to its left or right), that button moves into the center slot. Clicking one of the buttons two positions away 'sometimes' causes it to scroll to that letter, sometimes it's ignored. Any other buttons are always ignored.
Is this possible to set up, preferably without hugely modifying the class? I'm by no means an expert, but am learning every day :)
Thanks in advance.
Set carousel.centerItemWhenSelected = NO;
That will disable the behaviour where buttons other than the centre one are scrolled to the centre when you tap them.
As for the reason why some are not responding to taps at all, it is most likely because the frame of your carousel view is too small and the tap events are outside of the frame.
If you set carousel.clipsToBounds = YES; it will crop the carousel views to the frame as well so you'll be able to see exactly what size your carousel actually is.
I have a horizontal scroll view with paging enabled, and the children of this scroll view are vertical scroll views. It's like the iOS home screen, but imagine scrolling vertically on each home screen.
Now, when the vertical scroll is in progress, it's hard to swipe to the next or previous screen, because the vertical scroll view apparently captures the events. Even if the angle of the swipe is almost horizontal, it doesn't go to the next or previous "page". Only after the scroll stops fully can one easily swipe to the next or previous pages.
Unfortunately, because of the slow deceleration, the user might think the content stopped moving when it is in fact moving very slowly and just about to stop. But the horizontal swipe is interpreted as a vertical scroll gesture, and the scroll velocity increases, making things worse from the user's perspective.
I've noticed multiple people struggling with this when they test out our app, and I wonder if anyone here knows a solution, perhaps a way to consider the angle of the swipe to determine which scroll view should process the event. Thanks.
I would suggest stopping the vertical scroll on a touch begins event. This is how most apps I've seen do something like this.