【问题标题】:Autolayout'd control's ACTUAL position at run time?Autolayout'd 控件在运行时的实际位置?
【发布时间】:2014-10-08 03:18:31
【问题描述】:

使用 XCode 6.0.1、iOS 8。

我有一个通过自动布局/约束放置的 UIButton。

我正在尝试以编程方式添加相对于第一个按钮定位的按钮。具体来说,我将它们添加到初始按钮中心点周围的圆圈中。我用来查找新按钮坐标的数学是有效的,除了:

自动布局按钮报告它的来源是相对于 536x536 超级视图界面构建器正在使用的,而不是设备的实际屏幕尺寸。

我知道这一点是因为约束说“容器中的 X 和 Y 中心”并且它确实出现在屏幕中间,但无论设备/屏幕尺寸如何,frame.origin = (268, 268),即IB 中的视图中心 (536 / 2 = 268)。

那么有没有办法以某种方式将其转换为“实际设备坐标”而不是原始界面构建器坐标?

TIA

编辑:无论它是否居中,我都需要翻译它。我意识到我可以获取设备的屏幕尺寸,如果居中则除以 2。

Edit2:@jrturton - 它在哪里报告它在运行时的位置?什么财产?原点和中心都正确。无论如何,代码:

创建按钮:

- (void)setupButtons: (int)buttonCount
{
if ((buttonCount > MAX_BUTTONS) || (buttonCount < MIN_BUTTONS)) {
    return;
}

float totalRads = degreesToRadians(360.0);
float deltaRads = totalRads / (float)buttonCount;
float radius = 30.0f;

NSMutableArray *buttons = [[NSMutableArray alloc] init];
CGRect centerFrame = self.centerMenuButton.frame;
for (int i = 0; i < buttonCount; i++) {

    CGPoint dest = CGPointMake(
                               (radius * cosf(i * deltaRads) + centerFrame.origin.x),
                               (radius * sinf(i * deltaRads) + centerFrame.origin.y)
                               );

    CGRect frame = CGRectMake(dest.x, dest.y, 64.0, 64.0);
    UIButton *button = [[UIButton alloc] initWithFrame:frame];
    [button setImage:[UIImage imageNamed:@"pink_star"] forState:UIControlStateNormal];
    [buttons addObject:button];
}

_menuButtons = [[NSArray alloc] initWithArray:buttons];
}

并显示它们:

- (void)showMenu
{
NSLog(@"showMenu");

for (int i = 0; i < [_menuButtons count]; i++) {
    UIButton *btn = [_menuButtons objectAtIndex:i];
    NSLog(@"origin: %f, %f", btn.frame.origin.x, btn.frame.origin.y);
    [self.view addSubview:btn];
}

_menuOpen = YES;
}

我有一些 NSLogs 用于原始自动布局按钮的中心(在 IB 中设置了约束):

RadialMenuText[14125:6281339] x: 268.000000, y: 268.000000

每个按钮一个(目前 2 个):

RadialMenuText[14125:6281339] origin: 298.000000, 268.000000
RadialMenuText[14125:6281339] origin: 238.000000, 267.999997

除了舍入误差之外,数学看起来是半正确的,因为 X 坐标每次都以正确的方向移动半径。但同样 - 起始坐标不正确,因为自动布局按钮正在报告 (268, 268)。

【问题讨论】:

  • 尝试使用 Xcode 6 中内置的视图调试。当你这样做时,它会告诉你按钮在哪里以及运行时间限制和位置。这是 Apple 文档的 link,描述了使用它的基础知识。 – 大卫 L
  • 你什么时候做数学计算,你是如何定位新按钮的?我们可以看看一些代码吗?
  • 由自动布局定位的视图将在运行时报告其位置,就像其他任何视图一样。请记住,center 属性将位于按钮 superview 的坐标空间中。
  • 为我工作。让我们看一些代码。
  • 编辑您的帖子以包含创建按钮并设置其约束或位置等的代码。

标签: ios objective-c autolayout


【解决方案1】:

我猜你是从viewDidLoad 打电话给setupButtons:。这发生在视图控制器从情节提要加载其视图之后,但在系统针对当前设备和方向调整视图(及其子视图)的大小之前。

