【问题标题】:Relativelayout or LinearLayout in ios iphone development?ios iphone开发中的Relativelayout或LinearLayout?
【发布时间】:2011-08-16 02:22:07
【问题描述】:

我想在我的视图顶部添加一个子视图,我必须重新计算所有其他视图的原点 y 值并重新定位它们以便为新添加的视图留出空间。

这很无聊,因为我知道 android 有 r​​elativelayout 或 linearlayout 可以帮助自动做到这一点。

如何在ios开发中轻松解决这个问题?

【问题讨论】:

  • iOS 9 引入UIStackView,类似于LinearLayout

标签: iphone android objective-c ios layout


【解决方案1】:

我创建了一个库来解决这个问题:CSLinearLayoutView

你可以这样使用它:

// create the linear layout view
CSLinearLayoutView *linearLayoutView = [[[CSLinearLayoutView alloc] initWithFrame:self.view.bounds] autorelease];
linearLayoutView.orientation = CSLinearLayoutViewOrientationVertical;
[self.view addSubview:linearLayoutView];

// create a layout item for the view you want to display and add it to the layout view
CSLinearLayoutItem *item = [CSLinearLayoutItem layoutItemForView:someView];
item.padding = CSLinearLayoutMakePadding(5.0, 10.0, 5.0, 10.0);
item.horizontalAlignment = CSLinearLayoutItemHorizontalAlignmentCenter;
item.fillMode = CSLinearLayoutItemFillModeNormal;
[linearLayoutView addItem:item];

// add more items

