Весёлые табы в MAC OS X или история про тот самый Tab View

    Привет всем!

    История началась с того, что мне понадобилось написать приложение под 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 достачно развитый проект с хорошим функционалом, но уже давно не поддерживается. К слову именно он используется в 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

    Похожие публикации

    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 11

      +1
      Вы стали жертвой непонимания терминов.
      Табы в понимании Mac OS X — это именно то, что вы увидели.
      Вкладки сафари — стандартным элементом системы, вроде бы как, не являются.

      А вообще iOS в плане API по сравнению в OS X выглядит как большая работа над ошибками.
        0
        Ну тут еще сыграло то что я привык к QTabWidget, но не спорю что-то в Cocoa я новичек.
        0
        Забавно, что в упомянутом Qt такое есть. Правда, начиная с 10.10 работает как-то криво.

        Что касается ваших скриншотов, табы в том же Finder выглядят немного иначе — нет крестика и ширина растягивается на все окно.
          0
          Да, в QT чего только нету.

          Что касается табов то в MMTabBarView — есть стиль Safari который уже ближе к Finder, да и можно написать свой, есть опция setOnlyShowCloseOnHover, растягивание таба на я не нашел, но добавить его будет не проблема.
          +2
          Когда вы пишете "Какие-то примеры можно найти на сайте cocoacontrols.com" или "Что-то предлагалось на stackoverflow.com", то я ожидаю, что ссылки ведут на "как-то примеры" и "что-то", а никак не на главную страницу сайтов. Вы два раза сослались на обсуждения на СО, и оба раза дали ссылку на главную страницу. Если уж даёте ссылки, до делайте их полезными, а не для галочки. Вы бы ещё написали "нашёл в Google" и дали ссылку на главную страницу поисковика.
            +3
            На самом деле это просто редактор хабра преобразует их в ссылки, что же касается других примеров, добавил. Можете посмотреть :)
            0
            Да, помню, как брали PSMTabBarControl и допиливали до какого-то адекватного состояния…
            Кстати, а MMTabBarView нормально дружит с Autolayout?
              0
              Пока проблем вроде не возникало, но кто знает что еще может вылезти.
              +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! ^_^
                +2
                Почему все так хейтят InterfaceBuilder? Вас никто не заставляет в нем все делать. Это еще один инструмент. И иногда в нем быстрее и удобнее что-то сделать, чем написать дофига строк кода. Например, когда дизайн до конца не утвержден и заказчик хочет посмотреть как это будет на девайся, потыкать пальцами, а потом половину переделать. И здесь IB и Storyboard'ы очень даже помогают.

                AutoLayout даже в коде я использую безо всяких оберток (может потому что и спирт чистый пил когда-то давно). Я вообще не очень люблю тянуть кучу всего стороннего в проект. Не хочу зависеть от компонентов, которые написали непроверенные люди и неизвестно собираются ли они свои велосипеды поддерживать.

                И еще: не использую AppCode, не использую Cocoapods, хотя пробовал и умею пользоваться и тем и другим.

                Вообще, почему-то в среде iOS разработки популярно мнение: Apple сделало что-то (CoreData, AutoLayout, подключаемые Frameworks) слишком сложно, не хочу разбираться, скачаю что-нибудь попроще. А потом получается — а зачем мне использовать NSURLSession или ту же CoreData, если я уже умею AFNetworking и MagicalRecord, например.
                  0
                  Все хейтят IB потому что люди не умеют его готовить и строят громадные приложения в одной сториборде, а потом за ними переписывай.

                  И я заказчику накодю что угодно, и даже не буду ждать перекомпиляции проекта — хоткей и в симуляторе интерфейс перестроился. Если писать без обертки на чистом AL, то это действительно дольше, чем в IB.

                  AL без оберток очень плохо читаем.
                  iOS разработка != java dev != c++ dev. Тут другие правила и по факту 50 зависимостей в cocoapods гораздо лучше, чем свои решения и на практике проблем с ними не возникает. Есть непоправленная бага в стороннем проекте — форкни, поправь, в поде выставь ссылку на свой git, profit. Pull request не забыть сделать. Это гораздо быстрее, чем делать что либо самому. Потом на ваше место прийдет другой разработчик, и ему в этом всем разбираться.

                  А собственно ответьте на свой вопрос сами: а зачем? Чтобы понимать? Ясен перец нужно, а еще?

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

              Самое читаемое