Skip to content
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
ce34bf2
feat: add currentDisplayId setting for screenshots
jsteinberg7 Sep 25, 2026
d8cf1b8
chore: remove boolean check from currentDisplayId validation
jsteinberg7 Sep 25, 2026
35d9e85
feat: target the currentDisplayId display with W3C actions
jsteinberg7 Sep 25, 2026
4f152bc
fix: validate display settings and report available ids
jsteinberg7 Sep 28, 2026
5505557
Merge branch 'feat/current-display-id' into feat/current-display-id-a…
jsteinberg7 Sep 28, 2026
e1b1bda
test: fix available-display assertion syntax
jsteinberg7 Sep 28, 2026
05636fb
refactor: clarify the display coordinate correction
jsteinberg7 Sep 28, 2026
1070044
Merge branch 'feat/current-display-id' into feat/current-display-id-a…
jsteinberg7 Sep 28, 2026
3eb77b9
Merge branch 'master' into feat/current-display-id-actions
KazuCocoa Sep 30, 2026
1dce81f
feat: support Duo hinge control and secondary display capture
KazuCocoa Oct 3, 2026
c3f54e2
Merge #1269 as the basis for Duo display gestures
KazuCocoa Oct 3, 2026
16a38f3
fix: align element actions and scrolling on secondary displays
KazuCocoa Oct 3, 2026
85dd686
remove simulator only logic, temporary implementation
KazuCocoa Oct 3, 2026
db7aa9a
add get
KazuCocoa Oct 3, 2026
f0b1617
refactor a bit
KazuCocoa Oct 3, 2026
b320215
refactor: separate hinge capabilities and delegate screen lookup
KazuCocoa Oct 3, 2026
91baed9
fix: guard display APIs for older XCTest versions
KazuCocoa Oct 3, 2026
b655bf2
refactor: name hinge timeout and document runtime loading
KazuCocoa Oct 3, 2026
44ab7ce
docs: explain why hinge events bypass the existing HID helper
KazuCocoa Oct 3, 2026
feeb4d1
revert unnecessary chnages in the readme
KazuCocoa Oct 3, 2026
540e774
Merge branch 'fix/duo-display-app-detection' into fix/duo-display-ges…
KazuCocoa Oct 3, 2026
4c69596
refactor: unify display checks and scroll geometry
KazuCocoa Oct 3, 2026
858e143
Merge branch 'master' into fix/duo-display-gestures
KazuCocoa Oct 4, 2026
0045f94
Merge branch 'master' into fix/duo-display-gestures
KazuCocoa Oct 6, 2026
ecb650b
fix: guard scrolling orientation APIs on watchOS (#1294)
KazuCocoa Oct 6, 2026
86ae3a1
fix: preserve display-independent actions and correct landscape scrol…
KazuCocoa Oct 6, 2026
451fe29
refactor: clarify display validation and action synthesis stages
KazuCocoa Oct 6, 2026
947cc2a
test: preserve shared alert fixture in display-independent action test
KazuCocoa Oct 6, 2026
5ed90c8
fix: anchor native Duo coordinates to application windows (#1292)
KazuCocoa Oct 7, 2026
8045b49
Merge branch 'master' into fix/duo-display-gestures
KazuCocoa Oct 7, 2026
1b82530
docs: document legacy SDK coordinate limitations on Duo
KazuCocoa Oct 7, 2026
56a9dd5
test: wait for rotated gesture fixture geometry to settle
KazuCocoa Oct 7, 2026
44cfddc
docs: record verified Duo simulator capture and layout limitations
KazuCocoa Oct 7, 2026
c0765ed
fix: normalize portrait geometry for landscape-native screens
KazuCocoa Oct 7, 2026
5f4fa77
fix: align application origins on secondary displays
KazuCocoa Oct 7, 2026
1f944b5
fix: preserve native gesture edge coordinates
KazuCocoa Oct 7, 2026
5898cb6
shorten
KazuCocoa Oct 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
WebDriverAgent is a [WebDriver server](https://w3c.github.io/webdriver/webdriver-spec.html) implementation for iOS that can be used to remote control iOS devices. It allows you to launch & kill applications, tap & scroll views or confirm view presence on a screen. This makes it a perfect tool for application end-to-end testing or general purpose device automation. It works by linking `XCTest.framework` and calling Apple's API to execute commands directly on a device. WebDriverAgent is developed for end-to-end testing and is successfully adopted by [Appium](http://appium.io) via [XCUITest driver](https://github.com/appium/appium-xcuitest-driver).

## Features
* Both iOS and tvOS platforms are supported with devices & simulators
* Implements most of [WebDriver Spec](https://w3c.github.io/webdriver/webdriver-spec.html)
* Implements part of [Mobile JSON Wire Protocol Spec](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md)
* USB support for devices is implemented via [appium-ios-device](https://github.com/appium/appium-ios-device) library and has zero dependencies on third-party tools.
* Easy development cycle as it can be launched & debugged directly via Xcode
* Use [Mac2Driver](https://github.com/appium/appium-mac2-driver) to automate macOS apps
* Both iOS and tvOS platforms are supported with devices & simulators
* Implements most of [WebDriver Spec](https://w3c.github.io/webdriver/webdriver-spec.html)
* Implements part of [Mobile JSON Wire Protocol Spec](https://github.com/SeleniumHQ/mobile-spec/blob/master/spec-draft.md)
* USB support for devices is implemented via [appium-ios-device](https://github.com/appium/appium-ios-device) library and has zero dependencies on third-party tools.
* Easy development cycle as it can be launched & debugged directly via Xcode
* Use [Mac2Driver](https://github.com/appium/appium-mac2-driver) to automate macOS apps

## Getting Started On This Repository

Expand All @@ -35,20 +35,21 @@ See [Hinge angle](docs/hinge-angle.md) for reading angles, sending simulated hin
events, runtime requirements, and physical-device testing feedback.

## Known Issues

If you are having some issues please checkout [wiki](https://github.com/facebook/WebDriverAgent/wiki/Common-Issues) first.

## For Contributors

If you want to help us out, you are more than welcome to. However please make sure you have followed the guidelines in [CONTRIBUTING](CONTRIBUTING.md).

## Creating Bundles

`npm run bundle`

Then, you find `WebDriverAgentRunner-Runner-sim-<version>.zip` for iOS and `WebDriverAgentRunner-Runner-tv_sim-<version>.zip` for tvOS files in the current directory.
Then, you find `WebDriverAgentRunner-Runner-sim-<version>.zip` for iOS and `WebDriverAgentRunner-Runner-tv_sim-<version>.zip` for tvOS files in the current directory.

## License

[`WebDriverAgent` is BSD-licensed](LICENSE).


Have fun!
4 changes: 4 additions & 0 deletions WebDriverAgent.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,7 @@
715AFAC11FFA29180053896D /* FBScreen.h in Headers */ = {isa = PBXBuildFile; fileRef = 715AFABF1FFA29180053896D /* FBScreen.h */; };
715AFAC21FFA29180053896D /* FBScreen.m in Sources */ = {isa = PBXBuildFile; fileRef = 715AFAC01FFA29180053896D /* FBScreen.m */; };
715AFAC41FFA2AAF0053896D /* FBScreenTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 715AFAC31FFA2AAF0053896D /* FBScreenTests.m */; };
8EB95DF348A9438BBEAB4501 /* FBDisplayGestureTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EB95DF348A9438BBEAB4502 /* FBDisplayGestureTests.m */; };
715D554B2229891B00524509 /* FBExceptionHandlerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 715D554A2229891B00524509 /* FBExceptionHandlerTests.m */; };
715D5773224DE02E00DA2D99 /* libxml2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 716C9345224D540C004B8542 /* libxml2.tbd */; };
715D5774224DE05400DA2D99 /* libxml2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 716C9345224D540C004B8542 /* libxml2.tbd */; };
Expand Down Expand Up @@ -1627,6 +1628,7 @@
715AFABF1FFA29180053896D /* FBScreen.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBScreen.h; sourceTree = "<group>"; };
715AFAC01FFA29180053896D /* FBScreen.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBScreen.m; sourceTree = "<group>"; };
715AFAC31FFA2AAF0053896D /* FBScreenTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBScreenTests.m; sourceTree = "<group>"; };
8EB95DF348A9438BBEAB4502 /* FBDisplayGestureTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBDisplayGestureTests.m; sourceTree = "<group>"; };
715D554A2229891B00524509 /* FBExceptionHandlerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FBExceptionHandlerTests.m; sourceTree = "<group>"; };
71649EC82518C19C0087F212 /* IOSTestSettings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = IOSTestSettings.xcconfig; sourceTree = "<group>"; };
716C9342224D53A1004B8542 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/AppleTVOS.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
Expand Down Expand Up @@ -2704,6 +2706,7 @@
7119E1EB1E891F8600D0B125 /* FBPickerWheelSelectTests.m */,
71ACF5B7242F2FDC00F0AAD4 /* FBSafariAlertTests.m */,
715AFAC31FFA2AAF0053896D /* FBScreenTests.m */,
8EB95DF348A9438BBEAB4502 /* FBDisplayGestureTests.m */,
EE55B3261D1D54CF003AAAEC /* FBScrollingTests.m */,
7152EB2F1F41F9960047EEFF /* FBSessionIntegrationTests.m */,
EE26409A1D0EB5E8009BE6B0 /* FBTapTest.m */,
Expand Down Expand Up @@ -4861,6 +4864,7 @@
719CD8FF2126C90200C7D0C2 /* FBAutoAlertsHandlerTests.m in Sources */,
EE2202131ECC612200A29571 /* FBIntegrationTestCase.m in Sources */,
715AFAC41FFA2AAF0053896D /* FBScreenTests.m in Sources */,
8EB95DF348A9438BBEAB4501 /* FBDisplayGestureTests.m in Sources */,
71BB58EC2B96328700CB9BFE /* FBScreenRecordingRequest.m in Sources */,
EE22021E1ECC618900A29571 /* FBTapTest.m in Sources */,
71930C472066434000D3AFEC /* FBPasteboardTests.m in Sources */,
Expand Down
77 changes: 61 additions & 16 deletions WebDriverAgentLib/Categories/XCUIElement+FBScrolling.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
#import "XCUIElement+FBScrolling.h"

#import "FBErrorBuilder.h"
#import "FBExceptions.h"
#import "FBLogger.h"
#import "FBScreen.h"
#import "FBMacros.h"
#import "FBMathUtils.h"
#import "FBXCodeCompatibility.h"
Expand All @@ -20,6 +22,7 @@
#import "XCUIElement+FBUID.h"
#import "XCUIApplication.h"
#import "XCUICoordinate.h"
#import "XCUIScreen.h"
#import "XCUIElement+FBIsVisible.h"
#import "XCUIElement+FBVisibleFrame.h"
#import "XCUIElement.h"
Expand All @@ -35,14 +38,44 @@

#if !TARGET_OS_TV

static XCUIScreen *FBScreenForScrolling(void)
{
NSError *error = nil;
XCUIScreen *screen = [FBScreen currentScreenWithError:&error];
if (nil == screen) {
// Match active-app detection: never continue on a different coordinate space
// when the selected display is unavailable, including for void scroll APIs.
@throw [NSException exceptionWithName:FBInvalidArgumentException
Comment thread
KazuCocoa marked this conversation as resolved.
Resolved
reason:error.localizedDescription
userInfo:nil];
}
return screen;
}

static CGRect FBScrollFrameInApplication(CGRect frame, XCUIScreen *screen,
XCUIApplication *application)
{
#if !TARGET_OS_WATCH
if (screen.displayID != XCUIScreen.mainScreen.displayID) {
Comment thread
KazuCocoa marked this conversation as resolved.
Resolved
// On secondary displays, XCTest's visibleFrame is in portrait screen
// coordinates, whereas wdFrame uses the application's current orientation.
// Rotate the clipped visible rect before normalizing it against the anchor.
CGSize size = CGSizeMake(CGRectGetWidth(screen.bounds) / screen.scale,
CGRectGetHeight(screen.bounds) / screen.scale);
frame = FBRectFromPortraitCoordinates(frame, size, application.interfaceOrientation);
}
#endif
return frame;
}

@interface FBXCElementSnapshotWrapper (FBScrolling)

- (BOOL)fb_scrollUpByNormalizedDistance:(CGFloat)distance anchorElement:(XCUIElement *)anchorElement;
- (BOOL)fb_scrollDownByNormalizedDistance:(CGFloat)distance anchorElement:(XCUIElement *)anchorElement;
- (BOOL)fb_scrollLeftByNormalizedDistance:(CGFloat)distance anchorElement:(XCUIElement *)anchorElement;
- (BOOL)fb_scrollRightByNormalizedDistance:(CGFloat)distance anchorElement:(XCUIElement *)anchorElement;
- (BOOL)fb_scrollByNormalizedVector:(CGVector)normalizedScrollVector anchorElement:(XCUIElement *)anchorElement;
- (BOOL)fb_scrollByVector:(CGVector)vector anchorElement:(XCUIElement *)anchorElement error:(NSError **)error;
- (BOOL)fb_scrollByVector:(CGVector)vector inFrame:(CGRect)frame anchorElement:(XCUIElement *)anchorElement error:(NSError **)error;

@end

Expand Down Expand Up @@ -126,6 +159,7 @@ - (BOOL)fb_scrollToVisibleWithNormalizedScrollDistance:(CGFloat)normalizedScroll
scrollDirection:(FBXCUIElementScrollDirection)scrollDirection
error:(NSError **)error
{
FBScreenForScrolling();
FBXCElementSnapshotWrapper *prescrollSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:[self fb_customSnapshot]];

if (prescrollSnapshot.isWDVisible) {
Expand Down Expand Up @@ -260,13 +294,17 @@ - (BOOL)fb_scrollToVisibleWithNormalizedScrollDistance:(CGFloat)normalizedScroll
// Trying fb_cachedSnapshot first
FBXCElementSnapshotWrapper *targetCellSnapshotWrapped = [FBXCElementSnapshotWrapper ensureWrapped:[self fb_customSnapshot]];
targetCellSnapshot = [targetCellSnapshotWrapped fb_parentCellSnapshot];
CGRect visibleFrame = [FBXCElementSnapshotWrapper ensureWrapped:targetCellSnapshot].fb_visibleFrame;
XCUIScreen *screen = FBScreenForScrolling();
CGRect visibleFrame = FBScrollFrameInApplication(
[FBXCElementSnapshotWrapper ensureWrapped:targetCellSnapshot].fb_visibleFrame, screen, self.application);

CGVector scrollVector = CGVectorMake(visibleFrame.size.width - targetCellSnapshot.frame.size.width,
visibleFrame.size.height - targetCellSnapshot.frame.size.height
);
scrollViewWrapped = [FBXCElementSnapshotWrapper ensureWrapped:[scrollViewElement fb_customSnapshot]];
CGRect scrollingFrame = FBScrollFrameInApplication(scrollViewWrapped.visibleFrame, screen, self.application);
return [scrollViewWrapped fb_scrollByVector:scrollVector
inFrame:scrollingFrame
anchorElement:scrollViewElement
error:error];
}
Expand Down Expand Up @@ -296,9 +334,10 @@ - (BOOL)fb_isEquivalentElementSnapshotVisible:(id<FBXCElementSnapshot>)snapshot

@implementation FBXCElementSnapshotWrapper (FBScrolling)

- (CGRect)scrollingFrame
- (CGRect)scrollingFrameWithAnchor:(XCUIElement *)anchorElement
{
return self.visibleFrame;
XCUIScreen *screen = FBScreenForScrolling();
return FBScrollFrameInApplication(self.visibleFrame, screen, anchorElement.application);
}

- (BOOL)fb_scrollUpByNormalizedDistance:(CGFloat)distance
Expand Down Expand Up @@ -328,34 +367,40 @@ - (BOOL)fb_scrollRightByNormalizedDistance:(CGFloat)distance
- (BOOL)fb_scrollByNormalizedVector:(CGVector)normalizedScrollVector
anchorElement:(XCUIElement *)anchorElement
{
CGVector scrollVector = CGVectorMake(CGRectGetWidth(self.scrollingFrame) * normalizedScrollVector.dx,
CGRectGetHeight(self.scrollingFrame) * normalizedScrollVector.dy
CGRect frame = [self scrollingFrameWithAnchor:anchorElement];
CGVector scrollVector = CGVectorMake(CGRectGetWidth(frame) * normalizedScrollVector.dx,
CGRectGetHeight(frame) * normalizedScrollVector.dy
);
return [self fb_scrollByVector:scrollVector anchorElement:anchorElement error:nil];
return [self fb_scrollByVector:scrollVector inFrame:frame anchorElement:anchorElement error:nil];
}

- (BOOL)fb_scrollByVector:(CGVector)vector
inFrame:(CGRect)frame
anchorElement:(XCUIElement *)anchorElement
error:(NSError **)error
{
CGVector scrollBoundingVector = CGVectorMake(
CGRectGetWidth(self.scrollingFrame) * FBScrollTouchProportion,
CGRectGetHeight(self.scrollingFrame) * FBScrollTouchProportion
);
scrollBoundingVector.dx = (CGFloat)floor(copysign(scrollBoundingVector.dx, vector.dx));
scrollBoundingVector.dy = (CGFloat)floor(copysign(scrollBoundingVector.dy, vector.dy));

NSInteger preciseScrollAttemptsCount = 20;
CGVector CGZeroVector = CGVectorMake(0, 0);
BOOL shouldFinishScrolling = NO;
while (!shouldFinishScrolling) {
CGVector scrollBoundingVector = CGVectorMake(
(CGFloat)floor(copysign(CGRectGetWidth(frame) * FBScrollTouchProportion, vector.dx)),
(CGFloat)floor(copysign(CGRectGetHeight(frame) * FBScrollTouchProportion, vector.dy)));
CGVector scrollVector = CGVectorMake(fabs(vector.dx) > fabs(scrollBoundingVector.dx) ? scrollBoundingVector.dx : vector.dx,
fabs(vector.dy) > fabs(scrollBoundingVector.dy) ? scrollBoundingVector.dy : vector.dy);
vector = CGVectorMake(vector.dx - scrollVector.dx, vector.dy - scrollVector.dy);
shouldFinishScrolling = FBVectorFuzzyEqualToVector(vector, CGZeroVector, 1) || --preciseScrollAttemptsCount <= 0;
if (![self fb_scrollAncestorScrollViewByVectorWithinScrollViewFrame:scrollVector anchorElement:anchorElement error:error]){
if (![self fb_scrollAncestorScrollViewByVectorWithinScrollViewFrame:scrollVector
inFrame:frame
anchorElement:anchorElement
error:error]) {
return NO;
}
if (!shouldFinishScrolling) {
// Share geometry within a drag, but allow the next drag to observe rotation
// or display changes that occurred while the previous drag was executing.
frame = [self scrollingFrameWithAnchor:anchorElement];
Comment thread
KazuCocoa marked this conversation as resolved.
Resolved
}
}
return YES;
}
Expand All @@ -370,10 +415,10 @@ - (CGVector)fb_normalizedHitPointOffsetForScrollingVector:(CGVector)scrollingVec
}

- (BOOL)fb_scrollAncestorScrollViewByVectorWithinScrollViewFrame:(CGVector)vector
inFrame:(CGRect)scrollingFrame
anchorElement:(XCUIElement *)anchorElement
error:(NSError **)error
{
CGRect scrollingFrame = self.scrollingFrame;
// wdFrame matches scrollingFrame's coordinate space; raw .frame can be pre-scaled or
// dimension-swapped and drift out of sync with it (appium/appium#16185).
CGRect anchorFrame = anchorElement.wdFrame;
Expand Down
11 changes: 11 additions & 0 deletions WebDriverAgentLib/Utilities/FBMathUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,19 @@ BOOL FBSizeFuzzyEqualToSize(CGSize size1, CGSize size2, CGFloat threshold);
BOOL FBRectFuzzyEqualToRect(CGRect rect1, CGRect rect2, CGFloat threshold);

#if !TARGET_OS_TV && !TARGET_OS_WATCH
/*! Converts a portrait-screen rect into the application's orientation, preserving its clipping. */
CGRect FBRectFromPortraitCoordinates(CGRect frame, CGSize screenSize, UIInterfaceOrientation orientation);

/*! Inverts size if necessary to match current screen orientation */
CGSize FBAdjustDimensionsForApplication(CGSize actualSize, UIInterfaceOrientation orientation);

/*!
Offsets XCTest screenPoint coordinates for an explicitly selected display.
XCTest rotates these coordinates using the main screen's dimensions even when
the synthesized event record targets another display. Sizes are in points.
*/
CGVector FBDisplayCoordinateOffset(CGSize mainSize, CGSize displaySize,
UIInterfaceOrientation orientation);
#endif

#if !TARGET_OS_TV
Expand Down
38 changes: 38 additions & 0 deletions WebDriverAgentLib/Utilities/FBMathUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,27 @@ BOOL FBRectFuzzyEqualToRect(CGRect rect1, CGRect rect2, CGFloat threshold)

#if !TARGET_OS_TV && !TARGET_OS_WATCH

CGRect FBRectFromPortraitCoordinates(CGRect frame, CGSize screenSize, UIInterfaceOrientation orientation)
{
if (CGRectIsEmpty(frame)) {
return frame;
}
CGFloat width = MIN(screenSize.width, screenSize.height);
CGFloat height = MAX(screenSize.width, screenSize.height);
switch (orientation) {
case UIInterfaceOrientationLandscapeLeft:
return CGRectMake(height - CGRectGetMaxY(frame), CGRectGetMinX(frame), frame.size.height, frame.size.width);
case UIInterfaceOrientationLandscapeRight:
return CGRectMake(CGRectGetMinY(frame), width - CGRectGetMaxX(frame), frame.size.height, frame.size.width);
case UIInterfaceOrientationPortraitUpsideDown:
return CGRectMake(width - CGRectGetMaxX(frame), height - CGRectGetMaxY(frame), frame.size.width, frame.size.height);
case UIInterfaceOrientationUnknown:
case UIInterfaceOrientationPortrait:
default:
return frame;
}
}

CGSize FBAdjustDimensionsForApplication(CGSize actualSize, UIInterfaceOrientation orientation)
{
if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
Expand Down Expand Up @@ -107,3 +128,20 @@ BOOL FBScrollGestureOffsets(CGRect scrollingFrame,
(endPoint.y - anchorFrame.origin.y) / anchorFrame.size.height);
return YES;
}

#if !TARGET_OS_TV && !TARGET_OS_WATCH
CGVector FBDisplayCoordinateOffset(CGSize mainSize, CGSize displaySize,
UIInterfaceOrientation orientation)
{
CGVector offset = CGVectorMake(0, 0);
if (orientation == UIInterfaceOrientationLandscapeRight
|| orientation == UIInterfaceOrientationPortraitUpsideDown) {
offset.dx = displaySize.width - mainSize.width;
}
if (orientation == UIInterfaceOrientationLandscapeLeft
|| orientation == UIInterfaceOrientationPortraitUpsideDown) {
offset.dy = displaySize.height - mainSize.height;
}
return offset;
}
#endif
Loading
Loading