Scroll the cells using UI Testing - ios

Is there a method like
- (void)scrollByDeltaX:(CGFloat)deltaX deltaY:(CGFloat)deltaY;
for iOS?
I think the above method is only for OSX.
I would like to scroll my tableview according to the deltavalues provided.
Thanks in advance.

On iOS, you can use XCUIElement.press(forDuration:thenDragTo:) if you want to move in terms of elements.
To move in terms of relative co-ordinates, you can get the XCUICoordinate of an element, and then use XCUICoordinate.press(forDuration:thenDragTo:).
let table = XCUIApplication().tables.element(boundBy:0)
// Get the coordinate for the bottom of the table view
let tableBottom = table.coordinate(withNormalizedOffset:CGVector(dx: 0.5, dy: 1.0))
// Scroll from tableBottom to new coordinate
let scrollVector = CGVector(dx: 0.0, dy: -30.0) // Use whatever vector you like
tableBottom.press(forDuration: 0.5, thenDragTo: tableBottom.withOffset(scrollVector))
Or in Objective-C:
XCUIApplication *app = [[XCUIApplication alloc] init];
XCUIElement *table = [app.tables elementBoundByIndex: 0];
// Get the coordinate for the bottom of the table view
XCUICoordinate *tableBottom = [table coordinateWithNormalizedOffset:CGVectorMake(0.5, 1.0)];
// Scroll from tableBottom to new coordinate
CGVector scrollVector = CGVectorMake(0.0, -30.0); // Use whatever vector you like
[tableBottom pressForDuration:0.5 thenDragToCoordinate:[tableBottom coordinateWithOffset:scrollVector]];

Oletha's answer was exactly what I was looking for but there are a couple of minor mistakes in the Objective-C example. Since the edit was rejected, I'll include it here as a reply for anyone else that comes along:
XCUIApplication *app = [[XCUIApplication alloc] init];
XCUIElement *table = [app.tables elementBoundByIndex: 0];
// Get the coordinate for the bottom of the table view
XCUICoordinate *tableBottom = [table
coordinateWithNormalizedOffset:CGVectorMake( 0.5, 1.0)];
// Scroll from tableBottom to new coordinate
CGVector scrollVector = CGVectorMake( 0.0, -30.0); // Use whatever vector you like
[tableBottom pressForDuration:0.5 thenDragToCoordinate:[tableBottom coordinateWithOffset:scrollVector]];

This Swift4 version that worked for me. Hope it helps someone in the future.
let topCoordinate = XCUIApplication().statusBars.firstMatch.coordinate(withNormalizedOffset: .zero)
let myElement = XCUIApplication().staticTexts["NameOfTextLabelInCell"].coordinate(withNormalizedOffset: .zero)
// drag from element to top of screen (status bar)
myElement.press(forDuration: 0.1, thenDragTo: topCoordinate)

Related

XCode7 UITests how to test screen edge pan gestures?

I have the following gesture recognizer in my app. I've looked at xCode7 UI and see that it has swipe up/down/left/right, but no pan or edge pan gestures.
How can one test or initiate screen edge pan gesture for UITesting purposes?
UIScreenEdgePanGestureRecognizer *leftEdgeGesture = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:#selector(show)];
leftEdgeGesture.edges = UIRectEdgeLeft;
leftEdgeGesture.delegate = self;
[self.view addGestureRecognizer:leftEdgeGesture];
I spent a while trying to figure this out, navigating around the element hierarchy. Lots and lots of googling and finding nothing.
I gave up twice, then figured it out.
We just need two coords on the main app screen, and drag one to the other.
Works a treat!
XCUIApplication *app = [[XCUIApplication alloc] init];
[app launch];
// Set a coordinate near the left-edge, we have to use normalized coords
// so you set using percentages, 1% in on the left, 15% down from the top
XCUICoordinate *coord1 = [app coordinateWithNormalizedOffset:CGVectorMake(0.01, 0.15)];
// Then second coordinate 40 points to the right
XCUICoordinate *coord2 = [coord1 coordinateWithOffset:CGVectorMake(40, 0)];
// Perform a drag from coord1 to coord2
// Simulating swipe in from left edge
[coord1 pressForDuration:0.5f thenDragToCoordinate:coord2];
Hopefully this will help everyone else who has been struggling to simulate an edge swipe.
Piggybacking on Chris' awesome answer, here's the swift version:
func pressCoordinate(x xCoordinate: Double, y yCoordinate: Double, app2call: XCUIApplication=XCUIApplication())
{
let normalized = app2call.coordinate(withNormalizedOffset: CGVector(dx: 0.01, dy: 0.5))
let coordinate = normalized.withOffset(CGVector(dx: xCoordinate, dy: yCoordinate))
normalized.press(forDuration: 0.5, thenDragTo: coordinate)
}

Tap gesture not working

