ContainerController компонент UI пользовательского интерфейса. Это копия свайп-панели из приложения AppleMaps

Что он может:

  • Анимировано перемещаться на 3 позиции: (Верх / Середина / Вниз)
    Перемещаться программно 2 позиции: (Скрыть / Пользовательский)
    Можно настраивать позиции
    Можно настраивать позиции отдельно для ландшафтного разворота

  • Добавлять несколько ContainerController (друг на друга) в одном контроллере
    Таким образом можно осуществлять переход между ними.

  • Управлять панелью с помощью жеста PanGesture или свайпом (вертикально)

  • Добавлять любой тип ScrollView: TableView / CollectionView / TextView
    и управлять панелью за счет скрола

  • Можно закреплять HeaderView на вверху / и FooterView внизу

  • Настройка вьюшки панели ContainerView:
    - Изменять окружность углов cornerRadius
    - Добавлять тень контейнера
    - Фон:
    1) Добавлять цвет
    2) Размытие Blur Effects (может потребоваться для темной темы)
    3) Прозрачность

  • При поднятии наверх, можно включить добавление тени фона позади панели

  • 1) Можно настраивать левые / правые отступы
    2) И настраивать левые / правые отступы для ландшафтного разворота

Превью

Копия приложения Apple Maps

Видно что в 1 контейнере SearchBar закреплен на верхушке, а под ним tableView

А в 3 контейнере
TabBar находится внизу,
и тоже неподвижен, в открытом состоянии контейнера

- Для этого создан HeaderView / FooterView




Экран демонстрация
Полных настроек

Создание множества компонентов в одном контроллере

Добавить готовые ScrollView: TableView / CollectionView / TextView

Добавить готовые HeaderView / FooterView

Изменить позиции
Переместиться программно в позицию
Добавить цвет / блюр фона
Добавить тени
Добавить отступы (для ландшафтной оринтации отдельно)

И остальные параметры

Копия приложения Apple Maps
Перевернутый экран
Ландшафтная ориентаци
я

Применение Темной темы

Для это добавлен параметр Blur
.dark .light .extraLight

О проекте

Примеры использования компонента в популярных приложениях.
Используется в разных категориях приложений:

  • Карты / Меню / Плеер Музыка / Маркет / Спортивные новости / Такси / Финансы Банки Акции / Кошельки / Аналитика / Заметки

  • Оповещения / Всплывающие окна / Уведомления (Alerts / Popups / Notifications)

Функции

Требования

✏️ ContainerController написан на Swift 5.0+. Его можно собрать в Xcode 11 или более поздней версии. Совместим с iOS 13.0+.

Установка

CocoaPods

ContainerControllerSwift доступен через CocoaPods. Чтобы установить его, просто добавьте следующую строку в свой Podfile:

pod 'ContainerControllerSwift'

Swift Package Manager with Xcode 11

dependencies: [
    .package(url: "https://github.com/mrustaa/ContainerController.git")
]

Следуйте этому документу.

Примеры дизайна

Дизайны заимствованы с Dribbble

Для получения дизайна необходимо добавить ветку ui_examples

git clone https://github.com/mrustaa/ContainerController.git
cd ContainerController/
git checkout ui_examples

Видео

Авторы дизайн ui URL-адресов:

image
image

Плеер Музыка
YoutubeMusic

image
image

Магазин Покупка
Выбор товаров

image
image

Акции
Финансы
Банки

Начало работы

import UIKit
import ContainerControllerSwift

class ViewController: UIViewController, ContainerControllerDelegate {
    
    var container: ContainerController!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Create ContainerController Layout object
        let layout = ContainerLayout()
        layout.startPosition = .hide
        layout.backgroundShadowShow = true
        layout.positions = ContainerPosition(top: 70, middle: 250, bottom: 70)
        
        // Create ContainerController object, along with the container.view
        // Pass the current UIViewController 
        let container = ContainerController(addTo: self, layout: layout)
        container.view.cornerRadius = 15
        container.view.addShadow()
        
        // Create subclass scrollView
        let tableView = UITableView()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        tableView.delegate = self
        tableView.dataSource = self
        