【讨论】:

    【解决方案2】:

    我一直在尝试做一个相对(线性)布局,最后决定只继承 UIScrollView 来完成它。

    我一开始只是用一个简单的循环替换 layoutSubviews,通过子视图重置原点,同时保持运行的 Y。但是,滚动视图中添加了一些意想不到的东西,包括来自文本字段/视图的 UIInlineAutoCorrect 视图,这意味着这些东西是被布局破坏。所以我添加了一点逻辑,使用 UIView 的 tag 属性来确定是否应该将其布局:

    -(void) layoutSubviews{
        CGFloat runningY = 0.0f;
        CGFloat widestWidth = 0.0f;
        for (UIView *view in self.subviews) {
            if (view.tag != 1999) {
                continue;
            }
    
            view.origin = CGPointMake(view.origin.x, runningY);
            runningY += view.height;
    
            if ([view autoresizingMask] == UIViewAutoresizingFlexibleWidth) {
                view.width = self.width;
            }
    
    
    
            if (view.width > widestWidth) {
                widestWidth = view.width;
            }
        }
        [self setContentSize:CGSizeMake(widestWidth, runningY)];
    
    }
    

    如果您仍想为您的视图使用唯一标签,您应该只指定将包含在布局中的标签范围而不是单个值。

    【讨论】:

      【解决方案3】:

      UIView 子类化以理解-(void)addView:toRightOfView: 等方法的意义并不大。您可以随时执行此操作,只移植您需要的方法。然后,您可以按照 Benjamin 的指示在覆盖 layoutSubviews 时调用它们。

      视图可以使用 IB 构建,也可以通过编程方式编写; Android 在使布局可读方面取得了很好的成绩,您可以将这种好处带到以编程方式创建的 iOS 视图中。 iOS 设备很少意味着除了可读性之外,这种模式还没有(还没有?)很多实际好处。

      注意。 “XIB”文件是一个 XML 文件。在您喜欢的文本编辑器中打开它并查看。

      ** 编辑。

      这是我敲了一个简单的例子。它尚未经过测试,但类似这样的东西将在您的 UIView 子类中工作(也许称之为 UIRelativeView)。

      - (void) addSubview:(UIView *) viewOne
         toRightOfSubview:(UIView *) viewTwo
      {
        if (viewTwo == nil ||
            [self.subviews contains:viewTwo] == NO)
        {
          [self addSubview:viewOne];
        }
        else
        {
          CGRect frameTwo = viewTwo.frame;
          CGPoint originOne = CGPointMake(frameTwo.origin.x + frameTwo.size.width,
                                          frameTwo.origin.y);
      
          CGRect frameOne = CGRectZero;
          frameOne.origin = originOne;
          frameOne.size = viewOne.frame.size;
      
          [viewOne setFrame:frameOne];
          [self addSubview:viewOne];
        }
      }
      
      - (void) moveSubview:(UIView *) viewOne
          toRightOfSubview:(UIView *) viewTwo
      {
        if (viewTwo == nil ||
            [self.subviews contains:viewTwo] == NO)
        {
          [self addSubview:viewOne];
        }
        else if ([self.subviews contains:viewOne] == NO)
        {
          [self addSubview:viewOne toRightOfSubview:viewTwo];
        }
        else
        {
          CGRect frameTwo = viewTwo.frame;
          CGPoint originOne = CGPointMake(frameTwo.origin.x + frameTwo.size.width,
                                          frameTwo.origin.y);
      
          CGRect frameOne = CGRectZero;
          frameOne.origin = originOne;
          frameOne.size = viewOne.frame.size;
      
          [viewOne setFrame:frameOne];
        }
      }
      

      【讨论】:

      • 我不敢相信! Apple 没有提供更好的方法来进行相对布局?这个答案是迄今为止我所见过的最好的解决方法。
      • 当我有 5 个 UILabel,垂直堆叠,只有最上面的一个可以垂直增长时,这是最好的解决方案吗?然后,我需要为其余 4 个标签中的每一个调用类似 moveUnderView 的方法,对吗?一定有更好的方法。
      • 如果自动调整大小不能满足您的需求,您还可以继承 UIView 并覆盖 layoutSubviews
      • 但是我会在 layoutSubviews 中做什么呢?那不是你运行moveUnderView之类的代码的地方吗?我会编写相同的代码,只是从不同的地方调用它,对吧?
      【解决方案4】:

      你在这里没有运气。 iOS 没有规定将视图定位在不同的布局中,例如 Android。您需要重新定位所有其他子视图,以便为新视图腾出空间。

      有一些调整视图大小的方法,例如 sizeToFitautoResizingMask,但它们在这里对您的情况没有帮助。

      【讨论】:

      • 他并非完全不走运。通过一些工作,您可以像在 Android 中一样在 iOS 中进行布局。看我的回答。
      【解决方案5】:

      iOS 比 Android 更注重像素精度,Android 使用相对布局,因为它必须处理多种屏幕尺寸。但是,在 iOS 中,Interface Builder 是 XCode 中包含的一个非常好的工具,您可以使用它。

      另外,如果您只是以重复的方式添加子视图,您可以覆盖 layoutSubviews 方法并使用它来处理您的体力劳动。您提到必须“重新计算所有其他视图的原点 y 值并重新定位它们以便为新添加的视图留出空间”......您可以将其编码到您的 layoutSubviews 中,这样您就不必这样做每次都是自己。

      不幸的是,SDK 默认不包含任何这些。 autoresizingMask 很棒,但您不能将其用于初始布局;只在旋转时是自动的。

      【讨论】:

        【解决方案6】:

        从 iOS 9 开始,您可以使用 UIStackView,其工作方式与 LinearLayout 非常相似:您可以添加视图,堆栈视图会根据您的尺寸偏好根据需要排列它们:

        • 填充将使其中三个保留其自然大小,并使第四个占据最大空间。它使用自动布局的内容拥抱优先级来决定拉伸哪一个。

        • Fill Equally 将使每个子视图的大小相同,以便它们填充堆栈视图的所有可用空间。

        • Fill 按比例填充每个子视图的固有内容大小,以等量调整它们的大小。因此,视图 1 的高度设计为视图 2、3 和 4 的两倍,当它们调整大小时,该比例将保持不变——所有子视图按比例变大或变小。

        • Equal Spacing 不会调整子视图的大小,而是调整子视图之间的间距以填充空间。

        • 等距定心是最复杂的,但对许多人来说也是最美观的。它试图确保每个子视图的中心是等距的。

        您还可以在堆栈视图中设置视图之间的间距,添加一些填充。

        警告:在代码中添加堆栈视图子视图时,您应始终使用addArrangedSubview(),如下所示:

        stackView.addArrangedSubview(someView)
        

        如果您尝试使用普通的旧 addSubview(),它将无法正常工作,因为堆栈视图不知道如何安排它。

        至于删除,你需要小心使用stackView.removeArrangedSubview(someView) someView.removeFromSuperview() 否则视图将无法正确删除。

        您可能会发现我的UIStackView tutorial 很有用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-03
          • 1970-01-01
          • 2023-03-18
          相关资源
          最近更新 更多