// // UIViewExtension.swift // GMERemittance // // Created by Fm-user on 12/23/17. // Copyright © 2017 Gobal Money Express Co. Ltd. All rights reserved. // import Foundation import UIKit import VisualEffectView import RxSwift import RxCocoa extension UIView { func rounded() { self.layer.cornerRadius = self.frame.height / 2 } func addBlur() { let visualEffectView = VisualEffectView(frame: self.frame) visualEffectView.colorTint = .clear visualEffectView.colorTintAlpha = 0.2 visualEffectView.blurRadius = 3 visualEffectView.scale = 1 visualEffectView.isUserInteractionEnabled = false self.addSubview(visualEffectView) } } extension UIView { func fadeIn( duration: TimeInterval = 1.0, delay: TimeInterval = 0.0, completion: @escaping ((Bool) -> Void) = {(finished: Bool) -> Void in}) { UIView.animate( withDuration: duration, delay: delay, options: UIView.AnimationOptions.curveEaseIn, animations: { self.alpha = 1.0 }, completion: completion ) } func fadeOut( duration: TimeInterval = 1.0, delay: TimeInterval = 3.0, completion: @escaping (Bool) -> Void = {(finished: Bool) -> Void in} ) { UIView.animate( withDuration: duration, delay: delay, options: UIView.AnimationOptions.curveEaseIn, animations: { self.alpha = 0.0 }, completion: completion ) } } // MARK: - Animator extension UIView { func bottomToOrigin(duration: Double = 0.3, completion: (() -> Void)? = nil) { let transform = CGAffineTransform(translationX: 0, y: self.bounds.height * 2) self.transform = transform // let velocity = self.bounds.height * CGFloat(duration) UIView.animate( withDuration:duration, delay: duration, usingSpringWithDamping: 0.85, initialSpringVelocity: 2, animations: { let transform = CGAffineTransform(translationX: 0, y: 0) self.transform = transform }, completion: { _ in completion?() } ) } func originToBottom(duration: Double = 0.1, completion: @escaping () -> Void ) { let transform = CGAffineTransform(translationX: 0, y: 0) self.transform = transform let animator = UIViewPropertyAnimator( duration: duration, curve: .linear) { let transform = CGAffineTransform(translationX: 0, y: self.bounds.height * 2) self.transform = transform } animator.addCompletion { _ in completion() } animator.startAnimation() } func popUpBouncy(duration: Double = 0.1) { alpha = 0.0 let transform = CGAffineTransform(scaleX: 0.8, y: 0.8) self.transform = transform UIView.animate( withDuration:duration, delay: duration, usingSpringWithDamping: 0.2, initialSpringVelocity: 10, animations: { self.alpha = 1.0 let transform = CGAffineTransform(scaleX: 1, y: 1) self.transform = transform } ) } func animateHidden(isHidden: Bool, duration: Double = 0.5, completion: (() -> Void)? = nil) { if self.isHidden { self.isHidden = isHidden UIView.animate( withDuration: duration, animations: { self.alpha = isHidden ? 0 : 1 }, completion: { _ in completion?() } ) } else { UIView.animate( withDuration: duration, animations: { self.alpha = isHidden ? 0 : 1 }, completion: { _ in self.isHidden = isHidden completion?() } ) } } func travelSubView(block: (_ view: UIView, _ stop: inout Bool) -> Void) { var stop = false block(self, &stop) if !stop { self.subviews.forEach { $0.travelSubView(block: block) } } } func rotate(duration: Double = 0.1, angle: CGFloat = .pi) { let animator = UIViewPropertyAnimator( duration: duration, curve: .easeInOut ) { self.transform = CGAffineTransform(rotationAngle: .pi) } animator.startAnimation() } } // MARK: - FOR Badge extension UIView { /* * Assign badge with only text. */ /// - parameter text: The badge value, use nil to remove exsiting badge. @objc public func badge(text badgeText: String?) { badge(text: badgeText, appearance: BadgeAppearance()) } /// - parameter text: The badge value, use nil to remove exsiting badge. /// - parameter appearance: The appearance of the badge. public func badge(text badgeText: String?, appearance: BadgeAppearance) { badge(text: badgeText, badgeEdgeInsets: nil, appearance: appearance) } /* * Assign badge with text and edge insets. */ @available(*, deprecated, message: "Use badge(text: String?, appearance:BadgeAppearance)") /// badge /// /// - Parameters: /// - badgeText: badge's Text /// - badgeEdgeInsets: badge's Inset @objc public func badge(text badgeText: String?, badgeEdgeInsets: UIEdgeInsets) { badge(text: badgeText, badgeEdgeInsets: badgeEdgeInsets, appearance: BadgeAppearance()) } /* * Assign badge with text,insets, and appearance. */ public func badge ( text badgeText:String?, badgeEdgeInsets: UIEdgeInsets?, appearance: BadgeAppearance ) { //Create badge label var badgeLabel: BadgeLabel! var doesBadgeExist = false //Find badge in subviews if exists for view in subviews { if view.tag == 1, let label = view as? BadgeLabel { badgeLabel = label } } //If assigned text is nil (request to remove badge) and badge label is not nil: if badgeText == nil && badgeLabel != nil { if appearance.animate { UIView.animate( withDuration: appearance.duration, animations: { badgeLabel.alpha = 0.0 badgeLabel.transform = CGAffineTransform(scaleX: 0.1, y: 0.1) }, completion: { _ in badgeLabel.removeFromSuperview() } ) } else { badgeLabel.removeFromSuperview() } return } else if badgeText == nil && badgeLabel == nil { return } //Badge label is nil (There was no previous badge) if (badgeLabel == nil) { //init badge label variable badgeLabel = BadgeLabel() //assign tag to badge label badgeLabel.tag = 1 } else { doesBadgeExist = true } let oldWidth: CGFloat? = doesBadgeExist ? badgeLabel.frame.width : nil //Set the text on the badge label badgeLabel.text = badgeText //Set font size badgeLabel.font = UIFont.systemFont(ofSize: appearance.textSize) badgeLabel.sizeToFit() //set the allignment badgeLabel.textAlignment = appearance.textAlignment //set background color badgeLabel.layer.backgroundColor = appearance.backgroundColor.cgColor //set text color badgeLabel.textColor = appearance.textColor //get current badge size let badgeSize = badgeLabel.frame.size //calculate width and height with minimum height and width of 20 let height = max(18, Double(badgeSize.height) + 5.0) let width = max(height, Double(badgeSize.width) + 10.0) badgeLabel.frame.size = CGSize(width: width, height: height) //add to subview if doesBadgeExist { //remove view to delete constraints badgeLabel.removeFromSuperview() } addSubview(badgeLabel) //The distance from the center of the view (vertically) let centerY = appearance.distanceFromCenterY == 0 ? -(bounds.size.height / 2) : appearance.distanceFromCenterY //The distance from the center of the view (horizontally) let centerX = appearance.distanceFromCenterX == 0 ? (bounds.size.width / 2) : appearance.distanceFromCenterX //disable auto resizing mask badgeLabel.translatesAutoresizingMaskIntoConstraints = false //add height constraint addConstraint( NSLayoutConstraint( item: badgeLabel!, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: CGFloat(height) ) ) //add width constraint addConstraint( NSLayoutConstraint( item: badgeLabel!, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: CGFloat(width) ) ) //add vertical constraint addConstraint( NSLayoutConstraint( item: badgeLabel!, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1.0, constant: centerX ) ) //add horizontal constraint addConstraint( NSLayoutConstraint( item: badgeLabel!, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1.0, constant: centerY ) ) badgeLabel.layer.borderColor = appearance.borderColor.cgColor badgeLabel.layer.borderWidth = appearance.borderWidth //corner radius badgeLabel.layer.cornerRadius = badgeLabel.frame.size.height / 2 //setup shadow if appearance.allowShadow { badgeLabel.layer.shadowOffset = CGSize(width: 1, height: 1) badgeLabel.layer.shadowRadius = 1 badgeLabel.layer.shadowOpacity = 0.5 badgeLabel.layer.shadowColor = UIColor.black.cgColor } //badge does not exist, meaning we are adding a new one if !doesBadgeExist { //should it animate? if appearance.animate { badgeLabel.transform = CGAffineTransform(scaleX: 0, y: 0) UIView.animate( withDuration: appearance.duration, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.5, options: [], animations: { badgeLabel.transform = .identity }, completion: nil ) } } else { if appearance.animate, let oldWidth = oldWidth { let currentWidth = badgeLabel.frame.width badgeLabel.frame.size.width = oldWidth UIView.animate(withDuration: appearance.duration) { badgeLabel.frame.size.width = currentWidth } } } } } extension Reactive where Base: UIView { /// Bindable sink for `hidden` property. public var isAnimateHidden: Binder { return Binder(self.base) { view, hidden in view.animateHidden(isHidden: hidden) } } }