I am developing an app in which user can add some icons like hat, hair on the captured picture.For this I have a image view on the screen to hold the captured image and below this I have a scrollview to display various icons that user can apply.
When I tap any icon placed inside the scroll view, I need to move this icon to the center captured picture, but when I tried it with code this sets the image to the center of the scroll view not the entire view.
But when I remove the scroll view and put the image outside the image view this works. Please suggest.
//In view Did Load
//*************************************adding gusture******************************
//SINGLETAP
UITapGestureRecognizer *singleTapGestureRecognizer_For_image15 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTapAction_For_Image_15:)];
singleTapGestureRecognizer_For_image15.numberOfTapsRequired = 1;
[self.image_15 addGestureRecognizer:singleTapGestureRecognizer_For_image15];
//DOUBLE TAP
UITapGestureRecognizer *doubleTapGestureRecognizer_For_image15 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleTapAction_For_Image_15:)];
doubleTapGestureRecognizer_For_image15.numberOfTapsRequired = 2;
[self.image_15 addGestureRecognizer:doubleTapGestureRecognizer_For_image15];
//End Image 15
//***********************************Handling Tap
//SIngle TAP
-(void)handleSingleTapAction_For_Image_15:(UITapGestureRecognizer *)handleSingleTapAction_For_Image_15{
CGSize newSize = CGSizeMake(250.0, 250.0);
CGPoint currentCenter = self.view.center;
self.image_15.frame = CGRectMake(self.image_15.frame.origin.x, self.image_15.frame.origin.y, newSize.width, newSize.height);
self.image_15.center = currentCenter;
}
//Double Tap
-(void)handleDoubleTapAction_For_Image_15:(UITapGestureRecognizer *)doubleTapGestureRecognizer_For_image15
{
CGSize newSize = CGSizeMake(40.0, 40.0);
CGPoint currentCenter = self.view.center;
self.image_15.frame = CGRectMake(self.image_15.frame.origin.x, self.image_15.frame.origin.y, newSize.width, newSize.height);
self.image_15.center = currentCenter;
}
You are setting the center of the image from the self.view's center but I think you also have to take care of the scrollview frame offset from origin. So your image_15 center should be set like
self.image_15.center = CGPointMake(currentCenter.x-yourScrollView.frame.origin.x, currentCenter.y-yourScrollView.frame.origin.y);
(provided scrollview is also a direct subview of self.view)
I can refine my answer if you provide me details about your view hierarchy incode.

Having hard time placing a UIActivityIndicator inside a UIButton

I am having some problems placing a UIActivityIndicator inside a UIButton.
Here is how it looks like:
And this is what i always get:
with this code:
self.activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
CGFloat halfButtonHeight = self.updateEventButton.bounds.size.height / 2;
CGFloat buttonWidth = self.updateEventButton.bounds.size.width;
self.activityView.center = CGPointMake(buttonWidth - halfButtonHeight , halfButtonHeight);
[self.subSubView addSubview:self.activityView];
[self.activityView startAnimating];
I want the indicator to be in the buttom of the right corner. Just look where the indicator is right now and think if you dragged it down to the button and then a little to the right.
Here is how my view is setup:
You are calculating indicator position in coordinate system tied to the button, but then add it as a subview to the different view so coordinates are incorrect. To fix that you can add indicator view to the button directly:
[self.updateEventButton addSubview:self.activityView];
Or convert point in button's coordinate system to the coordinate system of self.subSubView before setting it to activityView:
CGPoint centerInButton = CGPointMake(buttonWidth - halfButtonHeight, halfButtonHeight);
self.activityView.center = [self.updateEventButton convertPoint:centerInButton
toView:self.subSubView];

How do we rotate 2 UIView planes simultaneously in 3D space

