mirror of
https://github.com/material-components/material-components-ios.git
synced 2026-02-20 08:27:32 +08:00
232 lines
7.8 KiB
Swift
232 lines
7.8 KiB
Swift
// Copyright 2020-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 MaterialComponents.MaterialAppBar
|
|
import MaterialComponents.MaterialAppBar_Theming
|
|
import MaterialComponents.MaterialBottomNavigation
|
|
import MaterialComponents.MaterialButtons
|
|
import MaterialComponents.MaterialButtons_Theming
|
|
import MaterialComponents.MaterialCards
|
|
import MaterialComponents.MaterialCards_Theming
|
|
import MaterialComponents.MaterialShadowElevations
|
|
import MaterialComponents.MaterialContainerScheme
|
|
|
|
/// An example for testing the performance of `MDCShadowLayer`. This example is not intended to
|
|
/// demonstrate how to setup any specific components but rather to push `MDCShadowLayer` to the
|
|
/// limits for metric testing.
|
|
class MDCShadowPerformanceExample:
|
|
UIViewController,
|
|
UICollectionViewDelegate,
|
|
UICollectionViewDataSource,
|
|
UICollectionViewDelegateFlowLayout
|
|
{
|
|
|
|
/// Injected `MDCAppBarViewController` so we can render the shadow on it.
|
|
lazy var appBar = makeAppBar()
|
|
|
|
/// The _plus_ FAB.
|
|
let createButton = MDCFloatingButton()
|
|
|
|
/// Used to render a _top_ shadow on a component that is pinned to the bottom.
|
|
let bottomNavBar = MDCBottomNavigationBar()
|
|
|
|
/// Used for styling the sub components based on the app container scheme.
|
|
// `@objc` is required for `setupTransition` to work within `MDCDragonsController`.
|
|
@objc var containerScheme: MDCContainerScheming = MDCContainerScheme()
|
|
|
|
/// The main scroll view content.
|
|
let collectionView = UICollectionView(
|
|
frame: .zero,
|
|
collectionViewLayout: UICollectionViewFlowLayout())
|
|
|
|
/// Number of cells in the `collectionView`.
|
|
let cellCount = 200
|
|
|
|
/// Cell reuse identifier.
|
|
let cellIdentifier = "Cell"
|
|
|
|
/// Padding between cells.
|
|
let defaultPadding: CGFloat = 8
|
|
|
|
/// The title of the example
|
|
fileprivate static let exampleTitle = "Shadow & Performance"
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
|
|
view.backgroundColor = containerScheme.colorScheme.backgroundColor
|
|
appBar.headerView.observesTrackingScrollViewScrollEvents = true
|
|
appBar.applyPrimaryTheme(withScheme: containerScheme)
|
|
appBar.didMove(toParent: self)
|
|
appBar.navigationBar.title = MDCShadowPerformanceExample.exampleTitle
|
|
|
|
collectionView.dataSource = self
|
|
collectionView.delegate = self
|
|
collectionView.backgroundColor = containerScheme.colorScheme.backgroundColor
|
|
collectionView.alwaysBounceVertical = true
|
|
collectionView.register(MDCCardCollectionCell.self, forCellWithReuseIdentifier: cellIdentifier)
|
|
collectionView.translatesAutoresizingMaskIntoConstraints = false
|
|
view.addSubview(collectionView)
|
|
view.addSubview(appBar.view)
|
|
appBar.headerView.trackingScrollView = collectionView
|
|
|
|
createButton.sizeToFit()
|
|
let plusImage = UIImage(named: "system_icons/add")
|
|
createButton.setImage(plusImage, for: .normal)
|
|
createButton.accessibilityLabel = "Create"
|
|
createButton.applySecondaryTheme(withScheme: containerScheme)
|
|
view.addSubview(createButton)
|
|
|
|
view.addSubview(bottomNavBar)
|
|
bottomNavBar.titleVisibility = .always
|
|
bottomNavBar.alignment = .centered
|
|
let tabBarItem1 = UITabBarItem(
|
|
title: "Home", image: UIImage(named: "system_icons/home"), tag: 0)
|
|
let tabBarItem2 =
|
|
UITabBarItem(title: "Messages", image: UIImage(named: "system_icons/email"), tag: 1)
|
|
bottomNavBar.items = [tabBarItem1, tabBarItem2]
|
|
bottomNavBar.selectedItem = tabBarItem2
|
|
}
|
|
|
|
override func viewWillLayoutSubviews() {
|
|
super.viewWillLayoutSubviews()
|
|
|
|
let width = view.bounds.width
|
|
let height = view.bounds.height
|
|
var safeArea: UIEdgeInsets = .zero
|
|
safeArea = view.safeAreaInsets
|
|
collectionView.contentInsetAdjustmentBehavior = .always
|
|
|
|
collectionView.frame = CGRect(
|
|
origin: .zero, size: CGSize(width: width, height: height - (safeArea.bottom + safeArea.top)))
|
|
|
|
let size = bottomNavBar.sizeThatFits(view.bounds.size)
|
|
var bottomNavBarFrame = CGRect(
|
|
x: 0,
|
|
y: height - size.height,
|
|
width: size.width,
|
|
height: size.height)
|
|
bottomNavBarFrame.size.height += safeArea.bottom
|
|
bottomNavBarFrame.origin.y -= safeArea.bottom
|
|
bottomNavBar.frame = bottomNavBarFrame
|
|
|
|
let createButtonDimension: CGFloat = 56
|
|
let createButtonPadding: CGFloat = 16
|
|
createButton.frame = CGRect(
|
|
x: width - (createButtonDimension + safeArea.left + createButtonPadding),
|
|
y: bottomNavBarFrame.origin.y - (createButtonDimension + createButtonPadding),
|
|
width: createButtonDimension,
|
|
height: createButtonDimension
|
|
)
|
|
}
|
|
|
|
private func makeAppBar() -> MDCAppBarViewController {
|
|
let appBarViewController = MDCAppBarViewController()
|
|
addChild(appBarViewController)
|
|
appBarViewController.headerView.minMaxHeightIncludesSafeArea = false
|
|
appBarViewController.inferTopSafeAreaInsetFromViewController = true
|
|
appBarViewController.headerView.canOverExtend = false
|
|
return appBarViewController
|
|
}
|
|
|
|
// MARK: Collection View methods
|
|
|
|
func collectionView(
|
|
_ collectionView: UICollectionView,
|
|
cellForItemAt indexPath: IndexPath
|
|
) -> UICollectionViewCell {
|
|
|
|
let cell = collectionView.dequeueReusableCell(
|
|
withReuseIdentifier: cellIdentifier, for: indexPath)
|
|
guard let cardCell = cell as? MDCCardCollectionCell else { return cell }
|
|
|
|
cardCell.enableRippleBehavior = true
|
|
cardCell.isAccessibilityElement = true
|
|
cardCell.accessibilityLabel = title
|
|
cardCell.setShadowElevation(.cardResting, for: .normal)
|
|
cardCell.applyTheme(withScheme: containerScheme)
|
|
|
|
return cardCell
|
|
}
|
|
|
|
func numberOfSections(in collectionView: UICollectionView) -> Int {
|
|
return 1
|
|
}
|
|
|
|
func collectionView(
|
|
_ collectionView: UICollectionView,
|
|
numberOfItemsInSection section: Int
|
|
) -> Int {
|
|
return cellCount
|
|
}
|
|
|
|
func collectionView(
|
|
_ collectionView: UICollectionView,
|
|
layout collectionViewLayout: UICollectionViewLayout,
|
|
sizeForItemAt indexPath: IndexPath
|
|
) -> CGSize {
|
|
let cardSize = (collectionView.bounds.size.width / 3) - 12
|
|
return CGSize(width: cardSize, height: cardSize)
|
|
}
|
|
|
|
func collectionView(
|
|
_ collectionView: UICollectionView,
|
|
layout collectionViewLayout: UICollectionViewLayout,
|
|
insetForSectionAt section: Int
|
|
) -> UIEdgeInsets {
|
|
return UIEdgeInsets(
|
|
top: defaultPadding,
|
|
left: defaultPadding,
|
|
bottom: defaultPadding,
|
|
right: defaultPadding
|
|
)
|
|
}
|
|
|
|
func collectionView(
|
|
_ collectionView: UICollectionView,
|
|
layout collectionViewLayout: UICollectionViewLayout,
|
|
minimumLineSpacingForSectionAt section: Int
|
|
) -> CGFloat {
|
|
return defaultPadding
|
|
}
|
|
|
|
func collectionView(
|
|
_ collectionView: UICollectionView,
|
|
layout collectionViewLayout: UICollectionViewLayout,
|
|
minimumInteritemSpacingForSectionAt section: Int
|
|
) -> CGFloat {
|
|
return defaultPadding
|
|
}
|
|
}
|
|
|
|
// MARK: Catalog by convention
|
|
extension MDCShadowPerformanceExample {
|
|
@objc class func catalogMetadata() -> [String: Any] {
|
|
return [
|
|
"breadcrumbs": ["Shadow", MDCShadowPerformanceExample.exampleTitle],
|
|
"primaryDemo": false,
|
|
"presentable": true,
|
|
"description": """
|
|
This example is not intended to demonstrate how to setup any specific components but rather to
|
|
push `MDCShadowLayer` to the limits for metric testing.
|
|
""",
|
|
]
|
|
}
|
|
|
|
@objc func catalogShouldHideNavigation() -> Bool {
|
|
return true
|
|
}
|
|
}
|