diff --git a/Exmple/ProfileVC.swift b/Exmple/ProfileVC.swift index 02d7524..611e1bf 100644 --- a/Exmple/ProfileVC.swift +++ b/Exmple/ProfileVC.swift @@ -8,10 +8,11 @@ import UIKit import ParallaxHeader +import SnapKit class ProfileVC: UIViewController, UITableViewDelegate, UITableViewDataSource { - + @IBOutlet weak var tableView: UITableView! weak var headerImageView: UIView? @@ -24,20 +25,34 @@ class ProfileVC: UIViewController, UITableViewDelegate, UITableViewDataSource { //MARK: private - + private func setupParallaxHeader() { let imageView = UIImageView() imageView.image = UIImage(named: "profile") imageView.contentMode = .scaleAspectFill + imageView.blurView.setup(style: UIBlurEffectStyle.dark, alpha: 1).enable() + headerImageView = imageView tableView.parallaxHeader.view = imageView tableView.parallaxHeader.height = 400 - tableView.parallaxHeader.minimumHeight = 0 - tableView.parallaxHeader.mode = .topFill + tableView.parallaxHeader.minimumHeight = 40 + tableView.parallaxHeader.mode = .centerFill tableView.parallaxHeader.parallaxHeaderDidScrollHandler = { parallaxHeader in print(parallaxHeader.progress) + parallaxHeader.view.blurView.alpha = 1 - parallaxHeader.progress + } + + // Label for vibrant text + let vibrantLabel = UILabel() + vibrantLabel.text = "Vibrant" + vibrantLabel.font = UIFont.systemFont(ofSize: 40.0) + vibrantLabel.sizeToFit() + vibrantLabel.textAlignment = .center + imageView.blurView.vibrancyContentView?.addSubview(vibrantLabel) + vibrantLabel.snp.makeConstraints { make in + make.edges.equalToSuperview() } } @@ -57,9 +72,9 @@ class ProfileVC: UIViewController, UITableViewDelegate, UITableViewDataSource { //MARK: actions @objc private func imageDidTap(gesture: UITapGestureRecognizer) { - UIView.animate(withDuration: 0.3) { + UIView.animate(withDuration: 0.3) { if self.tableView.parallaxHeader.height == 400 { - self.tableView.parallaxHeader.height = 200 + self.tableView.parallaxHeader.height = 200 } else { self.tableView.parallaxHeader.height = 400 } @@ -68,7 +83,7 @@ class ProfileVC: UIViewController, UITableViewDelegate, UITableViewDataSource { //MARK: table view data source/delegate - + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 20 } @@ -76,17 +91,9 @@ class ProfileVC: UIViewController, UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell() - cell.textLabel?.text = "height: \(Int(height(for: indexPath)))" + cell.textLabel?.text = "some row text" return cell } - - private func height(for indexPath: IndexPath) -> CGFloat { - return CGFloat(indexPath.row * 20 + 20) - } - - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - self.tableView.parallaxHeader.height = height(for: indexPath) - } } diff --git a/Exmple/UIView+Blur.swift b/Exmple/UIView+Blur.swift new file mode 100644 index 0000000..66b1d46 --- /dev/null +++ b/Exmple/UIView+Blur.swift @@ -0,0 +1,152 @@ +// +// UIView+Blur.swift +// Blur +// +// Created by Roman Sorochak on 6/27/17. +// Copyright © 2017 MagicLab. All rights reserved. +// + +import UIKit + +extension UIView { + + private struct AssociatedKeys { + static var descriptiveName = "AssociatedKeys.DescriptiveName.blurView" + } + + private (set) var blurView: BlurView { + get { + if let blurView = objc_getAssociatedObject( + self, + &AssociatedKeys.descriptiveName + ) as? BlurView { + return blurView + } + self.blurView = BlurView(to: self) + return self.blurView + } + set(blurView) { + objc_setAssociatedObject( + self, + &AssociatedKeys.descriptiveName, + blurView, + .OBJC_ASSOCIATION_RETAIN_NONATOMIC + ) + } + } + + class BlurView { + + private var superview: UIView + private var blur: UIVisualEffectView? + private var editing: Bool = false + private (set) var blurContentView: UIView? + private (set) var vibrancyContentView: UIView? + + var animationDuration: TimeInterval = 0.1 + + /** + * Blur style. After it is changed all subviews on + * blurContentView & vibrancyContentView will be deleted. + */ + var style: UIBlurEffectStyle = .light { + didSet { + guard oldValue != style, + !editing else { return } + applyBlurEffect() + } + } + /** + * Alpha component of view. It can be changed freely. + */ + var alpha: CGFloat = 0 { + didSet { + guard !editing else { return } + if blur == nil { + applyBlurEffect() + } + let alpha = self.alpha + UIView.animate(withDuration: animationDuration) { + self.blur?.alpha = alpha + } + } + } + + init(to view: UIView) { + self.superview = view + } + + func setup(style: UIBlurEffectStyle, alpha: CGFloat) -> Self { + self.editing = true + + self.style = style + self.alpha = alpha + + self.editing = false + + return self + } + + func enable(isHidden: Bool = false) { + if blur == nil { + applyBlurEffect() + } + + self.blur?.isHidden = isHidden + } + + private func applyBlurEffect() { + blur?.removeFromSuperview() + + applyBlurEffect( + style: style, + blurAlpha: alpha + ) + } + + private func applyBlurEffect(style: UIBlurEffectStyle, + blurAlpha: CGFloat) { + superview.backgroundColor = UIColor.clear + + let blurEffect = UIBlurEffect(style: style) + let blurEffectView = UIVisualEffectView(effect: blurEffect) + + let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect) + let vibrancyView = UIVisualEffectView(effect: vibrancyEffect) + blurEffectView.contentView.addSubview(vibrancyView) + + blurEffectView.alpha = blurAlpha + + superview.insertSubview(blurEffectView, at: 0) + + blurEffectView.addAlignedConstrains() + vibrancyView.addAlignedConstrains() + + self.blur = blurEffectView + self.blurContentView = blurEffectView.contentView + self.vibrancyContentView = vibrancyView.contentView + } + } + + private func addAlignedConstrains() { + translatesAutoresizingMaskIntoConstraints = false + addAlignConstraintToSuperview(attribute: NSLayoutAttribute.top) + addAlignConstraintToSuperview(attribute: NSLayoutAttribute.leading) + addAlignConstraintToSuperview(attribute: NSLayoutAttribute.trailing) + addAlignConstraintToSuperview(attribute: NSLayoutAttribute.bottom) + } + + private func addAlignConstraintToSuperview(attribute: NSLayoutAttribute) { + superview?.addConstraint( + NSLayoutConstraint( + item: self, + attribute: attribute, + relatedBy: NSLayoutRelation.equal, + toItem: superview, + attribute: attribute, + multiplier: 1, + constant: 0 + ) + ) + } +} diff --git a/ParallaxHeader.xcodeproj/project.pbxproj b/ParallaxHeader.xcodeproj/project.pbxproj index 39ff60e..6fb8526 100644 --- a/ParallaxHeader.xcodeproj/project.pbxproj +++ b/ParallaxHeader.xcodeproj/project.pbxproj @@ -32,6 +32,7 @@ B5CCB7D11EFD100100194CFB /* UIScrollView+ParallaxHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5CCB7D01EFD100100194CFB /* UIScrollView+ParallaxHeader.swift */; }; B5CCB7D21EFD109500194CFB /* ParallaxHeader.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5CCB78D1EFD0E5400194CFB /* ParallaxHeader.framework */; }; B5CCB7D31EFD109500194CFB /* ParallaxHeader.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B5CCB78D1EFD0E5400194CFB /* ParallaxHeader.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + B5DB06DE1F028E4D00DD1D43 /* UIView+Blur.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5DB06DD1F028E4D00DD1D43 /* UIView+Blur.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -105,6 +106,7 @@ B5CCB7CC1EFD0FA400194CFB /* ParallaxHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParallaxHeader.swift; sourceTree = ""; }; B5CCB7CE1EFD0FB400194CFB /* ParallaxHeaderMode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParallaxHeaderMode.swift; sourceTree = ""; }; B5CCB7D01EFD100100194CFB /* UIScrollView+ParallaxHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIScrollView+ParallaxHeader.swift"; sourceTree = ""; }; + B5DB06DD1F028E4D00DD1D43 /* UIView+Blur.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Blur.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -174,6 +176,7 @@ isa = PBXGroup; children = ( B5485F8C1F0269D40010D77C /* UIAplication+RLT.swift */, + B5DB06DD1F028E4D00DD1D43 /* UIView+Blur.swift */, ); name = Extensions; sourceTree = ""; @@ -575,6 +578,7 @@ B5CCB7B01EFD0F2300194CFB /* ProfileVC.swift in Sources */, B5CCB7AE1EFD0F2300194CFB /* AppDelegate.swift in Sources */, B506958B1F02686000078D26 /* ItemDetailedCell.swift in Sources */, + B5DB06DE1F028E4D00DD1D43 /* UIView+Blur.swift in Sources */, B50695821F02653C00078D26 /* CollectionVC.swift in Sources */, B5485F8D1F0269D40010D77C /* UIAplication+RLT.swift in Sources */, B5485F941F0270F70010D77C /* CollectionTableViewCell.swift in Sources */, diff --git a/Podfile b/Podfile index ce26bb2..6b6b13b 100644 --- a/Podfile +++ b/Podfile @@ -5,5 +5,6 @@ use_frameworks! target 'Exmple' do pod 'Reusable', :git => 'https://github.com/romansorochak/Reusable.git', :tag => '1.0.0' + pod 'SnapKit' end