我建议您通过使用约束来定位按钮而不是设置框架来解决此问题。

除非两个视图位于同一视图层次结构中,否则不能在两个视图之间设置约束。因此,将按钮添加到setupButtons: 中的视图层次结构中,但将它们设置为隐藏。在showMenu 中,使它们可见。

- (void)setupButtons:(int)buttonCount {
    if (buttonCount > MAX_BUTTONS |buttonCount < MIN_BUTTONS) {
        return;
    }

    float totalRads = degreesToRadians(360.0);
    float deltaRads = totalRads / (float)buttonCount;
    float radius = 30.0f;

    NSMutableArray *buttons = [[NSMutableArray alloc] init];
    UIView *centerView = self.centerMenuButton;
    for (int i = 0; i < buttonCount; i++) {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.translatesAutoresizingMaskIntoConstraints = NO;
        [button setImage:[UIImage imageNamed:@"pink_star"] forState:UIControlStateNormal];
        button.hidden = YES;
        [self.view addSubview:button];
        [buttons addObject:button];

        [button addConstraint:[NSLayoutConstraint
            constraintWithItem:button attribute:NSLayoutAttributeWidth
            relatedBy:NSLayoutRelationEqual
            toItem:nil attribute:NSLayoutAttributeNotAnAttribute
            multiplier:0 constant:64]];
        [button addConstraint:[NSLayoutConstraint
            constraintWithItem:button attribute:NSLayoutAttributeHeight
            relatedBy:NSLayoutRelationEqual
            toItem:nil attribute:NSLayoutAttributeNotAnAttribute
            multiplier:0 constant:64]];

        CGFloat radians = i * 2 * M_PI / buttonCount;
        [self.view addConstraint:[NSLayoutConstraint
            constraintWithItem:button attribute:NSLayoutAttributeCenterX
            relatedBy:NSLayoutRelationEqual
            toItem:centerView attribute:NSLayoutAttributeCenterX
            multiplier:1 constant:radius * cos(radians)]];
        [self.view addConstraint:[NSLayoutConstraint
            constraintWithItem:button attribute:NSLayoutAttributeCenterY
            relatedBy:NSLayoutRelationEqual
            toItem:centerView attribute:NSLayoutAttributeCenterY
            multiplier:1 constant:radius * sin(radians)]];
    }

    _menuButtons = [buttons copy];
}

- (void)showMenu {
    NSLog(@"showMenu");

    for (int i = 0; i < _menuButtons.count; i++) {
        UIButton *btn = _menuButtons[i];
        NSLog(@"origin: %f, %f", btn.frame.origin.x, btn.frame.origin.y);
        btn.hidden = NO;
    }

    _menuOpen = YES;
}

【讨论】:

  • 这就是事情,就像一个魅力!它还解决了我在使用框架时遇到的另一个问题:可变按钮大小导致定位偏移 X 量。这也是一些关于如何在代码中而不是在 IB 中设置约束的好知识。我仍在尝试使用 Autolayout,在 IB 中我几乎已经弄清楚了——但我以前没有做过这样的事情。谢谢你,先生。你既是绅士又是学者。 :)
【解决方案2】:

NSLayoutConstraints 在layoutSubviews 之后处理。如果您从自动布局视图中删除 NSLayoutConstraints 并替换为 UIViewAutoresizingFlexible* 常量,则当您在 layoutSubviews 覆盖中调用 [super layoutSubviews] 时,按钮的框架将更新。

@jrturton 在上面关于您的中心计算也提出了一个很好的观点。如果您的投诉是被报告的中心是其超级视图中的中心,那是预期的行为。如果您想要相对于屏幕的中心,则需要使用[[UIScreen mainScreen] convertPoint:point fromView:theView] 对其进行转换。

【讨论】:

  • 约束求解器在layoutSubviews 之前运行。 -[UIView layoutSubviews] 将解决方案应用于self 的子视图。这就是为什么如果你覆盖layoutSubviews,你需要调用[super layoutSubviews]
  • 根据我的经验,layoutSubviews 返回后将应用视图约束。
猜你喜欢
  • 2013-12-27
  • 1970-01-01
  • 2023-03-08
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多