如何在设备旋转后以编程方式创建的 UIButtons 保持在屏幕底部?

Posted

技术标签:

【中文标题】如何在设备旋转后以编程方式创建的 UIButtons 保持在屏幕底部?【英文标题】:How to keep programmatically created UIButtons at the bottom of the screen after device rotation? 【发布时间】:2014-02-02 09:34:40 【问题描述】:

出于某种原因,我必须以编程方式而不是在 .xib/.storyboard 文件中创建两个 UIButton,并且我希望它们始终位于屏幕底部。我发现如果我想让按钮处于完全相同的位置,如果它们是在 Interface Builder 中创建的,我必须像这样定义它们的框架:

CGRect captureCodeFrame = [[self captureCodeButton] frame];
CGRect captureReceiptFrame = [[self captureReceiptButton] frame];

captureCodeFrame.origin.x = MARGIN;
captureCodeFrame.origin.y = [[UIScreen mainScreen] bounds].size.height - [[UIApplication sharedApplication] statusBarFrame].size.height - [[[self navigationController] navigationBar] frame].size.height - BUTTON_HEIGHT - MARGIN;
captureReceiptFrame.origin.x = [[UIScreen mainScreen] bounds].size.width - BUTTON_WIDTH - MARGIN;
captureReceiptFrame.origin.y = [[UIScreen mainScreen] bounds].size.height - [[UIApplication sharedApplication] statusBarFrame].size.height - [[[self navigationController] navigationBar] frame].size.height - BUTTON_HEIGHT - MARGIN;

[[self captureCodeButton] setFrame:captureCodeFrame];
[[self captureReceiptButton] setFrame:captureReceiptFrame];

换句话说,我基本上是取整个屏幕的高度,减去状态和导航栏的高度,然后这些按钮的高度和屏幕底端的空间来设置Y坐标两个按钮。我正在使用类似的技术来确定右侧按钮的X 坐标。三个宏定义如下:

#define MARGIN 20
#define BUTTON_HEIGHT 30
#define BUTTON_WIDTH 136

最后,我有方法(void)didRotate:(NSNotification *)notification,每当用户旋转设备时都会调用该方法,并且我知道我需要为按钮设置新框架以供他们重绘(或者我可以吗?也许它是通过一些转换来完成的? ) 但无论我尝试将新框架分配给什么值,我都无法正确处理。我最近的尝试是这样的(缩短为仅包括左横向模式):

- (void)didRotate:(NSNotification *)notification

    UIDeviceOrientation deviceOrientation = [[UIDevice currentDevice] orientation];
    CGSize newSize = [[self view] bounds].size;
    CGRect captureCodeFrame = [[self captureCodeButton] frame];
    CGRect captureReceiptFrame = [[self captureReceiptButton] frame];

    [CATransaction begin];
    [CATransaction setAnimationDuration:0.0];
    [CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];

    [[self previewLayer] setPosition:CGPointMake(0.5 * newSize.width, 0.5 * newSize.height)];

    switch (deviceOrientation)
    
        case UIDeviceOrientationPortrait:
            captureCodeFrame.origin.x = MARGIN;
            captureCodeFrame.origin.y = [[UIScreen mainScreen] bounds].size.height - [[UIApplication sharedApplication] statusBarFrame].size.height - [[[self navigationController] navigationBar] frame].size.height - BUTTON_HEIGHT - MARGIN;
            captureReceiptFrame.origin.x = [[UIScreen mainScreen] bounds].size.width - BUTTON_WIDTH - MARGIN;
            captureReceiptFrame.origin.y = [[UIScreen mainScreen] bounds].size.height - [[UIApplication sharedApplication] statusBarFrame].size.height - [[[self navigationController] navigationBar] frame].size.height - BUTTON_HEIGHT - MARGIN;

            [[self captureCodeButton] setFrame:captureCodeFrame];
            [[self captureReceiptButton] setFrame:captureReceiptFrame];
            [[self view] setTransform:CGAffineTransformMakeRotation(0)];
            [[self previewLayer] setAffineTransform:CGAffineTransformMakeRotation(0)];
            break;
        case UIDeviceOrientationLandscapeLeft:
            captureCodeFrame.origin.x = [[UIScreen mainScreen] bounds].size.width - BUTTON_WIDTH - MARGIN;
            captureCodeFrame.origin.y = MARGIN;
            // TODO: adjust captureReceiptFrame here

            [[self captureCodeButton] setFrame:captureCodeFrame];
            [[self view] setTransform:CGAffineTransformMakeRotation((CGFloat) (M_PI / 2))];
            [[self previewLayer] setAffineTransform:CGAffineTransformMakeRotation((CGFloat) (-M_PI / 2))];
            break;
        case UIDeviceOrientationLandscapeRight:
            // TODO: something should be here
            [[self view] setTransform:CGAffineTransformMakeRotation((CGFloat) (-M_PI / 2))];
            [[self previewLayer] setAffineTransform:CGAffineTransformMakeRotation((CGFloat) (M_PI / 2))];
            break;
        default:
            break;
    

    [CATransaction commit];

但无论我尝试为origin.xorigin.y 分配什么值,按钮总是出现在屏幕外或完全奇怪的位置。奇怪的是,如果我为这两个属性都设置了100 的值,则按钮不会出现在距屏幕左上角大约 100 点的位置,而是在我看来完全随机的地方。似乎我不知道当设备旋转时坐标系会发生什么……嗯……这就是我想请你介入并保存我的应用程序的地方! :-)

PS:状态和导航栏从纵向(客户需求,客户获得)保持在其位置,这就是为什么它们不包括在新的原点计算中。

【问题讨论】:

你在使用自动布局吗?可能是负责任的。 在这个应用程序中没有任何地方(我还没有习惯“新”技术,即故事板和自动布局,没有时间阅读它们,并且不建议使用它们)我工作的公司因为其他程序员处于同样的情况——没有时间阅读新东西),加上这个视图控制器显然没有附加.xib,它主要只是相机输出(在AVCaptureVideoPreviewLayer层) 和这两个按钮。 另外,如果您缺少 .xib 并以编程方式创建所有内容,我什至不确定您是否可以使用自动布局?不知道:o UIView autoresizingMask - Interface Builder to Code - Programmatically create struts and springs的可能重复 【参考方案1】:

您需要为您的按钮设置适当的 UIViewAutoresizingMask 看到这个answer

【讨论】:

我明白了,我是否正确地认为左侧按钮的正确掩码是UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin,因为我希望按钮扩大宽度并保持在屏幕的左下角?它以某种方式起作用,但现在按钮在纵向模式下绝对距离屏幕底部超过 20 点。我想知道约束是否可以解决这个问题…… 如果答案在另一个问题中可用,最好将此问题标记为重复。

以上是关于如何在设备旋转后以编程方式创建的 UIButtons 保持在屏幕底部?的主要内容,如果未能解决你的问题,请参考以下文章

旋转后不采用 Swift 约束

定义状态变量后以编程方式推送视图

以编程方式创建UIView,在旋转设备时保留其大小

UITableView 滚动后以编程方式创建的 UITableViewCell 未正确显示

快速以编程方式创建后如何在情节提要中链接 UIButton

如何向放置在 UIStackView 中的以编程方式创建的 UIButton 添加约束