diff --git a/Example/Example tvOS/Assets.xcassets/baseline-account_circle-24px.imageset/Contents.json b/Example/Example tvOS/Assets.xcassets/baseline-account_circle-24px.imageset/Contents.json new file mode 100644 index 0000000..fb94720 --- /dev/null +++ b/Example/Example tvOS/Assets.xcassets/baseline-account_circle-24px.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "baseline-account_circle-24px.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/Example/Example tvOS/Assets.xcassets/baseline-account_circle-24px.imageset/baseline-account_circle-24px.pdf b/Example/Example tvOS/Assets.xcassets/baseline-account_circle-24px.imageset/baseline-account_circle-24px.pdf new file mode 100644 index 0000000..f3508d1 Binary files /dev/null and b/Example/Example tvOS/Assets.xcassets/baseline-account_circle-24px.imageset/baseline-account_circle-24px.pdf differ diff --git a/Example/Example tvOS/Assets.xcassets/baseline-folder-24px.imageset/Contents.json b/Example/Example tvOS/Assets.xcassets/baseline-folder-24px.imageset/Contents.json new file mode 100644 index 0000000..5334833 --- /dev/null +++ b/Example/Example tvOS/Assets.xcassets/baseline-folder-24px.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "baseline-folder-24px.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/Example/Example tvOS/Assets.xcassets/baseline-folder-24px.imageset/baseline-folder-24px.pdf b/Example/Example tvOS/Assets.xcassets/baseline-folder-24px.imageset/baseline-folder-24px.pdf new file mode 100644 index 0000000..5fc32f5 Binary files /dev/null and b/Example/Example tvOS/Assets.xcassets/baseline-folder-24px.imageset/baseline-folder-24px.pdf differ diff --git a/Example/Example tvOS/Assets.xcassets/baseline-home-24px.imageset/Contents.json b/Example/Example tvOS/Assets.xcassets/baseline-home-24px.imageset/Contents.json new file mode 100644 index 0000000..fa3189a --- /dev/null +++ b/Example/Example tvOS/Assets.xcassets/baseline-home-24px.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "baseline-home-24px.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/Example/Example tvOS/Assets.xcassets/baseline-home-24px.imageset/baseline-home-24px.pdf b/Example/Example tvOS/Assets.xcassets/baseline-home-24px.imageset/baseline-home-24px.pdf new file mode 100644 index 0000000..0b16a4d Binary files /dev/null and b/Example/Example tvOS/Assets.xcassets/baseline-home-24px.imageset/baseline-home-24px.pdf differ diff --git a/Example/Example tvOS/Assets.xcassets/baseline-search-24px.imageset/Contents.json b/Example/Example tvOS/Assets.xcassets/baseline-search-24px.imageset/Contents.json new file mode 100644 index 0000000..627e7fe --- /dev/null +++ b/Example/Example tvOS/Assets.xcassets/baseline-search-24px.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "baseline-search-24px.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/Example/Example tvOS/Assets.xcassets/baseline-search-24px.imageset/baseline-search-24px.pdf b/Example/Example tvOS/Assets.xcassets/baseline-search-24px.imageset/baseline-search-24px.pdf new file mode 100644 index 0000000..e304379 Binary files /dev/null and b/Example/Example tvOS/Assets.xcassets/baseline-search-24px.imageset/baseline-search-24px.pdf differ diff --git a/Example/Example tvOS/Assets.xcassets/baseline-settings-20px.imageset/Contents.json b/Example/Example tvOS/Assets.xcassets/baseline-settings-20px.imageset/Contents.json new file mode 100644 index 0000000..89dc1fb --- /dev/null +++ b/Example/Example tvOS/Assets.xcassets/baseline-settings-20px.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "baseline-settings-20px.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/Example/Example tvOS/Assets.xcassets/baseline-settings-20px.imageset/baseline-settings-20px.pdf b/Example/Example tvOS/Assets.xcassets/baseline-settings-20px.imageset/baseline-settings-20px.pdf new file mode 100644 index 0000000..9045087 Binary files /dev/null and b/Example/Example tvOS/Assets.xcassets/baseline-settings-20px.imageset/baseline-settings-20px.pdf differ diff --git a/Example/Example tvOS/Assets.xcassets/baseline-video_library-24px.imageset/Contents.json b/Example/Example tvOS/Assets.xcassets/baseline-video_library-24px.imageset/Contents.json new file mode 100644 index 0000000..e159376 --- /dev/null +++ b/Example/Example tvOS/Assets.xcassets/baseline-video_library-24px.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "baseline-video_library-24px.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/Example/Example tvOS/Assets.xcassets/baseline-video_library-24px.imageset/baseline-video_library-24px.pdf b/Example/Example tvOS/Assets.xcassets/baseline-video_library-24px.imageset/baseline-video_library-24px.pdf new file mode 100644 index 0000000..7b18b12 Binary files /dev/null and b/Example/Example tvOS/Assets.xcassets/baseline-video_library-24px.imageset/baseline-video_library-24px.pdf differ diff --git a/Example/Example tvOS/Assets.xcassets/yt_icon_rgb.imageset/Contents.json b/Example/Example tvOS/Assets.xcassets/yt_icon_rgb.imageset/Contents.json new file mode 100644 index 0000000..39c16bc --- /dev/null +++ b/Example/Example tvOS/Assets.xcassets/yt_icon_rgb.imageset/Contents.json @@ -0,0 +1,17 @@ +{ + "images" : [ + { + "idiom" : "tv", + "scale" : "1x" + }, + { + "idiom" : "tv", + "filename" : "yt_icon_rgb.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/Example tvOS/Assets.xcassets/yt_icon_rgb.imageset/yt_icon_rgb.png b/Example/Example tvOS/Assets.xcassets/yt_icon_rgb.imageset/yt_icon_rgb.png new file mode 100644 index 0000000..7f0b343 Binary files /dev/null and b/Example/Example tvOS/Assets.xcassets/yt_icon_rgb.imageset/yt_icon_rgb.png differ diff --git a/Example/Example tvOS/Base.lproj/Main.storyboard b/Example/Example tvOS/Base.lproj/Main.storyboard index 431028b..413b05d 100644 --- a/Example/Example tvOS/Base.lproj/Main.storyboard +++ b/Example/Example tvOS/Base.lproj/Main.storyboard @@ -4,16 +4,16 @@ - + - + - + @@ -21,53 +21,174 @@ - + - - - - + + - + - + + + + - - + + - - - - - - - - - - - - - - - - - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -85,553 +206,29 @@ + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + diff --git a/Example/Example tvOS/Colors.xcassets/Background.colorset/Contents.json b/Example/Example tvOS/Colors.xcassets/Background.colorset/Contents.json new file mode 100644 index 0000000..744d440 --- /dev/null +++ b/Example/Example tvOS/Colors.xcassets/Background.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "colors" : [ + { + "idiom" : "universal", + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "0.184", + "alpha" : "1.000", + "blue" : "0.184", + "green" : "0.180" + } + } + } + ] +} \ No newline at end of file diff --git a/Example/Example tvOS/Colors.xcassets/Contents.json b/Example/Example tvOS/Colors.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Example/Example tvOS/Colors.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/Example tvOS/Colors.xcassets/Theme.colorset/Contents.json b/Example/Example tvOS/Colors.xcassets/Theme.colorset/Contents.json new file mode 100644 index 0000000..d2be700 --- /dev/null +++ b/Example/Example tvOS/Colors.xcassets/Theme.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "colors" : [ + { + "idiom" : "universal", + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "0.157", + "alpha" : "1.000", + "blue" : "0.157", + "green" : "0.157" + } + } + } + ] +} \ No newline at end of file diff --git a/Example/Example tvOS/Info.plist b/Example/Example tvOS/Info.plist index 02942a3..bf610cf 100644 --- a/Example/Example tvOS/Info.plist +++ b/Example/Example tvOS/Info.plist @@ -27,6 +27,6 @@ arm64 UIUserInterfaceStyle - Automatic + Dark diff --git a/Example/Example tvOS/YoutubeTabBar.swift b/Example/Example tvOS/YoutubeTabBar.swift new file mode 100644 index 0000000..5bc3f8b --- /dev/null +++ b/Example/Example tvOS/YoutubeTabBar.swift @@ -0,0 +1,258 @@ +// +// YoutubeTabBar.swift +// TabBarController_Example tvOS +// +// Created by Arnaud Dorgans on 11/09/2018. +// Copyright © 2018 CocoaPods. All rights reserved. +// + +import UIKit +import TabBarController + +@objc enum YoutubeAction: Int { + case search + + var image: UIImage? { + switch self { + case .search: + return UIImage(named: "baseline-search-24px", in: Bundle(for: YoutubeTabBar.self), compatibleWith: nil) + } + } +} + +class YoutubeTabBarItem: UITabBarItem { + + @IBInspectable var isAccessory: Bool = false + var action: YoutubeAction? + + var isAction: Bool { + return action != nil + } + + convenience init(image: UIImage?, isAccessory: Bool) { + self.init() + self.isAccessory = isAccessory + self.image = image + } + + convenience init(action: YoutubeAction, isAccessory: Bool) { + self.init() + self.action = action + self.isAccessory = isAccessory + self.image = action.image + } +} + +@objc protocol YoutubeTabBarDelegate: class { + + @objc func youtubeTabBar(_ youtubeTabBar: YoutubeTabBar, didTriggerAction action: YoutubeAction) +} + +@IBDesignable class YoutubeTabBar: UIView, TabBarProtocol { + + private let logoImageView = UIImageView() + private let contentView = UIView() + private let stackView = UIStackView() + private let accessoryStackView = UIStackView() + + private let youtubeAnimator = YoutubeTabBarAnimator() + + weak var delegate: TabBarDelegate? + @IBOutlet weak var youtubeDelegate: YoutubeTabBarDelegate? + + override var preferredFocusEnvironments: [UIFocusEnvironment] { + return [stackView.arrangedSubviews, accessoryStackView.arrangedSubviews] + .flatMap { $0 } + .sorted(by: { lhs, _ in (lhs as? YoutubeTabBarButton)?.isSelected == true }) + } + + override init(frame: CGRect) { + super.init(frame: frame) + sharedInit() + } + + override func awakeFromNib() { + super.awakeFromNib() + sharedInit() + } + + private func sharedInit() { + self.layer.shadowColor = UIColor.black.cgColor + self.layer.shadowOffset = CGSize(width: 8, height: 0) + self.layer.shadowOpacity = 0.3 + + contentView.translatesAutoresizingMaskIntoConstraints = false + contentView.backgroundColor = UIColor(named: "Theme", in: Bundle(for: YoutubeTabBar.self), compatibleWith: nil) + self.addSubview(contentView) + contentView.widthAnchor.constraint(equalToConstant: 200).isActive = true + contentView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true + contentView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true + contentView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true + contentView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true + + logoImageView.image = UIImage(named: "yt_icon_rgb", in: Bundle(for: YoutubeTabBar.self), compatibleWith: nil) + logoImageView.translatesAutoresizingMaskIntoConstraints = false + logoImageView.contentMode = .center + self.addSubview(logoImageView) + logoImageView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true + logoImageView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true + logoImageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true + logoImageView.heightAnchor.constraint(equalTo: logoImageView.widthAnchor).isActive = true + + stackView.translatesAutoresizingMaskIntoConstraints = false + self.addSubview(stackView) + stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true + stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true + stackView.topAnchor.constraint(equalTo: logoImageView.bottomAnchor).isActive = true + + accessoryStackView.translatesAutoresizingMaskIntoConstraints = false + self.addSubview(accessoryStackView) + accessoryStackView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true + accessoryStackView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true + accessoryStackView.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor).isActive = true + + [stackView, accessoryStackView].forEach { + $0.axis = .vertical + $0.distribution = .fillEqually + } + } + + func setSelectedItem(_ item: UITabBarItem?, animated: Bool) { + [stackView.arrangedSubviews, accessoryStackView.arrangedSubviews] + .flatMap { $0 } + .forEach { + guard let button = $0 as? YoutubeTabBarButton else { + return + } + button.isSelected = button.item == item + } + } + + func setItems(_ items: [UITabBarItem]?, animated: Bool) { + [stackView.arrangedSubviews, accessoryStackView.arrangedSubviews] + .flatMap { $0 } + .forEach { $0.removeFromSuperview() } + let items = [[YoutubeTabBarItem(action: .search, isAccessory: false)], items ?? []].flatMap { $0 } + items.forEach { + guard let button = YoutubeTabBarButton(item: $0) else { + return + } + button.addTarget(self, action: #selector(self.didTapButton(_:)), for: .primaryActionTriggered) + if button.item.isAccessory { + accessoryStackView.addArrangedSubview(button) + } else { + stackView.addArrangedSubview(button) + } + } + } + + @objc func didTapButton(_ sender: Any) { + guard let button = sender as? YoutubeTabBarButton, + let action = button.item.action else { + return + } + self.youtubeDelegate?.youtubeTabBar(self, didTriggerAction: action) + } + + override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) { + guard let button = context.nextFocusedView as? YoutubeTabBarButton else { + return + } + self.delegate?.tabBar(self, didSelect: button.item) + } + + func animator() -> TabBarAnimator? { + return youtubeAnimator + } + + override func prepareForInterfaceBuilder() { + let items = [YoutubeTabBarItem(image: UIImage(named: "baseline-home-24px", in: Bundle(for: YoutubeTabBar.self), compatibleWith: nil), isAccessory: false), + YoutubeTabBarItem(image: UIImage(named: "baseline-video_library-24px", in: Bundle(for: YoutubeTabBar.self), compatibleWith: nil), isAccessory: false), + YoutubeTabBarItem(image: UIImage(named: "baseline-folder-24px", in: Bundle(for: YoutubeTabBar.self), compatibleWith: nil), isAccessory: false), + YoutubeTabBarItem(image: UIImage(named: "baseline-account_circle-24px", in: Bundle(for: YoutubeTabBar.self), compatibleWith: nil), isAccessory: true), + YoutubeTabBarItem(image: UIImage(named: "baseline-settings-20px", in: Bundle(for: YoutubeTabBar.self), compatibleWith: nil), isAccessory: true)] + self.setItems(items, animated: false) + self.setSelectedItem(items.first, animated: false) + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } +} + +private class YoutubeTabBarButton: UIButton { + + private let logoView = UIImageView() + private let backgroundView = UIView() + private let roundedBackgroundView = UIView() + + let item: YoutubeTabBarItem + + init?(item: UITabBarItem) { + guard let item = item as? YoutubeTabBarItem else { + return nil + } + self.item = item + super.init(frame: .zero) + + roundedBackgroundView.layer.shadowOffset = CGSize(width: 0, height: 5) + roundedBackgroundView.layer.shadowColor = UIColor.black.cgColor + roundedBackgroundView.layer.shadowOpacity = 1 + roundedBackgroundView.isUserInteractionEnabled = false + roundedBackgroundView.translatesAutoresizingMaskIntoConstraints = false + self.addSubview(roundedBackgroundView) + roundedBackgroundView.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true + roundedBackgroundView.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true + roundedBackgroundView.heightAnchor.constraint(equalTo: self.heightAnchor, multiplier: 0.9).isActive = true + roundedBackgroundView.widthAnchor.constraint(equalTo: roundedBackgroundView.heightAnchor).isActive = true + + backgroundView.isUserInteractionEnabled = false + backgroundView.translatesAutoresizingMaskIntoConstraints = false + self.addSubview(backgroundView) + backgroundView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true + backgroundView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true + backgroundView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true + backgroundView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true + + logoView.image = item.image + logoView.contentMode = .center + logoView.translatesAutoresizingMaskIntoConstraints = false + self.addSubview(logoView) + logoView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true + logoView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true + logoView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true + logoView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true + logoView.heightAnchor.constraint(equalTo: logoView.widthAnchor, multiplier: 0.6).isActive = true + + update() + } + + private func update() { + logoView.tintColor = { + guard !self.isFocused else { + return UIColor(named: "Theme", in: Bundle(for: YoutubeTabBar.self), compatibleWith: nil) + } + return self.isSelected ? UIColor.white : UIColor.white.withAlphaComponent(0.4) + }() + backgroundView.backgroundColor = self.isFocused ? .white : .clear + roundedBackgroundView.backgroundColor = backgroundView.backgroundColor + backgroundView.isHidden = self.item.isAction + roundedBackgroundView.isHidden = !backgroundView.isHidden + } + + override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) { + coordinator.addCoordinatedAnimations({ + self.update() + }, completion: nil) + } + + override func layoutSubviews() { + super.layoutSubviews() + + roundedBackgroundView.layer.cornerRadius = roundedBackgroundView.frame.height / 2 + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/Example/Example tvOS/YoutubeTabBarAnimator.swift b/Example/Example tvOS/YoutubeTabBarAnimator.swift new file mode 100644 index 0000000..f57f285 --- /dev/null +++ b/Example/Example tvOS/YoutubeTabBarAnimator.swift @@ -0,0 +1,30 @@ +// +// YoutubeTabBarAnimator.swift +// TabBarController_Example tvOS +// +// Created by Arnaud Dorgans on 11/09/2018. +// Copyright © 2018 CocoaPods. All rights reserved. +// + +import UIKit +import TabBarController + +class YoutubeTabBarAnimator: TabBarAnimator { + + private var tabBarConstraints = [NSLayoutConstraint]() + + func tabBarInsets(withContext context: TabBarAnimatorContext) -> UIEdgeInsets { + return UIEdgeInsets(top: 0, left: context.tabBar.frame.width, bottom: 0, right: 0) + } + + func animateTabBar(using context: TabBarAnimatorContext) { + if tabBarConstraints.isEmpty { + context.tabBar.translatesAutoresizingMaskIntoConstraints = false + context.containerView.addSubview(context.tabBar) + tabBarConstraints.append(context.tabBar.leadingAnchor.constraint(equalTo: context.containerView.leadingAnchor)) + tabBarConstraints.append(context.tabBar.topAnchor.constraint(equalTo: context.containerView.topAnchor)) + tabBarConstraints.append(context.tabBar.bottomAnchor.constraint(equalTo: context.containerView.bottomAnchor)) + NSLayoutConstraint.activate(tabBarConstraints) + } + } +} diff --git a/Example/Example tvOS/YoutubeTabBarController.swift b/Example/Example tvOS/YoutubeTabBarController.swift new file mode 100644 index 0000000..e1dd3f6 --- /dev/null +++ b/Example/Example tvOS/YoutubeTabBarController.swift @@ -0,0 +1,42 @@ +// +// YoutubeTabBarController.swift +// TabBarController_Example tvOS +// +// Created by Arnaud Dorgans on 11/09/2018. +// Copyright © 2018 CocoaPods. All rights reserved. +// + +import UIKit +import TabBarController + +class YoutubeTabBarController: TabBarController { + + let tabBarFocusGuide = UIFocusGuide() + + override func viewDidLoad() { + super.viewDidLoad() + + self.view.addLayoutGuide(tabBarFocusGuide) + tabBarFocusGuide.topAnchor.constraint(equalTo: tabBar.topAnchor).isActive = true + tabBarFocusGuide.bottomAnchor.constraint(equalTo: tabBar.bottomAnchor).isActive = true + tabBarFocusGuide.leftAnchor.constraint(equalTo: tabBar.rightAnchor).isActive = true + tabBarFocusGuide.widthAnchor.constraint(equalToConstant: 1).isActive = true + } + + override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) { + super.didUpdateFocus(in: context, with: coordinator) + + guard let item = context.nextFocusedItem else { + return + } + tabBarFocusGuide.preferredFocusEnvironments = [self.tabBar.contains(item) ? containerView : tabBar] + } +} + +extension YoutubeTabBarController: YoutubeTabBarDelegate { + + func youtubeTabBar(_ youtubeTabBar: YoutubeTabBar, didTriggerAction action: YoutubeAction) { + let searchController = UISearchController(searchResultsController: nil) + self.present(searchController, animated: true, completion: nil) + } +} diff --git a/Example/Podfile.lock b/Example/Podfile.lock index e8442ec..9bbef99 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -1,5 +1,5 @@ PODS: - - TabBarController (0.1.0) + - TabBarController (1.0) DEPENDENCIES: - TabBarController (from `../`) @@ -9,7 +9,7 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - TabBarController: c2e762e8898f5d3af42beb108a639771baf4fae3 + TabBarController: afe4560c4934f25088b0f13129e95d0d76410ad8 PODFILE CHECKSUM: 8947fba8d959d70de552e8e03041ad5648b8e41c diff --git a/Example/TabBarController.xcodeproj/project.pbxproj b/Example/TabBarController.xcodeproj/project.pbxproj index f568c80..395aac6 100644 --- a/Example/TabBarController.xcodeproj/project.pbxproj +++ b/Example/TabBarController.xcodeproj/project.pbxproj @@ -24,6 +24,10 @@ D486CDC121284B380015BE9A /* iOS9TableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D486CDC021284B380015BE9A /* iOS9TableViewController.swift */; }; D49561132129AF08008363D2 /* SpringboardTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D49561122129AF08008363D2 /* SpringboardTabBar.swift */; }; D4EDE0A721270D7900B5346A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; }; + D4EEEE022147EF580082FB08 /* YoutubeTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4EEEE012147EF580082FB08 /* YoutubeTabBar.swift */; }; + D4EEEE042147F1DB0082FB08 /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D4EEEE032147F1DB0082FB08 /* Colors.xcassets */; }; + D4EEEE0621480AEF0082FB08 /* YoutubeTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4EEEE0521480AEF0082FB08 /* YoutubeTabBarController.swift */; }; + D4EEEE082148364B0082FB08 /* YoutubeTabBarAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4EEEE072148364B0082FB08 /* YoutubeTabBarAnimator.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -64,6 +68,10 @@ D45C21C02126EFA4004D21C2 /* SpringboardTabBarTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpringboardTabBarTransition.swift; sourceTree = ""; }; D486CDC021284B380015BE9A /* iOS9TableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOS9TableViewController.swift; sourceTree = ""; }; D49561122129AF08008363D2 /* SpringboardTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpringboardTabBar.swift; sourceTree = ""; }; + D4EEEE012147EF580082FB08 /* YoutubeTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YoutubeTabBar.swift; sourceTree = ""; }; + D4EEEE032147F1DB0082FB08 /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = ""; }; + D4EEEE0521480AEF0082FB08 /* YoutubeTabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YoutubeTabBarController.swift; sourceTree = ""; }; + D4EEEE072148364B0082FB08 /* YoutubeTabBarAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YoutubeTabBarAnimator.swift; sourceTree = ""; }; DDC31CB3904783CBD80ADB30 /* Pods-TabBarController_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TabBarController_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-TabBarController_Example/Pods-TabBarController_Example.debug.xcconfig"; sourceTree = ""; }; E6D42CFDD2DF28A3B3C61818 /* Pods_TabBarController_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_TabBarController_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; EB8401B9CBC7D663C150F67D /* Pods-TabBarController_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TabBarController_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-TabBarController_Example/Pods-TabBarController_Example.release.xcconfig"; sourceTree = ""; }; @@ -188,9 +196,11 @@ D45C21AD2126B7AF004D21C2 /* Example tvOS */ = { isa = PBXGroup; children = ( + D4EEEE002147EF350082FB08 /* Youtube */, D45C21AE2126B7AF004D21C2 /* AppDelegate.swift */, D45C21B22126B7AF004D21C2 /* Main.storyboard */, D45C21B52126B7B0004D21C2 /* Assets.xcassets */, + D4EEEE032147F1DB0082FB08 /* Colors.xcassets */, D45C21B72126B7B0004D21C2 /* Info.plist */, ); path = "Example tvOS"; @@ -206,6 +216,16 @@ name = Springboard; sourceTree = ""; }; + D4EEEE002147EF350082FB08 /* Youtube */ = { + isa = PBXGroup; + children = ( + D4EEEE012147EF580082FB08 /* YoutubeTabBar.swift */, + D4EEEE0521480AEF0082FB08 /* YoutubeTabBarController.swift */, + D4EEEE072148364B0082FB08 /* YoutubeTabBarAnimator.swift */, + ); + name = Youtube; + sourceTree = ""; + }; D7136837F9A4A10D451C19B0 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -346,6 +366,7 @@ buildActionMask = 2147483647; files = ( D4EDE0A721270D7900B5346A /* Images.xcassets in Resources */, + D4EEEE042147F1DB0082FB08 /* Colors.xcassets in Resources */, D45C21B62126B7B0004D21C2 /* Assets.xcassets in Resources */, D45C21B42126B7AF004D21C2 /* Main.storyboard in Resources */, ); @@ -472,7 +493,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D4EEEE0621480AEF0082FB08 /* YoutubeTabBarController.swift in Sources */, D45C21AF2126B7AF004D21C2 /* AppDelegate.swift in Sources */, + D4EEEE082148364B0082FB08 /* YoutubeTabBarAnimator.swift in Sources */, + D4EEEE022147EF580082FB08 /* YoutubeTabBar.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -714,7 +738,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 9.0; + TVOS_DEPLOYMENT_TARGET = 11.0; }; name = Debug; }; @@ -741,7 +765,7 @@ SDKROOT = appletvos; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 3; - TVOS_DEPLOYMENT_TARGET = 9.0; + TVOS_DEPLOYMENT_TARGET = 11.0; }; name = Release; }; diff --git a/Images/004.gif b/Images/004.gif index dd78ee6..f73ad40 100644 Binary files a/Images/004.gif and b/Images/004.gif differ diff --git a/TabBarController/Classes/TabBarController.swift b/TabBarController/Classes/TabBarController.swift index 713e4fa..e0f4b38 100644 --- a/TabBarController/Classes/TabBarController.swift +++ b/TabBarController/Classes/TabBarController.swift @@ -56,6 +56,10 @@ open class TabBarController: UIViewController { } #endif + public var containerView: UIView { + return containerController.view + } + private var _tabBarAnchor: TabBarAnchor = .default public var tabBarAnchor: TabBarAnchor { get { return _tabBarAnchor }