blob: a9e0cc3e63cd4fceb19b7249c1e11ed5602adfa7 [file] [log] [blame] [edit]
// Copyright 2018-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.MaterialCards
import MaterialComponents.MaterialShapeLibrary
@available(iOS 9.0, *)
class CardView: MDCCard {
let contentView = UIView()
let label = UILabel()
let imageView = UIImageView()
var imageWidthConstraint: NSLayoutConstraint!
var shouldUpdateConstraints = true
override init(frame: CGRect) {
super.init(frame: frame)
commonCardViewInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonCardViewInit()
}
func commonCardViewInit() {
self.layoutMargins = .zero
contentView.layoutMargins = .zero
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.isUserInteractionEnabled = false
self.addSubview(contentView)
label.text = "abcde fghi jklm nopq rstuv wxyz abcd efgh ijkl mnop qrst uvw xyz abcde fghi jkl" +
"nopq rstuv wxyz abcd efgh ijkl mnop qrst uvw xyz abcde fghi jklm nopq rstuv wxyz abcdefg"
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(label)
imageView.clipsToBounds = true
imageView.contentMode = .scaleAspectFill
imageView.translatesAutoresizingMaskIntoConstraints = false
let bundle = Bundle(for: ShapedCardViewController.self)
imageView.image = UIImage(named: "sample-image", in: bundle, compatibleWith: nil)
self.contentView.addSubview(imageView)
setupConstraints()
}
func setupConstraints() {
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
let margins = self.contentView.layoutMarginsGuide
label.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true
label.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true
imageView.centerXAnchor.constraint(equalTo: margins.centerXAnchor).isActive = true
imageView.topAnchor.constraint(equalTo: self.contentView.topAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor).isActive = true
imageView.bottomAnchor.constraint(equalTo: label.topAnchor).isActive = true
imageView.heightAnchor.constraint(equalTo: label.heightAnchor, multiplier: 1).isActive = true
imageWidthConstraint = imageView.widthAnchor.constraint(equalToConstant: 0)
imageWidthConstraint.isActive = true
}
override func layoutSubviews() {
super.layoutSubviews()
let shapeLayer = (self.layer as! MDCShapedShadowLayer).shapeLayer
contentView.layer.mask = shapeLayer
imageWidthConstraint.constant = shapeLayer.path!.boundingBox.size.width
}
}
@available(iOS 9.0, *)
class ShapedCardViewController: UIViewController {
var card = CardView()
var primarySlider = UISlider()
var secondarySlider = UISlider()
override func viewDidLoad() {
view.backgroundColor = .white
super.viewDidLoad()
initialShape()
view.addSubview(card)
view.addSubview(primarySlider)
view.addSubview(secondarySlider)
card.translatesAutoresizingMaskIntoConstraints = false
card.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: 20).isActive = true
card.bottomAnchor.constraint(equalTo: primarySlider.topAnchor, constant: -20).isActive = true
card.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
card.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true
primarySlider.translatesAutoresizingMaskIntoConstraints = false
primarySlider.bottomAnchor.constraint(equalTo: secondarySlider.topAnchor,
constant: -20).isActive = true
primarySlider.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
primarySlider.widthAnchor.constraint(equalTo: view.widthAnchor,
multiplier: 0.5,
constant: 0).isActive = true
primarySlider.addTarget(self,
action: #selector(didChangeSliderValue(slider:)),
for: .valueChanged)
secondarySlider.translatesAutoresizingMaskIntoConstraints = false
secondarySlider.bottomAnchor.constraint(equalTo: view.bottomAnchor,
constant: -20).isActive = true
secondarySlider.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
secondarySlider.widthAnchor.constraint(equalTo: view.widthAnchor,
multiplier: 0.5,
constant: 0).isActive = true
secondarySlider.addTarget(self,
action: #selector(didChangeSliderValue(slider:)),
for: .valueChanged)
let barButton = UIBarButtonItem(title: "Change Shape",
style: .plain,
target: self,
action: #selector(changeShape))
self.navigationItem.rightBarButtonItem = barButton
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
primarySlider.maximumValue = Float(min(card.bounds.width, card.bounds.height)/2)
primarySlider.sendActions(for: .valueChanged)
secondarySlider.maximumValue = Float(min(card.bounds.width, card.bounds.height)/2)
secondarySlider.sendActions(for: .valueChanged)
}
@objc func didChangeSliderValue(slider: UISlider) {
if let shape = card.shapeGenerator as? MDCRectangleShapeGenerator {
if slider == primarySlider {
let cutCornerTreatment = MDCCutCornerTreatment(cut: CGFloat(slider.value))
shape.setCorners(cutCornerTreatment)
} else if slider == secondarySlider {
let triangleEdgeTreatment = MDCTriangleEdgeTreatment(size: CGFloat(slider.value),
style: MDCTriangleEdgeStyleCut)
shape.setEdges(triangleEdgeTreatment)
}
card.setNeedsLayout()
}
}
override public var traitCollection: UITraitCollection {
if UIDevice.current.userInterfaceIdiom == .pad && UIDevice.current.orientation.isPortrait {
return UITraitCollection(traitsFrom:[UITraitCollection(horizontalSizeClass: .compact),
UITraitCollection(verticalSizeClass: .regular)])
}
return super.traitCollection
}
@objc func changeShape() {
primarySlider.isHidden = true
secondarySlider.isHidden = true
switch(card.shapeGenerator) {
case is MDCRectangleShapeGenerator:
let shapeGenerator = MDCCurvedRectShapeGenerator(cornerSize: CGSize(width: 50,
height: 100))
card.shapeGenerator = shapeGenerator
card.contentView.layoutMargins = UIEdgeInsets(top: 0, left: 40, bottom: 0, right: 40)
case is MDCCurvedRectShapeGenerator:
let shapeGenerator = MDCPillShapeGenerator()
card.shapeGenerator = shapeGenerator
card.contentView.layoutMargins = UIEdgeInsets(top: 0, left: 80, bottom: 0, right: 80)
case is MDCPillShapeGenerator:
let shapeGenerator = MDCSlantedRectShapeGenerator()
shapeGenerator.slant = 40
card.shapeGenerator = shapeGenerator
card.contentView.layoutMargins = UIEdgeInsets(top: 0, left: 40, bottom: 0, right: 40)
case is MDCSlantedRectShapeGenerator:
fallthrough
default:
initialShape()
}
card.setNeedsLayout()
}
func initialShape() {
primarySlider.isHidden = false
secondarySlider.isHidden = false
let shapeGenerator = MDCRectangleShapeGenerator()
let cutCornerTreatment = MDCCutCornerTreatment(cut: 0)
shapeGenerator.setCorners(cutCornerTreatment)
let triangleEdgeTreatment = MDCTriangleEdgeTreatment(size: 0, style: MDCTriangleEdgeStyleCut)
shapeGenerator.setEdges(triangleEdgeTreatment)
card.shapeGenerator = shapeGenerator
card.contentView.layoutMargins = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
}
}
@available(iOS 9.0, *)
extension ShapedCardViewController {
@objc class func catalogMetadata() -> [String: Any] {
return [
"breadcrumbs": ["Cards", "Shaped Card"],
"primaryDemo": false,
"presentable": false,
]
}
}