Relativelayout или LinearLayout в разработке ios iphone?

Я хочу добавить подвью в верхней части моего представления, мне нужно пересчитать значение начала y для всех других видов и переставить их, чтобы оставить место для нового добавленного вида.

Это очень скучно, поскольку я знаю, что андроид имеет relativelayout или linearlayout может помочь автоматически сделать это.

Как легко решить эту проблему при разработке ios?

Ответ 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 простой петлей через subviews, что reset истоки, сохраняя при этом запуск Y. Но некоторые неожиданные вещи добавляются в scrollview, включая представления UIInlineAutoCorrect из текстовых полей/представлений, что означает, что эти вещи были искалечены макетом. Поэтому я добавил немного логики, которая использует свойство тега UIView, чтобы определить, следует ли его выложить:

-(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: и т.д. Вы можете сделать это, когда идете, портируя только те методы, которые вам нужны. Затем вы можете называть их в своем переопределении layoutSubviews, как указывает Бенджамин.

Представления могут быть созданы с использованием IB или они могут быть написаны программно; Android отлично подходит для создания читаемых макетов, и вы можете принести эту пользу для iOS-представлений, созданных программно. То, что есть несколько устройств iOS, означает сверх читаемость, нет (пока?) Много практических преимуществ для этого шаблона.

NB. Файл "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];
  }
}

Ответ 4

Вам не повезло. iOS не имеет положений для позиционирования просмотров в разных макетах, таких как Android. Чтобы создать новый вид, вам нужно переместить все остальные подпункты.

Существуют некоторые методы изменения размера, такие как sizeToFit и autoResizingMask, но они не помогут вам в вашем случае здесь.

Ответ 5

iOS гораздо более ориентирована на точность пикселей, чем у Android, и использует относительные макеты, поскольку имеет дело с несколькими размерами экрана. Тем не менее, в iOS интерфейс Builder является невероятно хорошим инструментом, включенным в XCode, который вы можете использовать.

Кроме того, если вы просто добавляете subviews повторяющимся образом, вы можете переопределить метод layoutSubviews и использовать его для ручного труда для вас. Вы говорите, что нужно "пересчитать значение начала y для всех других видов и переставить их, чтобы оставить место для нового добавленного вида"... Вы можете записать это в свой layoutSubviews, чтобы вам не пришлось это делать каждый раз.

К сожалению, SDK по умолчанию не имеет такого значения. autoresizingMask велики, но вы не можете использовать их для начальной компоновки; это для автоматического действительно при вращении только.

Ответ 6

Как и в iOS 9, вы можете использовать UIStackView, который очень похож на LinearLayout: вы добавляете представления и представление стека упорядочивает их по мере необходимости на основе ваших настроек размера:

  • Заполнение оставит три из них их натурального размера и сделает четвертое занятие самым большим пространством. Он использует приоритет обхода содержимого Auto Layout, чтобы решить, какой из них растянуть.

  • Заполните равномерно, чтобы каждый subview имел одинаковый размер, чтобы заполнить все пространство, доступное для представления стека.

  • Fill Пропорционально использует собственный размер содержимого каждого поднабора для изменения их размера на равную сумму. Таким образом, просмотр 1 был спроектирован так, чтобы иметь вдвое большую высоту, чем виды 2, 3 и 4, это соотношение останется, когда оно будет изменено - все подзоны будут пропорционально больше или меньше.

  • Equal Spacing не изменяет размеры подзонов и вместо этого изменяет интервал между подзонами, чтобы заполнить пробел.

  • Равное центрирование является самым сложным, но для многих людей также наиболее эстетично. Он пытается обеспечить, чтобы центры каждого подсмотра находились на равном расстоянии.

Вы также можете установить интервал между представлениями в представлении стека, добавив некоторые дополнения.

ПРЕДУПРЕЖДЕНИЕ. При добавлении представлений дочерних элементов стека в коде вы всегда должны использовать addArrangedSubview() следующим образом:

stackView.addArrangedSubview(someView)

Если вы попытаетесь использовать простой старый addSubview(), он не будет работать правильно, потому что представление стека не будет знать, чтобы его организовать.

Как для удаления, вам нужно быть осторожным, чтобы использовать stackView.removeArrangedSubview(someView) и someView.removeFromSuperview(), иначе представление не будет удалено правильно.

Вы можете найти полезный учебник UIStackView.