        // Add scrollView to container
        container.add(scrollView: tableView)
        
        // Finishing settings ContainerController,
        // Animated move position Top
        container.move(type: .top)
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        
        // Remove the subviews ContainerController
        container.remove()
        container = nil
    }
}

Действие

Анимированное перемещение к позициям

Основные позиции 3 Можно перемещаться свайпом жестом между ними

Вверх | .top
Середина | .middle
Вниз | .bottom

Остальные 2 Можно перемещать только программно

Скрыть | .hide (Скрыть за пределы экрана)
Пользовательский | .custom (Пользовательская установленная позиция)

container.move(type: .top)
container.move(type: .middle)
container.move(type: .bottom)
container.move(type: .hide)
container.move(type: .custom)

Добавление кастомных вьюшек в ContainerController

Добавлять ScrollView

let tableView = UITableView()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.backgroundColor = .clear
tableView.tableFooterView = UIView()
tableView.delegate = self
tableView.dataSource = self

// Add scrollView to container
container.add(scrollView: tableView)

Delegate self ?

Если вы реализуете делегат ScrollView (TableView, CollectionView, TextView) для self, то вам нужно вызвать 4 функции в ContainerController

extension ViewController: UIScrollViewDelegate {
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        container.scrollViewDidScroll(scrollView)
    }
    
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        container.scrollViewWillBeginDragging(scrollView)
    }
    
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        container.scrollViewDidEndDecelerating(scrollView)
    }
    
    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        container.scrollViewDidEndDragging(scrollView, willDecelerate: decelerate)
    }
}

extension ViewController: UITableViewDelegate {
    ...
}

extension ViewController: UITableViewDataSource {
    ...
}

Добавить HeaderView

let headerView = ExampleHeaderGripView()
headerView.height = 20

container.add(headerView: headerView)

Добавить FooterView

let tabBarView = HeaderTabBarView()
tabBarView.height = 49.0

container.add(footerView: tabBarView)

Добавить кастомное вью CustomView

// Add custom shadow
let layer = container.view.layer
layer.shadowOpacity = 0.5
layer.shadowColor = UIColor.red.cgColor
layer.shadowOffset = CGSize(width: 1, height: 4)
layer.shadowRadius = 5

// Add view in container.view
let viewRed = UIView(frame: CGRect(x: 50, y: 50, width: 50, height: 50))
viewRed.backgroundColor = .systemRed
container.view.addSubview(viewRed)

// Add view under scrollView container.view
let viewGreen = UIView(frame: CGRect(x: 25, y: 25, width: 50, height: 50))
viewGreen.backgroundColor = .systemGreen
container.view.insertSubview(viewGreen, at: 0)

Настройки ⚙️

Layout Макет

Настройте Layout с помощью создания подкласса ContainerLayout при инициализации

class NewContainerLayout: ContainerLayout {
    
    override init() {
        super.init()
        
        // Initialization start position.
        startPosition = .hide
        
        // Disables any moving with gestures.
        movingEnabled = true
        
        // Sets the new value for positions of animated movement (top, middle, bottom).
        positions = ContainerPosition(top: 70, middle: 250, bottom: 70)
        
        // Sets insets container.view  (left, right).
        insets = ContainerInsets(right: 20, left: 20)
    }
}

class ViewController: UIViewController {

    var container: ContainerController!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        container = ContainerController(addTo: self, layout: NewContainerLayout())
        container.move(type: .top)
    }
}

Или создайте объект ContainerLayout

override func viewDidLoad() {
    super.viewDidLoad()
    
    // Create ContainerController Layout object
    let layout = ContainerLayout()
    layout.startPosition = .hide
    layout.backgroundShadowShow = true
    layout.positions = ContainerPosition(top: 70, middle: 250, bottom: 70)
    
    container = ContainerController(addTo: self, layout: layout)
}

Измените настройки контейнера сразу - не обновляя Layout

// Properties
container.set(movingEnabled: true)
container.set(trackingPosition: false)
container.set(footerPadding: 100)

