You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
409 lines
10 KiB
409 lines
10 KiB
//
|
|
// 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<Bool> {
|
|
return Binder(self.base) { view, hidden in
|
|
view.animateHidden(isHidden: hidden)
|
|
}
|
|
}
|
|
}
|