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.

472 lines
14 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
4 years ago
  1. //
  2. // UIViewExtension.swift
  3. // GMERemittance
  4. //
  5. // Created by Fm-user on 12/23/17.
  6. // Copyright © 2017 Gobal Money Express Co. Ltd. All rights reserved.
  7. //
  8. import Foundation
  9. import UIKit
  10. import VisualEffectView
  11. import RxSwift
  12. import RxCocoa
  13. extension UIView {
  14. func rounded() {
  15. self.layer.cornerRadius = self.frame.height / 2
  16. }
  17. func addBlur() {
  18. let visualEffectView = VisualEffectView(frame: self.frame)
  19. visualEffectView.colorTint = .clear
  20. visualEffectView.colorTintAlpha = 0.2
  21. visualEffectView.blurRadius = 3
  22. visualEffectView.scale = 1
  23. visualEffectView.isUserInteractionEnabled = false
  24. self.addSubview(visualEffectView)
  25. }
  26. }
  27. extension UIView {
  28. func fadeIn(
  29. duration: TimeInterval = 1.0,
  30. delay: TimeInterval = 0.0,
  31. completion: @escaping ((Bool) -> Void) = {(finished: Bool) -> Void in}) {
  32. UIView.animate(
  33. withDuration: duration,
  34. delay: delay,
  35. options: UIView.AnimationOptions.curveEaseIn,
  36. animations: {
  37. self.alpha = 1.0
  38. },
  39. completion: completion
  40. )
  41. }
  42. func fadeOut(
  43. duration: TimeInterval = 1.0,
  44. delay: TimeInterval = 3.0,
  45. completion: @escaping (Bool) -> Void = {(finished: Bool) -> Void in}
  46. ) {
  47. UIView.animate(
  48. withDuration: duration,
  49. delay: delay,
  50. options: UIView.AnimationOptions.curveEaseIn,
  51. animations: {
  52. self.alpha = 0.0
  53. },
  54. completion: completion
  55. )
  56. }
  57. }
  58. extension CALayer {
  59. func applyCornerRadiusShadow(
  60. color: UIColor = UIColor.themeShadow,
  61. alpha: Float = 1,
  62. x: CGFloat = 0,
  63. y: CGFloat = 3,
  64. blur: CGFloat = 10,
  65. spread: CGFloat = 0,
  66. cornerRadiusValue: CGFloat = 0)
  67. {
  68. cornerRadius = cornerRadiusValue
  69. shadowColor = color.cgColor
  70. shadowOpacity = alpha
  71. shadowOffset = CGSize(width: x, height: y)
  72. shadowRadius = blur / 2.0
  73. if spread == 0 {
  74. shadowPath = nil
  75. } else {
  76. let dx = -spread
  77. let rect = bounds.insetBy(dx: dx, dy: dx)
  78. shadowPath = UIBezierPath(rect: rect).cgPath
  79. }
  80. }
  81. }
  82. // MARK: - Animator
  83. extension UIView {
  84. func bottomToOrigin(duration: Double = 0.3, completion: (() -> Void)? = nil) {
  85. let transform = CGAffineTransform(translationX: 0, y: self.bounds.height * 2)
  86. self.transform = transform
  87. // let velocity = self.bounds.height * CGFloat(duration)
  88. UIView.animate(
  89. withDuration:duration,
  90. delay: duration,
  91. usingSpringWithDamping: 0.85,
  92. initialSpringVelocity: 2,
  93. animations: {
  94. let transform = CGAffineTransform(translationX: 0, y: 0)
  95. self.transform = transform
  96. },
  97. completion: { _ in
  98. completion?()
  99. }
  100. )
  101. }
  102. func originToBottom(duration: Double = 0.1, completion: @escaping () -> Void ) {
  103. let transform = CGAffineTransform(translationX: 0, y: 0)
  104. self.transform = transform
  105. let animator = UIViewPropertyAnimator(
  106. duration: duration,
  107. curve: .linear) {
  108. let transform = CGAffineTransform(translationX: 0, y: self.bounds.height * 2)
  109. self.transform = transform
  110. }
  111. animator.addCompletion { _ in
  112. completion()
  113. }
  114. animator.startAnimation()
  115. }
  116. func popUpBouncy(duration: Double = 0.1) {
  117. alpha = 0.0
  118. let transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
  119. self.transform = transform
  120. UIView.animate(
  121. withDuration:duration,
  122. delay: duration,
  123. usingSpringWithDamping: 0.2,
  124. initialSpringVelocity: 10,
  125. animations: {
  126. self.alpha = 1.0
  127. let transform = CGAffineTransform(scaleX: 1, y: 1)
  128. self.transform = transform
  129. }
  130. )
  131. }
  132. func animateHidden(isHidden: Bool, duration: Double = 0.5, completion: (() -> Void)? = nil) {
  133. if self.isHidden {
  134. self.isHidden = isHidden
  135. UIView.animate(
  136. withDuration: duration,
  137. animations: {
  138. self.alpha = isHidden ? 0 : 1
  139. },
  140. completion: { _ in
  141. completion?()
  142. }
  143. )
  144. } else {
  145. UIView.animate(
  146. withDuration: duration,
  147. animations: {
  148. self.alpha = isHidden ? 0 : 1
  149. },
  150. completion: { _ in
  151. self.isHidden = isHidden
  152. completion?()
  153. }
  154. )
  155. }
  156. }
  157. func travelSubView(block: (_ view: UIView, _ stop: inout Bool) -> Void) {
  158. var stop = false
  159. block(self, &stop)
  160. if !stop {
  161. self.subviews.forEach { $0.travelSubView(block: block) }
  162. }
  163. }
  164. func rotate(duration: Double = 0.1, angle: CGFloat = .pi) {
  165. let animator = UIViewPropertyAnimator(
  166. duration: duration,
  167. curve: .easeInOut
  168. ) {
  169. self.transform = CGAffineTransform(rotationAngle: .pi)
  170. }
  171. animator.startAnimation()
  172. }
  173. }
  174. // MARK: - FOR Badge
  175. extension UIView {
  176. /*
  177. * Assign badge with only text.
  178. */
  179. /// - parameter text: The badge value, use nil to remove exsiting badge.
  180. @objc public func badge(text badgeText: String?) {
  181. badge(text: badgeText, appearance: BadgeAppearance())
  182. }
  183. /// - parameter text: The badge value, use nil to remove exsiting badge.
  184. /// - parameter appearance: The appearance of the badge.
  185. public func badge(text badgeText: String?, appearance: BadgeAppearance) {
  186. badge(text: badgeText, badgeEdgeInsets: nil, appearance: appearance)
  187. }
  188. /*
  189. * Assign badge with text and edge insets.
  190. */
  191. @available(*, deprecated, message: "Use badge(text: String?, appearance:BadgeAppearance)")
  192. /// badge
  193. ///
  194. /// - Parameters:
  195. /// - badgeText: badge's Text
  196. /// - badgeEdgeInsets: badge's Inset
  197. @objc public func badge(text badgeText: String?, badgeEdgeInsets: UIEdgeInsets) {
  198. badge(text: badgeText, badgeEdgeInsets: badgeEdgeInsets, appearance: BadgeAppearance())
  199. }
  200. /*
  201. * Assign badge with text,insets, and appearance.
  202. */
  203. public func badge (
  204. text badgeText:String?,
  205. badgeEdgeInsets: UIEdgeInsets?,
  206. appearance: BadgeAppearance
  207. ) {
  208. //Create badge label
  209. var badgeLabel: BadgeLabel!
  210. var doesBadgeExist = false
  211. //Find badge in subviews if exists
  212. for view in subviews {
  213. if view.tag == 1, let label = view as? BadgeLabel {
  214. badgeLabel = label
  215. }
  216. }
  217. //If assigned text is nil (request to remove badge) and badge label is not nil:
  218. if badgeText == nil && badgeLabel != nil {
  219. if appearance.animate {
  220. UIView.animate(
  221. withDuration: appearance.duration,
  222. animations: {
  223. badgeLabel.alpha = 0.0
  224. badgeLabel.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
  225. },
  226. completion: { _ in
  227. badgeLabel.removeFromSuperview()
  228. }
  229. )
  230. } else {
  231. badgeLabel.removeFromSuperview()
  232. }
  233. return
  234. } else if badgeText == nil && badgeLabel == nil {
  235. return
  236. }
  237. //Badge label is nil (There was no previous badge)
  238. if (badgeLabel == nil) {
  239. //init badge label variable
  240. badgeLabel = BadgeLabel()
  241. //assign tag to badge label
  242. badgeLabel.tag = 1
  243. } else {
  244. doesBadgeExist = true
  245. }
  246. let oldWidth: CGFloat? = doesBadgeExist ? badgeLabel.frame.width : nil
  247. //Set the text on the badge label
  248. badgeLabel.text = badgeText
  249. //Set font size
  250. badgeLabel.font = UIFont.systemFont(ofSize: appearance.textSize)
  251. badgeLabel.sizeToFit()
  252. //set the allignment
  253. badgeLabel.textAlignment = appearance.textAlignment
  254. //set background color
  255. badgeLabel.layer.backgroundColor = appearance.backgroundColor.cgColor
  256. //set text color
  257. badgeLabel.textColor = appearance.textColor
  258. //get current badge size
  259. let badgeSize = badgeLabel.frame.size
  260. //calculate width and height with minimum height and width of 20
  261. let height = max(18, Double(badgeSize.height) + 5.0)
  262. let width = max(height, Double(badgeSize.width) + 10.0)
  263. badgeLabel.frame.size = CGSize(width: width, height: height)
  264. //add to subview
  265. if doesBadgeExist {
  266. //remove view to delete constraints
  267. badgeLabel.removeFromSuperview()
  268. }
  269. addSubview(badgeLabel)
  270. //The distance from the center of the view (vertically)
  271. let centerY =
  272. appearance.distanceFromCenterY == 0 ? -(bounds.size.height / 2) : appearance.distanceFromCenterY
  273. //The distance from the center of the view (horizontally)
  274. let centerX =
  275. appearance.distanceFromCenterX == 0 ? (bounds.size.width / 2) : appearance.distanceFromCenterX
  276. //disable auto resizing mask
  277. badgeLabel.translatesAutoresizingMaskIntoConstraints = false
  278. //add height constraint
  279. addConstraint(
  280. NSLayoutConstraint(
  281. item: badgeLabel!,
  282. attribute: .height,
  283. relatedBy: .equal,
  284. toItem: nil,
  285. attribute: .notAnAttribute,
  286. multiplier: 1.0,
  287. constant: CGFloat(height)
  288. )
  289. )
  290. //add width constraint
  291. addConstraint(
  292. NSLayoutConstraint(
  293. item: badgeLabel!,
  294. attribute: .width,
  295. relatedBy: .equal,
  296. toItem: nil,
  297. attribute: .notAnAttribute,
  298. multiplier: 1.0,
  299. constant: CGFloat(width)
  300. )
  301. )
  302. //add vertical constraint
  303. addConstraint(
  304. NSLayoutConstraint(
  305. item: badgeLabel!,
  306. attribute: .centerX,
  307. relatedBy: .equal,
  308. toItem: self,
  309. attribute: .centerX,
  310. multiplier: 1.0,
  311. constant: centerX
  312. )
  313. )
  314. //add horizontal constraint
  315. addConstraint(
  316. NSLayoutConstraint(
  317. item: badgeLabel!,
  318. attribute: .centerY,
  319. relatedBy: .equal,
  320. toItem: self,
  321. attribute: .centerY,
  322. multiplier: 1.0,
  323. constant: centerY
  324. )
  325. )
  326. badgeLabel.layer.borderColor = appearance.borderColor.cgColor
  327. badgeLabel.layer.borderWidth = appearance.borderWidth
  328. //corner radius
  329. badgeLabel.layer.cornerRadius = badgeLabel.frame.size.height / 2
  330. //setup shadow
  331. if appearance.allowShadow {
  332. badgeLabel.layer.shadowOffset = CGSize(width: 1, height: 1)
  333. badgeLabel.layer.shadowRadius = 1
  334. badgeLabel.layer.shadowOpacity = 0.5
  335. badgeLabel.layer.shadowColor = UIColor.black.cgColor
  336. }
  337. //badge does not exist, meaning we are adding a new one
  338. if !doesBadgeExist {
  339. //should it animate?
  340. if appearance.animate {
  341. badgeLabel.transform = CGAffineTransform(scaleX: 0, y: 0)
  342. UIView.animate(
  343. withDuration: appearance.duration,
  344. delay: 0,
  345. usingSpringWithDamping: 0.5,
  346. initialSpringVelocity: 0.5,
  347. options: [],
  348. animations: {
  349. badgeLabel.transform = .identity
  350. },
  351. completion: nil
  352. )
  353. }
  354. } else {
  355. if appearance.animate, let oldWidth = oldWidth {
  356. let currentWidth = badgeLabel.frame.width
  357. badgeLabel.frame.size.width = oldWidth
  358. UIView.animate(withDuration: appearance.duration) {
  359. badgeLabel.frame.size.width = currentWidth
  360. }
  361. }
  362. }
  363. }
  364. }
  365. extension Reactive where Base: UIView {
  366. /// Bindable sink for `hidden` property.
  367. public var isAnimateHidden: Binder<Bool> {
  368. return Binder(self.base) { view, hidden in
  369. view.animateHidden(isHidden: hidden)
  370. }
  371. }
  372. }
  373. extension UIView{
  374. func addArc(path: UIBezierPath, offset: CGFloat, radius: CGFloat){
  375. var offsets: CGFloat = offset
  376. path.addArc(withCenter: CGPoint(x: (offset + radius), y: self.frame.height),
  377. radius: radius,
  378. startAngle: CGFloat(180.0).toRadians(),
  379. endAngle: CGFloat(0.0).toRadians(),
  380. clockwise: true)
  381. offsets += (15*2 + radius)
  382. if offset < self.frame.width{
  383. addArc(path: path, offset: offsets, radius: radius)
  384. }
  385. }
  386. func bottomArc(){
  387. let path = UIBezierPath()
  388. path.move(to: CGPoint(x: 0.0, y: 0.0))
  389. path.addLine(to: CGPoint(x: 0, y: self.frame.height))
  390. path.addLine(to: CGPoint(x: 15, y: self.frame.height))
  391. addArc(path: path, offset: 15.0, radius: 15)
  392. path.addLine(to: CGPoint(x: self.frame.size.width, y: self.frame.size.height))
  393. path.addLine(to: CGPoint(x: self.frame.size.width, y: 0))
  394. path.close()
  395. let shapeLayer = CAShapeLayer()
  396. shapeLayer.path = path.cgPath
  397. self.layer.mask = shapeLayer
  398. }
  399. }
  400. extension CGFloat {
  401. func toRadians() -> CGFloat {
  402. return self * CGFloat(Double.pi) / 180.0
  403. }
  404. }