I'm trying to create a "page flip effect" using UIView instead of CALayer due to a project limitation. This requires flipping 1 UIView 180 degrees and essentially "sticking it" to the back of the other UIView. You then rotate the two UIViews simultaneously by rotating the superview in 3D space.
I'm trying to port AFKPageFlipper's "initFlip" method to use UIView instead of UIImage.
Below is a snippet of my attempt to port it. The initial page flip works, but the "front layer" in the code doesn't seem to show up. As if I"m not able to see the backend of the page. When I'm flipping the page, the animation is initially correct (back layer is fine), but then the other side of the page (front layer), I see the inverted view of the first page (backLayer).
Any help would be awesome!
flipAnimationLayer = [[UIView alloc] init];
flipAnimationLayer.layer.anchorPoint = CGPointMake(1.0, 0.5);
flipAnimationLayer.layer.frame = rect;
[self addSubview:flipAnimationLayer];
UIView *backLayer;
UIView *frontLayer;
if (flipDirection == AFKPageFlipperDirectionRight)
{
backLayer = currentViewSnap2;
backLayer.layer.contentsGravity = kCAGravityLeft;
frontLayer = nextViewSnap2;
frontLayer.layer.contentsGravity = kCAGravityRight;
}else
{
backLayer = nextViewSnap2;
backLayer.layer.contentsGravity = kCAGravityLeft;
frontLayer= currentViewSnap2;
frontLayer.layer.contentsGravity = kCAGravityRight;
}
backLayer.frame = flipAnimationLayer.bounds;
backLayer.layer.doubleSided = NO;
backLayer.clipsToBounds = YES;
[flipAnimationLayer addSubview:backLayer];
frontLayer.frame = flipAnimationLayer.bounds;
frontLayer.layer.doubleSided = NO;
frontLayer.clipsToBounds = YES;
frontLayer.layer.transform = CATransform3DMakeRotation(M_PI, 0, 1.0, 0);
[flipAnimationLayer addSubview:frontLayer];
if (flipDirection == AFKPageFlipperDirectionRight)
{
CATransform3D transform = CATransform3DMakeRotation(0.0, 0.0, 1.0, 0.0);
transform.m34 = 1.0f / 2500.0f;
flipAnimationLayer.layer.transform = transform;
currentAngle = startFlipAngle = 0;
endFlipAngle = -M_PI;
} else
{
CATransform3D transform = CATransform3DMakeRotation(-M_PI / 1.1, 0.0, 1.0, 0.0);
transform.m34 = 1.0f / 2500.0f;
flipAnimationLayer.layer.transform = transform;
currentAngle = startFlipAngle = -M_PI;
endFlipAngle = 0;
}
Your code is rotating layers, not views. That's fine.
I would not expect the code you posted to animate, since a layer's backing view doesn't do implicit animation, You could make it animate by using a CABasicAnimation. Or, you could create layers for your front and back views and attach them as sublayers of your view's layers. If you do that than manipulating the transform on the layers will use implicit animations.
What I've done to create my own font-to-back flip as you describe is to fake it.
I animate in 2 steps: First from zero degrees (flat) to 90 degrees (where the layers become invisible.) At that moment I hide the first layer and make the second layer visible, rotated 90 degrees the other way, and then rotate the other layer back to zero. This creates the same visual effect as showing the back face of the rotation.
If you use implicit layer animation to do this you'll need to put the changes to the transform inside a CATransaction block and set the animation timing to linear, or use ease-in for the first half and ease-out for the second half. That's because animations default to ease-in,ease-out timing, and the first animation to 90 degrees will slow down at the end, and then the second 90 degree animation will ease in.

Using convertPoint to get the relative position inside a parent UIView

I've looked at a dozen SO questions on this topic, and none of the answers have worked for me. Maybe this will help get me back on the right path.
Imagine this setup:
I want to get the center coordinates of the UIButton relative to the UIView.
In other words, the UIButton center may be 215, 80 within the UITableViewCell, but relative to the UIView they should be more like 260, 165. How do I convert between the two?
Here's what I've tried:
[[self.view superview] convertPoint:button.center fromView:button]; // fail
[button convertPoint:button.center toView:self.view]; // fail
[button convertPoint:button.center toView:nil]; // fail
[button convertPoint:button.center toView:[[UIApplication sharedApplication] keyWindow]]; // fail
I could do it the hard way by looping through all of the button's superviews and adding up the x and y coordinates, but I suspect that's overkill. I just need to find the right combination of covertPoint settings. Right?
button.center is the center specified within the coordinate system of its superview, so I
assume that the following works:
CGPoint p = [button.superview convertPoint:button.center toView:self.view]
Or you compute the button's center in its own coordinate system and use that:
CGPoint buttonCenter = CGPointMake(button.bounds.origin.x + button.bounds.size.width/2,
button.bounds.origin.y + button.bounds.size.height/2);
CGPoint p = [button convertPoint:buttonCenter toView:self.view];
Swift 4+
let p = button.superview!.convert(button.center, to: self.view)
// or
let buttonCenter = CGPoint(x: button.bounds.midX, y: button.bounds.midY)
let p = button.convert(buttonCenter, to: self.view)
Swift 5.2 You need to call convert from the button, not the superview. In my case I needed width data so I converted the bounds instead of just center point. The code below works for me:
let buttonAbsoluteFrame = button.convert(button.bounds, to: self.view)
Martin answer is correct. For developers using Swift, you can get the position of an object (button, view,...) relative to the screen by using:
var p = obj.convertPoint(obj.center, toView: self.view)
println(p.x) // this prints the x coordinate of 'obj' relative to the screen
println(p.y) // this prints the y coordinate of 'obj' relative to the screen
Here is Swift 3 update of #Pablo's answer, which off course worked great in my case.
if let window = UIApplication.shared.keyWindow {
parent.convert(child.frame.origin, to: window)
}
in swift 2.2 worked for me:
var OrignTxtNomeCliente:CGPoint!
if let orign = TXT_NomeCliente.superview, let win = UIApplication.sharedApplication().keyWindow {
OrignTxtNomeCliente = orign.convertPoint(TXT_NomeCliente.frame.origin, toView: win)
}

Resources