История началась с того, что мне понадобилось написать приложение под Mac OS X. Все реже можно увидеть статьи по поводу разработок под desktop, да еще и под Mac OS X, но эта тема именно об этом.
Я уже писал много чего на QT, а тут встала задача использовать исключительно Cocoa.
Существует определенная аура святости вокруг продуктов apple, ну и я наивно подпал под нее от моего макбука. Мне казалось что с пользовательским интерфейсом особых проблем не будет, ну разве что какие-то мелочи, которые встречаются везде (ох, как я ошибался).
Вот в проекте я дошел до разработки пользовательского интерфейса и тут мне понадобился классический шаблон Tab View. Продолжение читайте уже под катом.
Предыстория
В общем проект самый обычный в плане пользовательского интерфейса. Пользователь кликает кнопку connect, вводит данные для входа на сервер жмет OK и появляется вкладка для этого сервера и т.д. Войти можно на много серверов и они будут в разных вкладках. Что за сервера и зачем это все нужно это уже другая предметная область не относящаяся к данной статье, поэтому эту информацию я может быть расскажу в другой раз.
Наивный разработчик
Под Mac OS X, да и даже под iOS я еще ни разу не разрабатывал, это мой первый опыт, возможно именно это меня и сделало еще более наивным.
Я думал что тут все проще простого, кину в конструкторе Tab View или как он будет называться в Cocoa в окно, настрою отображение и все, но не тут-то было.
Нахожу в Xcode tab view, кидаю в окно и вижу вот это
Тут уже у меня появились подозрения, что могут возникнуть какие-то сложности.
Ладно подумал я, начал искать другие виджеты для вкладок, их нет. Хорошо, решил разобраться с настройками этого Tab View. Минут 10 повозившись с настройками и поняв, что Tab View к виду вкладок в том же Safari/Finder/Xcode и прочих, его не привести, я отправился на поиски по безграничным просторам интернета.
За первые несколько просмотров постов на http://stackoverflow.com стало ясно, что Tab View это совсем не то что нужно, я не одинок.
Поиск альтернативного решения
Тут наступил такой момент в разработке когда не пишется ни строчки кода зато читается очень много текста и выпивается очень много кофе.
Вначале я всё-таки попробовал найти что-то от самих Apple, но очень быстро стало ясно что это бесполезно.
Далее я отправился на различные форумы где обсуждалась эта проблема и пути ее решения. Довольно быстро я нашел уже несколько вариантов добавления вкладок в приложения под Mac OS X.
- PSMTabBarControl
- MMTabBarView
- Какие-то примеры можно найти на сайте cocoacontrols.
- Что-то предлагалось на stackoverflow.
- github.com/aaron-elkins/ENTabBarView
- www.cocoacontrols.com/controls/litabcontrol
- www.cocoacontrols.com/controls/kpctabscontrol
Первые два варианта были самыми распространенными и с большим количеством функционала и я решил разбираться с ними.
PSMTabBarControl достачно развитый проект с хорошим функционалом, но уже давно не поддерживается. К слову именно он используется в Adium.
MMTabBarView по сути является продолжением и развитием PSMTabBarControl, но не смотря на это, с поддержкой у его не лучше.
Если взглянуть на его страницу на github, то у него имеется 44 форка, а все это потому что разработчик уже год как не коммитил ничего в master ветку хотя и делал некоторые доработки в develop(но это судя по всему мало кто замечает).
44 форка и среди них несколько активных уходящих от последнего коммита в master и утверждающих что они исправили какие-то баги.
Тут я решил взять тот который активнее других поддерживается.
Был выбран один из форков (как оказалось в последствии совсем не важно какой).
В MMTabBarView есть демо проект который без проблем был откомпилен и работал:
Тут я подумал, что все нормально, форк живой и можно с ним работать.
Я включил фреймворк в сборку своего проекта, сделал все настройки, написал нужный код, запускаю и ничего. Табов нет!
Тупик
Табов нет, ладно, я начал разбираться и выяснил что что-то похожее на табы появляется если я не обновляю Tab View
Если например добавить таб то все пропадает
Вот тут началось веселье. Я начал пробовать все что можно, сначала все разумные средства, а потом уже и не разумные.
- Разные форки. Пришлось перебрать порядка 3-4 форков.
- Настройки. Пробовал разные настройки.
- Я делал новый проект и пробовал все в нем с разными форками.
- На github и в поиске я нашел проекты использующие MMTabBarView и разбирался с ними. Искал отличия с моим кодом.
- Перекапывал форумы в интернете на эту тему.
В общем на многочисленные эксперименты ушел не один день.
В конце у меня было 2 проекта, практически пустых и полностью одинаковых. В одном табы работают, а в другом нет. Встречаясь с таким необъяснимым, наши предки начинали верить в сверхъестественное.
Начали возникать мысли что нужно поискать другую библиотеку.
Эврика или скорее удача
В итоге после долгих поисков непонятной проблемы я решил найти на github максимально простой и маленький проект использующий MMTabBarView и сравнить его с моим.
Был найден какой-то маленький браузер. Из него я убрал все лишнее, и начал сравнивать со своим проектом. Все было идентично. Он так же без проблем работал со сборками MMTabBarView из разных форков.
Дальше возникла идея в этом работающем проекте сделать новое окно и попробовать в нем подключить табы.
И тут победа, табы не заработали. И вот у меня один проект, с одним xib-файлом табы работают с другим нет.
Вывод был очевиден, надо сравнить эти файлы.
Тут работает:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6751" systemVersion="13F1603" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" promptedForUpgradeToXcode5="NO">
Тут не работает:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6751" systemVersion="13F1603" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
В первом же теге я нашел проблему:
customObjectInstantitationMethod="direct"
Если убрать этот атрибут то MMTabBarView начинает корректно работать.
Видимо это связано с тем что отрисовка MMTabBarView ведется как раз в CustomView и этот атрибут как-то на него влияет.
Начинаем разбираться что это такое:
Гугл и яндекс дают кучу ссылок на проиндексированные xib файлы.
Я нашел несколько упоминаний об этом атрибуте, связанных с другими проблема, но для чего он так и не разобрался. Если кто-то знает что это за атрибут и зачем он нужен отпишите, буду очень благодарен.
Заключение
MMTabBarView досточно хороший проект, он поддерживает разное отображение табов, счетчик на табах, добавление иконок, добавление кнопок закрытия и добавление нового таба и многое другое. Жаль только что он размазался по куче форков и непонятно на данный момент как его собрать воедино.
Apple конечно меня огорчил, ну как такое может быть, во всех приложениях элемент пользовательского интерфейса есть, а в библиотеке его нет!?
Самое забавное что табы есть в xcode :)
PS
Вот маленький пример, как подключить MMTabBarView к вашему проекту.
Полезные ссылки:
stackoverflow.com/questions/27354262/safari-style-tabs-cocoa-control?rq=1
stackoverflow.com/questions/2774668/does-anyone-know-a-safari-style-tab-control-for-mac-os-x-applications?rq=1
stackoverflow.com/questions/22789341/better-psmtabbarcontrol-cocoa-tabs
stackoverflow.com/questions/4986920/tabs-style-in-the-cocoa?rq=1
Комментарии (11)
kafeman
29.02.2016 00:00Забавно, что в упомянутом Qt такое есть. Правда, начиная с 10.10 работает как-то криво.
Что касается ваших скриншотов, табы в том же Finder выглядят немного иначе — нет крестика и ширина растягивается на все окно.xanm
29.02.2016 07:32Да, в QT чего только нету.
Что касается табов то в MMTabBarView — есть стиль Safari который уже ближе к Finder, да и можно написать свой, есть опция setOnlyShowCloseOnHover, растягивание таба на я не нашел, но добавить его будет не проблема.
Athari
29.02.2016 10:03+2Когда вы пишете "Какие-то примеры можно найти на сайте cocoacontrols.com" или "Что-то предлагалось на stackoverflow.com", то я ожидаю, что ссылки ведут на "как-то примеры" и "что-то", а никак не на главную страницу сайтов. Вы два раза сослались на обсуждения на СО, и оба раза дали ссылку на главную страницу. Если уж даёте ссылки, до делайте их полезными, а не для галочки. Вы бы ещё написали "нашёл в Google" и дали ссылку на главную страницу поисковика.
xanm
29.02.2016 11:03+3На самом деле это просто редактор хабра преобразует их в ссылки, что же касается других примеров, добавил. Можете посмотреть :)
aspcartman
29.02.2016 11:43+1Добро пожаловать на борт.
Не используйте InterfaceBuilder. Он принесет больше боли, чем пользы. На всех платформах боль от использования средств создания интерфейса графическим путем примерно одинакова, но в случае ios/osx интерфейс эпически просто создавать из кода благодаря оберткам над AutoLayout (использовать его в чистом виде это как пить чистый спирт, не надо).
https://github.com/Tricertops/KeepLayout
Добавление Вашего таб бара бы выглядело в методе -loadView следующим образом:
```
MMTabBarView *tabBar = [MMTabBarView new];
tabBar.foo = bar; // тут выставляем всякие параметры
[view addSubview:tabBar];
tabBar.keepTopInset.equal = 0;
tabBar.keepHorizontalInsets.equal = 0;
tabBar.keepHeight.equal = 20; // Опционально, если автор не указал стандартный размер через -intrinsicContentSize
_tabBarIvar = tabBar;
```
Накодить эти строчки гораздо быстре, чем искать в списке, перетягивать, растягивать, раставлять констрейнты мышкой, создавать IBOutlet, линковать его с вьюхой, о боже.
И еще: AppCode, Cocoapods.
Happy coding! ^_^obyknovenius
29.02.2016 13:14+2Почему все так хейтят InterfaceBuilder? Вас никто не заставляет в нем все делать. Это еще один инструмент. И иногда в нем быстрее и удобнее что-то сделать, чем написать дофига строк кода. Например, когда дизайн до конца не утвержден и заказчик хочет посмотреть как это будет на девайся, потыкать пальцами, а потом половину переделать. И здесь IB и Storyboard'ы очень даже помогают.
AutoLayout даже в коде я использую безо всяких оберток (может потому что и спирт чистый пил когда-то давно). Я вообще не очень люблю тянуть кучу всего стороннего в проект. Не хочу зависеть от компонентов, которые написали непроверенные люди и неизвестно собираются ли они свои велосипеды поддерживать.
И еще: не использую AppCode, не использую Cocoapods, хотя пробовал и умею пользоваться и тем и другим.
Вообще, почему-то в среде iOS разработки популярно мнение: Apple сделало что-то (CoreData, AutoLayout, подключаемые Frameworks) слишком сложно, не хочу разбираться, скачаю что-нибудь попроще. А потом получается — а зачем мне использовать NSURLSession или ту же CoreData, если я уже умею AFNetworking и MagicalRecord, например.aspcartman
29.02.2016 13:24Все хейтят IB потому что люди не умеют его готовить и строят громадные приложения в одной сториборде, а потом за ними переписывай.
И я заказчику накодю что угодно, и даже не буду ждать перекомпиляции проекта — хоткей и в симуляторе интерфейс перестроился. Если писать без обертки на чистом AL, то это действительно дольше, чем в IB.
AL без оберток очень плохо читаем.
iOS разработка != java dev != c++ dev. Тут другие правила и по факту 50 зависимостей в cocoapods гораздо лучше, чем свои решения и на практике проблем с ними не возникает. Есть непоправленная бага в стороннем проекте — форкни, поправь, в поде выставь ссылку на свой git, profit. Pull request не забыть сделать. Это гораздо быстрее, чем делать что либо самому. Потом на ваше место прийдет другой разработчик, и ему в этом всем разбираться.
А собственно ответьте на свой вопрос сами: а зачем? Чтобы понимать? Ясен перец нужно, а еще?
Krypt
Вы стали жертвой непонимания терминов.
Табы в понимании Mac OS X — это именно то, что вы увидели.
Вкладки сафари — стандартным элементом системы, вроде бы как, не являются.
А вообще iOS в плане API по сравнению в OS X выглядит как большая работа над ошибками.
xanm
Ну тут еще сыграло то что я привык к QTabWidget, но не спорю что-то в Cocoa я новичек.