代码之家  ›  专栏  ›  技术社区  ›  Mark

iPhone/iPad定向处理

  •  34
  • Mark  · 技术社区  · 15 年前

    这是一个更为普遍的问题,让人们为我提供指导,基本上我在学习ipad/iphone开发,并最终遇到了多方位的支持问题。

    我已经查阅了相当多的doco,我的书《开始iPhone3开发》有一个很好的章节。

    但我的问题是,如果我要通过编程改变我的控件(或者甚至对每个方向使用不同的视图),到底如何让人们维护他们的代码库?我可以想象意大利面条代码有这么多问题,成千上万的“如果”检查遍布各地,这会让我抓狂做一个小的改变,用户界面的安排。

    有没有人有处理这个问题的经验?控制它的好方法是什么?

    谢谢 作记号

    6 回复  |  直到 13 年前
        1
  •  41
  •   Alex Reynolds    15 年前

    我使用视图控制器中的两个简单方法进行此操作:

    - (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
        [self adjustViewsForOrientation:toInterfaceOrientation];
    }
    
    - (void) adjustViewsForOrientation:(UIInterfaceOrientation)orientation {
        if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
            titleImageView.center = CGPointMake(235.0f, 42.0f);
            subtitleImageView.center = CGPointMake(355.0f, 70.0f);
            ...
        }
        else if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
            titleImageView.center = CGPointMake(160.0f, 52.0f);
            subtitleImageView.center = CGPointMake(275.0f, 80.0f);
            ...
        }
    }
    

    为了保持这一点的整洁,您可以使用从单个对象内部调用的方法轻松地划分视图调整/重新加载/等等。 if-else 有条件的。

        2
  •  7
  •   drawnonward    15 年前

    这真的取决于你在布置什么。

    如果您查看Apple设置应用程序,可以看到它们使用表格视图进行布局,大多数行使用自定义单元格。这样,只需填充单元格的宽度,就可以让简单的界面以相当低的成本旋转。这甚至适用于像邮件这样的事情,在每一行中都有编辑文本单元格。而且表可以很容易全部透明,只有按钮或标签可见,所以它们看起来不像表。

    你可以从每个uiview的自动调整大小页面中得到很多里程。如果您有一个或多个项目可以有灵活的高度,那么您通常可以得到一个界面布局,在任何一个方向上看起来都不错。根据它的外观,有时你可以把所有东西都钉在上面。

    在极少数情况下,如果所有接口元素都适合一个正方形,则可以将它们就地旋转。

    有两次您必须显式地处理方向更改。一种是视图在旋转时从旁边移动到下面。另一种情况是,当每个方向都有不同的图像时,例如,如果您总是希望全宽。

    有时有办法解决这两个问题。您可以使用可伸缩的图像,或者每行仅限一个视图。或者您可以锁定某些视图的方向。

    如果必须更改视图布局,则存在显式的layoutSubviews方法。您应该尝试在这个方法中处理所有条件布局。只有当视图边界发生变化时才调用它,例如在旋转时,或者在为键盘留出空间时。为需要响应旋转的每个视图层次创建自定义视图,并从中布局子视图。

        3
  •  2
  •   Winder    15 年前

    iPhone SDK是基于MVC架构构建的,因此理论上,如果您将所有逻辑(模型)与UI(视图)分开,那么您只需在一个地方担心UI:视图控制器。对于这些,您可以为每个方向都有一个单独的视图控制器,然后每个视图控制器都将加载一个if/else来选择要加载的视图控制器。

    同样的想法也适用于iPhone/iPad支持,在这里你可以加载另一个视图控制器,它可以处理更大的显示器。

        5
  •  0
  •   johndpope    13 年前

    我不能保证这段代码,老实说,上面的willrotatetInterfaceOrientation工作得很好。这是Facebook为iPhone/iPad开发的fbdialog.m的另一个版本。(尽管如此,我认为这是为了一个网络视图)

    以下是要点

    [[NSNotificationCenter defaultCenter] addObserver:self
      selector:@selector(deviceOrientationDidChange:)
      name:@"UIDeviceOrientationDidChangeNotification" object:nil];
    
    
    - (void)deviceOrientationDidChange:(void*)object {
      UIDeviceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
      if ([self shouldRotateToOrientation:orientation]) {
    
    
        CGFloat duration = [UIApplication sharedApplication].statusBarOrientationAnimationDuration;
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:duration];
        [self sizeToFitOrientation:YES];
        [UIView commitAnimations];
      }
    }
    
    
    -(CGAffineTransform)transformForOrientation {
      UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
      if (orientation == UIInterfaceOrientationLandscapeLeft) {
        return CGAffineTransformMakeRotation(M_PI*1.5);
      } else if (orientation == UIInterfaceOrientationLandscapeRight) {
        return CGAffineTransformMakeRotation(M_PI/2);
      } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
        return CGAffineTransformMakeRotation(-M_PI);
      } else {
        return CGAffineTransformIdentity;
      }
    }
    
    - (void)sizeToFitOrientation:(BOOL)transform {
      if (transform) {
        self.transform = CGAffineTransformIdentity;
      }
    
      CGRect frame = [UIScreen mainScreen].applicationFrame;
      CGPoint center = CGPointMake(
        frame.origin.x + ceil(frame.size.width/2),
        frame.origin.y + ceil(frame.size.height/2));
    
      CGFloat scale_factor = 1.0f;
      if (FBIsDeviceIPad()) {
        // On the iPad the dialog's dimensions should only be 60% of the screen's
        scale_factor = 0.6f;
      }
    
      CGFloat width = floor(scale_factor * frame.size.width) - kPadding * 2;
      CGFloat height = floor(scale_factor * frame.size.height) - kPadding * 2;
    
      _orientation = [UIApplication sharedApplication].statusBarOrientation;
      if (UIInterfaceOrientationIsLandscape(_orientation)) {
        self.frame = CGRectMake(kPadding, kPadding, height, width);
      } else {
        self.frame = CGRectMake(kPadding, kPadding, width, height);
      }
      self.center = center;
    
      if (transform) {
        self.transform = [self transformForOrientation];
      }
    }
    
        6
  •  0
  •   matsr    13 年前

    在您的问题中,您写道:

    我可以想象意大利面条代码有这么多问题,成千上万的“如果”检查遍布各地,这会让我抓狂做一个小的改变,用户界面的安排。

    避免这种情况的一种方法是创建一个视图层次结构,从一开始就将处理iPhone/iPad特定的更改分开。您只需要为每个设备设置最初加载的视图。然后像通常那样创建一个viewcontroller,但也要将创建的viewcontroller子类化。每个设备都有一个子类。这就是您可以放置设备特定代码的地方,比如方向处理。这样地:

    MyViewController.h            // Code that is used on both devices
        MyViewController_iPhone.h // iPhone specific code, like orientation handling
        MyViewController_iPad.h   // iPad specific code, like orientation handling
    

    如果你对这种方法感兴趣,我建议你阅读 this article . 它以一种非常好的方式解释了这一点。

    文章提到的一件事是:

    --报价单开头--

    这种模式的好处在于,我们不必在代码中乱扔垃圾,这些垃圾看起来像这样:

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        // The device is an iPad running iPhone 3.2 or later.
        // set up the iPad-specific view
    } else {
        // The device is an iPhone or iPod touch.
        // set up the iPhone/iPod Touch view
    }
    

    ---报价结束--

    希望有帮助。祝你好运!