// Copyright 2017-present the Material Components for iOS authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import UIKit import CoreGraphics import MaterialComponents.MaterialAppBar_ColorThemer import MaterialComponents.MaterialAppBar_TypographyThemer import MaterialComponents.MaterialButtons import MaterialComponents.MaterialContainerScheme import MaterialComponents.MaterialTabs import MaterialComponents.MaterialTabs_Theming class TabBarIndicatorTemplateExample: UIViewController { // MARK: Properties var alignment: MDCTabBarAlignment { get { return tabBar.alignment } set(newAlignment) { tabBar.setAlignment(newAlignment, animated: true) } } var itemAppearance: MDCTabBarItemAppearance { get { return tabBar.itemAppearance } set { tabBar.itemAppearance = newValue // itemAppearance affects the height of the tab bar. appBarViewController.headerStackView.setNeedsLayout() } } lazy var alignmentButton: MDCButton = self.makeAlignmentButton() lazy var appearanceButton: MDCButton = self.makeAppearanceButton() lazy var appBarViewController: MDCAppBarViewController = self.makeAppBar() @objc var containerScheme = MDCContainerScheme() lazy var tabBar: MDCTabBar = { let tabBar = MDCTabBar() tabBar.alignment = .justified tabBar.applyPrimaryTheme(withScheme: containerScheme) let bundle = Bundle(for: TabBarIndicatorTemplateExample.self) let info = UIImage.init(named: "TabBarDemo_ic_info", in: bundle, compatibleWith:nil) let star = UIImage.init(named: "TabBarDemo_ic_star", in: bundle, compatibleWith:nil) tabBar.items = [ UITabBarItem(title: "Fly", image: info, tag:0), UITabBarItem(title: "Sleep", image: star, tag:0), UITabBarItem(title: "Eat", image: info, tag:0), ] // Set lighter ink so the indicator animation is more visible. tabBar.inkColor = UIColor.white.withAlphaComponent(0.15) tabBar.itemAppearance = .titles // Configure custom title fonts tabBar.selectedItemTitleFont = UIFont.boldSystemFont(ofSize: 12) tabBar.unselectedItemTitleFont = UIFont.systemFont(ofSize: 12) // Configure custom indicator template tabBar.selectionIndicatorTemplate = IndicatorTemplate() return tabBar }() // MARK: Methods override func viewDidLoad() { super.viewDidLoad() setupExampleViews() alignmentButton.addTarget( self, action:#selector(changeAlignmentDidTouch(sender:)), for: .touchUpInside) appearanceButton.addTarget( self, action: #selector(changeAppearance), for: .touchUpInside) MDCAppBarColorThemer.applyColorScheme(containerScheme.colorScheme, to: self.appBarViewController) MDCAppBarTypographyThemer.applyTypographyScheme(containerScheme.typographyScheme, to: self.appBarViewController) } @objc func changeAlignmentDidTouch(sender: UIButton) { let sheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) sheet.popoverPresentationController?.sourceView = self.alignmentButton sheet.popoverPresentationController?.sourceRect = self.alignmentButton.bounds sheet.addAction(UIAlertAction(title: "Leading", style: .default, handler: { _ in self.alignment = .leading })) sheet.addAction(UIAlertAction(title: "Center", style: .default, handler: { _ in self.alignment = .center })) sheet.addAction(UIAlertAction(title: "Justified", style: .default, handler: { _ in self.alignment = .justified })) sheet.addAction(UIAlertAction(title: "Selected Center", style: .default, handler: { _ in self.alignment = .centerSelected })) present(sheet, animated: true, completion:nil) } @objc func changeAppearance(fromSender sender: UIButton) { let sheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) sheet.popoverPresentationController?.sourceView = self.appearanceButton sheet.popoverPresentationController?.sourceRect = self.appearanceButton.bounds sheet.addAction(UIAlertAction(title: "Titles", style: .default, handler: { _ in self.itemAppearance = .titles })) sheet.addAction(UIAlertAction(title: "Images", style: .default, handler: { _ in self.itemAppearance = .images })) sheet.addAction(UIAlertAction(title: "Titled Images", style: .default, handler: { _ in self.itemAppearance = .titledImages })) present(sheet, animated: true, completion:nil) } // MARK: Private class IndicatorTemplate: NSObject, MDCTabBarIndicatorTemplate { func indicatorAttributes( for context: MDCTabBarIndicatorContext ) -> MDCTabBarIndicatorAttributes { let attributes = MDCTabBarIndicatorAttributes() // Outset frame, round corners, and stroke. let indicatorFrame = context.contentFrame.insetBy(dx: -8, dy: -4) let path = UIBezierPath(roundedRect: indicatorFrame, cornerRadius: 4) attributes.path = path.stroked(withWidth: 2) return attributes } } } extension UIBezierPath { /// Returns a copy of the path, stroked with the given line width. func stroked(withWidth width: CGFloat) -> UIBezierPath { let strokedPath = cgPath.copy( strokingWithWidth: width, lineCap: .butt, lineJoin: .miter, miterLimit: 0) return UIBezierPath(cgPath: strokedPath) } }