// Add ScrollInsets Top/Bottom
container.set(scrollIndicatorTop: 5) // ↓
container.set(scrollIndicatorBottom: 5) // ↑

// Positions
container.set(top: 70) // ↓
container.set(middle: 250) // ↑
container.set(bottom: 80) // ↑

// Middle Enable/Disable
container.set(middle: 250)
container.set(middle: nil)

// Background Shadow
container.set(backgroundShadowShow: true)

// Insets View
container.set(left: 5) // →
container.set(right: 5) // ←

// Landscape params
container.setLandscape(top: 30)
container.setLandscape(middle: 150)
container.setLandscape(bottom: 70)
container.setLandscape(middle: nil)

container.setLandscape(backgroundShadowShow: false)

container.setLandscape(left: 10)
container.setLandscape(right: 100)

ContainerController View

Используйте готовое решение

ContainerViewгенерируется автоматически при создании ContainerController Используйте готовое решение для изменения радиуса, добавления тени и размытия.

Изменить окружность краев CornerRadius

// Change cornerRadius global for all subviews
container.view.cornerRadius = 15 

Добавить слой Shadow

container.view.addShadow(opacity: 0.1) 

Добавить фон Blur

// add blur UIVisualEffectView
container.view.addBlur(style: .dark) 

Подробнее

Изменение положения на экране Верх / Середина / Низ ( .top / .middle / .bottom)

// These parameters set the new position value.
container.layout.positions = ContainerPosition(top: 70, middle: 250, bottom: 70)

// Change settings right away
container.set(top: 70) // ↓
container.set(middle: 250) // ↑
container.set(bottom: 80) // ↑

Настройте отступы

// Sets insets container.view  (left, right).
container.layout.insets = ContainerInsets(right: 20, left: 20)

container.layout.landscapeInsets = ContainerInsets(right: 20, left: 100)


// Change settings right away
container.set(left: 5) // →
container.set(right: 5) // ←

container.setLandscape(left: 10)
container.setLandscape(right: 100)

Настроить для альбомной ориентации

// Sets the background shadow under container. (Default: backgroundShadowShow).
container.layout.landscapeBackgroundShadowShow = false

// Sets the new value for positions of animated movement (top, middle, bottom). (Default: positions).
container.layout.landscapePositions = ContainerPosition(top: 20, middle: 150, bottom: 70)

// Sets insets container.view (left, right). (Default: insets).
container.layout.landscapeInsets = ContainerInsets(right: 20, left: 100)


// Change settings right away

container.setLandscape(top: 30)
container.setLandscape(middle: 150)
container.setLandscape(bottom: 70)
container.setLandscape(middle: nil)

container.setLandscape(backgroundShadowShow: false)

container.setLandscape(left: 10)
container.setLandscape(right: 100)

Параметры для управления footerView

// Padding-top from container.view, if headerView is added, then its + height is summed.
container.layout.footerPadding = 100

// Tracking position container.view during animated movement.
container.layout.trackingPosition = false

// Change settings right away

container.set(footerPadding: 100)
container.set(trackingPosition: false)
изображение
изображение

 

изображение
изображение

ContainerController Delegate

class ViewController: UIViewController, ContainerControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let container = ContainerController(addTo: self, layout: layout)
        container.delegate = self
    }
}

/// Reports rotation and orientation changes
func containerControllerRotation(_ containerController: ContainerController) {
    ...
}

/// Reports a click on the background shadow
func containerControllerShadowClick(_ containerController: ContainerController) {
    ...
}

/// Reports the changes current position of the container, after its use
func containerControllerMove(_ containerController: ContainerController, position: CGFloat, type: ContainerMoveType, animation: Bool) {
    ...
}

Получение событий от делегата

func containerControllerRotation

Сообщает об изменениях поворота и ориентации

func containerControllerShadowClick

Сообщает о нажатии на фоновую тень

func containerControllerMove

Сообщает об изменениях текущего положения контейнера

Позиция значение — position: CGFloat,
Тип позиции — type: ContainerMoveType,
Анимированное перемещение — animation: Bool

Комментарии (0)