Давайте признаем очевидное. Верстка экранов в iOS ужасна. Сравнивая с html, с WPF, с Android, с WinPhone — везде iOS проигрывает.
Верстка в iOS исторически напоминала WinForms (с аналогом якорей-Anchor’ов в виде AutoresizingMask). Однако WinForms уже давно отошло в прошлое, а iOS всё живет и живет :)
Да, на смену AutoresizingMask пришли Constraints, но работа с ними до жути неудобна, дизайнер ненаглядный, а результат работы — нечитаемый уже через неделю после создания.
А вообще, помимо удобства, наибольшей проблемой, конечно, становится динамическая верстка элементов. Если мы пришли из мира WPF/Android, то скучать по простейшему StackLayout/LinearLayout будем очень-очень сильно.
Возьмем например типичную задача: верстка элементов в строчку, при этом некоторые элементы могут быть спрятаны.
<StackLayout>
<Button />
<Button Visibility="Collapsed" />
<Button />
</StackLayout>
Чтобы задать такую верстку в iOS — придется изрядно помучаться. В случае со «старым» AutoresizingMask — это и вовсе невозможно, и придется разруливать координаты кнопок руками при каждом изменении видимости кнопок.
В случае «нового» и «продвинутого» LayoutConstraints — это, конечно, возможно, но намного сложнее и куда менее очевидно, чем xml-верстка.
Решение нашлось на просторах сети — XibFree. Это довольно простой layout-движок, который позволяет верстать экраны в iOS без использования .xib-файлов или Storyboard’ов, полностью в c#-файлах.
Вот как выглядит верстка, аналогичная верхней:
var layout = new LinearLayout(Orientation.Horizontal)
{
Padding = new UIEdgeInsets(10, 10, 10, 10),
LayoutParameters = new LayoutParameters()
{
Width = AutoSize.FillParent,
Height = AutoSize.WrapContent,
},
SubViews = new View[]
{
new NativeView()
{
View = new UIButton()
{
},
Init = v => {
v.As<UIButton>().SetTitle("Test1", UIControlState.Normal)
},
LayoutParameters = new LayoutParameters(AutoSize.WrapContent, AutoSize.WrapContent)
},
new NativeView()
{
View = new UIButton()
{
},
Init = v => {
v.As<UIButton>().SetTitle("Test2", UIControlState.Normal)
},
LayoutParameters = new LayoutParameters(AutoSize.WrapContent, AutoSize.WrapContent)
Gone = true,
},
new NativeView()
{
View = new UIButton()
{
},
Init = v => {
v.As<UIButton>().SetTitle("Test3", UIControlState.Normal)
},
LayoutParameters = new LayoutParameters(AutoSize.WrapContent, AutoSize.WrapContent)
Gone = true,
},
},
};
А в чем же отличие от Xamarin.Forms, спросите вы? Да, действительно, есть некоторое сходство. Основное отличие же в том, что XibFree реализует исключительно View-часть и не претендует на кроссплатформенность. За счет этого XibFree работает быстрее, практически не влияет на минимальный размер приложения (который для Xamarin.Forms — 32Mb), и не накладывает на iOS-разработчика никаких ограничений (кроме языка c#, если кто-то это считает ограничением :)).
Из преимуществ можно выделить:
- Простоту освоения, схожесть с аналогами на Андроид/WPF
- Простота использования, отсутствие каких-либо абстракций над UI-элементами (используются напрямую UIButton/UILabel/etc.)
- Счастье при создании динамической верстки, под разные разрешения
- Отсутствие претензий по производительности
- Удобство при работе с системой контроля версий и поддержке — XibFree это код, а не нечитаемый xml как в случае xib и Storyboard
Из объективных минусов можно выделить «заброшенность» библиотеки: оригинальные разработчики не обновляли XibFree с января 2015. Тем не менее, весь функционал работает и вмешательства не требует.
Возможно, стандартных LinearLayout/FrameLayout будет и недостаточно для чересчур изощренных экранов — это тоже надо иметь ввиду.
Тем не менее, мы в своих проектах с такими ограничениями не столкнулись, активно используем XibFree и исключительно довольны.
Рекомендую :)
P.S. Некоторые существующие проблемы мы самостоятельно решаем. В частности, в нашем форке мы добавили WrapLayout, ведется работа над GridLayout.
Подытоживая, список ссылок: