Сегодня я расскажу про новую рубрику нашего сайта, а также про то, как сделать стильный Segmented control для вашего приложения, не потратив много времени.

Pod digest

Новая рубрика называется pod digest, возможно, вы уже догадались о чем пойдет речь, эта рубрика собирает самые интересные, свежие и полезные Pod’ы. Сегодня у нас пойдет речь об очень интересном проекте под названием Segmentio.

Сегментированный элемент управления

Итак, что же вообще такое segmented control? Как говорит компания Apple: segmented control это горизонтальный элемент управления, выполненный из нескольких сегментов, каждый из которых представлен своей кнопкой. Такой элемент обычно выглядит следующим образом:

и скорее всего, вам неоднократно приходилось с ним сталкиваться, работая со стандартными приложениями от Apple. Обычно, такие элементы используют для переключения приложения между различными типами содержимого на экране. Стандартный segmented control в Cocoa представлен классом UISegmentedControl и является типичным представителем UIKit фреймворка. Он довольно прост в обращении, поэтому сейчас мы не будем рассматривать его стандартную реализацию, а сразу перейдем к Segmentio.

Segmentio

Pod требует Xсode 8.x, Swift 3.x и поддерживает iOS начиная с 8’ой версии. Проект имеет хороший рейтинг на GitHub’е и свежую дату релиза, плюс MIT лицензия делают его неплохим кандидатом на импорт в ваш проект. Segmentio поддерживает довольно много режимов работы и предоставляет богатые возможности для кастомизации дизайна вашего приложения.

Segmentio API

Segmentio поддерживает довольно простой, но вместе с тем функциональный API. Для того что-бы получить экземпляр Segmentio — необходимо задать его положение на экране, воспользовавшись стандартным классом CGRect.


var segmentioView: Segmentio!

let segmentioViewRect = CGRect(x: 0, y: 0, width: UIScreen.mainScreen().bounds.width, height: 125)
segmentioView = Segmentio(frame: segmentioViewRect)
view.addSubview(segmentioView)

Мы создали эземпляр класса Segmentio и установили его в иерархии View. Для того чтобы сконфигурировать наш объект, необходимо воспользоваться методом setupContent. Давайте взглянем на его сигнатуру:


segmentioView.setupContent(
    content: [SegmentioItem],
    style: SegmentioStyle,
    options: SegmentioOptions
)

Как можно заметить он имеет 3 параметра, с довольно содержательными названиями, content — определяет содержимое элемента, style — задает режим отображения, а options — определяет настройки для выбранного режима. Посмотрим, как будут обрабатываться нажатия кнопок на сегментированном элементе:


segmentioView.valueDidChange = { segmentio, segmentIndex in
    print("Selected item: ", segmentIndex)
}

Мы задаем параметр valueDidChange небольшим замыканием, принимающим экземпляр объекта Segmentio и индекс, соответствующий выбранной пользователем кнопке. Этих знаний нам вполне хватит для того, чтобы написать свое приложение.

Пример использования Segmentio

Segmentio имеет солидное количество настроек, поэтому мы реализуем небольшую обертку, для того, чтобы не тащить лишнюю логику в свой контроллер. Мы не будем рассматривать полиморфную реализацию нашей обертки в рамках данной статьи, ограничившись написанием статичной реализации сегментированного элемента под flat-дизайн.

Создадим новый класс CBSegmentedControl, который будет определять реализацию нашего segemented control’а.


import Segmentio

class CBSegmentedControl {
    let segmentioView: Segmentio!
	
var index: Int !
	var indicatorOptions: SegmentioIndicatorOptions! 
	var horizontalSeparatorOptions: SegmentioHorizontalSeparatorOptions! 
	var verticalSeparatorOptions: SegmentioVerticalSeparatorOptions! 
	var states: SegmentioStates! 
	var options: SegmentioOptions! 
	
    init(items: [SegmentioItem], view: UIView, handler: @escaping SegmentioSelectionCallback) {
        
    }
}

Здесь мы декларируем класс CBSegmentedControl и определяем поля напрямую или косвенно необходимые для работы с Segmentio. Обратите внимание на инициализатор нашего класса, сейчас он принимает три параметра: items — элементы segmeted control’а, view — на который необходимо установить наш элемент и handler — который будет обрабатывать изменение состояния нашего объекта. Пока все поля помечены как опциональные, просто ради поддержания работоспособности кода.

Для начала давайте инициализируем хранимые поля нашего класса:


    init(items: [SegmentioItem], view: UIView, handler: @escaping SegmentioSelectionCallback) {
        
        self.segmentioView = Segmentio(frame: CGRect(
            x: 0,
            y: 0,
            width: view.bounds.width,
            height: 90
        ))
}

Теперь можно продетализировать вычисляемые поля, первым делом определим настройки сепараторов:


 var horizontalSeparatorOptions: SegmentioHorizontalSeparatorOptions {
        return SegmentioHorizontalSeparatorOptions(
            type: SegmentioHorizontalSeparatorType.bottom,
            height: 1,
            color: UIColor.clear
        )
    }
    
    var verticalSeparatorOptions: SegmentioVerticalSeparatorOptions {
        return  SegmentioVerticalSeparatorOptions(
            ratio: 0.5,
            color: UIColor.clear
        )
    }

Мы устанавили геттеры для вычисляемых полей, ответсвенные за настройку вертикальных и горизонтальных разделителей. Теперь установим настройки индикатора выбранной кнопки на нашем элементе:


    var indicatorOptions: SegmentioIndicatorOptions {
        return SegmentioIndicatorOptions(
            type: .bottom,
            ratio: 0.85,
            height: 2,
            color: UIColor.white
        )
    }

Основные настройки индикатора включают его

  • Цвет
  • Тип
  • Масштаб
  • Толщину

Теперь зададим настройки состояния кнопок на индикаторе:


    var states: SegmentioStates {
        return SegmentioStates(
            defaultState: SegmentioState(
                backgroundColor: UIColor.clear,
                titleFont: UIFont.systemFont(ofSize: 13),
                titleTextColor: UIColor.white
            ),
            selectedState: SegmentioState(
                backgroundColor: UIColor.clear,
                titleFont: UIFont.boldSystemFont(ofSize: 13),
                titleTextColor: UIColor.white
            ),
            highlightedState: SegmentioState(
                backgroundColor: UIColor.clear,
                titleFont: UIFont.boldSystemFont(ofSize: 13),
                titleTextColor: UIColor.white
            )
        )
    }

Сейчас мы установили шрифт надписей, цвет фона и текста для каждого из состояний кнопок:

  • Обычное
  • Выбранное
  • Нажатое

Это практически все настройки необходимые Segmentio, осталось только собрать объект SegmentioOptions, который мы будем использовать при конфигурации нашего segmented control’a:


    var options: SegmentioOptions {
        return SegmentioOptions(
            backgroundColor: UIColor.red,
            maxVisibleItems: 3,
            scrollEnabled: false,
            indicatorOptions: self.indicatorOptions,
            horizontalSeparatorOptions:
            self.horizontalSeparatorOptions,
            verticalSeparatorOptions:
            self.verticalSeparatorOptions,
            imageContentMode: .center,
            labelTextAlignment: .center,
            segmentStates: self.states
        )
    }

Обновим наш конструктор:


    init(items: [SegmentioItem], view: UIView, handler: @escaping SegmentioSelectionCallback) {
        
        self.segmentioView = Segmentio(frame: CGRect(
            x: 0,
            y: 0,
            width: view.bounds.width,
            height: 90
        ))
        
        self.segmentioView.setup(
            content: items,
            style: .onlyLabel,
            options: self.options
        )
        
        self.segmentioView.valueDidChange = handler
        view.addSubview(segmentioView)
    }

Готово. Давайте подключим наш объект и посмотрим как он работает, для этого допишем несколько функций во ViewController и обновим viewDidLoad():


    func segmentedControlCallback(
        _ segmentio: Segmentio, _ selectedSegmentioIndex: Int) -> Void {
        
    }

    func prepareSegmentedControl() -> Void {
        
        let items: [SegmentioItem] = [
            SegmentioItem(
                title: "Новости",
                image: nil
            ),
            SegmentioItem(
                title: "Главная",
                image: nil
            ),
            SegmentioItem(
                title: "Избранное",
                image: nil
            )
        ]
        
        let segmentedControl = CBSegmentedControl(
            items: items,
            view: self.view,
            handler: self.segmentedControlCallback
        )
        
        segmentedControl.index = 1
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.prepareSegmentedControl()
    }

Отлично, давайте соберем проект и посмотрим, как все работает.

Заключение

На этом все, надеюсь, вам понравилась наша новая рубрика так же, как мне писать для нее. Буду рад услышать ваши предложения о развитии данной ветки нашего сайта, не стесняйтесь присылать названия интересных вам Pod’ов на обзор.

Полную версию проекта можно посмотреть у меня на GitHub’е: hol0d/CBSegmentedControl

 

Автор фото: @madeawkward

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.