Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f044cef62c | |||
| 15376fdf98 | |||
| 55f4bf8ae3 | |||
| 769058a952 | |||
| a5404f12a4 | |||
| cac1ea555f | |||
| f856082f63 |
@@ -8,7 +8,7 @@
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'ContainerControllerSwift'
|
||||
s.version = '1.1.7'
|
||||
s.version = '1.1.4'
|
||||
s.summary = 'This is a swipe-panel from application: https://www.apple.com/ios/maps/'
|
||||
|
||||
# This description is used to generate tags and improve search results.
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
//
|
||||
// irbis-Bridging-Header.h
|
||||
// irbis
|
||||
//
|
||||
// Created by Aleksandr Lobyncev on 07.04.2021.
|
||||
// Copyright © 2021 ИТСофт. All rights reserved.
|
||||
//
|
||||
|
||||
//#import "AppDelegate.h"
|
||||
|
||||
#import "NSObject+Extension.h"
|
||||
|
||||
//#import "Coffee.h"
|
||||
|
||||
//#import <Foundation/Foundation.h>
|
||||
//#import <Firebase/Firebase.h>
|
||||
//#import <GoogleMaps/GoogleMaps.h>
|
||||
//#import "Constants.h"
|
||||
//#import "ChangeAppIcon.h"
|
||||
//#import "CoffeeFilterType.h"
|
||||
//#import "CoffeeInstagram.h"
|
||||
//#import "Alert.h"
|
||||
////#import "AppDelegate.h"
|
||||
//
|
||||
////MARK: - CoffeeOld
|
||||
//
|
||||
//#import "UIView+Frame.h"
|
||||
//#import "Utils.h"
|
||||
//#import "NSString+JSONString.h"
|
||||
//#import "NSDate+Utils.h"
|
||||
//
|
||||
//#import "KGLocalizationManager.h"
|
||||
//#import "KGNotificationsManager.h"
|
||||
//
|
||||
//#import "CustomSegmentView.h"
|
||||
//
|
||||
//#import <MessageUI/MessageUI.h>
|
||||
//#import <MessageUI/MFMailComposeViewController.h>
|
||||
//
|
||||
//#import "Reachability.h"
|
||||
//#import "ReachabilityAddons.h"
|
||||
//
|
||||
////MARK: - CoffeeNew
|
||||
//
|
||||
//#import "AddonsNew.h"
|
||||
//
|
||||
////MARK: - Xib / Designable Views
|
||||
//
|
||||
//#import "DesignView.h"
|
||||
//#import "DesignButton.h"
|
||||
//#import "DesignSegmentBar.h"
|
||||
//
|
||||
////MARK: - Table Block
|
||||
//
|
||||
//#import "TableItem.h"
|
||||
//#import "BlockTableView.h"
|
||||
//
|
||||
////MARK: - Tag Styled
|
||||
//
|
||||
//#import "CollectionItem.h"
|
||||
//#import "TagsStyledView.h"
|
||||
//
|
||||
////MARK: - Xib / Storyboard loadNib
|
||||
//
|
||||
//#import "XibView.h"
|
||||
//#import "XibCell.h"
|
||||
//#import "XibCollectionCell.h"
|
||||
//#import "StoryboardController.h"
|
||||
//
|
||||
////MARK: - Container View
|
||||
//
|
||||
//#import "ContainerTypes.h"
|
||||
//#import "ContainerView.h" // View
|
||||
//#import "ContainerData.h" // Data
|
||||
//#import "ContainerViewController.h" // Screens
|
||||
//#import "ContainerMapViewController.h"
|
||||
//
|
||||
////MARK: - Coffee Data
|
||||
//
|
||||
//#import "CoffeeUtils.h" // utils
|
||||
//
|
||||
///// models
|
||||
//#import "CoffeeNew.h"
|
||||
//@class Coffee;
|
||||
//#import "Coffee.h"
|
||||
//#import "CoffeeInfoIP.h"
|
||||
//#import "CoffeeAddress.h"
|
||||
//#import "CoffeeCountry.h"
|
||||
//#import "CoffeeEvent.h"
|
||||
//#import "CoffeeMarketStore.h"
|
||||
//#import "CoffeeMarket.h"
|
||||
//#import "CoffeeAdmin.h"
|
||||
//
|
||||
///// container data
|
||||
////#import "CoffeeOldListContainerData.h"
|
||||
////#import "CoffeeOldDetailsContainerData.h"
|
||||
////#import "CoffeeOld2ListContainerData.h"
|
||||
////#import "CoffeeOld2DetailsContainerData.h"
|
||||
//#import "CoffeeListContainerData.h"
|
||||
//#import "CoffeeDetailsContainerData.h"
|
||||
//
|
||||
///// managers
|
||||
//#import "ConfigManager.h"
|
||||
//#import "DownloadManager.h"
|
||||
//#import "DownloadInfoSite.h"
|
||||
//#import "CoffeeMapGetJSON.h"
|
||||
//#import "CoffeeDataManager.h"
|
||||
//#import "CoffeeMapManager.h"
|
||||
//
|
||||
//#define DATA_MGR [CoffeeDataManager managers]
|
||||
//#define MAP_MGR [CoffeeMapManager managers]
|
||||
//
|
||||
////MARK: - UI
|
||||
//
|
||||
///// cells
|
||||
//#import "MenuCells.h"
|
||||
//#import "TextTitleCell.h" // text
|
||||
//#import "CoffeeSegmentCell.h"
|
||||
//#import "CoffeeMenuAboutCell.h"
|
||||
//#import "CoffeeMenuTextCell.h"
|
||||
//#import "CoffeeCell.h" // coffee
|
||||
////#import "CoffeeDetailsCell.h"
|
||||
//#import "CoffeeDetailsTitleCell.h"
|
||||
//#import "CoffeeDetailsRouteCell.h"
|
||||
//#import "CoffeeDetailsContentCell.h"
|
||||
//#import "CoffeeDetailsInstaCell.h"
|
||||
//#import "CoffeeDetailsAddressCell.h"
|
||||
//#import "CoffeeDetailsInfoNewCell.h"
|
||||
//#import "CoffeeDetailsInfoCell.h"
|
||||
//#import "CoffeeListEventCell.h" // events
|
||||
//#import "CoffeeDetailsEventTitleCell.h"
|
||||
//#import "CoffeeDetailsEventPhotoCell.h"
|
||||
//#import "CoffeeDetailsEventInfoCell.h"
|
||||
//#import "CoffeeMarketTitleCell.h" // market
|
||||
//#import "CoffeeMarketNameCell.h"
|
||||
//#import "CoffeeMarketSectionCell.h"
|
||||
//#import "CoffeeMarketSubtitleCell.h"
|
||||
//#import "CoffeeMarketInfoCell.h"
|
||||
//#import "CoffeeMenuSocItemsCell.h"
|
||||
//#import "CoffeeMenuSectionCell.h"
|
||||
//#import "CoffeeListEmptyCell.h" // empty
|
||||
//#import "GTRideMapCell.h"
|
||||
//#import "CoffeeMapPlaceEventCell.h"
|
||||
//
|
||||
///// cells collection
|
||||
//#import "CoffeeMenuSocCell.h"
|
||||
//#import "CoffeeTagCell.h"
|
||||
//#import "CoffeeMarketCell.h"
|
||||
//#import "CoffeeMarketEmptyTagCell.h"
|
||||
//#import "CoffeeMarketSectionTagCell.h"
|
||||
//#import "CoffeeMarketOneStoreTagCell.h"
|
||||
//#import "CoffeeMarketStoresTagCell.h"
|
||||
//
|
||||
///// view
|
||||
//#import "CoffeeHeaderView.h" // coffee
|
||||
//#import "CoffeeHeaderGripView.h"
|
||||
//#import "CoffeeHeaderGripTitleView.h"
|
||||
//#import "CoffeeHeaderSearchBarView.h"
|
||||
//#import "CoffeeDetailsHeaderView.h"
|
||||
//#import "CoffeeDetailsTitleHeaderView.h"
|
||||
//#import "CoffeeNavBarView.h"
|
||||
////#import "CoffeeTabBarOld2View.h"
|
||||
//#import "CoffeeTabBarView.h"
|
||||
//#import "CoffeeListEmptyView.h"
|
||||
//
|
||||
///// screen
|
||||
//#import "WorkspaceController.h"
|
||||
//#import "CoffeeViewController.h" // coffee
|
||||
//#import "FLAnimatedImage.h"
|
||||
//#import "InstagramManager.h"
|
||||
////#import "CoffeeOld2ViewController.h"
|
||||
////#import "CoffeeOldViewController.h"
|
||||
//#import "CoffeeMenuViewController.h"
|
||||
//
|
||||
//#import "CoffeeEventsViewController.h"
|
||||
//#import "CoffeeEventsDetailsViewController.h"
|
||||
//#import "CoffeeMarketsViewController.h"
|
||||
//#import "CoffeeMarketsDetailsViewController.h"
|
||||
//#import "DbCoffeeImagesViewController.h"
|
||||
//#import "CoffeeNewsFeedViewController.h"
|
||||
//#import "ContainerMapRedViewController.h"
|
||||
//#import "CoffeeAdminViewController.h"
|
||||
//#import "CoffeePushViewController.h"
|
||||
//#import "SendPush.h"
|
||||
//
|
||||
//
|
||||
//#import "SafariViewController.h"
|
||||
//#import "WebViewController.h"
|
||||
File diff suppressed because it is too large
Load Diff
+1
-8
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1540"
|
||||
LastUpgradeVersion = "1150"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -83,13 +83,6 @@
|
||||
ReferencedContainer = "container:ContainerControllerSwift.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "IDEPreferLogStreaming"
|
||||
value = "YES"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
location = "group:..">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:/Users/rustam/.cocoapods/repos/ContainerControllerSwift/Example/ContainerControllerSwift.xcodeproj">
|
||||
location = "group:ContainerControllerSwift.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="cIu-62-xtU">
|
||||
<device id="retina5_9" orientation="portrait" appearance="light"/>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="cIu-62-xtU">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
@@ -13,22 +13,22 @@
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="ContainerController" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="718"/>
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="603"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" contentViewInsetsToSafeArea="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UYm-tY-WGa" customClass="TableAdapterView" customModule="ContainerControllerSwift">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="718"/>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="UYm-tY-WGa" customClass="TableAdapterView" customModule="ContainerControllerSwift">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="603"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="W4d-9e-HAg"/>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="UYm-tY-WGa" secondAttribute="bottom" id="kha-w5-3Yg"/>
|
||||
<constraint firstItem="UYm-tY-WGa" firstAttribute="top" secondItem="8bC-Xf-vdC" secondAttribute="top" id="qmS-hQ-rSa"/>
|
||||
<constraint firstAttribute="trailing" secondItem="UYm-tY-WGa" secondAttribute="trailing" id="vQK-T0-eQf"/>
|
||||
<constraint firstItem="UYm-tY-WGa" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="wXp-OO-MUn"/>
|
||||
<constraint firstItem="6Tk-OE-BBY" firstAttribute="bottom" secondItem="UYm-tY-WGa" secondAttribute="bottom" id="Usw-ep-vba"/>
|
||||
<constraint firstItem="UYm-tY-WGa" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" id="qmS-hQ-rSa"/>
|
||||
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="UYm-tY-WGa" secondAttribute="trailing" id="vQK-T0-eQf"/>
|
||||
<constraint firstItem="UYm-tY-WGa" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="wXp-OO-MUn"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="x48-lm-dG7"/>
|
||||
@@ -38,14 +38,14 @@
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="132" y="136.69950738916256"/>
|
||||
<point key="canvasLocation" x="132" y="137.18140929535232"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="jWl-Kd-Y9J">
|
||||
<objects>
|
||||
<navigationController id="cIu-62-xtU" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="y83-TR-htY">
|
||||
<rect key="frame" x="0.0" y="50" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="barTintColor" systemColor="secondaryLabelColor"/>
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIColor {
|
||||
var redValue: CGFloat{ return CIColor(color: self).red }
|
||||
var greenValue: CGFloat{ return CIColor(color: self).green }
|
||||
var blueValue: CGFloat{ return CIColor(color: self).blue }
|
||||
var alphaValue: CGFloat{ return CIColor(color: self).alpha }
|
||||
|
||||
|
||||
|
||||
static let playFullPanelOld = UIColor(named: "PlayFullPanelOld")!
|
||||
static let playFullBackground = UIColor(named: "PlayFullBackground")!
|
||||
static let playFullBackgroundOld = UIColor(named: "PlayFullBackgroundOld")!
|
||||
static let playlistColor = UIColor(named: "PlaylistColor")!
|
||||
static let playMusicColor = UIColor(named: "PlayMusicColor")! // red
|
||||
static let sportColor = UIColor(named: "SportColor")!
|
||||
}
|
||||
|
||||
class Colors {
|
||||
|
||||
class func hex(_ hex: Int) -> UIColor {
|
||||
let mask = 0xFF
|
||||
let r = CGFloat((hex >> 16) & mask) / 255
|
||||
let g = CGFloat((hex >> 8) & mask) / 255
|
||||
let b = CGFloat((hex) & mask) / 255
|
||||
return UIColor(red: r, green: g, blue: b, alpha: 1)
|
||||
}
|
||||
|
||||
|
||||
class func hexStr(_ hex: String) -> UIColor {
|
||||
let input = hex.replacingOccurrences(of: "#", with: "").uppercased()
|
||||
var a: CGFloat = 1.0, r: CGFloat = 0.0, b: CGFloat = 0.0, g: CGFloat = 0.0
|
||||
func colorComponent(from string: String, start: Int, length: Int) -> CGFloat {
|
||||
let substring = (string as NSString).substring(with: NSRange(location: start, length: length))
|
||||
let fullHex = length == 2 ? substring : "\(substring)\(substring)"
|
||||
var hexComponent: UInt64 = 0
|
||||
Scanner(string: fullHex).scanHexInt64(&hexComponent)
|
||||
return CGFloat(Double(hexComponent) / 255.0)
|
||||
}
|
||||
switch (input.count) {
|
||||
case 3 /* #RGB */:
|
||||
r = colorComponent(from: input, start: 0, length: 1)
|
||||
g = colorComponent(from: input, start: 1, length: 1)
|
||||
b = colorComponent(from: input, start: 2, length: 1)
|
||||
case 4 /* #ARGB */:
|
||||
a = colorComponent(from: input, start: 0, length: 1)
|
||||
r = colorComponent(from: input, start: 1, length: 1)
|
||||
g = colorComponent(from: input, start: 2, length: 1)
|
||||
b = colorComponent(from: input, start: 3, length: 1)
|
||||
case 6 /* #RRGGBB */:
|
||||
r = colorComponent(from: input, start: 0, length: 2)
|
||||
g = colorComponent(from: input, start: 2, length: 2)
|
||||
b = colorComponent(from: input, start: 4, length: 2)
|
||||
case 8 /* #AARRGGBB */:
|
||||
a = colorComponent(from: input, start: 0, length: 2)
|
||||
r = colorComponent(from: input, start: 2, length: 2)
|
||||
g = colorComponent(from: input, start: 4, length: 2)
|
||||
b = colorComponent(from: input, start: 6, length: 2)
|
||||
default:
|
||||
break
|
||||
}
|
||||
return UIColor(red: r, green: g, blue: b, alpha: a)
|
||||
}
|
||||
|
||||
class func rgba( _ red: CGFloat, _ green: CGFloat, _ blue: CGFloat, _ alpha: CGFloat) -> UIColor {
|
||||
return UIColor(red: red / 255, green: green / 255, blue: blue / 255, alpha: alpha)
|
||||
}
|
||||
|
||||
class func rgb( _ red: CGFloat, _ green: CGFloat, _ blue: CGFloat) -> UIColor {
|
||||
return rgba(red, green, blue, 1)
|
||||
}
|
||||
|
||||
class func grayLevel(_ gray: CGFloat) -> UIColor {
|
||||
return rgb(gray * 255, gray * 255, gray * 255)
|
||||
}
|
||||
|
||||
class func blackAlpha(_ alpha: CGFloat) -> UIColor {
|
||||
return rgba(0, 0, 0, alpha)
|
||||
}
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
static public let lightGray = blackAlpha(0.1)
|
||||
static public let slightlyDark = blackAlpha(0.3)
|
||||
static public let halfBlack = blackAlpha(0.5)
|
||||
|
||||
static public let black = grayLevel(0) // 0 %
|
||||
static public let gray = grayLevel(127) // 49 %
|
||||
static public let lightInactiveGray = grayLevel(178) // 69 %
|
||||
static public let silver = grayLevel(229) // 89 %
|
||||
static public let inactiveGray = grayLevel(246) // 96 %
|
||||
static public let white = grayLevel(255) // 100 %
|
||||
|
||||
static public let transparentGray = rgba(225, 225, 225, 0.3)
|
||||
static public let lightOrange = rgba(255, 105, 0, 0.1)
|
||||
|
||||
static public let red = rgb(255, 59, 48)
|
||||
static public let blue = rgb(44, 174, 233)
|
||||
static public let yellow = rgb(254, 219, 6)
|
||||
static public let orange = rgb(255, 105, 0)
|
||||
static public let purple = rgb(128, 0, 128)
|
||||
static public let gold = rgb(226, 201, 127)
|
||||
static public let beige = rgb(245, 245, 220)
|
||||
static public let brand = rgb(255, 105, 0)
|
||||
static public let approveGreen = rgb(49, 183, 0)
|
||||
static public let darkBlue = rgb(74, 144, 226)
|
||||
static public let semidarkBlue = rgb(0, 107, 202)
|
||||
static public let darkGray = rgb(142, 142, 147)
|
||||
static public let lightYellow = rgb(254, 229, 6)
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.129",
|
||||
"green" : "0.086",
|
||||
"red" : "0.078"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.129",
|
||||
"green" : "0.086",
|
||||
"red" : "0.078"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.137",
|
||||
"green" : "0.122",
|
||||
"red" : "0.118"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.137",
|
||||
"green" : "0.122",
|
||||
"red" : "0.118"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.157",
|
||||
"green" : "0.129",
|
||||
"red" : "0.125"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.157",
|
||||
"green" : "0.129",
|
||||
"red" : "0.125"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.365",
|
||||
"green" : "0.267",
|
||||
"red" : "0.922"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.365",
|
||||
"green" : "0.267",
|
||||
"red" : "0.922"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.937",
|
||||
"green" : "0.518",
|
||||
"red" : "0.310"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.937",
|
||||
"green" : "0.518",
|
||||
"red" : "0.310"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.000",
|
||||
"green" : "0.541",
|
||||
"red" : "1.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.000",
|
||||
"green" : "0.541",
|
||||
"red" : "1.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -118,7 +118,8 @@ extension ExampleAddCollectionViewController: UICollectionViewDataSource {
|
||||
case 4: color = .systemYellow
|
||||
case 5: color = .systemOrange
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
||||
cell.backgroundColor = color
|
||||
cell.layer.cornerRadius = 12
|
||||
return cell
|
||||
+2
-19
@@ -51,7 +51,7 @@ func createCollectionAdapterView(width: CGFloat) -> CollectionAdapterView {
|
||||
|
||||
// MARK: - TableAdapterView
|
||||
|
||||
func createTableAdapterView(items: [TableAdapterItem]? = nil, view: UIView? = nil) -> TableAdapterView {
|
||||
func createTableAdapterView(items: [TableAdapterItem]? = nil, view: UIView) -> TableAdapterView {
|
||||
|
||||
let table = TableAdapterView()
|
||||
table.separatorColor = Colors.grayLevel(0.75)
|
||||
@@ -61,27 +61,11 @@ func createTableAdapterView(items: [TableAdapterItem]? = nil, view: UIView? = ni
|
||||
}
|
||||
|
||||
table.didScrollCallback = {
|
||||
view?.endEditing(true)
|
||||
view.endEditing(true)
|
||||
}
|
||||
return table
|
||||
}
|
||||
|
||||
|
||||
// MARK: - TableView
|
||||
|
||||
func createTableViewTestItems(number: Int = 25) -> TableAdapterView {
|
||||
|
||||
var items: [TableAdapterItem] = []
|
||||
|
||||
for index in 1...number {
|
||||
items.append( TitleTextxItem(title: "Subtitle", subtitle: "Title \(index)" ))
|
||||
|
||||
|
||||
}
|
||||
|
||||
return createTableAdapterView(items: items)
|
||||
}
|
||||
|
||||
// MARK: - TableView
|
||||
|
||||
func createTableView() -> UITableView {
|
||||
@@ -102,7 +86,6 @@ func createTextView() -> UITextView {
|
||||
let textView = UITextView()
|
||||
textView.returnKeyType = .done
|
||||
textView.backgroundColor = .clear
|
||||
textView.textContainerInset = .init(top: 9, left: 18, bottom: 18, right: 18)
|
||||
textView.font = UIFont.systemFont(ofSize: 15)
|
||||
textView.text = """
|
||||
This example demonstrates a block quote. Because some introductory phrases will lead
|
||||
+1
-1
@@ -107,7 +107,7 @@ class ExamplesSettingsViewController: StoryboardController {
|
||||
let subTitle = String(describing: type(of: container))
|
||||
let title = style.rawValue
|
||||
|
||||
items.append( TitleTextxItem(title: title, subtitle: subTitle, editing: true) )
|
||||
items.append( TitleTextItem(title: title, subtitle: subTitle, editing: true) )
|
||||
tableView?.set(items: items, animated: true)
|
||||
}
|
||||
|
||||
+11
-18
@@ -7,35 +7,34 @@ import ContainerControllerSwift
|
||||
|
||||
// MARK: - Item
|
||||
|
||||
class TitleTextxItem: TableAdapterItem {
|
||||
class TitleTextItem: TableAdapterItem {
|
||||
|
||||
init(title: String? = nil,
|
||||
subtitle: String? = nil,
|
||||
separator: Bool = false,
|
||||
clss: AnyClass? = nil,
|
||||
img: UIImage? = nil,
|
||||
touchAnimationHide: Bool = false,
|
||||
editing: Bool = false) {
|
||||
|
||||
let cellData = TitleTextxCellData(title, subtitle, separator, clss, img, touchAnimationHide, editing)
|
||||
let cellData = TitleTextCellData(title, subtitle, separator, clss, touchAnimationHide, editing)
|
||||
|
||||
super.init(cellClass: TitleTextxCell.self, cellData: cellData)
|
||||
super.init(cellClass: TitleTextCell.self, cellData: cellData)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Data
|
||||
|
||||
class TitleTextxCellData: TableAdapterCellData {
|
||||
class TitleTextCellData: TableAdapterCellData {
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
var title: String?
|
||||
var subtitle: String?
|
||||
var clss: AnyClass?
|
||||
var img: UIImage?
|
||||
var separatorVisible: Bool
|
||||
var touchAnimationHide: Bool
|
||||
|
||||
var editing: Bool
|
||||
|
||||
// MARK: Inits
|
||||
|
||||
@@ -43,7 +42,6 @@ class TitleTextxCellData: TableAdapterCellData {
|
||||
_ subtitle: String? = nil,
|
||||
_ separator: Bool,
|
||||
_ clss: AnyClass? = nil,
|
||||
_ img: UIImage? = nil,
|
||||
_ touchAnimationHide: Bool,
|
||||
_ editing: Bool) {
|
||||
|
||||
@@ -51,12 +49,11 @@ class TitleTextxCellData: TableAdapterCellData {
|
||||
self.subtitle = subtitle
|
||||
|
||||
self.clss = clss
|
||||
self.img = img
|
||||
|
||||
self.separatorVisible = separator
|
||||
self.touchAnimationHide = touchAnimationHide
|
||||
|
||||
// self.editing = editing
|
||||
self.editing = editing
|
||||
|
||||
super.init()
|
||||
}
|
||||
@@ -77,11 +74,11 @@ class TitleTextxCellData: TableAdapterCellData {
|
||||
|
||||
// MARK: - Cell
|
||||
|
||||
class TitleTextxCell: TableAdapterCell {
|
||||
class TitleTextCell: TableAdapterCell {
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
public var data: TitleTextxCellData?
|
||||
public var data: TitleTextCellData?
|
||||
|
||||
// MARK: Outlets
|
||||
|
||||
@@ -93,7 +90,6 @@ class TitleTextxCell: TableAdapterCell {
|
||||
@IBOutlet private weak var subtitleLabel: UILabel?
|
||||
@IBOutlet private weak var separatorView: UIView?
|
||||
@IBOutlet private weak var separatorHeightConstraint: NSLayoutConstraint?
|
||||
@IBOutlet var iconFigureVView: DesignFigure!
|
||||
|
||||
// MARK: Initialize
|
||||
|
||||
@@ -103,18 +99,15 @@ class TitleTextxCell: TableAdapterCell {
|
||||
}
|
||||
|
||||
override func fill(data: TableAdapterCellData?) {
|
||||
guard let data = data as? TitleTextxCellData else { return }
|
||||
guard let data = data as? TitleTextCellData else { return }
|
||||
self.data = data
|
||||
|
||||
// self._hideAnimation = data.touchAnimationHide
|
||||
|
||||
// titleLabel?.text = (data.clss != nil) ? classNameString(data.clss!) : data.title
|
||||
titleLabel?.text = data.title
|
||||
subtitleLabel?.text = data.subtitle
|
||||
|
||||
iconFigureVView?.isHidden = (data.img == nil)
|
||||
iconFigureVView?.image = data.img
|
||||
iconFigureVView?.layoutSubviews()
|
||||
subtitleLabel?.text = (data.clss != nil) ? classNameString(data.clss!) : data.subtitle
|
||||
|
||||
separatorView?.isHidden = !data.separatorVisible
|
||||
}
|
||||
|
||||
+8
-37
@@ -1,32 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22685"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="64" id="ADc-Wu-299" customClass="TitleTextxCell" customModule="ContainerController" customModuleProvider="target">
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="64" id="ADc-Wu-299" customClass="TitleTextCell" customModule="ContainerControllerSwift_Example" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="64"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="ADc-Wu-299" id="Qrk-n6-aPT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="64"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" alpha="0.29999999999999999" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Tite" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="MbP-dL-b7J">
|
||||
<rect key="frame" x="16" y="12" width="359" height="14"/>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Tite" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="MbP-dL-b7J">
|
||||
<rect key="frame" x="16" y="12" width="360" height="14"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="14" id="ybu-0n-7d1"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Subtitle subtitle subtitle" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="erD-8k-fq0">
|
||||
<rect key="frame" x="16" y="32" width="359" height="19"/>
|
||||
<rect key="frame" x="16" y="32" width="360" height="19"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="19" id="DgX-EK-d6R"/>
|
||||
</constraints>
|
||||
@@ -40,47 +39,22 @@
|
||||
<constraint firstAttribute="height" constant="1" id="Mwb-A9-GWL"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="rzf-Pz-Z0t" customClass="DesignFigure" customModule="ContainerController" customModuleProvider="target">
|
||||
<rect key="frame" x="329" y="17" width="30" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="30" id="eQh-TL-5c0"/>
|
||||
<constraint firstAttribute="height" constant="30" id="frA-oo-ZRS"/>
|
||||
</constraints>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="image" keyPath="image" value="img_big_disclosure"/>
|
||||
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
|
||||
<real key="value" value="8"/>
|
||||
</userDefinedRuntimeAttribute>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</view>
|
||||
<view alpha="0.0" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Vbr-OH-Bds">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="64"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="y4e-nG-Zu6" secondAttribute="trailing" constant="16" id="6tU-aV-NOW"/>
|
||||
<constraint firstItem="MbP-dL-b7J" firstAttribute="leading" secondItem="Qrk-n6-aPT" secondAttribute="leading" constant="16" id="CVY-pT-bde"/>
|
||||
<constraint firstItem="rzf-Pz-Z0t" firstAttribute="centerY" secondItem="Qrk-n6-aPT" secondAttribute="centerY" id="K6u-Hl-rVK"/>
|
||||
<constraint firstItem="y4e-nG-Zu6" firstAttribute="leading" secondItem="Qrk-n6-aPT" secondAttribute="leading" constant="16" id="QFm-sF-aRI"/>
|
||||
<constraint firstItem="Vbr-OH-Bds" firstAttribute="leading" secondItem="Qrk-n6-aPT" secondAttribute="leading" id="QR1-bs-lr1"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Vbr-OH-Bds" secondAttribute="trailing" id="QUK-HO-u0U"/>
|
||||
<constraint firstItem="y4e-nG-Zu6" firstAttribute="top" secondItem="erD-8k-fq0" secondAttribute="bottom" constant="12" id="QZO-jk-KTF"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Vbr-OH-Bds" secondAttribute="bottom" id="SVO-8W-bz2"/>
|
||||
<constraint firstItem="MbP-dL-b7J" firstAttribute="top" secondItem="Qrk-n6-aPT" secondAttribute="top" constant="12" id="bPX-J8-yKW"/>
|
||||
<constraint firstItem="erD-8k-fq0" firstAttribute="trailing" secondItem="Qrk-n6-aPT" secondAttribute="trailingMargin" constant="16" id="coB-XR-Ksl"/>
|
||||
<constraint firstItem="erD-8k-fq0" firstAttribute="leading" secondItem="Qrk-n6-aPT" secondAttribute="leading" constant="16" id="fId-PQ-DA7"/>
|
||||
<constraint firstAttribute="bottom" secondItem="y4e-nG-Zu6" secondAttribute="bottom" id="lV9-iJ-0gZ"/>
|
||||
<constraint firstItem="Vbr-OH-Bds" firstAttribute="top" secondItem="Qrk-n6-aPT" secondAttribute="top" id="stb-Id-OY3"/>
|
||||
<constraint firstAttribute="trailing" secondItem="rzf-Pz-Z0t" secondAttribute="trailing" constant="16" id="tLT-Xz-ZX8"/>
|
||||
<constraint firstItem="MbP-dL-b7J" firstAttribute="trailing" secondItem="Qrk-n6-aPT" secondAttribute="trailingMargin" constant="16" id="yAB-Bt-Wbb"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<connections>
|
||||
<outlet property="iconFigureVView" destination="rzf-Pz-Z0t" id="TZl-ZS-Co1"/>
|
||||
<outlet property="selectedView" destination="Vbr-OH-Bds" id="0lB-r8-sw8"/>
|
||||
<outlet property="separatorHeightConstraint" destination="Mwb-A9-GWL" id="PQz-KX-a42"/>
|
||||
<outlet property="separatorView" destination="y4e-nG-Zu6" id="iw9-9r-qpC"/>
|
||||
<outlet property="subtitleLabel" destination="erD-8k-fq0" id="Ggx-EQ-sNx"/>
|
||||
@@ -89,7 +63,4 @@
|
||||
<point key="canvasLocation" x="127.2" y="111.54422788605699"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="img_big_disclosure" width="500" height="500"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2020 Pavel Puzyrev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -1,58 +0,0 @@
|
||||
# Blurberry
|
||||
|
||||
Transparent blur using UIVisualEffectView without subclassing.
|
||||
|
||||

|
||||
|
||||
[[video demo]](https://vimeo.com/457206677)
|
||||
|
||||
[[appetize demo]](https://appetize.io/app/u2udhgwh0cgm12at0rmgjxtphr)
|
||||
|
||||
## Features
|
||||
- Based on UIVisualEffectView
|
||||
- Supports **iOS 14** and animation blocks
|
||||
- Super safe and super easy
|
||||
|
||||
## Usage
|
||||
|
||||
Just create a `UIVisualEffectView` in any way. Code, storyboards, XIBs, etc.
|
||||
|
||||
Customize it like example bellow via `blur` wrapper:
|
||||
```swift
|
||||
visualEffectView.blur.radius = 5.0
|
||||
visualEffectView.blur.tintColor = .clear
|
||||
```
|
||||
|
||||
Don't forget to set a `tintColor` value, otherwise it will be 30% white like `UIBlurEffect.Style.Light` by default.
|
||||
|
||||
## Installation
|
||||
|
||||
### Cocoapods
|
||||
|
||||
Add the Blurberry pod to your Podfile:
|
||||
```ruby
|
||||
platform :ios, '10.0'
|
||||
|
||||
use_frameworks!
|
||||
|
||||
target 'BlurryApp' do
|
||||
pod 'Blurberry'
|
||||
end
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [x] iOS 10, 11, 12 support
|
||||
- [ ] Other platform support (such as macOS)
|
||||
- [ ] Remove ObjC code or make it private
|
||||
- [ ] Add manager to check blur availability and other service info
|
||||
- [ ] Hide private API class names, method names, etc.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This framework uses private API, so just keep in mind it before submitting to the AppStore.
|
||||
|
||||
## Requirements
|
||||
|
||||
- iOS 10.0+
|
||||
- Swift 5
|
||||
@@ -1,37 +0,0 @@
|
||||
//
|
||||
// Blurberry.h
|
||||
// Blurberry
|
||||
//
|
||||
// Created by Pavel Puzyrev on 09.09.2020.
|
||||
//
|
||||
// Copyright (c) 2020 Pavel Puzyrev <cannedapp@yahoo.com>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
//! Project version number for Blurberry.
|
||||
FOUNDATION_EXPORT double BlurberryVersionNumber;
|
||||
|
||||
//! Project version string for Blurberry.
|
||||
FOUNDATION_EXPORT const unsigned char BlurberryVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <Blurberry/PublicHeader.h>
|
||||
|
||||
#import <Blurberry/NSObject+Extension.h>
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
//
|
||||
// NSObject+Extension.h
|
||||
// Blurberry
|
||||
//
|
||||
// Created by Pavel Puzyrev on 07.09.2020.
|
||||
//
|
||||
// Copyright (c) 2020 Pavel Puzyrev <cannedapp@yahoo.com>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ContainerControllerSwift-Swift.h"
|
||||
|
||||
struct BlurWrapper;
|
||||
|
||||
@class UIColor;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSObject (Extension)
|
||||
|
||||
#pragma mark *** Values getting ***
|
||||
|
||||
- (nullable NSArray<NSObject *> *)arrayValueByGetterNamed:(NSString *)getterName NS_SWIFT_NAME(arrayValue(getter:));
|
||||
- (nullable NSDictionary<NSString *, id> *)dictionaryValueByGetterNamed:(NSString *)getterName NS_SWIFT_NAME(dictionaryValue(getter:));
|
||||
- (nullable NSString *)stringValueByGetterNamed:(NSString *)getterName NS_SWIFT_NAME(stringValue(getter:));
|
||||
- (nullable UIColor *)colorValueByGetterNamed:(NSString *)getterName NS_SWIFT_NAME(colorValue(getter:));
|
||||
|
||||
#pragma mark *** Values setting ***
|
||||
|
||||
- (void)setIVarValue:(nullable id)value getterNamed:(NSString *)getterName NS_SWIFT_NAME(setIVarValue(value:getter:));
|
||||
- (void)setValueUsingSetter:(nullable id)value getterNamed:(NSString *)getterName NS_SWIFT_NAME(setValueUsingSetter(value:getter:));
|
||||
- (void)setObjectInDictionary:(id)object
|
||||
forKey:(NSString *)key
|
||||
getterNamed:(NSString *)getterName NS_SWIFT_NAME(setObjectInDictionary(object:key:getter:));
|
||||
|
||||
- (nullable id)valueSafeForKey:(NSString *)key NS_SWIFT_NAME(valueSafe(key:));
|
||||
- (void)setValueSafe:(id)value forKey:(NSString *)key NS_SWIFT_NAME(setValueSafe(value:key:));
|
||||
|
||||
#pragma mark *** Methods calling ***
|
||||
|
||||
- (void)callMethodNamed:(NSString *)methodName NS_SWIFT_NAME(callMethod(named:));
|
||||
- (void)callMethodNamed:(NSString *)methodName withObject:(nullable id)argument NS_SWIFT_NAME(callMethod(named:with:));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
-161
@@ -1,161 +0,0 @@
|
||||
//
|
||||
// NSObject+Extension.m
|
||||
// Blurberry
|
||||
//
|
||||
// Created by Pavel Puzyrev on 07.09.2020.
|
||||
//
|
||||
// Copyright (c) 2020 Pavel Puzyrev <cannedapp@yahoo.com>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "NSObject+Extension.h"
|
||||
#import <objc/runtime.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
|
||||
//@class BlurWrapper;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation NSObject (Extension)
|
||||
|
||||
#pragma mark - Public Methods
|
||||
|
||||
#pragma mark *** Values getting ***
|
||||
|
||||
- (nullable NSArray<NSObject *> *)arrayValueByGetterNamed:(NSString *)getterName {
|
||||
return [self valueOfType:[NSArray class] getterNamed:getterName];
|
||||
}
|
||||
|
||||
- (nullable NSDictionary<NSString *, id> *)dictionaryValueByGetterNamed:(NSString *)getterName {
|
||||
return [self valueOfType:[NSDictionary class] getterNamed:getterName];
|
||||
}
|
||||
|
||||
- (nullable NSString *)stringValueByGetterNamed:(NSString *)getterName {
|
||||
return [self valueOfType:[NSString class] getterNamed:getterName];
|
||||
}
|
||||
|
||||
- (nullable UIColor *)colorValueByGetterNamed:(NSString *)getterName {
|
||||
return [self valueOfType:[UIColor class] getterNamed:getterName];
|
||||
}
|
||||
|
||||
#pragma mark *** Values setting ***
|
||||
|
||||
- (void)setIVarValue:(nullable id)value getterNamed:(NSString *)getterName {
|
||||
@try {
|
||||
SEL getterSelector = NSSelectorFromString(getterName);
|
||||
SEL setterSelector = NSSelectorFromString([self setterMethodName:getterName]);
|
||||
NSString *ivarName = [NSString stringWithFormat:@"_%@", getterName];
|
||||
if ([self respondsToSelector:getterSelector] && [self respondsToSelector:setterSelector]) {
|
||||
[self setValue:value forKey:ivarName];
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setValueUsingSetter:(nullable id)value getterNamed:(NSString *)getterName {
|
||||
[self callMethodNamed:[self setterMethodName:getterName] withObject:value];
|
||||
}
|
||||
|
||||
- (void)setObjectInDictionary:(id)object forKey:(NSString *)key getterNamed:(NSString *)getterName {
|
||||
NSMutableDictionary *dictionary = [[self dictionaryValueByGetterNamed:getterName] mutableCopy];
|
||||
if (!dictionary) {
|
||||
return;
|
||||
}
|
||||
|
||||
dictionary[key] = object;
|
||||
|
||||
[self callMethodNamed:[self setterMethodName:getterName] withObject:[dictionary copy]];
|
||||
}
|
||||
|
||||
- (nullable id)valueSafeForKey:(NSString *)key {
|
||||
@try {
|
||||
return [self valueForKey:key];
|
||||
} @catch (NSException *exception) {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setValueSafe:(id)value forKey:(NSString *)key {
|
||||
@try {
|
||||
[self setValue:value forKey:key];
|
||||
} @catch (NSException *exception) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark *** Methods calling ***
|
||||
|
||||
- (void)callMethodNamed:(NSString *)methodName {
|
||||
[self callMethodNamed:methodName withObject:nil];
|
||||
}
|
||||
|
||||
- (void)callMethodNamed:(NSString *)methodName withObject:(nullable id)argument {
|
||||
@try {
|
||||
SEL selector = NSSelectorFromString(methodName);
|
||||
if ([self respondsToSelector:selector]) {
|
||||
_Pragma("clang diagnostic push")
|
||||
_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"")
|
||||
if (argument) {
|
||||
[self performSelector:selector withObject:argument];
|
||||
} else {
|
||||
[self performSelector:selector];
|
||||
}
|
||||
_Pragma("clang diagnostic pop")
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Private Methods
|
||||
|
||||
- (nullable id)valueOfType:(Class)type getterNamed:(NSString *)getterName {
|
||||
id typedValue;
|
||||
@try {
|
||||
SEL selector = NSSelectorFromString(getterName);
|
||||
if ([self respondsToSelector:selector]) {
|
||||
_Pragma("clang diagnostic push")
|
||||
_Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"")
|
||||
id value = [self performSelector:selector];
|
||||
if ([value isKindOfClass:type]) {
|
||||
typedValue = value;
|
||||
}_Pragma("clang diagnostic pop")
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
|
||||
} @finally {
|
||||
return typedValue;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)setterMethodName:(NSString *)getterMethodName {
|
||||
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en-US"];
|
||||
NSString *firstChar = [getterMethodName substringToIndex:1];
|
||||
NSString *folded = [firstChar stringByFoldingWithOptions:NSDiacriticInsensitiveSearch locale:locale];
|
||||
NSString *pascalCasedResult = [folded.uppercaseString stringByAppendingString:[getterMethodName substringFromIndex:1]];
|
||||
|
||||
return [NSString stringWithFormat:@"set%@:", pascalCasedResult];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -1,50 +0,0 @@
|
||||
//
|
||||
// Blurberry.swift
|
||||
// Blurberry
|
||||
//
|
||||
// Created by Pavel Puzyrev on 09.09.2020.
|
||||
//
|
||||
// Copyright (c) 2020 Pavel Puzyrev <cannedapp@yahoo.com>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
|
||||
public struct BlurWrapper<Base> {
|
||||
|
||||
public let base: Base
|
||||
|
||||
public init(_ base: Base) {
|
||||
self.base = base
|
||||
}
|
||||
}
|
||||
|
||||
public protocol BlurCompatible: AnyObject { }
|
||||
|
||||
public extension BlurCompatible {
|
||||
|
||||
var blur: BlurWrapper<Self> {
|
||||
get {
|
||||
BlurWrapper(self)
|
||||
}
|
||||
set { }
|
||||
}
|
||||
}
|
||||
|
||||
extension UIVisualEffectView: BlurCompatible { }
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
//
|
||||
// VisualEffectView+Internal.swift
|
||||
// Blurberry
|
||||
//
|
||||
// Created by Pavel Puzyrev on 07.09.2020.
|
||||
//
|
||||
// Copyright (c) 2020 Pavel Puzyrev <cannedapp@yahoo.com>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
import UIKit
|
||||
|
||||
internal extension BlurWrapper where Base: UIVisualEffectView {
|
||||
|
||||
// MARK: iOS 13, 14
|
||||
|
||||
var backdropView: UIView? {
|
||||
base.subviews.first {
|
||||
type(of: $0) == NSClassFromString("_UIVisualEffectBackdropView")
|
||||
}
|
||||
}
|
||||
|
||||
var overlayView: UIView? {
|
||||
base.subviews.first {
|
||||
type(of: $0) == NSClassFromString("_UIVisualEffectSubview")
|
||||
}
|
||||
}
|
||||
|
||||
var gaussianBlurFilter: NSObject? {
|
||||
backdropView?.arrayValue(getter: "filters")?.first {
|
||||
$0.stringValue(getter: "filterType") == "gaussianBlur"
|
||||
}
|
||||
}
|
||||
|
||||
var sourceOverEffect: NSObject? {
|
||||
overlayView?.arrayValue(getter: "viewEffects")?.first {
|
||||
$0.stringValue(getter: "filterType") == "sourceOver"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: iOS 10, 11, 12
|
||||
|
||||
var blurEffect: NSObject? {
|
||||
guard let effect = base.effect, type(of: effect) == NSClassFromString("_UICustomBlurEffect") else {
|
||||
return nil
|
||||
}
|
||||
return base.effect
|
||||
}
|
||||
|
||||
func updateBlurEffect(blurRadius: CGFloat, tintColor: UIColor?) {
|
||||
let effect = (NSClassFromString("_UICustomBlurEffect") as? UIBlurEffect.Type)?.init()
|
||||
effect?.setValueSafe(value: blurRadius, key: "blurRadius")
|
||||
effect?.setValueSafe(value: tintColor ?? UIColor(white: 1.0, alpha: 0.3), key: "colorTint")
|
||||
effect?.setValueSafe(value: 1.0, key: "scale")
|
||||
effect?.setValueSafe(value: 1.0, key: "colorTintAlpha")
|
||||
base.effect = effect
|
||||
}
|
||||
|
||||
// MARK: Changes
|
||||
|
||||
func prepareForChanges() {
|
||||
if #available(iOS 13, *) {
|
||||
base.effect = UIBlurEffect(style: .light)
|
||||
gaussianBlurFilter?.setIVarValue(value: 1.0, getter: "requestedScaleHint")
|
||||
}
|
||||
}
|
||||
|
||||
func applyChanges() {
|
||||
if #available(iOS 13, *) {
|
||||
backdropView?.callMethod(named: "applyRequestedFilterEffects")
|
||||
}
|
||||
}
|
||||
}
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
//
|
||||
// VisualEffectView+Public.swift
|
||||
// Blurberry
|
||||
//
|
||||
// Created by Pavel Puzyrev on 09.09.2020.
|
||||
//
|
||||
// Copyright (c) 2020 Pavel Puzyrev <cannedapp@yahoo.com>
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
|
||||
import UIKit
|
||||
import ContainerControllerSwift
|
||||
|
||||
|
||||
|
||||
public extension BlurWrapper where Base: UIVisualEffectView {
|
||||
|
||||
var radius: CGFloat {
|
||||
get {
|
||||
if #available(iOS 13, *) {
|
||||
return gaussianBlurFilter?.dictionaryValue(getter: "requestedValues")?["inputRadius"] as? CGFloat ?? 0.0
|
||||
} else {
|
||||
return blurEffect?.valueSafe(key: "blurRadius") as? CGFloat ?? 0.0
|
||||
}
|
||||
}
|
||||
set {
|
||||
prepareForChanges()
|
||||
|
||||
if #available(iOS 13, *) {
|
||||
gaussianBlurFilter?.setObjectInDictionary(object: newValue, key: "inputRadius", getter: "requestedValues")
|
||||
} else {
|
||||
updateBlurEffect(blurRadius: newValue, tintColor: tintColor)
|
||||
}
|
||||
|
||||
applyChanges()
|
||||
}
|
||||
}
|
||||
|
||||
var tintColor: UIColor? {
|
||||
get {
|
||||
if #available(iOS 13, *) {
|
||||
return sourceOverEffect?.colorValue(getter: "color")
|
||||
} else {
|
||||
return blurEffect?.colorValue(getter: "colorTint")
|
||||
}
|
||||
}
|
||||
set {
|
||||
prepareForChanges()
|
||||
|
||||
if #available(iOS 13, *) {
|
||||
sourceOverEffect?.setValueUsingSetter(value: newValue, getter: "color")
|
||||
sourceOverEffect?.callMethod(named: "applyRequestedEffectToView:", with: overlayView)
|
||||
} else {
|
||||
updateBlurEffect(blurRadius: radius, tintColor: newValue)
|
||||
}
|
||||
|
||||
applyChanges()
|
||||
}
|
||||
}
|
||||
}
|
||||
-345
@@ -1,345 +0,0 @@
|
||||
//
|
||||
// UIButton+AllAnimations.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 20.08.2021.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
import AVFoundation
|
||||
|
||||
// MARK: Animations
|
||||
|
||||
extension UIButton {
|
||||
|
||||
// MARK: - Alpha
|
||||
|
||||
func updateChangeAlpha(with views: [UIView], visible: Alpha, value: CGFloat, duration: Speed?) {
|
||||
|
||||
var alpha: CGFloat = 1.0
|
||||
if visible != .visible {
|
||||
alpha = value
|
||||
}
|
||||
|
||||
if let duration = duration {
|
||||
UIView.animate(with: duration) {
|
||||
for view in views {
|
||||
view.alpha = alpha
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for view in views {
|
||||
view.alpha = alpha
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Layer Gray
|
||||
|
||||
func updateLayerGray(with views: [UIView], visible: Alpha, value: CGFloat, duration: Speed?) {
|
||||
|
||||
guard let mainView = views.last else { return }
|
||||
let shTag = 31
|
||||
let spechialColor = UIColor(red: 10.0 / 255.0, green: 13.0 / 255.0, blue: 38.0 / 255.0, alpha: value)
|
||||
|
||||
if visible == .visible {
|
||||
|
||||
if let view = mainView.viewWithTag(shTag) {
|
||||
view.alpha = 1
|
||||
|
||||
if let duration = duration {
|
||||
UIView.animate(
|
||||
with: duration,
|
||||
animations: {
|
||||
view.alpha = 0
|
||||
},
|
||||
completion: { fin in
|
||||
view.removeFromSuperview()
|
||||
}
|
||||
)
|
||||
} else {
|
||||
view.alpha = 0
|
||||
view.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if mainView.viewWithTag(shTag) == nil {
|
||||
|
||||
var radius = mainView.layer.cornerRadius
|
||||
if radius == 0 {
|
||||
for sv in mainView.subviews {
|
||||
if sv.layer.cornerRadius != 0 {
|
||||
radius = mainView.layer.cornerRadius
|
||||
}
|
||||
if let desFig = mainView as? DesignFigure {
|
||||
radius = desFig.cornerRadius
|
||||
if radius == -1 {
|
||||
let minSize = min(mainView.frame.width, mainView.bounds.height)
|
||||
radius = minSize / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let shadowView = UIView(frame: mainView.bounds)
|
||||
shadowView.tag = shTag
|
||||
shadowView.backgroundColor = spechialColor
|
||||
shadowView.layer.cornerRadius = radius
|
||||
mainView.addSubview(shadowView)
|
||||
shadowView.alpha = ((duration == nil) ? 1 : 0)
|
||||
if let duration = duration {
|
||||
if duration == .zero {
|
||||
shadowView.alpha = 1
|
||||
} else {
|
||||
UIView.animate(with: duration) {
|
||||
shadowView.alpha = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UIView {
|
||||
|
||||
// MARK: - Flash
|
||||
|
||||
func flash(duration: Speed = .ms200) {
|
||||
|
||||
let flash = CABasicAnimation(keyPath: "opacity")
|
||||
flash.duration = duration.rawValue
|
||||
flash.fromValue = 1
|
||||
flash.toValue = 0.1
|
||||
flash.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
|
||||
flash.autoreverses = true
|
||||
flash.repeatCount = 3
|
||||
|
||||
layer.add(flash, forKey: nil)
|
||||
}
|
||||
|
||||
// MARK: - Change Color
|
||||
|
||||
|
||||
func animationOpacity(duration: CGFloat, value: CGFloat, beginTime: CGFloat = 0.0) {
|
||||
//
|
||||
let pulseAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.opacity))// "opacity")
|
||||
pulseAnimation.fromValue = 0
|
||||
pulseAnimation.toValue = 1 // 0.1
|
||||
pulseAnimation.duration = 100
|
||||
|
||||
pulseAnimation.isRemovedOnCompletion = false
|
||||
pulseAnimation.beginTime = CACurrentMediaTime() + beginTime //CACurrentMediaTime() + AVCoreAnimationBeginTimeAtZero + 1.0
|
||||
pulseAnimation.fillMode = .both
|
||||
pulseAnimation.isAdditive = false
|
||||
// pulseAnimation.repeatCount = .infinit
|
||||
layer.add(pulseAnimation, forKey: "opacityIn")
|
||||
|
||||
|
||||
|
||||
let animtingLayer: CALayer = CALayer(layer: layer)
|
||||
|
||||
|
||||
let pulseAnimation2 = CABasicAnimation(keyPath: #keyPath(CALayer.opacity))// "opacity")
|
||||
pulseAnimation2.fromValue = 1
|
||||
pulseAnimation2.toValue = beginTime // 0.1
|
||||
pulseAnimation2.duration = 100
|
||||
pulseAnimation2.isRemovedOnCompletion = false
|
||||
pulseAnimation2.beginTime = 1.0// AVCoreAnimationBeginTimeAtZero + 0.0
|
||||
pulseAnimation2.fillMode = .both
|
||||
pulseAnimation2.isAdditive = false
|
||||
// pulseAnimation2.repeatCount = .infinit
|
||||
|
||||
|
||||
animtingLayer.add(pulseAnimation2, forKey: "opacityOut")
|
||||
layer.addSublayer(animtingLayer)
|
||||
|
||||
|
||||
layer.opacity = 0.0
|
||||
|
||||
}
|
||||
|
||||
func animationColor(duration: Speed = .s1, colors: [UIColor]) {
|
||||
|
||||
// layer.removeAnimation(forKey: "backgroundColor")
|
||||
// layer.sublayers?.forEach {
|
||||
// $0.mask?.removeAnimation(forKey: "backgroundColor")
|
||||
// }
|
||||
// layer.removeAllAnimations()
|
||||
// layer.removeFromSuperlayer()
|
||||
let darkerColor = colors[0]
|
||||
let lighterColor = colors[1]
|
||||
let pulseAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.backgroundColor))
|
||||
pulseAnimation.fromValue = darkerColor
|
||||
pulseAnimation.toValue = lighterColor
|
||||
pulseAnimation.duration = 1
|
||||
pulseAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
|
||||
pulseAnimation.autoreverses = true
|
||||
pulseAnimation.repeatCount = .infinity
|
||||
pulseAnimation.isRemovedOnCompletion = false
|
||||
|
||||
// let color = CABasicAnimation(keyPath: "backgroundColor")
|
||||
// color.fromValue = colors[0]// UIColor.green.cgColor
|
||||
// color.toValue = colors[1] // UIColor.red.cgColor
|
||||
// color.duration = duration.rawValue
|
||||
// color.beginTime = CACurrentMediaTime() + 0.3
|
||||
//// color.autoreverses = true
|
||||
//// color.repeatDuration = 1
|
||||
// color.autoreverses = true
|
||||
// color.repeatCount = 500
|
||||
// layer.cornerRadius = self.layer.cornerRadius
|
||||
//// layer.add(color, forKey: "animationColor")
|
||||
|
||||
|
||||
|
||||
layer.removeAnimation(forKey: "animationColor")
|
||||
layer.add(pulseAnimation, forKey: "animationColor")
|
||||
backgroundColor = .clear
|
||||
}
|
||||
|
||||
// MARK: - Pulsate
|
||||
|
||||
func pulsate(duration: Speed = .ms200, value: CGFloat = 0.9) {
|
||||
|
||||
let pulse = CASpringAnimation(keyPath: "transform.scale")
|
||||
pulse.duration = duration.rawValue
|
||||
pulse.fromValue = value
|
||||
pulse.toValue = 1.0
|
||||
pulse.autoreverses = true
|
||||
pulse.repeatCount = 2
|
||||
pulse.initialVelocity = 0.5
|
||||
pulse.damping = 1.0
|
||||
|
||||
layer.add(pulse, forKey: "pulse")
|
||||
}
|
||||
|
||||
// MARK: - Pulsate 2
|
||||
|
||||
func pulsateNew(visible: Alpha, value: CGFloat = 0.9) {
|
||||
if visible == .visible {
|
||||
animate(self, transform: .identity)
|
||||
} else {
|
||||
animate(self, transform: CGAffineTransform.identity.scaledBy(x: value, y: value))
|
||||
}
|
||||
}
|
||||
|
||||
private func animate(_ view: UIView, transform: CGAffineTransform) {
|
||||
UIView.animate(withDuration: 0.4,
|
||||
delay: 0,
|
||||
usingSpringWithDamping: 0.5,
|
||||
initialSpringVelocity: 3,
|
||||
options: [.curveEaseInOut],
|
||||
animations: {
|
||||
view.transform = transform
|
||||
}, completion: nil)
|
||||
}
|
||||
|
||||
// MARK: - Shake
|
||||
|
||||
func shake() {
|
||||
let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
|
||||
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
|
||||
animation.duration = 0.6
|
||||
animation.values = [-20.0, 20.0, -20.0, 20.0, -10.0, 10.0, -5.0, 5.0, 0.0 ]
|
||||
layer.add(animation, forKey: "shake")
|
||||
}
|
||||
|
||||
// MARK: - Shake 2
|
||||
|
||||
func shakeNew(duration: Speed = .ms50) {
|
||||
|
||||
let shake = CABasicAnimation(keyPath: "position")
|
||||
shake.duration = duration.rawValue
|
||||
shake.repeatCount = 2
|
||||
shake.autoreverses = true
|
||||
|
||||
let fromPoint = CGPoint(x: center.x - 5, y: center.y)
|
||||
let fromValue = NSValue(cgPoint: fromPoint)
|
||||
|
||||
let toPoint = CGPoint(x: center.x + 5, y: center.y)
|
||||
let toValue = NSValue(cgPoint: toPoint)
|
||||
|
||||
shake.fromValue = fromValue
|
||||
shake.toValue = toValue
|
||||
|
||||
layer.add(shake, forKey: "position")
|
||||
}
|
||||
|
||||
// MARK: - Android Pulse
|
||||
|
||||
func androidPulseAnimation( duration: Speed = .ms1, color: UIColor, position: CGPoint) {
|
||||
|
||||
let pulse = PulseAnimation(numberOfPulse: 1, radius: 200, postion: position)
|
||||
pulse.animationDuration = duration.rawValue
|
||||
pulse.backgroundColor = color.cgColor // #colorLiteral(red: 0.05282949957, green: 0.5737867104, blue: 1, alpha: 1)
|
||||
layer.insertSublayer(pulse, below: layer)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class PulseAnimation: CALayer {
|
||||
|
||||
var animationGroup = CAAnimationGroup()
|
||||
var animationDuration: TimeInterval = 1.5
|
||||
var radius: CGFloat = 200
|
||||
var numebrOfPulse: Float = Float.infinity
|
||||
|
||||
override init(layer: Any) {
|
||||
super.init(layer: layer)
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
init(numberOfPulse: Float = Float.infinity, radius: CGFloat, postion: CGPoint){
|
||||
super.init()
|
||||
self.backgroundColor = UIColor.black.cgColor
|
||||
self.contentsScale = UIScreen.main.scale
|
||||
self.opacity = 0
|
||||
self.radius = radius
|
||||
self.numebrOfPulse = numberOfPulse
|
||||
self.position = postion
|
||||
|
||||
self.bounds = CGRect(x: 0, y: 0, width: radius*2, height: radius*2)
|
||||
self.cornerRadius = radius
|
||||
|
||||
DispatchQueue.global(qos: .default).async {
|
||||
self.setupAnimationGroup()
|
||||
DispatchQueue.main.async {
|
||||
self.add(self.animationGroup, forKey: "pulse")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func scaleAnimation() -> CABasicAnimation {
|
||||
let scaleAnimaton = CABasicAnimation(keyPath: "transform.scale.xy")
|
||||
scaleAnimaton.fromValue = NSNumber(value: 0)
|
||||
scaleAnimaton.toValue = NSNumber(value: 1)
|
||||
scaleAnimaton.duration = animationDuration
|
||||
return scaleAnimaton
|
||||
}
|
||||
|
||||
func createOpacityAnimation() -> CAKeyframeAnimation {
|
||||
let opacityAnimiation = CAKeyframeAnimation(keyPath: "opacity")
|
||||
opacityAnimiation.duration = animationDuration
|
||||
opacityAnimiation.values = [0.4,0.8,0]
|
||||
opacityAnimiation.keyTimes = [0,0.3,1]
|
||||
return opacityAnimiation
|
||||
}
|
||||
|
||||
func setupAnimationGroup() {
|
||||
self.animationGroup.duration = animationDuration
|
||||
self.animationGroup.repeatCount = numebrOfPulse
|
||||
let defaultCurve = CAMediaTimingFunction(name: CAMediaTimingFunctionName.default)
|
||||
self.animationGroup.timingFunction = defaultCurve
|
||||
self.animationGroup.animations = [scaleAnimation(),createOpacityAnimation()]
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
-84
@@ -1,84 +0,0 @@
|
||||
//
|
||||
// UIButton+Extention.swift
|
||||
// FigmaConvertXib
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 06.11.2021.
|
||||
// Copyright © 2021 mrusta. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class Button: UIButton {
|
||||
|
||||
var onPressed: (() -> Void)?
|
||||
var onReleased: (() -> Void)?
|
||||
|
||||
init() {
|
||||
super.init(frame: .zero)
|
||||
addTarget(self, action: #selector(self.pressed), for: .touchDown)
|
||||
addTarget(self, action: #selector(self.released), for: .touchUpInside)
|
||||
addTarget(self, action: #selector(self.released), for: .touchUpOutside)
|
||||
setup()
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) { fatalError() }
|
||||
|
||||
@objc func setup() {}
|
||||
|
||||
@objc func pressed() {
|
||||
onPressed?()
|
||||
}
|
||||
|
||||
@objc func released() {
|
||||
onReleased?()
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple tap implementation
|
||||
typealias Closure = () -> ()
|
||||
typealias ClosureClick = (_ event: UIControl.Event) -> ()
|
||||
|
||||
|
||||
class ClosureSleeve {
|
||||
let closure: Closure
|
||||
init(_ closure: @escaping Closure) {
|
||||
self.closure = closure
|
||||
}
|
||||
@objc func invoke () {
|
||||
closure()
|
||||
}
|
||||
}
|
||||
|
||||
extension UIControl {
|
||||
func tap(for controlEvents: UIControl.Event = .touchUpInside,
|
||||
_ closure: @escaping Closure) {
|
||||
let sleeve = ClosureSleeve(closure)
|
||||
addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvents)
|
||||
objc_setAssociatedObject(self,
|
||||
String(format: "[%d]", arc4random()),
|
||||
sleeve,
|
||||
objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
|
||||
}
|
||||
|
||||
func tapClassic(_ closure: @escaping ClosureClick) {
|
||||
self.tap(for: .touchDown) { // [weak self] in
|
||||
print(" btn tapClassic touchDown")
|
||||
closure(.touchDown)
|
||||
}
|
||||
self.tap(for: .touchUpInside) { // [weak self] in
|
||||
print(" btn tapClassic touchUpInside")
|
||||
closure(.touchUpInside)
|
||||
}
|
||||
self.tap(for: .touchUpOutside) { // [weak self] in
|
||||
print(" btn tapClassic touchUpOutside")
|
||||
closure(.touchUpOutside)
|
||||
}
|
||||
self.tap(for: .touchCancel) { // [weak self] in
|
||||
print(" btn tapClassic touchCancel")
|
||||
closure(.touchCancel)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
-362
@@ -1,362 +0,0 @@
|
||||
//
|
||||
// ViewAnimationSelect.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 22.06.2021.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@IBDesignable
|
||||
class ButtonAnimationView: UIView {
|
||||
|
||||
@IBInspectable var cornerRadius: CGFloat = 0.0
|
||||
@IBInspectable var animationType: Int = 0
|
||||
|
||||
public var type: UIButton.TapType = .alpha(0.5)
|
||||
private var subviewsAnimation = false
|
||||
public var button: UIButton?
|
||||
|
||||
// MARK: - Initialize
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
updateSubviews()
|
||||
}
|
||||
|
||||
public init() {
|
||||
super.init(frame: .zero)
|
||||
updateSubviews()
|
||||
}
|
||||
|
||||
override func layoutSubviews() { updateSubviews() }
|
||||
|
||||
public func setAnimation(type: UIButton.TapType, views: [UIView]? = nil) {
|
||||
self.type = type
|
||||
// updateSubviews()
|
||||
|
||||
layer.cornerRadius = cornerRadius
|
||||
|
||||
var nviews: [UIView] = []
|
||||
if let views = views {
|
||||
nviews = views
|
||||
} else {
|
||||
nviews.append(self)
|
||||
subviews.forEach {
|
||||
nviews.append($0)
|
||||
}
|
||||
}
|
||||
|
||||
button?.tapHideAnimation(views: nviews, type: type, callback: { type in
|
||||
if type == .touchUpInside {
|
||||
|
||||
}
|
||||
})
|
||||
subviewsAnimation = true
|
||||
}
|
||||
|
||||
public func updateSubviews() {
|
||||
|
||||
if button == nil {
|
||||
createButton()
|
||||
}
|
||||
|
||||
|
||||
if animationType != 0 {
|
||||
|
||||
let type: UIButton.TapType = {
|
||||
switch animationType {
|
||||
case 1: return .alpha(0.5)
|
||||
case 2: return .layerGray(0.1845)
|
||||
case 3: return .pulsate(new: false, value: 0.9)
|
||||
case 4: return .pulsate(new: true, value: 0.9)
|
||||
case 5: return .shake(new: false)
|
||||
case 6: return .shake(new: true)
|
||||
case 7: return .flash
|
||||
case 8: return .color([.white, .red])
|
||||
case 9: return .androidStyle(color: .white)
|
||||
default: return .alpha(0.5)
|
||||
}
|
||||
}()
|
||||
|
||||
setAnimation(type: type)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public func createButton() {
|
||||
let btn = UIButton(type: .system)
|
||||
btn.frame = bounds
|
||||
btn.backgroundColor = .clear
|
||||
btn.setTitle(nil, for: .normal)
|
||||
btn.contentVerticalAlignment = .center
|
||||
btn.autoresizingMask = [ .flexibleTopMargin,
|
||||
.flexibleBottomMargin,
|
||||
.flexibleLeftMargin,
|
||||
.flexibleRightMargin,
|
||||
.flexibleWidth,
|
||||
.flexibleHeight ]
|
||||
addSubview(btn)
|
||||
self.button = btn
|
||||
}
|
||||
}
|
||||
|
||||
extension UIButton {
|
||||
|
||||
// MARK: Tap Animation Type
|
||||
|
||||
static let setTag = 963
|
||||
|
||||
enum TapType {
|
||||
case alpha(_ value: CGFloat) // 0.5
|
||||
case layerGray(_ value: CGFloat = 0.1845) // 0.1845 add black shadow
|
||||
case pulsate(new: Bool = false, value: CGFloat = 0.9)
|
||||
case shake(new: Bool = false)
|
||||
case flash
|
||||
case color(_ arr: [UIColor] = [.white, .red])
|
||||
case androidStyle(color: UIColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1))
|
||||
}
|
||||
|
||||
// MARK: Set
|
||||
|
||||
func tapHideAnimation(
|
||||
view: UIView?,
|
||||
type: TapType = .alpha(0.0),
|
||||
hideSpeed: Speed? = .ms100,
|
||||
callback: ((UIControl.Event) -> Void)? = nil
|
||||
) {
|
||||
guard let view = view else { return }
|
||||
tapHideAnimation(views: [view], type: type, callback: callback)
|
||||
}
|
||||
|
||||
func tapHideAnimation(
|
||||
views: [UIView],
|
||||
type: TapType = .alpha(0.0),
|
||||
hideSpeed: Speed? = .ms100,
|
||||
callback: ((UIControl.Event) -> Void)? = nil
|
||||
) {
|
||||
|
||||
switch type {
|
||||
case .androidStyle(let color): do {
|
||||
|
||||
var tapAdded: Bool = false
|
||||
gestureRecognizers?.forEach {
|
||||
if $0 is BindableGestureRecognizer {
|
||||
tapAdded = true
|
||||
}
|
||||
}
|
||||
if !tapAdded {
|
||||
|
||||
let tapp = BindableGestureRecognizer { [weak self] sender in
|
||||
|
||||
guard let superview = self?.superview else { return }
|
||||
let touchPoint = sender.location(in: superview)
|
||||
|
||||
guard let dur: Speed = self?.defaultDuration(type: type) else { return }
|
||||
self?.androidPulseAnimation(duration: dur, color: color, position: touchPoint)
|
||||
|
||||
|
||||
if sender.state == .began {
|
||||
callback?(.touchDown)
|
||||
} else if sender.state == .changed {
|
||||
callback?(.touchDown)
|
||||
} else if sender.state == .ended {
|
||||
callback?(.touchUpInside)
|
||||
}
|
||||
// callback?(.touchUpInside)
|
||||
}
|
||||
addGestureRecognizer(tapp)
|
||||
}
|
||||
}
|
||||
default: break
|
||||
}
|
||||
|
||||
|
||||
// if tag != UIButton.setTag { return }
|
||||
// tag = UIButton.setTag
|
||||
|
||||
tap(for: .touchDown) { [weak self] in
|
||||
callback?(.touchDown)
|
||||
self?.hideAnimation(with: views, type: type, event: .touchDown, duration: hideSpeed)
|
||||
}
|
||||
tap(for: .touchUpInside) { [weak self] in
|
||||
callback?(.touchUpInside)
|
||||
self?.hideAnimation(with: views, visible: .visible, type: type, event: .touchUpInside)
|
||||
}
|
||||
tap(for: .touchUpOutside) { [weak self] in
|
||||
callback?(.touchUpOutside)
|
||||
self?.hideAnimation(with: views, visible: .visible, type: type, event: .touchUpOutside)
|
||||
}
|
||||
tap(for: .touchCancel) { [weak self] in
|
||||
callback?(.touchCancel)
|
||||
self?.hideAnimation(with: views, visible: .visible, type: type, event: .touchCancel)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - De-Select
|
||||
|
||||
func deselected(_ views: [UIView]) {
|
||||
hideAnimation(
|
||||
with: views,
|
||||
visible: .visible
|
||||
)
|
||||
}
|
||||
|
||||
func defaultDuration(type: TapType) -> Speed {
|
||||
switch type {
|
||||
case .alpha(_), .layerGray(_): return .ms300
|
||||
case .pulsate(_, _), .flash: return .ms200
|
||||
case .shake(_): return .ms50
|
||||
case .color(_), .androidStyle(_): return .s1
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Animation Filter
|
||||
|
||||
func hideAnimation(
|
||||
with views: [UIView],
|
||||
visible: Alpha = .invisible,
|
||||
type: TapType = .alpha(0.0),
|
||||
event: UIControl.Event = .touchUpInside,
|
||||
duration: Speed? = nil
|
||||
) {
|
||||
|
||||
let dur: Speed = defaultDuration(type: type)
|
||||
switch type {
|
||||
case .alpha(let value):
|
||||
updateChangeAlpha(with: views, visible: visible, value: value, duration: dur)
|
||||
case .layerGray(let value):
|
||||
if event == .touchDown {
|
||||
updateLayerGray(with: views, visible: .invisible, value: value, duration: nil)
|
||||
} else {
|
||||
updateLayerGray(with: views, visible: .visible, value: value, duration: dur)
|
||||
}
|
||||
default: break
|
||||
}
|
||||
|
||||
views.forEach {
|
||||
switch type {
|
||||
case .flash: $0.flash(duration: dur)
|
||||
case .color(let arr): $0.animationColor(duration: dur, colors: arr)
|
||||
case .pulsate(let new, let value):
|
||||
if new { $0.pulsateNew(visible: visible, value: value) }
|
||||
else { $0.pulsate(duration: dur, value: value) }
|
||||
case .shake(let new):
|
||||
if new { $0.shake() }
|
||||
else { $0.shakeNew(duration: dur) }
|
||||
// case .androidClickable:
|
||||
// androidPulseAnimation(duration: dur)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension UIControl.Event {
|
||||
|
||||
func strName() -> String {
|
||||
return enevtName(self)
|
||||
}
|
||||
|
||||
func enevtName(_ event: UIControl.Event) -> String {
|
||||
switch event {
|
||||
case .touchDown: return "touch.Down"
|
||||
case .touchCancel: return "touch.Cancel"
|
||||
case .touchUpOutside: return "touch.Up.Outside"
|
||||
case .touchUpInside: return "touch.Up.Inside"
|
||||
default: return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typealias Interval = TimeInterval
|
||||
|
||||
enum Speed: Interval {
|
||||
case zero = 0.0
|
||||
case ms1 = 0.001
|
||||
case ms50 = 0.05
|
||||
case ms100 = 0.1
|
||||
case ms200 = 0.2
|
||||
case ms300 = 0.3
|
||||
case ms350 = 0.35
|
||||
case ms400 = 0.4
|
||||
case ms450 = 0.45
|
||||
case ms500 = 0.5
|
||||
case s1 = 1.0
|
||||
case s2 = 2.0
|
||||
case s3 = 3.0
|
||||
case s4 = 4.0
|
||||
case s5 = 5.0
|
||||
}
|
||||
|
||||
enum Delay: Interval {
|
||||
case ms1 = 0.001
|
||||
case ms100 = 0.1
|
||||
case ms200 = 0.2
|
||||
case ms300 = 0.3
|
||||
case ms400 = 0.4
|
||||
case ms500 = 0.5
|
||||
case s1 = 1.0
|
||||
case s2 = 2.0
|
||||
case s3 = 3.0
|
||||
case s4 = 4.0
|
||||
case s5 = 5.0
|
||||
}
|
||||
|
||||
|
||||
enum Alpha: CGFloat {
|
||||
case invisible = 0.0
|
||||
case halfTransluent = 0.5
|
||||
case visible = 1.0
|
||||
}
|
||||
|
||||
extension UIView {
|
||||
func setAlpha(_ alpha: Alpha) {
|
||||
self.alpha = alpha.rawValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//MARK: - Override animations
|
||||
extension UIView {
|
||||
|
||||
static func animate(with duration: Speed,
|
||||
animations: @escaping () -> Void) {
|
||||
UIView.animate(withDuration: duration.rawValue, animations: animations)
|
||||
}
|
||||
|
||||
static func animate(with duration: Speed,
|
||||
animations: @escaping () -> Void,
|
||||
completion: ((Bool) -> Void)?) {
|
||||
UIView.animate(withDuration: duration.rawValue,
|
||||
animations: animations,
|
||||
completion: completion)
|
||||
}
|
||||
|
||||
static func animate(with duration: Speed,
|
||||
delay: Delay,
|
||||
options: AnimationOptions,
|
||||
animations: @escaping () -> Void,
|
||||
completion: ((Bool) -> Void)?) {
|
||||
UIView.animate(withDuration: duration.rawValue,
|
||||
delay: delay.rawValue,
|
||||
options: options,
|
||||
animations: animations,
|
||||
completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
final class BindableGestureRecognizer: UITapGestureRecognizer {
|
||||
private var action: (UITapGestureRecognizer) -> Void
|
||||
|
||||
init(action: @escaping (UITapGestureRecognizer) -> Void) {
|
||||
self.action = action
|
||||
super.init(target: nil, action: nil)
|
||||
self.addTarget(self, action: #selector(execute(_:)))
|
||||
}
|
||||
|
||||
@objc private func execute(_ sender: UITapGestureRecognizer) {
|
||||
action(sender)
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
|
||||
|
||||
import UIKit
|
||||
|
||||
class CopyableLabel: UILabel {
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
self.sharedInit()
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
self.sharedInit()
|
||||
}
|
||||
|
||||
func sharedInit() {
|
||||
self.isUserInteractionEnabled = true
|
||||
let gesture = UILongPressGestureRecognizer(target: self, action: #selector(self.showMenu))
|
||||
self.addGestureRecognizer(gesture)
|
||||
}
|
||||
|
||||
@objc func showMenu(_ recognizer: UILongPressGestureRecognizer) {
|
||||
self.becomeFirstResponder()
|
||||
|
||||
let menu = UIMenuController.shared
|
||||
|
||||
let locationOfTouchInLabel = recognizer.location(in: self)
|
||||
|
||||
if !menu.isMenuVisible {
|
||||
var rect = bounds
|
||||
rect.origin = locationOfTouchInLabel
|
||||
rect.size = CGSize(width: 1, height: 1)
|
||||
|
||||
if #available(iOS 13.0, *) {
|
||||
menu.showMenu(from: self, rect: rect)
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func copy(_ sender: Any?) {
|
||||
let board = UIPasteboard.general
|
||||
|
||||
board.string = text
|
||||
|
||||
let menu = UIMenuController.shared
|
||||
|
||||
if #available(iOS 13.0, *) {
|
||||
menu.showMenu(from: self, rect: bounds)
|
||||
} else {
|
||||
menu.setMenuVisible(false, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
override var canBecomeFirstResponder: Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
|
||||
return action == #selector(UIResponderStandardEditActions.copy)
|
||||
}
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
|
||||
|
||||
import UIKit
|
||||
|
||||
@IBDesignable
|
||||
class DesignButton: UIButton {
|
||||
|
||||
@IBInspectable var hideAnimation: Bool = true
|
||||
|
||||
//MARK: Fill
|
||||
|
||||
@IBInspectable var fillColor: UIColor = .clear
|
||||
|
||||
//MARK: Gradient
|
||||
|
||||
@IBInspectable var grColor1: UIColor?
|
||||
@IBInspectable var grColor2: UIColor?
|
||||
@IBInspectable var grColor3: UIColor?
|
||||
@IBInspectable var grColor4: UIColor?
|
||||
@IBInspectable var grColor5: UIColor?
|
||||
@IBInspectable var grColor6: UIColor?
|
||||
|
||||
@IBInspectable var grStartPoint: CGPoint = .zero
|
||||
@IBInspectable var grEndPoint: CGPoint = .zero
|
||||
|
||||
//MARK: Inner Shadow
|
||||
|
||||
@IBInspectable var inShColor: UIColor = .clear
|
||||
@IBInspectable var inShRadius: CGFloat = 0.0
|
||||
@IBInspectable var inShOffset: CGSize = .zero
|
||||
|
||||
//MARK: Shadow
|
||||
|
||||
@IBInspectable var shColor: UIColor = .clear
|
||||
@IBInspectable var shRadius: CGFloat = 0.0
|
||||
@IBInspectable var shOffset: CGSize = .zero
|
||||
|
||||
//MARK: Border
|
||||
|
||||
@IBInspectable var brColor: UIColor = .clear
|
||||
@IBInspectable var brWidth: CGFloat = 0.0
|
||||
|
||||
//MARK: Blur
|
||||
|
||||
@IBInspectable var blur: CGFloat = 0.0
|
||||
|
||||
//MARK: Radius
|
||||
|
||||
@IBInspectable var cornerRadius: CGFloat = 0.0
|
||||
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
|
||||
layer.cornerRadius = self.cornerRadius(cornerRadius)
|
||||
layer.backgroundColor = fillColor.cgColor
|
||||
|
||||
addGradient()
|
||||
addInnerShadow()
|
||||
addShadow()
|
||||
addBorder()
|
||||
|
||||
add(blur: blur)
|
||||
}
|
||||
|
||||
private func addGradient() {
|
||||
|
||||
_ = add(gradient: grColor1,
|
||||
color2: grColor2,
|
||||
color3: grColor3,
|
||||
color4: grColor4,
|
||||
color5: grColor5,
|
||||
color6: grColor6,
|
||||
pointStart: grStartPoint,
|
||||
pointEnd: grEndPoint,
|
||||
cornerRadius: cornerRadius)
|
||||
|
||||
}
|
||||
|
||||
private func addInnerShadow() {
|
||||
|
||||
addInnerShadow(color: inShColor,
|
||||
radius: inShRadius,
|
||||
offset: inShOffset,
|
||||
cornerRadius: cornerRadius)
|
||||
|
||||
}
|
||||
|
||||
private func addShadow() {
|
||||
layer.shadowOffset = shOffset
|
||||
layer.shadowOpacity = 1.0
|
||||
layer.shadowRadius = shRadius
|
||||
layer.shadowColor = shColor.cgColor
|
||||
}
|
||||
|
||||
private func addBorder() {
|
||||
layer.borderColor = brColor.cgColor
|
||||
layer.borderWidth = brWidth
|
||||
}
|
||||
|
||||
override var isSelected: Bool {
|
||||
didSet {
|
||||
super.isSelected = isSelected
|
||||
}
|
||||
}
|
||||
|
||||
override var isHighlighted: Bool {
|
||||
didSet {
|
||||
// super.isHighlighted = isHighlighted
|
||||
}
|
||||
}
|
||||
|
||||
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
|
||||
selectedLayer(show: true)
|
||||
return super.beginTracking(touch, with: event)
|
||||
}
|
||||
|
||||
override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
|
||||
let point = touch.location(in: self)
|
||||
let someFrame = bounds
|
||||
let highlighted = someFrame.contains(point)
|
||||
selectedLayer(show: highlighted)
|
||||
return super.continueTracking(touch, with: event)
|
||||
}
|
||||
|
||||
override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
|
||||
selectedLayer(show: false)
|
||||
super.endTracking(touch, with: event)
|
||||
}
|
||||
|
||||
override func cancelTracking(with event: UIEvent?) {
|
||||
selectedLayer(show: false)
|
||||
super.cancelTracking(with: event)
|
||||
}
|
||||
|
||||
func radius() -> CGFloat {
|
||||
let minSize = min(frame.size.width, frame.size.height)
|
||||
let radius = ((cornerRadius < 0) ? (minSize / 2) : cornerRadius)
|
||||
return radius
|
||||
}
|
||||
|
||||
func selectedLayer(show: Bool) {
|
||||
|
||||
func selectAnimationHide(show: Bool) {
|
||||
if show {
|
||||
setAlpha(.halfTransluent)
|
||||
} else {
|
||||
UIView.animate(with: .ms350) {
|
||||
self.setAlpha(.visible)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func selectAnimationShadow(show: Bool) {
|
||||
let tag = 1
|
||||
let view = viewWithTag(tag)
|
||||
if show {
|
||||
if view == nil {
|
||||
let view = UIView(frame: bounds)
|
||||
view.backgroundColor = UIColor.init(white: 0.0, alpha: 0.2)
|
||||
view.tag = tag
|
||||
view.layer.cornerRadius = radius()
|
||||
addSubview(view)
|
||||
}
|
||||
} else {
|
||||
if let view = view {
|
||||
UIView.animate(with: .ms350, animations: {
|
||||
view.setAlpha(.invisible)
|
||||
}, completion: { (fin: Bool) in
|
||||
view.removeFromSuperview()
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hideAnimation {
|
||||
selectAnimationHide(show: show)
|
||||
} else {
|
||||
selectAnimationShadow(show: show)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,716 +0,0 @@
|
||||
//
|
||||
// DesignTest.swift
|
||||
// FigmaConvertXib
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 28.07.2020.
|
||||
// Copyright © 2020 mrusta. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
@IBDesignable
|
||||
class DesignFigure: UIView {
|
||||
/// Rectange | Ellipse | Polygon | Star
|
||||
@IBInspectable var figureType: Int = 0
|
||||
@IBInspectable var starRadius: CGFloat = 0
|
||||
@IBInspectable var starCount: Int = 5
|
||||
@IBInspectable var cornerRadius: CGFloat = 0.0
|
||||
@IBInspectable var blur: CGFloat = 0.0
|
||||
@IBInspectable var image: UIImage?
|
||||
/// ScaleToFill | Fit | Fill
|
||||
@IBInspectable var imageMode: Int = 1
|
||||
@IBInspectable var fillColor: UIColor?
|
||||
@IBInspectable var grColor1: UIColor?
|
||||
@IBInspectable var grColor2: UIColor?
|
||||
@IBInspectable var grColor3: UIColor?
|
||||
@IBInspectable var grColor4: UIColor?
|
||||
@IBInspectable var grColor5: UIColor?
|
||||
@IBInspectable var grColor6: UIColor?
|
||||
@IBInspectable var grStartPoint: CGPoint = .zero
|
||||
@IBInspectable var grEndPoint: CGPoint = .zero
|
||||
/// Default: Linear
|
||||
@IBInspectable var grRadial: Bool = false
|
||||
@IBInspectable var grDrawsOptions: Bool = true
|
||||
@IBInspectable var grDebug: Bool = false
|
||||
@IBInspectable var grPointPercent: Bool = true
|
||||
@IBInspectable var grBlendMode: Int = 0
|
||||
@IBInspectable var brColor: UIColor = .clear
|
||||
@IBInspectable var brWidth: CGFloat = 0.0
|
||||
@IBInspectable var brDash: Int = 0
|
||||
@IBInspectable var inShColor: UIColor = .clear
|
||||
@IBInspectable var inShRadius: CGFloat = 0.0
|
||||
@IBInspectable var inShOffset: CGSize = .zero
|
||||
@IBInspectable var shColor: UIColor = .clear
|
||||
@IBInspectable var shRadius: CGFloat = 0.0
|
||||
@IBInspectable var shOffset: CGSize = .zero
|
||||
|
||||
func setup() {
|
||||
|
||||
if let foundView = viewWithTag(55) {
|
||||
foundView.removeFromSuperview()
|
||||
}
|
||||
|
||||
let d = DesignFigure_(frame: bounds)
|
||||
d.backgroundColor = .clear
|
||||
d.tag = 55
|
||||
d.figureType = figureType
|
||||
d.starRadius = starRadius
|
||||
d.starCount = starCount
|
||||
d.cornerRadius = cornerRadius
|
||||
d.blur = blur
|
||||
d.image = image
|
||||
d.imageMode = imageMode
|
||||
d.fillColor = fillColor
|
||||
d.grColor1 = grColor1
|
||||
d.grColor2 = grColor2
|
||||
d.grColor3 = grColor3
|
||||
d.grColor4 = grColor4
|
||||
d.grColor5 = grColor5
|
||||
d.grColor6 = grColor6
|
||||
d.grStartPoint = grStartPoint
|
||||
d.grEndPoint = grEndPoint
|
||||
d.grRadial = grRadial
|
||||
d.grDrawsOptions = grDrawsOptions
|
||||
d.grDebug = grDebug
|
||||
d.grPointPercent = grPointPercent
|
||||
d.grBlendMode = grBlendMode
|
||||
d.brWidth = brWidth
|
||||
d.brColor = brColor
|
||||
d.brDash = brDash
|
||||
d.inShColor = inShColor
|
||||
d.inShRadius = inShRadius
|
||||
d.inShOffset = inShOffset
|
||||
d.shColor = shColor
|
||||
d.shRadius = shRadius
|
||||
d.shOffset = shOffset
|
||||
insertSubview(d, at: 0)
|
||||
|
||||
if grDebug {
|
||||
if let foundView = viewWithTag(44) {
|
||||
foundView.removeFromSuperview()
|
||||
}
|
||||
|
||||
let d = DesignFigureDebug(frame: bounds)
|
||||
d.backgroundColor = .clear
|
||||
d.tag = 44
|
||||
d.grStartPoint = grStartPoint
|
||||
d.grEndPoint = grEndPoint
|
||||
d.grPointPercent = grPointPercent
|
||||
|
||||
insertSubview(d, at: 1)
|
||||
}
|
||||
}
|
||||
|
||||
override func layoutSubviews() { setup() }
|
||||
|
||||
}
|
||||
|
||||
@IBDesignable
|
||||
class DesignFigureDebug: UIView {
|
||||
|
||||
@IBInspectable var grStartPoint: CGPoint = .zero
|
||||
@IBInspectable var grEndPoint: CGPoint = .zero
|
||||
@IBInspectable var grPointPercent: Bool = true
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
super.draw(rect)
|
||||
|
||||
addGradientDebugPoints()
|
||||
}
|
||||
|
||||
func addGradientDebugPoints() {
|
||||
|
||||
var start = grStartPoint
|
||||
var end = grStartPoint
|
||||
|
||||
if grPointPercent {
|
||||
end = CGPoint(x: grEndPoint.x * frame.width, y: grEndPoint.y * frame.height)
|
||||
start = CGPoint(x: grStartPoint.x * frame.width, y: grStartPoint.y * frame.height)
|
||||
}
|
||||
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
let radius: CGFloat = 5
|
||||
|
||||
context.setBlendMode(CGBlendMode.normal)
|
||||
context.setLineWidth(3.0)
|
||||
|
||||
|
||||
context.setFillColor(UIColor.black.cgColor)
|
||||
|
||||
context.setStrokeColor(UIColor.systemRed.cgColor)
|
||||
|
||||
let circleRect = CGRect(x: start.x - radius,
|
||||
y: start.y - radius,
|
||||
width: radius * 2,
|
||||
height: radius * 2)
|
||||
|
||||
context.fillEllipse(in: circleRect)
|
||||
context.strokeEllipse(in: circleRect)
|
||||
|
||||
context.setStrokeColor(UIColor.green.cgColor)
|
||||
|
||||
let circleRect2 = CGRect(x: end.x - radius,
|
||||
y: end.y - radius,
|
||||
width: radius * 2,
|
||||
height: radius * 2)
|
||||
|
||||
context.fillEllipse(in: circleRect2)
|
||||
context.strokeEllipse(in: circleRect2)
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum DesignFigureType: Int {
|
||||
case rectange = 0
|
||||
case ellipse = 1
|
||||
case polygon = 2
|
||||
case star = 3
|
||||
}
|
||||
|
||||
@IBDesignable
|
||||
class DesignFigure_: UIView {
|
||||
|
||||
@IBInspectable var figureType: Int = 0 /// Rectange Ellipse Polygon Star
|
||||
|
||||
@IBInspectable var starRadius: CGFloat = 0
|
||||
@IBInspectable var starCount: Int = 5
|
||||
//MARK: Radius
|
||||
|
||||
@IBInspectable var cornerRadius: CGFloat = 0.0
|
||||
|
||||
//MARK: Blur
|
||||
|
||||
@IBInspectable var blur: CGFloat = 0.0
|
||||
|
||||
//MARK: Image
|
||||
|
||||
@IBInspectable var image: UIImage?
|
||||
@IBInspectable var imageMode: Int = 1 /// Scale to fill / Aspect fit / fill
|
||||
|
||||
//MARK: Fill
|
||||
|
||||
@IBInspectable var fillColor: UIColor?
|
||||
|
||||
//MARK: Gradient
|
||||
|
||||
@IBInspectable var grColor1: UIColor?
|
||||
@IBInspectable var grColor2: UIColor?
|
||||
@IBInspectable var grColor3: UIColor?
|
||||
@IBInspectable var grColor4: UIColor?
|
||||
@IBInspectable var grColor5: UIColor?
|
||||
@IBInspectable var grColor6: UIColor?
|
||||
|
||||
@IBInspectable var grStartPoint: CGPoint = .zero
|
||||
@IBInspectable var grEndPoint: CGPoint = .zero
|
||||
|
||||
@IBInspectable var grRadial: Bool = false /// default: linear
|
||||
@IBInspectable var grDrawsOptions: Bool = true
|
||||
@IBInspectable var grDebug: Bool = false
|
||||
@IBInspectable var grPointPercent: Bool = true
|
||||
@IBInspectable var grBlendMode: Int = 0
|
||||
|
||||
//MARK: Border
|
||||
|
||||
@IBInspectable var brColor: UIColor = .clear
|
||||
@IBInspectable var brWidth: CGFloat = 0.0
|
||||
@IBInspectable var brDash: Int = 0
|
||||
|
||||
//MARK: Inner Shadow
|
||||
|
||||
@IBInspectable var inShColor: UIColor = .clear
|
||||
@IBInspectable var inShRadius: CGFloat = 0.0
|
||||
@IBInspectable var inShOffset: CGSize = .zero
|
||||
|
||||
//MARK: Shadow
|
||||
|
||||
@IBInspectable var shColor: UIColor = .clear
|
||||
@IBInspectable var shRadius: CGFloat = 0.0
|
||||
@IBInspectable var shOffset: CGSize = .zero
|
||||
|
||||
|
||||
|
||||
//MARK: - Draw
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
super.draw(rect)
|
||||
|
||||
guard let bezier = figurePath(bounds) else { return }
|
||||
|
||||
addFill(bezier: bezier)
|
||||
|
||||
addImage(bezier: bezier)
|
||||
|
||||
addGradient(bezier: bezier)
|
||||
|
||||
addInnerShadow(bezier: bezier)
|
||||
addBorder()
|
||||
addShadow()
|
||||
|
||||
addBlur()
|
||||
}
|
||||
|
||||
//MARK: - Figure Type
|
||||
|
||||
private func figurePath(_ rect: CGRect) -> UIBezierPath? {
|
||||
|
||||
let starR = starRadius / 50
|
||||
if starCount < 1 { starCount = 1 }
|
||||
|
||||
switch figureType {
|
||||
case 1: return UIBezierPath(ovalIn: rect)
|
||||
case 2: return star(polygon: true, rect: rect, radius: starR, pointsOnStar: starCount)
|
||||
case 3: return star(rect: rect, radius: starR, pointsOnStar: starCount)
|
||||
default: return rectangle(rect: rect, radius: cornerRadius)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Border / Stroke
|
||||
|
||||
private func addBorder() {
|
||||
|
||||
if brWidth < 0 { brWidth = 0 }
|
||||
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
// brColor.setStroke()
|
||||
|
||||
guard let bezier = figurePath(bounds) else { return }
|
||||
|
||||
context.saveGState()
|
||||
|
||||
if brDash > 0 {
|
||||
|
||||
UIColor.clear.setFill()
|
||||
bezier.fill()
|
||||
|
||||
brColor.setStroke()
|
||||
bezier.lineWidth = brWidth * 2
|
||||
|
||||
let dashPattern : [CGFloat] = [ CGFloat(brDash), CGFloat(brDash)]
|
||||
bezier.setLineDash(dashPattern, count: 2, phase: 0)
|
||||
bezier.stroke()
|
||||
|
||||
} else {
|
||||
|
||||
brColor.setStroke()
|
||||
|
||||
bezier.lineWidth = brWidth * 2
|
||||
bezier.stroke()
|
||||
}
|
||||
|
||||
|
||||
|
||||
bezier.stroke()
|
||||
bezier.stroke()
|
||||
|
||||
context.restoreGState()
|
||||
context.restoreGState()
|
||||
}
|
||||
|
||||
|
||||
private func addImage(bezier: UIBezierPath) {
|
||||
|
||||
guard let image = image else { return }
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
var f: CGRect = CGRect(x: 0, y: -bounds.height, width: bounds.width, height: bounds.height)
|
||||
|
||||
if imageMode == 1 || imageMode == 2 {
|
||||
|
||||
var w: CGFloat = 0
|
||||
var h: CGFloat = 0
|
||||
|
||||
let percent = bounds.height / image.size.height
|
||||
w = image.size.width * percent
|
||||
h = bounds.height
|
||||
|
||||
if (imageMode == 1) && (w > bounds.width) ||
|
||||
(imageMode == 2) && (bounds.width > w) {
|
||||
|
||||
let percent = bounds.width / image.size.width
|
||||
h = image.size.height * percent
|
||||
w = bounds.width
|
||||
}
|
||||
|
||||
let x = (bounds.width / 2) - (w / 2)
|
||||
let y = (-h + (((bounds.height / 2) - (h / 2)) * (-1)))
|
||||
|
||||
f = CGRect(x: x, y: y, width: w, height: h)
|
||||
}
|
||||
|
||||
context.saveGState()
|
||||
bezier.addClip()
|
||||
context.scaleBy(x: 1, y: -1)
|
||||
context.draw(image.cgImage!, in: f, byTiling: false)
|
||||
context.restoreGState()
|
||||
|
||||
}
|
||||
|
||||
//MARK: - Fill
|
||||
|
||||
private func addFill(bezier: UIBezierPath) {
|
||||
|
||||
guard let fillColor = fillColor else { return }
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
bezier.close()
|
||||
context.saveGState()
|
||||
fillColor.setFill()
|
||||
bezier.fill()
|
||||
context.restoreGState()
|
||||
}
|
||||
|
||||
//MARK: - Gradient
|
||||
|
||||
private func addGradient(bezier: UIBezierPath) {
|
||||
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
var colors: [CGColor] = []
|
||||
|
||||
if let c = grColor1 { colors.append(c.cgColor) }
|
||||
if let c = grColor2 { colors.append(c.cgColor) }
|
||||
if let c = grColor3 { colors.append(c.cgColor) }
|
||||
if let c = grColor4 { colors.append(c.cgColor) }
|
||||
if let c = grColor5 { colors.append(c.cgColor) }
|
||||
if let c = grColor6 { colors.append(c.cgColor) }
|
||||
|
||||
if colors.count < 2 {
|
||||
colors.append(UIColor.clear.cgColor)
|
||||
colors.append(UIColor.clear.cgColor)
|
||||
} else if colors.count < 1 {
|
||||
if grColor1 != nil {
|
||||
colors.append(UIColor.clear.cgColor)
|
||||
} else {
|
||||
colors.insert(UIColor.clear.cgColor, at: 0)
|
||||
}
|
||||
}
|
||||
|
||||
guard let gradient = CGGradient(colorsSpace: nil,
|
||||
colors: colors as CFArray,
|
||||
locations: nil) else { return }
|
||||
|
||||
let bMode = CGBlendMode(rawValue: CGBlendMode.RawValue(grBlendMode)) ?? CGBlendMode.sourceAtop
|
||||
context.setBlendMode(bMode)
|
||||
|
||||
let options: CGGradientDrawingOptions =
|
||||
grDrawsOptions ? [ .drawsBeforeStartLocation, .drawsAfterEndLocation ] : [ ]
|
||||
|
||||
var grEndPointR: CGPoint = grEndPoint
|
||||
var grStartPointR: CGPoint = grStartPoint
|
||||
if grPointPercent {
|
||||
grEndPointR = CGPoint(x: (grEndPoint.x * frame.width), y: (grEndPoint.y * frame.height))
|
||||
grStartPointR = CGPoint(x: (grStartPoint.x * frame.width), y: (grStartPoint.y * frame.height))
|
||||
}
|
||||
|
||||
bezier.close()
|
||||
context.saveGState()
|
||||
bezier.addClip()
|
||||
|
||||
if grRadial {
|
||||
|
||||
let x: CGFloat = (grEndPointR.x - grStartPointR.x)
|
||||
let y: CGFloat = (grEndPointR.y - grStartPointR.y)
|
||||
let distance: CGFloat = sqrt((x * x) + (y * y))
|
||||
|
||||
context.drawRadialGradient(gradient,
|
||||
startCenter: grStartPointR,
|
||||
startRadius: 0,
|
||||
endCenter: grStartPointR,
|
||||
endRadius: distance,
|
||||
options: options)
|
||||
} else {
|
||||
|
||||
context.drawLinearGradient(gradient,
|
||||
start: grStartPointR,
|
||||
end: grEndPointR,
|
||||
options: options)
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - Shadow
|
||||
|
||||
private func addShadow() {
|
||||
|
||||
if shRadius < 0 { shRadius = 0 }
|
||||
|
||||
layer.shadowOffset = shOffset
|
||||
layer.shadowOpacity = 1.0
|
||||
layer.shadowRadius = shRadius
|
||||
layer.shadowColor = shColor.cgColor
|
||||
}
|
||||
|
||||
private func addShadowContext(bezier: UIBezierPath) {
|
||||
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
bezier.close()
|
||||
|
||||
//// Shadow Declarations
|
||||
let shadow = NSShadow()
|
||||
shadow.shadowColor = shColor
|
||||
shadow.shadowOffset = shOffset
|
||||
shadow.shadowBlurRadius = shRadius * 2
|
||||
|
||||
context.saveGState()
|
||||
|
||||
context.setShadow(offset: shadow.shadowOffset,
|
||||
blur: shadow.shadowBlurRadius,
|
||||
color: (shadow.shadowColor as! UIColor).cgColor)
|
||||
|
||||
context.restoreGState()
|
||||
}
|
||||
|
||||
//MARK: - Inner Shadow
|
||||
|
||||
private func addInnerShadow(bezier: UIBezierPath) {
|
||||
|
||||
if inShRadius < 0 { inShRadius = 0 }
|
||||
|
||||
let innerShadow = NSShadow()
|
||||
innerShadow.shadowColor = inShColor
|
||||
innerShadow.shadowOffset = inShOffset
|
||||
innerShadow.shadowBlurRadius = inShRadius * 2
|
||||
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
////// Star Inner Shadow
|
||||
context.saveGState()
|
||||
context.clip(to: bezier.bounds)
|
||||
context.setShadow(offset: .zero, blur: 0)
|
||||
context.setAlpha((innerShadow.shadowColor as! UIColor).cgColor.alpha)
|
||||
context.beginTransparencyLayer(auxiliaryInfo: nil)
|
||||
|
||||
let starOpaqueShadow = (innerShadow.shadowColor as! UIColor).withAlphaComponent(1)
|
||||
context.setShadow(offset: innerShadow.shadowOffset,
|
||||
blur: innerShadow.shadowBlurRadius,
|
||||
color: starOpaqueShadow.cgColor)
|
||||
|
||||
context.setBlendMode(.sourceOut)
|
||||
context.beginTransparencyLayer(auxiliaryInfo: nil)
|
||||
|
||||
starOpaqueShadow.setFill()
|
||||
|
||||
bezier.fill()
|
||||
|
||||
context.endTransparencyLayer()
|
||||
context.endTransparencyLayer()
|
||||
context.restoreGState()
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Blur
|
||||
|
||||
private func addBlur() {
|
||||
|
||||
guard blur > 0 else { return }
|
||||
|
||||
guard let image = screenShotContext() else { return }
|
||||
|
||||
self.addblur(screen: image, blur: blur)
|
||||
}
|
||||
|
||||
// MARK: Screen Shot Context
|
||||
|
||||
private func screenShotContext() -> UIImage? {
|
||||
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return nil }
|
||||
guard let cgimage: CGImage = context.makeImage() else { return nil }
|
||||
let image = UIImage(cgImage: cgimage)
|
||||
|
||||
return image
|
||||
}
|
||||
|
||||
// MARK: Clear Context
|
||||
|
||||
private func clearContext() {
|
||||
|
||||
let f = CGRect(x: 0, y: 0,
|
||||
width: frame.width * 2,
|
||||
height: frame.height * 2)
|
||||
|
||||
let context = UIGraphicsGetCurrentContext()
|
||||
context?.clear(f)
|
||||
}
|
||||
|
||||
|
||||
private func addblur(screen: UIImage, blur: CGFloat) {
|
||||
|
||||
clearContext()
|
||||
|
||||
func blurImage(image: UIImage) -> UIImage? {
|
||||
|
||||
guard let ciscreen: CIImage = CIImage(image: screen) else { return nil }
|
||||
|
||||
guard let filter: CIFilter = CIFilter(name: "CIGaussianBlur") else { return nil }
|
||||
filter.setDefaults()
|
||||
filter.setValue(ciscreen, forKey: kCIInputImageKey)
|
||||
filter.setValue(blur, forKey: kCIInputRadiusKey)
|
||||
|
||||
|
||||
let bl2 = ((blur * 3) * -1)
|
||||
let bl4 = (blur * 6)
|
||||
|
||||
let contextFrame = CGRect(
|
||||
x: bl2,
|
||||
y: bl2,
|
||||
width: bl4 + image.size.width,
|
||||
height: bl4 + image.size.height
|
||||
)
|
||||
|
||||
// let bl2 = ((blur * 2) * -1)
|
||||
// let bl4 = (blur * 4)
|
||||
// let contextFrame2 = CGRect(x: bl2,
|
||||
// y: bl2,
|
||||
// width: bl4 + (frame.width * 2),
|
||||
// height: bl4 + (frame.height * 2))
|
||||
|
||||
let ciContext = CIContext(options: nil)
|
||||
guard let ci: CIImage = filter.value(forKey: kCIOutputImageKey) as? CIImage else { return nil }
|
||||
guard let cImg = ciContext.createCGImage(ci, from: contextFrame) else { return nil }
|
||||
|
||||
let finalImage = UIImage(cgImage: cImg)
|
||||
|
||||
return finalImage
|
||||
}
|
||||
|
||||
let p2: CGFloat = 1
|
||||
let p4: CGFloat = p2 * 2
|
||||
|
||||
let bl2 = ((blur * p2) * -1)
|
||||
let bl4 = (blur * p4)
|
||||
|
||||
let x: CGFloat = 0
|
||||
let ofW = (x * 1) * -1
|
||||
let ofH = (x * 1) * -1
|
||||
|
||||
let ofW2 = (x * 2)
|
||||
let ofH2 = (x * 2)
|
||||
|
||||
let contextFrame = CGRect(x: bl2 + ofW,
|
||||
y: bl2 + ofH,
|
||||
width: bl4 + ofW2 + frame.width,
|
||||
height: bl4 + ofH2 + frame.height)
|
||||
|
||||
let blurImageView = UIImageView(frame: contextFrame)
|
||||
blurImageView.image = blurImage(image: screen)
|
||||
blurImageView.contentMode = .scaleAspectFill
|
||||
|
||||
|
||||
addSubview(blurImageView)
|
||||
}
|
||||
|
||||
//MARK: - Rectangle Bezier
|
||||
|
||||
func rectangle(rect: CGRect, radius: CGFloat) -> UIBezierPath {
|
||||
|
||||
let r = self.cornerRadius(radius)
|
||||
let w = rect.width
|
||||
let h = rect.height
|
||||
|
||||
let path = UIBezierPath()
|
||||
path.move(to: CGPoint(x: r, y: 0.0))
|
||||
|
||||
path.addLine(to: CGPoint(x: w - r, y: 0.0))
|
||||
path.addArc(withCenter: CGPoint(x: w - r, y: r),
|
||||
radius: r,
|
||||
startAngle: 3.0 * .pi / 2.0,
|
||||
endAngle: 2 * .pi,
|
||||
clockwise: true)
|
||||
|
||||
path.addLine(to: CGPoint(x: w, y: h - r))
|
||||
path.addArc(withCenter: CGPoint(x: w - r, y: h - r),
|
||||
radius: r,
|
||||
startAngle: 0.0,
|
||||
endAngle: .pi / 2.0,
|
||||
clockwise: true)
|
||||
|
||||
path.addLine(to: CGPoint(x: r, y: h))
|
||||
path.addArc(withCenter: CGPoint(x: r, y: h - r),
|
||||
radius: r,
|
||||
startAngle: .pi / 2.0,
|
||||
endAngle: .pi,
|
||||
clockwise: true)
|
||||
|
||||
path.addLine(to: CGPoint(x: 0.0, y: r))
|
||||
path.addArc(withCenter: CGPoint(x: r, y: r),
|
||||
radius: r,
|
||||
startAngle: .pi,
|
||||
endAngle: 3.0 * .pi / 2.0,
|
||||
clockwise: true)
|
||||
|
||||
path.close()
|
||||
return path
|
||||
}
|
||||
|
||||
//MARK: - Star Bezier
|
||||
|
||||
func star(polygon: Bool = false, rect: CGRect, radius: CGFloat, pointsOnStar: Int) -> UIBezierPath {
|
||||
|
||||
let path = UIBezierPath()
|
||||
|
||||
let minSize = max(rect.width, rect.height)
|
||||
var starExtrusion: CGFloat = minSize * 0.18695652173
|
||||
if radius != 0 {
|
||||
starExtrusion = minSize * radius
|
||||
}
|
||||
|
||||
let center: CGPoint = .zero
|
||||
|
||||
var angle: CGFloat = -CGFloat(.pi / 2.0)
|
||||
let angleIncrement = CGFloat(.pi * 2.0 / Double(pointsOnStar))
|
||||
let radius = minSize / 2.0
|
||||
|
||||
var firstPoint = true
|
||||
|
||||
func pointFrom(angle: CGFloat, radius: CGFloat, offset: CGPoint) -> CGPoint {
|
||||
return CGPoint(x: radius * cos(angle) + offset.x,
|
||||
y: radius * sin(angle) + offset.y)
|
||||
}
|
||||
|
||||
for _ in 1...pointsOnStar {
|
||||
|
||||
let point: CGPoint = pointFrom(angle: angle, radius: radius, offset: center)
|
||||
let nextPoint: CGPoint = pointFrom(angle: angle + angleIncrement, radius: radius, offset: center)
|
||||
let midPoint: CGPoint = pointFrom(angle: angle + angleIncrement / 2.0, radius: starExtrusion, offset: center)
|
||||
|
||||
var perY: CGFloat = 1.0
|
||||
var perX: CGFloat = 1.0
|
||||
|
||||
if rect.height < rect.width {
|
||||
perY = (rect.height / minSize)
|
||||
} else {
|
||||
perX = (rect.width / minSize)
|
||||
}
|
||||
|
||||
let p = CGPoint(x: (point.x * perX) + (rect.width / 2.0),
|
||||
y: (point.y * perY) + (rect.height / 2.0))
|
||||
|
||||
let n = CGPoint(x: (nextPoint.x * perX) + (rect.width / 2.0),
|
||||
y: (nextPoint.y * perY) + (rect.height / 2.0))
|
||||
|
||||
let m = CGPoint(x: (midPoint.x * perX) + (rect.width / 2.0),
|
||||
y: (midPoint.y * perY) + (rect.height / 2.0))
|
||||
|
||||
if firstPoint {
|
||||
firstPoint = false
|
||||
path.move(to: p)
|
||||
}
|
||||
|
||||
if !polygon {
|
||||
path.addLine(to: m)
|
||||
}
|
||||
path.addLine(to: n)
|
||||
|
||||
angle += angleIncrement
|
||||
}
|
||||
|
||||
path.close()
|
||||
|
||||
return path
|
||||
}
|
||||
}
|
||||
@@ -1,716 +0,0 @@
|
||||
//
|
||||
// DesignTest.swift
|
||||
// FigmaConvertXib
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 28.07.2020.
|
||||
// Copyright © 2020 mrusta. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
@IBDesignable
|
||||
class DesignFigure: UIView {
|
||||
/// Rectange | Ellipse | Polygon | Star
|
||||
@IBInspectable var figureType: Int = 0
|
||||
@IBInspectable var starRadius: CGFloat = 0
|
||||
@IBInspectable var starCount: Int = 5
|
||||
@IBInspectable var cornerRadius: CGFloat = 0.0
|
||||
@IBInspectable var blur: CGFloat = 0.0
|
||||
@IBInspectable var image: UIImage?
|
||||
/// ScaleToFill | Fit | Fill
|
||||
@IBInspectable var imageMode: Int = 1
|
||||
@IBInspectable var fillColor: UIColor?
|
||||
@IBInspectable var grColor1: UIColor?
|
||||
@IBInspectable var grColor2: UIColor?
|
||||
@IBInspectable var grColor3: UIColor?
|
||||
@IBInspectable var grColor4: UIColor?
|
||||
@IBInspectable var grColor5: UIColor?
|
||||
@IBInspectable var grColor6: UIColor?
|
||||
@IBInspectable var grStartPoint: CGPoint = .zero
|
||||
@IBInspectable var grEndPoint: CGPoint = .zero
|
||||
/// Default: Linear
|
||||
@IBInspectable var grRadial: Bool = false
|
||||
@IBInspectable var grDrawsOptions: Bool = true
|
||||
@IBInspectable var grDebug: Bool = false
|
||||
@IBInspectable var grPointPercent: Bool = true
|
||||
@IBInspectable var grBlendMode: Int = 0
|
||||
@IBInspectable var brColor: UIColor = .clear
|
||||
@IBInspectable var brWidth: CGFloat = 0.0
|
||||
@IBInspectable var brDash: Int = 0
|
||||
@IBInspectable var inShColor: UIColor = .clear
|
||||
@IBInspectable var inShRadius: CGFloat = 0.0
|
||||
@IBInspectable var inShOffset: CGSize = .zero
|
||||
@IBInspectable var shColor: UIColor = .clear
|
||||
@IBInspectable var shRadius: CGFloat = 0.0
|
||||
@IBInspectable var shOffset: CGSize = .zero
|
||||
|
||||
func setup() {
|
||||
|
||||
if let foundView = viewWithTag(55) {
|
||||
foundView.removeFromSuperview()
|
||||
}
|
||||
|
||||
let d = DesignFigure_(frame: bounds)
|
||||
d.backgroundColor = .clear
|
||||
d.tag = 55
|
||||
d.figureType = figureType
|
||||
d.starRadius = starRadius
|
||||
d.starCount = starCount
|
||||
d.cornerRadius = cornerRadius
|
||||
d.blur = blur
|
||||
d.image = image
|
||||
d.imageMode = imageMode
|
||||
d.fillColor = fillColor
|
||||
d.grColor1 = grColor1
|
||||
d.grColor2 = grColor2
|
||||
d.grColor3 = grColor3
|
||||
d.grColor4 = grColor4
|
||||
d.grColor5 = grColor5
|
||||
d.grColor6 = grColor6
|
||||
d.grStartPoint = grStartPoint
|
||||
d.grEndPoint = grEndPoint
|
||||
d.grRadial = grRadial
|
||||
d.grDrawsOptions = grDrawsOptions
|
||||
d.grDebug = grDebug
|
||||
d.grPointPercent = grPointPercent
|
||||
d.grBlendMode = grBlendMode
|
||||
d.brWidth = brWidth
|
||||
d.brColor = brColor
|
||||
d.brDash = brDash
|
||||
d.inShColor = inShColor
|
||||
d.inShRadius = inShRadius
|
||||
d.inShOffset = inShOffset
|
||||
d.shColor = shColor
|
||||
d.shRadius = shRadius
|
||||
d.shOffset = shOffset
|
||||
insertSubview(d, at: 0)
|
||||
|
||||
if grDebug {
|
||||
if let foundView = viewWithTag(44) {
|
||||
foundView.removeFromSuperview()
|
||||
}
|
||||
|
||||
let d = DesignFigureDebug(frame: bounds)
|
||||
d.backgroundColor = .clear
|
||||
d.tag = 44
|
||||
d.grStartPoint = grStartPoint
|
||||
d.grEndPoint = grEndPoint
|
||||
d.grPointPercent = grPointPercent
|
||||
|
||||
insertSubview(d, at: 1)
|
||||
}
|
||||
}
|
||||
|
||||
override func layoutSubviews() { setup() }
|
||||
|
||||
}
|
||||
|
||||
@IBDesignable
|
||||
class DesignFigureDebug: UIView {
|
||||
|
||||
@IBInspectable var grStartPoint: CGPoint = .zero
|
||||
@IBInspectable var grEndPoint: CGPoint = .zero
|
||||
@IBInspectable var grPointPercent: Bool = true
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
super.draw(rect)
|
||||
|
||||
addGradientDebugPoints()
|
||||
}
|
||||
|
||||
func addGradientDebugPoints() {
|
||||
|
||||
var start = grStartPoint
|
||||
var end = grStartPoint
|
||||
|
||||
if grPointPercent {
|
||||
end = CGPoint(x: grEndPoint.x * frame.width, y: grEndPoint.y * frame.height)
|
||||
start = CGPoint(x: grStartPoint.x * frame.width, y: grStartPoint.y * frame.height)
|
||||
}
|
||||
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
let radius: CGFloat = 5
|
||||
|
||||
context.setBlendMode(CGBlendMode.normal)
|
||||
context.setLineWidth(3.0)
|
||||
|
||||
|
||||
context.setFillColor(UIColor.black.cgColor)
|
||||
|
||||
context.setStrokeColor(UIColor.systemRed.cgColor)
|
||||
|
||||
let circleRect = CGRect(x: start.x - radius,
|
||||
y: start.y - radius,
|
||||
width: radius * 2,
|
||||
height: radius * 2)
|
||||
|
||||
context.fillEllipse(in: circleRect)
|
||||
context.strokeEllipse(in: circleRect)
|
||||
|
||||
context.setStrokeColor(UIColor.green.cgColor)
|
||||
|
||||
let circleRect2 = CGRect(x: end.x - radius,
|
||||
y: end.y - radius,
|
||||
width: radius * 2,
|
||||
height: radius * 2)
|
||||
|
||||
context.fillEllipse(in: circleRect2)
|
||||
context.strokeEllipse(in: circleRect2)
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum DesignFigureType: Int {
|
||||
case rectange = 0
|
||||
case ellipse = 1
|
||||
case polygon = 2
|
||||
case star = 3
|
||||
}
|
||||
|
||||
@IBDesignable
|
||||
class DesignFigure_: UIView {
|
||||
|
||||
@IBInspectable var figureType: Int = 0 /// Rectange Ellipse Polygon Star
|
||||
|
||||
@IBInspectable var starRadius: CGFloat = 0
|
||||
@IBInspectable var starCount: Int = 5
|
||||
//MARK: Radius
|
||||
|
||||
@IBInspectable var cornerRadius: CGFloat = 0.0
|
||||
|
||||
//MARK: Blur
|
||||
|
||||
@IBInspectable var blur: CGFloat = 0.0
|
||||
|
||||
//MARK: Image
|
||||
|
||||
@IBInspectable var image: UIImage?
|
||||
@IBInspectable var imageMode: Int = 1 /// Scale to fill / Aspect fit / fill
|
||||
|
||||
//MARK: Fill
|
||||
|
||||
@IBInspectable var fillColor: UIColor?
|
||||
|
||||
//MARK: Gradient
|
||||
|
||||
@IBInspectable var grColor1: UIColor?
|
||||
@IBInspectable var grColor2: UIColor?
|
||||
@IBInspectable var grColor3: UIColor?
|
||||
@IBInspectable var grColor4: UIColor?
|
||||
@IBInspectable var grColor5: UIColor?
|
||||
@IBInspectable var grColor6: UIColor?
|
||||
|
||||
@IBInspectable var grStartPoint: CGPoint = .zero
|
||||
@IBInspectable var grEndPoint: CGPoint = .zero
|
||||
|
||||
@IBInspectable var grRadial: Bool = false /// default: linear
|
||||
@IBInspectable var grDrawsOptions: Bool = true
|
||||
@IBInspectable var grDebug: Bool = false
|
||||
@IBInspectable var grPointPercent: Bool = true
|
||||
@IBInspectable var grBlendMode: Int = 0
|
||||
|
||||
//MARK: Border
|
||||
|
||||
@IBInspectable var brColor: UIColor = .clear
|
||||
@IBInspectable var brWidth: CGFloat = 0.0
|
||||
@IBInspectable var brDash: Int = 0
|
||||
|
||||
//MARK: Inner Shadow
|
||||
|
||||
@IBInspectable var inShColor: UIColor = .clear
|
||||
@IBInspectable var inShRadius: CGFloat = 0.0
|
||||
@IBInspectable var inShOffset: CGSize = .zero
|
||||
|
||||
//MARK: Shadow
|
||||
|
||||
@IBInspectable var shColor: UIColor = .clear
|
||||
@IBInspectable var shRadius: CGFloat = 0.0
|
||||
@IBInspectable var shOffset: CGSize = .zero
|
||||
|
||||
|
||||
|
||||
//MARK: - Draw
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
super.draw(rect)
|
||||
|
||||
guard let bezier = figurePath(bounds) else { return }
|
||||
|
||||
addFill(bezier: bezier)
|
||||
|
||||
addImage(bezier: bezier)
|
||||
|
||||
addGradient(bezier: bezier)
|
||||
|
||||
addInnerShadow(bezier: bezier)
|
||||
addBorder()
|
||||
addShadow()
|
||||
|
||||
addBlur()
|
||||
}
|
||||
|
||||
//MARK: - Figure Type
|
||||
|
||||
private func figurePath(_ rect: CGRect) -> UIBezierPath? {
|
||||
|
||||
let starR = starRadius / 50
|
||||
if starCount < 1 { starCount = 1 }
|
||||
|
||||
switch figureType {
|
||||
case 1: return UIBezierPath(ovalIn: rect)
|
||||
case 2: return star(polygon: true, rect: rect, radius: starR, pointsOnStar: starCount)
|
||||
case 3: return star(rect: rect, radius: starR, pointsOnStar: starCount)
|
||||
default: return rectangle(rect: rect, radius: cornerRadius)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Border / Stroke
|
||||
|
||||
private func addBorder() {
|
||||
|
||||
if brWidth < 0 { brWidth = 0 }
|
||||
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
// brColor.setStroke()
|
||||
|
||||
guard let bezier = figurePath(bounds) else { return }
|
||||
|
||||
context.saveGState()
|
||||
|
||||
if brDash > 0 {
|
||||
|
||||
UIColor.clear.setFill()
|
||||
bezier.fill()
|
||||
|
||||
brColor.setStroke()
|
||||
bezier.lineWidth = brWidth * 2
|
||||
|
||||
let dashPattern : [CGFloat] = [ CGFloat(brDash), CGFloat(brDash)]
|
||||
bezier.setLineDash(dashPattern, count: 2, phase: 0)
|
||||
bezier.stroke()
|
||||
|
||||
} else {
|
||||
|
||||
brColor.setStroke()
|
||||
|
||||
bezier.lineWidth = brWidth * 2
|
||||
bezier.stroke()
|
||||
}
|
||||
|
||||
|
||||
|
||||
bezier.stroke()
|
||||
bezier.stroke()
|
||||
|
||||
context.restoreGState()
|
||||
context.restoreGState()
|
||||
}
|
||||
|
||||
|
||||
private func addImage(bezier: UIBezierPath) {
|
||||
|
||||
guard let image = image else { return }
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
var f: CGRect = CGRect(x: 0, y: -bounds.height, width: bounds.width, height: bounds.height)
|
||||
|
||||
if imageMode == 1 || imageMode == 2 {
|
||||
|
||||
var w: CGFloat = 0
|
||||
var h: CGFloat = 0
|
||||
|
||||
let percent = bounds.height / image.size.height
|
||||
w = image.size.width * percent
|
||||
h = bounds.height
|
||||
|
||||
if (imageMode == 1) && (w > bounds.width) ||
|
||||
(imageMode == 2) && (bounds.width > w) {
|
||||
|
||||
let percent = bounds.width / image.size.width
|
||||
h = image.size.height * percent
|
||||
w = bounds.width
|
||||
}
|
||||
|
||||
let x = (bounds.width / 2) - (w / 2)
|
||||
let y = (-h + (((bounds.height / 2) - (h / 2)) * (-1)))
|
||||
|
||||
f = CGRect(x: x, y: y, width: w, height: h)
|
||||
}
|
||||
|
||||
context.saveGState()
|
||||
bezier.addClip()
|
||||
context.scaleBy(x: 1, y: -1)
|
||||
context.draw(image.cgImage!, in: f, byTiling: false)
|
||||
context.restoreGState()
|
||||
|
||||
}
|
||||
|
||||
//MARK: - Fill
|
||||
|
||||
private func addFill(bezier: UIBezierPath) {
|
||||
|
||||
guard let fillColor = fillColor else { return }
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
bezier.close()
|
||||
context.saveGState()
|
||||
fillColor.setFill()
|
||||
bezier.fill()
|
||||
context.restoreGState()
|
||||
}
|
||||
|
||||
//MARK: - Gradient
|
||||
|
||||
private func addGradient(bezier: UIBezierPath) {
|
||||
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
var colors: [CGColor] = []
|
||||
|
||||
if let c = grColor1 { colors.append(c.cgColor) }
|
||||
if let c = grColor2 { colors.append(c.cgColor) }
|
||||
if let c = grColor3 { colors.append(c.cgColor) }
|
||||
if let c = grColor4 { colors.append(c.cgColor) }
|
||||
if let c = grColor5 { colors.append(c.cgColor) }
|
||||
if let c = grColor6 { colors.append(c.cgColor) }
|
||||
|
||||
if colors.count < 2 {
|
||||
colors.append(UIColor.clear.cgColor)
|
||||
colors.append(UIColor.clear.cgColor)
|
||||
} else if colors.count < 1 {
|
||||
if grColor1 != nil {
|
||||
colors.append(UIColor.clear.cgColor)
|
||||
} else {
|
||||
colors.insert(UIColor.clear.cgColor, at: 0)
|
||||
}
|
||||
}
|
||||
|
||||
guard let gradient = CGGradient(colorsSpace: nil,
|
||||
colors: colors as CFArray,
|
||||
locations: nil) else { return }
|
||||
|
||||
let bMode = CGBlendMode(rawValue: CGBlendMode.RawValue(grBlendMode)) ?? CGBlendMode.sourceAtop
|
||||
context.setBlendMode(bMode)
|
||||
|
||||
let options: CGGradientDrawingOptions =
|
||||
grDrawsOptions ? [ .drawsBeforeStartLocation, .drawsAfterEndLocation ] : [ ]
|
||||
|
||||
var grEndPointR: CGPoint = grEndPoint
|
||||
var grStartPointR: CGPoint = grStartPoint
|
||||
if grPointPercent {
|
||||
grEndPointR = CGPoint(x: (grEndPoint.x * frame.width), y: (grEndPoint.y * frame.height))
|
||||
grStartPointR = CGPoint(x: (grStartPoint.x * frame.width), y: (grStartPoint.y * frame.height))
|
||||
}
|
||||
|
||||
bezier.close()
|
||||
context.saveGState()
|
||||
bezier.addClip()
|
||||
|
||||
if grRadial {
|
||||
|
||||
let x: CGFloat = (grEndPointR.x - grStartPointR.x)
|
||||
let y: CGFloat = (grEndPointR.y - grStartPointR.y)
|
||||
let distance: CGFloat = sqrt((x * x) + (y * y))
|
||||
|
||||
context.drawRadialGradient(gradient,
|
||||
startCenter: grStartPointR,
|
||||
startRadius: 0,
|
||||
endCenter: grStartPointR,
|
||||
endRadius: distance,
|
||||
options: options)
|
||||
} else {
|
||||
|
||||
context.drawLinearGradient(gradient,
|
||||
start: grStartPointR,
|
||||
end: grEndPointR,
|
||||
options: options)
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - Shadow
|
||||
|
||||
private func addShadow() {
|
||||
|
||||
if shRadius < 0 { shRadius = 0 }
|
||||
|
||||
layer.shadowOffset = shOffset
|
||||
layer.shadowOpacity = 1.0
|
||||
layer.shadowRadius = shRadius
|
||||
layer.shadowColor = shColor.cgColor
|
||||
}
|
||||
|
||||
private func addShadowContext(bezier: UIBezierPath) {
|
||||
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
bezier.close()
|
||||
|
||||
//// Shadow Declarations
|
||||
let shadow = NSShadow()
|
||||
shadow.shadowColor = shColor
|
||||
shadow.shadowOffset = shOffset
|
||||
shadow.shadowBlurRadius = shRadius * 2
|
||||
|
||||
context.saveGState()
|
||||
|
||||
context.setShadow(offset: shadow.shadowOffset,
|
||||
blur: shadow.shadowBlurRadius,
|
||||
color: (shadow.shadowColor as! UIColor).cgColor)
|
||||
|
||||
context.restoreGState()
|
||||
}
|
||||
|
||||
//MARK: - Inner Shadow
|
||||
|
||||
private func addInnerShadow(bezier: UIBezierPath) {
|
||||
|
||||
if inShRadius < 0 { inShRadius = 0 }
|
||||
|
||||
let innerShadow = NSShadow()
|
||||
innerShadow.shadowColor = inShColor
|
||||
innerShadow.shadowOffset = inShOffset
|
||||
innerShadow.shadowBlurRadius = inShRadius * 2
|
||||
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
////// Star Inner Shadow
|
||||
context.saveGState()
|
||||
context.clip(to: bezier.bounds)
|
||||
context.setShadow(offset: .zero, blur: 0)
|
||||
context.setAlpha((innerShadow.shadowColor as! UIColor).cgColor.alpha)
|
||||
context.beginTransparencyLayer(auxiliaryInfo: nil)
|
||||
|
||||
let starOpaqueShadow = (innerShadow.shadowColor as! UIColor).withAlphaComponent(1)
|
||||
context.setShadow(offset: innerShadow.shadowOffset,
|
||||
blur: innerShadow.shadowBlurRadius,
|
||||
color: starOpaqueShadow.cgColor)
|
||||
|
||||
context.setBlendMode(.sourceOut)
|
||||
context.beginTransparencyLayer(auxiliaryInfo: nil)
|
||||
|
||||
starOpaqueShadow.setFill()
|
||||
|
||||
bezier.fill()
|
||||
|
||||
context.endTransparencyLayer()
|
||||
context.endTransparencyLayer()
|
||||
context.restoreGState()
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Blur
|
||||
|
||||
private func addBlur() {
|
||||
|
||||
guard blur > 0 else { return }
|
||||
|
||||
guard let image = screenShotContext() else { return }
|
||||
|
||||
self.addblur(screen: image, blur: blur)
|
||||
}
|
||||
|
||||
// MARK: Screen Shot Context
|
||||
|
||||
private func screenShotContext() -> UIImage? {
|
||||
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return nil }
|
||||
guard let cgimage: CGImage = context.makeImage() else { return nil }
|
||||
let image = UIImage(cgImage: cgimage)
|
||||
|
||||
return image
|
||||
}
|
||||
|
||||
// MARK: Clear Context
|
||||
|
||||
private func clearContext() {
|
||||
|
||||
let f = CGRect(x: 0, y: 0,
|
||||
width: frame.width * 2,
|
||||
height: frame.height * 2)
|
||||
|
||||
let context = UIGraphicsGetCurrentContext()
|
||||
context?.clear(f)
|
||||
}
|
||||
|
||||
|
||||
private func addblur(screen: UIImage, blur: CGFloat) {
|
||||
|
||||
clearContext()
|
||||
|
||||
func blurImage(image: UIImage) -> UIImage? {
|
||||
|
||||
guard let ciscreen: CIImage = CIImage(image: screen) else { return nil }
|
||||
|
||||
guard let filter: CIFilter = CIFilter(name: "CIGaussianBlur") else { return nil }
|
||||
filter.setDefaults()
|
||||
filter.setValue(ciscreen, forKey: kCIInputImageKey)
|
||||
filter.setValue(blur, forKey: kCIInputRadiusKey)
|
||||
|
||||
|
||||
let bl2 = ((blur * 3) * -1)
|
||||
let bl4 = (blur * 6)
|
||||
|
||||
let contextFrame = CGRect(
|
||||
x: bl2,
|
||||
y: bl2,
|
||||
width: bl4 + image.size.width,
|
||||
height: bl4 + image.size.height
|
||||
)
|
||||
|
||||
// let bl2 = ((blur * 2) * -1)
|
||||
// let bl4 = (blur * 4)
|
||||
// let contextFrame2 = CGRect(x: bl2,
|
||||
// y: bl2,
|
||||
// width: bl4 + (frame.width * 2),
|
||||
// height: bl4 + (frame.height * 2))
|
||||
|
||||
let ciContext = CIContext(options: nil)
|
||||
guard let ci: CIImage = filter.value(forKey: kCIOutputImageKey) as? CIImage else { return nil }
|
||||
guard let cImg = ciContext.createCGImage(ci, from: contextFrame) else { return nil }
|
||||
|
||||
let finalImage = UIImage(cgImage: cImg)
|
||||
|
||||
return finalImage
|
||||
}
|
||||
|
||||
let p2: CGFloat = 1
|
||||
let p4: CGFloat = p2 * 2
|
||||
|
||||
let bl2 = ((blur * p2) * -1)
|
||||
let bl4 = (blur * p4)
|
||||
|
||||
let x: CGFloat = 0
|
||||
let ofW = (x * 1) * -1
|
||||
let ofH = (x * 1) * -1
|
||||
|
||||
let ofW2 = (x * 2)
|
||||
let ofH2 = (x * 2)
|
||||
|
||||
let contextFrame = CGRect(x: bl2 + ofW,
|
||||
y: bl2 + ofH,
|
||||
width: bl4 + ofW2 + frame.width,
|
||||
height: bl4 + ofH2 + frame.height)
|
||||
|
||||
let blurImageView = UIImageView(frame: contextFrame)
|
||||
blurImageView.image = blurImage(image: screen)
|
||||
blurImageView.contentMode = .scaleAspectFill
|
||||
|
||||
|
||||
addSubview(blurImageView)
|
||||
}
|
||||
|
||||
//MARK: - Rectangle Bezier
|
||||
|
||||
func rectangle(rect: CGRect, radius: CGFloat) -> UIBezierPath {
|
||||
|
||||
let r = self.cornerRadius(radius)
|
||||
let w = rect.width
|
||||
let h = rect.height
|
||||
|
||||
let path = UIBezierPath()
|
||||
path.move(to: CGPoint(x: r, y: 0.0))
|
||||
|
||||
path.addLine(to: CGPoint(x: w - r, y: 0.0))
|
||||
path.addArc(withCenter: CGPoint(x: w - r, y: r),
|
||||
radius: r,
|
||||
startAngle: 3.0 * .pi / 2.0,
|
||||
endAngle: 2 * .pi,
|
||||
clockwise: true)
|
||||
|
||||
path.addLine(to: CGPoint(x: w, y: h - r))
|
||||
path.addArc(withCenter: CGPoint(x: w - r, y: h - r),
|
||||
radius: r,
|
||||
startAngle: 0.0,
|
||||
endAngle: .pi / 2.0,
|
||||
clockwise: true)
|
||||
|
||||
path.addLine(to: CGPoint(x: r, y: h))
|
||||
path.addArc(withCenter: CGPoint(x: r, y: h - r),
|
||||
radius: r,
|
||||
startAngle: .pi / 2.0,
|
||||
endAngle: .pi,
|
||||
clockwise: true)
|
||||
|
||||
path.addLine(to: CGPoint(x: 0.0, y: r))
|
||||
path.addArc(withCenter: CGPoint(x: r, y: r),
|
||||
radius: r,
|
||||
startAngle: .pi,
|
||||
endAngle: 3.0 * .pi / 2.0,
|
||||
clockwise: true)
|
||||
|
||||
path.close()
|
||||
return path
|
||||
}
|
||||
|
||||
//MARK: - Star Bezier
|
||||
|
||||
func star(polygon: Bool = false, rect: CGRect, radius: CGFloat, pointsOnStar: Int) -> UIBezierPath {
|
||||
|
||||
let path = UIBezierPath()
|
||||
|
||||
let minSize = max(rect.width, rect.height)
|
||||
var starExtrusion: CGFloat = minSize * 0.18695652173
|
||||
if radius != 0 {
|
||||
starExtrusion = minSize * radius
|
||||
}
|
||||
|
||||
let center: CGPoint = .zero
|
||||
|
||||
var angle: CGFloat = -CGFloat(.pi / 2.0)
|
||||
let angleIncrement = CGFloat(.pi * 2.0 / Double(pointsOnStar))
|
||||
let radius = minSize / 2.0
|
||||
|
||||
var firstPoint = true
|
||||
|
||||
func pointFrom(angle: CGFloat, radius: CGFloat, offset: CGPoint) -> CGPoint {
|
||||
return CGPoint(x: radius * cos(angle) + offset.x,
|
||||
y: radius * sin(angle) + offset.y)
|
||||
}
|
||||
|
||||
for _ in 1...pointsOnStar {
|
||||
|
||||
let point: CGPoint = pointFrom(angle: angle, radius: radius, offset: center)
|
||||
let nextPoint: CGPoint = pointFrom(angle: angle + angleIncrement, radius: radius, offset: center)
|
||||
let midPoint: CGPoint = pointFrom(angle: angle + angleIncrement / 2.0, radius: starExtrusion, offset: center)
|
||||
|
||||
var perY: CGFloat = 1.0
|
||||
var perX: CGFloat = 1.0
|
||||
|
||||
if rect.height < rect.width {
|
||||
perY = (rect.height / minSize)
|
||||
} else {
|
||||
perX = (rect.width / minSize)
|
||||
}
|
||||
|
||||
let p = CGPoint(x: (point.x * perX) + (rect.width / 2.0),
|
||||
y: (point.y * perY) + (rect.height / 2.0))
|
||||
|
||||
let n = CGPoint(x: (nextPoint.x * perX) + (rect.width / 2.0),
|
||||
y: (nextPoint.y * perY) + (rect.height / 2.0))
|
||||
|
||||
let m = CGPoint(x: (midPoint.x * perX) + (rect.width / 2.0),
|
||||
y: (midPoint.y * perY) + (rect.height / 2.0))
|
||||
|
||||
if firstPoint {
|
||||
firstPoint = false
|
||||
path.move(to: p)
|
||||
}
|
||||
|
||||
if !polygon {
|
||||
path.addLine(to: m)
|
||||
}
|
||||
path.addLine(to: n)
|
||||
|
||||
angle += angleIncrement
|
||||
}
|
||||
|
||||
path.close()
|
||||
|
||||
return path
|
||||
}
|
||||
}
|
||||
@@ -1,324 +0,0 @@
|
||||
//
|
||||
// DesignTest.swift
|
||||
// FigmaConvertXib
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 28.07.2020.
|
||||
// Copyright © 2020 mrusta. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@IBDesignable
|
||||
class DesignFillView_: UIView {
|
||||
|
||||
|
||||
@IBInspectable var cornerRadius: CGFloat = 0.0
|
||||
|
||||
//MARK: Blur
|
||||
|
||||
@IBInspectable var blur: CGFloat = 0.0
|
||||
|
||||
//MARK: Image
|
||||
|
||||
@IBInspectable var image: UIImage?
|
||||
@IBInspectable var imageMode: Int = 1 /// Scale to fill / Aspect fit / fill
|
||||
|
||||
//MARK: Fill
|
||||
|
||||
@IBInspectable var fillColor: UIColor?
|
||||
//MARK: Border
|
||||
|
||||
@IBInspectable var brColor: UIColor = .clear
|
||||
@IBInspectable var brWidth: CGFloat = 0.0
|
||||
@IBInspectable var brDash: Int = 0
|
||||
|
||||
|
||||
|
||||
@IBInspectable var shColor: UIColor = .clear
|
||||
@IBInspectable var shRadius: CGFloat = 0.0
|
||||
@IBInspectable var shOffset: CGSize = .zero
|
||||
|
||||
//MARK: - Draw
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
super.draw(rect)
|
||||
|
||||
guard let bezier = figurePath(bounds) else { return }
|
||||
|
||||
addFill(bezier: bezier)
|
||||
addImage(bezier: bezier)
|
||||
addBorder()
|
||||
addShadow()
|
||||
addBlur()
|
||||
}
|
||||
|
||||
//MARK: - Figure Type
|
||||
|
||||
private func figurePath(_ rect: CGRect) -> UIBezierPath? {
|
||||
return rectangle(rect: rect, radius: cornerRadius)
|
||||
}
|
||||
|
||||
|
||||
|
||||
private func addImage(bezier: UIBezierPath) {
|
||||
|
||||
guard let image = image else { return }
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
var f: CGRect = CGRect(x: 0, y: -bounds.height, width: bounds.width, height: bounds.height)
|
||||
|
||||
if imageMode == 1 || imageMode == 2 {
|
||||
|
||||
var w: CGFloat = 0
|
||||
var h: CGFloat = 0
|
||||
|
||||
let percent = bounds.height / image.size.height
|
||||
w = image.size.width * percent
|
||||
h = bounds.height
|
||||
|
||||
if (imageMode == 1) && (w > bounds.width) ||
|
||||
(imageMode == 2) && (bounds.width > w) {
|
||||
|
||||
let percent = bounds.width / image.size.width
|
||||
h = image.size.height * percent
|
||||
w = bounds.width
|
||||
}
|
||||
|
||||
let x = (bounds.width / 2) - (w / 2)
|
||||
let y = (-h + (((bounds.height / 2) - (h / 2)) * (-1)))
|
||||
|
||||
f = CGRect(x: x, y: y, width: w, height: h)
|
||||
}
|
||||
|
||||
context.saveGState()
|
||||
bezier.addClip()
|
||||
context.scaleBy(x: 1, y: -1)
|
||||
context.draw(image.cgImage!, in: f, byTiling: false)
|
||||
context.restoreGState()
|
||||
|
||||
}
|
||||
|
||||
//MARK: - Fill
|
||||
|
||||
private func addFill(bezier: UIBezierPath) {
|
||||
|
||||
guard let fillColor = fillColor else { return }
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
bezier.close()
|
||||
context.saveGState()
|
||||
fillColor.setFill()
|
||||
bezier.fill()
|
||||
context.restoreGState()
|
||||
}
|
||||
|
||||
|
||||
//MARK: - Shadow
|
||||
|
||||
private func addShadow() {
|
||||
|
||||
if shRadius < 0 { shRadius = 0 }
|
||||
|
||||
layer.shadowOffset = shOffset
|
||||
layer.shadowOpacity = 1.0
|
||||
layer.shadowRadius = shRadius
|
||||
layer.shadowColor = shColor.cgColor
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MARK: - Border / Stroke
|
||||
|
||||
private func addBorder() {
|
||||
|
||||
if brWidth < 0 { brWidth = 0 }
|
||||
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
// brColor.setStroke()
|
||||
|
||||
guard let bezier = figurePath(bounds) else { return }
|
||||
|
||||
context.saveGState()
|
||||
|
||||
if brDash > 0 {
|
||||
|
||||
UIColor.clear.setFill()
|
||||
bezier.fill()
|
||||
|
||||
brColor.setStroke()
|
||||
bezier.lineWidth = brWidth * 2
|
||||
|
||||
let dashPattern : [CGFloat] = [ CGFloat(brDash), CGFloat(brDash)]
|
||||
bezier.setLineDash(dashPattern, count: 2, phase: 0)
|
||||
bezier.stroke()
|
||||
|
||||
} else {
|
||||
|
||||
brColor.setStroke()
|
||||
|
||||
bezier.lineWidth = brWidth * 2
|
||||
bezier.stroke()
|
||||
}
|
||||
|
||||
|
||||
|
||||
bezier.stroke()
|
||||
bezier.stroke()
|
||||
|
||||
context.restoreGState()
|
||||
context.restoreGState()
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MARK: - Blur
|
||||
|
||||
private func addBlur() {
|
||||
|
||||
guard blur > 0 else { return }
|
||||
|
||||
guard let image = screenShotContext() else { return }
|
||||
|
||||
self.addblur(screen: image, blur: blur)
|
||||
}
|
||||
|
||||
// MARK: Screen Shot Context
|
||||
|
||||
private func screenShotContext() -> UIImage? {
|
||||
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return nil }
|
||||
guard let cgimage: CGImage = context.makeImage() else { return nil }
|
||||
let image = UIImage(cgImage: cgimage)
|
||||
|
||||
return image
|
||||
}
|
||||
|
||||
// MARK: Clear Context
|
||||
|
||||
private func clearContext() {
|
||||
|
||||
let f = CGRect(x: 0, y: 0,
|
||||
width: frame.width * 2,
|
||||
height: frame.height * 2)
|
||||
|
||||
let context = UIGraphicsGetCurrentContext()
|
||||
context?.clear(f)
|
||||
}
|
||||
|
||||
|
||||
private func addblur(screen: UIImage, blur: CGFloat) {
|
||||
|
||||
clearContext()
|
||||
|
||||
func blurImage(image: UIImage) -> UIImage? {
|
||||
|
||||
guard let ciscreen: CIImage = CIImage(image: screen) else { return nil }
|
||||
|
||||
guard let filter: CIFilter = CIFilter(name: "CIGaussianBlur") else { return nil }
|
||||
filter.setDefaults()
|
||||
filter.setValue(ciscreen, forKey: kCIInputImageKey)
|
||||
filter.setValue(blur, forKey: kCIInputRadiusKey)
|
||||
|
||||
|
||||
let bl2 = ((blur * 3) * -1)
|
||||
let bl4 = (blur * 6)
|
||||
|
||||
let contextFrame = CGRect(
|
||||
x: bl2,
|
||||
y: bl2,
|
||||
width: bl4 + image.size.width,
|
||||
height: bl4 + image.size.height
|
||||
)
|
||||
|
||||
// let bl2 = ((blur * 2) * -1)
|
||||
// let bl4 = (blur * 4)
|
||||
// let contextFrame2 = CGRect(x: bl2,
|
||||
// y: bl2,
|
||||
// width: bl4 + (frame.width * 2),
|
||||
// height: bl4 + (frame.height * 2))
|
||||
|
||||
let ciContext = CIContext(options: nil)
|
||||
guard let ci: CIImage = filter.value(forKey: kCIOutputImageKey) as? CIImage else { return nil }
|
||||
guard let cImg = ciContext.createCGImage(ci, from: contextFrame) else { return nil }
|
||||
|
||||
let finalImage = UIImage(cgImage: cImg)
|
||||
|
||||
return finalImage
|
||||
}
|
||||
|
||||
let p2: CGFloat = 1
|
||||
let p4: CGFloat = p2 * 2
|
||||
|
||||
let bl2 = ((blur * p2) * -1)
|
||||
let bl4 = (blur * p4)
|
||||
|
||||
let x: CGFloat = 0
|
||||
let ofW = (x * 1) * -1
|
||||
let ofH = (x * 1) * -1
|
||||
|
||||
let ofW2 = (x * 2)
|
||||
let ofH2 = (x * 2)
|
||||
|
||||
let contextFrame = CGRect(x: bl2 + ofW,
|
||||
y: bl2 + ofH,
|
||||
width: bl4 + ofW2 + frame.width,
|
||||
height: bl4 + ofH2 + frame.height)
|
||||
|
||||
let blurImageView = UIImageView(frame: contextFrame)
|
||||
blurImageView.image = blurImage(image: screen)
|
||||
blurImageView.contentMode = .scaleAspectFill
|
||||
|
||||
|
||||
addSubview(blurImageView)
|
||||
}
|
||||
|
||||
//MARK: - Rectangle Bezier
|
||||
|
||||
func rectangle(rect: CGRect, radius: CGFloat) -> UIBezierPath {
|
||||
|
||||
let r = self.cornerRadius(radius)
|
||||
let w = rect.width
|
||||
let h = rect.height
|
||||
|
||||
let path = UIBezierPath()
|
||||
path.move(to: CGPoint(x: r, y: 0.0))
|
||||
|
||||
path.addLine(to: CGPoint(x: w - r, y: 0.0))
|
||||
path.addArc(withCenter: CGPoint(x: w - r, y: r),
|
||||
radius: r,
|
||||
startAngle: 3.0 * .pi / 2.0,
|
||||
endAngle: 2 * .pi,
|
||||
clockwise: true)
|
||||
|
||||
path.addLine(to: CGPoint(x: w, y: h - r))
|
||||
path.addArc(withCenter: CGPoint(x: w - r, y: h - r),
|
||||
radius: r,
|
||||
startAngle: 0.0,
|
||||
endAngle: .pi / 2.0,
|
||||
clockwise: true)
|
||||
|
||||
path.addLine(to: CGPoint(x: r, y: h))
|
||||
path.addArc(withCenter: CGPoint(x: r, y: h - r),
|
||||
radius: r,
|
||||
startAngle: .pi / 2.0,
|
||||
endAngle: .pi,
|
||||
clockwise: true)
|
||||
|
||||
path.addLine(to: CGPoint(x: 0.0, y: r))
|
||||
path.addArc(withCenter: CGPoint(x: r, y: r),
|
||||
radius: r,
|
||||
startAngle: .pi,
|
||||
endAngle: 3.0 * .pi / 2.0,
|
||||
clockwise: true)
|
||||
|
||||
path.close()
|
||||
return path
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
//
|
||||
// DesignImageView.swift
|
||||
// FigmaConvertXib
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 21.07.2020.
|
||||
// Copyright © 2020 mrusta. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@IBDesignable
|
||||
class DesignImage: UIImageView {
|
||||
|
||||
@IBInspectable var cornerRadius: CGFloat = 0.0
|
||||
|
||||
/// Shadow
|
||||
@IBInspectable var shColor: UIColor = .clear
|
||||
@IBInspectable var shRadius: CGFloat = 0.0
|
||||
@IBInspectable var shOffset: CGSize = .zero
|
||||
|
||||
/// Border
|
||||
@IBInspectable var brColor: UIColor = .clear
|
||||
@IBInspectable var brWidth: CGFloat = 0.0
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
|
||||
super.draw(rect)
|
||||
|
||||
layer.backgroundColor = UIColor.black.cgColor
|
||||
|
||||
let l = CALayer()
|
||||
l.frame = rect
|
||||
l.borderColor = brColor.cgColor
|
||||
l.borderWidth = brWidth
|
||||
l.cornerRadius = cornerRadius
|
||||
layer.addSublayer(l)
|
||||
|
||||
add(shadow: shRadius, offset: shOffset, color: shColor)
|
||||
add(border: brWidth, color: brColor)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@IBDesignable
|
||||
class DesignImageView: UIView {
|
||||
|
||||
//MARK: Properties
|
||||
|
||||
@IBInspectable var image: UIImage?
|
||||
@IBInspectable var contModeFill: Bool = false
|
||||
|
||||
/// Radius
|
||||
@IBInspectable var cornerRadius: CGFloat = 0.0
|
||||
|
||||
/// Blur
|
||||
@IBInspectable var blur: CGFloat = 0.0
|
||||
|
||||
/// Fill
|
||||
@IBInspectable var fillColor: UIColor = .clear
|
||||
|
||||
/// Gradient
|
||||
@IBInspectable var grColor2: UIColor?
|
||||
@IBInspectable var grColor3: UIColor?
|
||||
@IBInspectable var grColor4: UIColor?
|
||||
@IBInspectable var grColor5: UIColor?
|
||||
@IBInspectable var grColor6: UIColor?
|
||||
|
||||
@IBInspectable var grStartPoint: CGPoint = .zero
|
||||
@IBInspectable var grEndPoint: CGPoint = .zero
|
||||
|
||||
/// Inner Shadow
|
||||
@IBInspectable var inShColor: UIColor = .clear
|
||||
@IBInspectable var inShRadius: CGFloat = 0.0
|
||||
@IBInspectable var inShOffset: CGSize = .zero
|
||||
|
||||
/// Shadow
|
||||
@IBInspectable var shColor: UIColor = .clear
|
||||
@IBInspectable var shRadius: CGFloat = 0.0
|
||||
@IBInspectable var shOffset: CGSize = .zero
|
||||
|
||||
/// Border
|
||||
@IBInspectable var brColor: UIColor = .clear
|
||||
@IBInspectable var brWidth: CGFloat = 0.0
|
||||
|
||||
var imageView: UIImageView!
|
||||
|
||||
|
||||
//MARK: - Draw
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
|
||||
let radius = self.cornerRadius(cornerRadius)
|
||||
|
||||
layer.cornerRadius = radius
|
||||
|
||||
layer.backgroundColor = fillColor.cgColor
|
||||
|
||||
addShadow()
|
||||
addBorder()
|
||||
|
||||
addImage()
|
||||
|
||||
addGradient()
|
||||
addInnerShadow()
|
||||
|
||||
add(blur: blur) { [weak self] in
|
||||
|
||||
guard let _self = self else { return }
|
||||
_self.imageView.setAlpha(.invisible)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private func addGradient() {
|
||||
|
||||
guard let glayer = add(gradient: fillColor,
|
||||
color2: grColor2,
|
||||
color3: grColor3,
|
||||
color4: grColor4,
|
||||
color5: grColor5,
|
||||
color6: grColor6,
|
||||
pointStart: grStartPoint,
|
||||
pointEnd: grEndPoint,
|
||||
cornerRadius: cornerRadius) else { return }
|
||||
|
||||
imageView.layer.insertSublayer(glayer, at: 0)
|
||||
|
||||
}
|
||||
|
||||
private func addInnerShadow() {
|
||||
|
||||
addInnerShadow(color: inShColor,
|
||||
radius: inShRadius,
|
||||
offset: inShOffset,
|
||||
cornerRadius: cornerRadius)
|
||||
|
||||
}
|
||||
|
||||
private func addShadow() {
|
||||
layer.shadowOffset = shOffset
|
||||
layer.shadowOpacity = 1.0
|
||||
layer.shadowRadius = shRadius
|
||||
layer.shadowColor = shColor.cgColor
|
||||
}
|
||||
|
||||
private func addBorder() {
|
||||
layer.borderColor = brColor.cgColor
|
||||
layer.borderWidth = brWidth
|
||||
}
|
||||
|
||||
private func addImage() {
|
||||
let f = CGRect(x: 0, y: 0, width: frame.width, height: frame.height)
|
||||
imageView = UIImageView(frame: f)
|
||||
imageView.image = image
|
||||
imageView.contentMode = contModeFill ? .scaleAspectFill : .scaleAspectFit
|
||||
imageView.clipsToBounds = true
|
||||
imageView.layer.cornerRadius = self.cornerRadius(cornerRadius)
|
||||
insertSubview(imageView, at: 0)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
//
|
||||
// DesignInnerShadow.swift
|
||||
// FigmaConvertXib
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 12.02.2021.
|
||||
// Copyright © 2021 mrusta. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@IBDesignable
|
||||
class DesignInnerShadow: UIView {
|
||||
|
||||
@IBInspectable var cornerRadius: CGFloat = 0.0
|
||||
@IBInspectable var inShColor: UIColor = .clear
|
||||
@IBInspectable var inShRadius: CGFloat = 0.0
|
||||
@IBInspectable var inShOffset: CGSize = .zero
|
||||
|
||||
@IBInspectable var fillColor: UIColor?
|
||||
|
||||
//MARK: - Draw
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
super.draw(rect)
|
||||
|
||||
addInnerShadow(rect)
|
||||
|
||||
layer.backgroundColor = fillColor?.cgColor
|
||||
layer.cornerRadius = cornerRadius
|
||||
}
|
||||
|
||||
//MARK: - Add Shadow
|
||||
|
||||
func addInnerShadow(_ rect: CGRect) {
|
||||
/// General Declarations
|
||||
|
||||
let context = UIGraphicsGetCurrentContext()!
|
||||
let path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius)
|
||||
|
||||
UIColor(white: 1.0, alpha: 0.00001).setFill()
|
||||
|
||||
path.fill()
|
||||
context.saveGState()
|
||||
context.clip(to: path.bounds)
|
||||
context.setAlpha(CGFloat(1.0))
|
||||
context.beginTransparencyLayer(auxiliaryInfo: nil)
|
||||
|
||||
|
||||
let innerShadow = NSShadow()
|
||||
innerShadow.shadowColor = inShColor
|
||||
innerShadow.shadowOffset = inShOffset
|
||||
innerShadow.shadowBlurRadius = inShRadius * 2
|
||||
|
||||
context.setShadow(offset: inShOffset,
|
||||
blur: inShRadius,
|
||||
color: inShColor.cgColor)
|
||||
context.setBlendMode(.sourceOut)
|
||||
context.beginTransparencyLayer(auxiliaryInfo: nil)
|
||||
let ovalOpaqueShadow = UIColor.init(cgColor: inShColor.cgColor)
|
||||
ovalOpaqueShadow.setFill()
|
||||
path.fill()
|
||||
context.endTransparencyLayer()
|
||||
context.endTransparencyLayer()
|
||||
context.restoreGState()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
//
|
||||
// DesignLabel.swift
|
||||
// FigmaConvertXib
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 25.07.2020.
|
||||
// Copyright © 2020 mrusta. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@IBDesignable
|
||||
class DesignLabel: UILabel {
|
||||
|
||||
//MARK: Gradient
|
||||
@IBInspectable var grColor1: UIColor?
|
||||
@IBInspectable var grColor2: UIColor?
|
||||
@IBInspectable var grColor3: UIColor?
|
||||
@IBInspectable var grColor4: UIColor?
|
||||
@IBInspectable var grColor5: UIColor?
|
||||
@IBInspectable var grColor6: UIColor?
|
||||
|
||||
@IBInspectable var grStartPoint: CGPoint = .zero
|
||||
@IBInspectable var grEndPoint: CGPoint = .zero
|
||||
|
||||
@IBInspectable var grRadial: Bool = false /// default: linear
|
||||
@IBInspectable var grDrawsOptions: Bool = true
|
||||
@IBInspectable var grDebug: Bool = false
|
||||
@IBInspectable var grPointPercent: Bool = true
|
||||
@IBInspectable var grBlendMode: Int = 20 /// заполнители
|
||||
|
||||
//MARK: - Shadow
|
||||
|
||||
@IBInspectable var shColor: UIColor = .clear
|
||||
@IBInspectable var shRadius: CGFloat = 0.0
|
||||
@IBInspectable var shOffset: CGSize = .zero
|
||||
|
||||
//MARK: Border
|
||||
|
||||
@IBInspectable var brColor: UIColor = .clear
|
||||
@IBInspectable var brWidth: CGFloat = 0.0
|
||||
|
||||
//MARK: - Draw
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
super.draw(rect)
|
||||
shadow()
|
||||
gradient()
|
||||
gradientDebug()
|
||||
border()
|
||||
}
|
||||
|
||||
//MARK: - Add Shadow
|
||||
|
||||
private func shadow() {
|
||||
layer.shadowOpacity = 1.0
|
||||
layer.shadowOffset = shOffset
|
||||
layer.shadowRadius = shRadius
|
||||
layer.shadowColor = shColor.cgColor
|
||||
}
|
||||
|
||||
//MARK: - Add Border
|
||||
|
||||
func border() {
|
||||
|
||||
guard brColor != .clear, brWidth != 0.0 else { return }
|
||||
|
||||
let borderLabel = UILabel(frame: bounds)
|
||||
borderLabel.text = text
|
||||
borderLabel.font = font
|
||||
borderLabel.textColor = .clear
|
||||
borderLabel.numberOfLines = numberOfLines
|
||||
borderLabel.backgroundColor = .clear
|
||||
|
||||
|
||||
let strokeTextAttributes: [NSAttributedString.Key : Any] = [
|
||||
.strokeColor : brColor,
|
||||
.strokeWidth : (-1 * (brWidth * 2)),
|
||||
]
|
||||
|
||||
borderLabel.attributedText = NSAttributedString(string: text ?? "",
|
||||
attributes: strokeTextAttributes)
|
||||
|
||||
addSubview(borderLabel)
|
||||
}
|
||||
|
||||
//MARK: - Add Gradient
|
||||
|
||||
func gradient() {
|
||||
var colors: [CGColor] = []
|
||||
|
||||
if grColor1 != nil || grColor2 != nil || grColor3 != nil || grColor4 != nil || grColor5 != nil {
|
||||
|
||||
if let color1 = grColor1 { colors.append(color1.cgColor) }
|
||||
if let color2 = grColor2 { colors.append(color2.cgColor) }
|
||||
if let color3 = grColor3 { colors.append(color3.cgColor) }
|
||||
if let color4 = grColor4 { colors.append(color4.cgColor) }
|
||||
if let color5 = grColor5 { colors.append(color5.cgColor) }
|
||||
if let color6 = grColor6 { colors.append(color6.cgColor) }
|
||||
|
||||
} else { return }
|
||||
|
||||
guard let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(),
|
||||
colors: colors as CFArray,
|
||||
locations: nil) else { return }
|
||||
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
let bMode = CGBlendMode(rawValue: CGBlendMode.RawValue(grBlendMode)) ?? CGBlendMode.sourceAtop
|
||||
context.setBlendMode(bMode)
|
||||
|
||||
let options: CGGradientDrawingOptions =
|
||||
grDrawsOptions ? [ .drawsBeforeStartLocation, .drawsAfterEndLocation ] : [ ]
|
||||
|
||||
|
||||
if grPointPercent {
|
||||
grEndPoint = CGPoint(x: grEndPoint.x * frame.width, y: grEndPoint.y * frame.height)
|
||||
grStartPoint = CGPoint(x: grStartPoint.x * frame.width, y: grStartPoint.y * frame.height)
|
||||
}
|
||||
|
||||
//MARK: Gr. Radial / Linear
|
||||
if grRadial {
|
||||
let x: CGFloat = (grEndPoint.x - grStartPoint.x)
|
||||
let y: CGFloat = (grEndPoint.y - grStartPoint.y)
|
||||
let distance: CGFloat = sqrt((x * x) + (y * y))
|
||||
|
||||
context.drawRadialGradient(gradient,
|
||||
startCenter: grStartPoint,
|
||||
startRadius: 0,
|
||||
endCenter: grStartPoint,
|
||||
endRadius: distance,
|
||||
options: options)
|
||||
} else {
|
||||
context.drawLinearGradient(gradient,
|
||||
start: grStartPoint,
|
||||
end: grEndPoint,
|
||||
options: options)
|
||||
}
|
||||
context.saveGState()
|
||||
|
||||
}
|
||||
|
||||
//MARK: - Gr. Debug
|
||||
|
||||
func gradientDebug() {
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
guard grDebug else { return }
|
||||
|
||||
context.setBlendMode(CGBlendMode.normal)
|
||||
context.setLineWidth(3.0)
|
||||
context.setFillColor(UIColor.black.cgColor)
|
||||
context.setStrokeColor(UIColor.systemRed.cgColor)
|
||||
|
||||
let ellipseRadius: CGFloat = 5
|
||||
let circleRect = CGRect(x: grStartPoint.x - ellipseRadius,
|
||||
y: grStartPoint.y - ellipseRadius,
|
||||
width: ellipseRadius * 2,
|
||||
height: ellipseRadius * 2)
|
||||
|
||||
context.fillEllipse(in: circleRect)
|
||||
context.strokeEllipse(in: circleRect)
|
||||
context.setStrokeColor(UIColor.green.cgColor)
|
||||
|
||||
let circleRect2 = CGRect(x: grEndPoint.x - ellipseRadius,
|
||||
y: grEndPoint.y - ellipseRadius,
|
||||
width: ellipseRadius * 2,
|
||||
height: ellipseRadius * 2)
|
||||
|
||||
context.fillEllipse(in: circleRect2)
|
||||
context.strokeEllipse(in: circleRect2)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
//
|
||||
// DesignTest.swift
|
||||
// FigmaConvertXib
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 28.07.2020.
|
||||
// Copyright © 2020 mrusta. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
private extension UIButton {
|
||||
|
||||
func style(selected: Bool) {
|
||||
if selected {
|
||||
self.setTitleColor(#colorLiteral(red: 1, green: 1, blue: 1, alpha: 1), for: .normal)
|
||||
} else {
|
||||
self.setTitleColor(#colorLiteral(red: 0.3098039216, green: 0.3098039216, blue: 0.3098039216, alpha: 1), for: .normal)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension UIView {
|
||||
|
||||
func selectedView() {
|
||||
|
||||
self.layer.cornerRadius = 8
|
||||
self.layer.backgroundColor = #colorLiteral(red: 0.9960784314, green: 0.3137254902, blue: 0, alpha: 1).cgColor
|
||||
|
||||
self.add(shadow: 6 / 2, offset: CGSize(width: -4, height: -4), color: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1))
|
||||
|
||||
self.addInnerShadow(color: #colorLiteral(red: 0.4784313725, green: 0.1960784314, blue: 0.01568627451, alpha: 0.3674445752),
|
||||
radius: 9 / 2,
|
||||
offset: CGSize(width: -4, height: -4),
|
||||
cornerRadius: 8)
|
||||
|
||||
self.addInnerShadow(color: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0.3720056395),
|
||||
radius: 8 / 2,
|
||||
offset: CGSize(width: 4, height: 4),
|
||||
cornerRadius: 8)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@IBDesignable
|
||||
class DesignSegmentBar: UIView {
|
||||
|
||||
@IBInspectable var textItems: String = ""
|
||||
@IBInspectable var index: Int = 0
|
||||
|
||||
private var views: [UIView] = []
|
||||
private var buttons: [UIButton] = []
|
||||
private var stackView: UIStackView!
|
||||
private var seView: UIImageView!
|
||||
|
||||
var changeIndex: ((Int) -> ())?
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
super.draw(rect)
|
||||
|
||||
layer.cornerRadius = 8
|
||||
layer.backgroundColor = #colorLiteral(red: 0.9411764706, green: 0.9411764706, blue: 0.9529411765, alpha: 1).cgColor
|
||||
|
||||
for view in buttons {
|
||||
view.removeFromSuperview()
|
||||
}
|
||||
for view in views {
|
||||
view.removeFromSuperview()
|
||||
}
|
||||
for view in subviews {
|
||||
view.removeFromSuperview()
|
||||
}
|
||||
|
||||
let items = textItems.components(separatedBy: ",")
|
||||
let width = (self.frame.width / CGFloat(items.count))
|
||||
let frame = CGRect(x: (width * CGFloat(index)), y: 0, width: width, height: self.frame.height)
|
||||
|
||||
views = []
|
||||
buttons = []
|
||||
|
||||
for i in 0..<items.count {
|
||||
|
||||
let x = ((width * CGFloat(i+1)) - 0.5)
|
||||
|
||||
if (i+1) != items.count {
|
||||
let separatorView = UIView(frame: CGRect(x: x, y: 11, width: 1, height: self.frame.height - 22))
|
||||
separatorView.backgroundColor = #colorLiteral(red: 0.7411764706, green: 0.7411764706, blue: 0.7411764706, alpha: 1)
|
||||
separatorView.layer.cornerRadius = 0.5
|
||||
addSubview(separatorView)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var i = 0
|
||||
for oneText in items {
|
||||
let x = (width * CGFloat(i))
|
||||
|
||||
let view = UIView(frame: frame)
|
||||
view.set(x: x)
|
||||
let oneButton = UIButton(type: .system)
|
||||
oneButton.frame = view.bounds
|
||||
view.addSubview(oneButton)
|
||||
|
||||
/// Btn Size
|
||||
|
||||
view.backgroundColor = .clear
|
||||
oneButton.backgroundColor = .clear
|
||||
oneButton.style(selected: false)
|
||||
|
||||
/// Btn
|
||||
oneButton.setTitle(oneText , for: .normal)
|
||||
oneButton.contentVerticalAlignment = .center
|
||||
|
||||
if let font = UIFont(name: "TTNorms-Regular", size: 18) {
|
||||
oneButton.titleLabel?.font = font
|
||||
}
|
||||
|
||||
if i == index {
|
||||
oneButton.style(selected: true)
|
||||
}
|
||||
|
||||
oneButton.addTarget(self, action: #selector(buttonAction(_:)), for: .touchUpInside)
|
||||
|
||||
//oneButton.set(width: width)
|
||||
views.append(view)
|
||||
buttons.append(oneButton)
|
||||
//self.addSubview(oneButton)
|
||||
i += 1
|
||||
}
|
||||
|
||||
let stackView = UIStackView()
|
||||
stackView.axis = .horizontal
|
||||
stackView.distribution = .fillEqually
|
||||
|
||||
for btn in views {
|
||||
stackView.addArrangedSubview(btn)
|
||||
}
|
||||
|
||||
|
||||
seView = UIImageView(frame: frame)
|
||||
seView.selectedView()
|
||||
addSubview(seView)
|
||||
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
self.addSubview(stackView)
|
||||
|
||||
stackView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
|
||||
stackView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
|
||||
stackView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
|
||||
stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
|
||||
self.stackView = stackView
|
||||
}
|
||||
|
||||
@objc func buttonAction(_ button: UIButton) {
|
||||
|
||||
var i = 0
|
||||
for btn in buttons {
|
||||
btn.style(selected: false)
|
||||
|
||||
if btn == button {
|
||||
self.index = i
|
||||
changeIndex?(i)
|
||||
let x = (btn.frame.width * CGFloat(i))
|
||||
UIView.animate(withDuration: 0.35) {
|
||||
self.seView.set(x: x)
|
||||
}
|
||||
btn.style(selected: true)
|
||||
}
|
||||
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
//
|
||||
// DesignnGradientView.swift
|
||||
// ContainerControllerSwift_Example
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 04.09.2024.
|
||||
// Copyright © 2024 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@IBDesignable
|
||||
class DesignnGradientView: UIView {
|
||||
|
||||
@IBInspectable var cornerRadius: CGFloat = 0.0
|
||||
|
||||
@IBInspectable var fillColor: UIColor?
|
||||
|
||||
@IBInspectable var brColor: UIColor = .clear
|
||||
@IBInspectable var brWidth: CGFloat = 0.0
|
||||
@IBInspectable var brDash: Int = 0
|
||||
|
||||
@IBInspectable var grColor1: UIColor?
|
||||
@IBInspectable var grColor2: UIColor?
|
||||
@IBInspectable var grColor3: UIColor?
|
||||
@IBInspectable var grStartPoint: CGPoint = .zero
|
||||
@IBInspectable var grEndPoint: CGPoint = .zero
|
||||
@IBInspectable var grRadial: Bool = false /// default: linear
|
||||
|
||||
func setup() {
|
||||
|
||||
if let foundView = viewWithTag(55) {
|
||||
foundView.removeFromSuperview()
|
||||
}
|
||||
|
||||
let d = DesignFigure_(frame: bounds)
|
||||
d.backgroundColor = .clear
|
||||
d.tag = 55
|
||||
d.cornerRadius = cornerRadius
|
||||
// d.blur = blur
|
||||
// d.image = image
|
||||
// d.imageMode = imageMode
|
||||
d.fillColor = fillColor
|
||||
d.brWidth = brWidth
|
||||
d.brColor = brColor
|
||||
d.brDash = brDash
|
||||
|
||||
d.grColor1 = grColor1
|
||||
d.grColor2 = grColor2
|
||||
d.grColor3 = grColor3
|
||||
// d.grColor4 = grColor4
|
||||
// d.grColor5 = grColor5
|
||||
// d.grColor6 = grColor6
|
||||
d.grStartPoint = grStartPoint
|
||||
d.grEndPoint = grEndPoint
|
||||
d.grRadial = grRadial
|
||||
// d.grDrawsOptions = grDrawsOptions
|
||||
// d.grDebug = grDebug
|
||||
// d.grPointPercent = grPointPercent
|
||||
// d.grBlendMode = grBlendMode
|
||||
|
||||
insertSubview(d, at: 0)
|
||||
|
||||
}
|
||||
|
||||
override func layoutSubviews() { setup() }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,674 +0,0 @@
|
||||
//
|
||||
// DesignnGraphView.swift
|
||||
// ContainerControllerSwift_Example
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 04.09.2024.
|
||||
// Copyright © 2024 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
|
||||
@IBDesignable
|
||||
class DesignnGraphView: UIView {
|
||||
|
||||
|
||||
@IBInspectable var gr2Color1: UIColor?
|
||||
@IBInspectable var gr2Color2: UIColor?
|
||||
@IBInspectable var gr2Color3: UIColor?
|
||||
@IBInspectable var gr2StartPoint: CGPoint = .zero
|
||||
@IBInspectable var gr2EndPoint: CGPoint = .zero
|
||||
@IBInspectable var gr2BlendMode: Int = 0
|
||||
|
||||
@IBInspectable var grColor1: UIColor?
|
||||
@IBInspectable var grColor2: UIColor?
|
||||
@IBInspectable var grColor3: UIColor?
|
||||
@IBInspectable var grStartPoint: CGPoint = .zero
|
||||
@IBInspectable var grEndPoint: CGPoint = .zero
|
||||
@IBInspectable var grRadial: Bool = false /// default: linear
|
||||
@IBInspectable var grBlendMode: Int = 0
|
||||
|
||||
@IBInspectable var fillColor: UIColor?
|
||||
@IBInspectable var padding: CGFloat = 0
|
||||
@IBInspectable var cornerRadius: CGFloat = 0.0
|
||||
|
||||
@IBInspectable var brColor: UIColor = .clear
|
||||
@IBInspectable var brWidth: CGFloat = 0.0
|
||||
|
||||
@IBInspectable var addPoints: Bool = true
|
||||
@IBInspectable var arrStr: String = ""
|
||||
|
||||
var data: [CGFloat] {
|
||||
get {
|
||||
|
||||
let result = arrStr.components(separatedBy: ",")
|
||||
|
||||
let newResult = result.map {
|
||||
CGFloat(Int($0) ?? 0)
|
||||
}
|
||||
return newResult
|
||||
}
|
||||
set {
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
override func layoutSubviews() { setup() }
|
||||
|
||||
func setup() {
|
||||
self.layer.backgroundColor = UIColor.clear.cgColor
|
||||
self.backgroundColor = UIColor.clear
|
||||
self.layer.cornerRadius = cornerRadius
|
||||
// self.cornerRadius = cornerRadius
|
||||
self.clipsToBounds = true
|
||||
|
||||
|
||||
let bezier = rectanglee(rect: bounds, radius: cornerRadius)
|
||||
|
||||
addFill(bezier: bezier, fillColor: fillColor)
|
||||
|
||||
// guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
let curve = quadCurvedPath()
|
||||
let path = curve.0
|
||||
let points = curve.1
|
||||
|
||||
addGradient(
|
||||
bezier: path,
|
||||
grColor1: gr2Color1,
|
||||
grColor2: gr2Color2,
|
||||
grColor3: gr2Color3,
|
||||
grStartPoint: gr2StartPoint,
|
||||
grEndPoint: gr2EndPoint,
|
||||
grBlendMode: gr2BlendMode
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
// context.saveGState()
|
||||
// path.addClip()
|
||||
// context.drawLinearGradient(gradient,
|
||||
// start: grStartPointR,
|
||||
// end: grEndPointR,
|
||||
// options: options)
|
||||
|
||||
|
||||
|
||||
// brColor.setStroke()
|
||||
// path.lineWidth = brWidth
|
||||
// path.stroke()
|
||||
|
||||
|
||||
gradientCurve(points: points)
|
||||
|
||||
|
||||
|
||||
// addInfoLabels()
|
||||
|
||||
// addGradient(bezier: bezier)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// if let foundView = viewWithTag(55) {
|
||||
// foundView.removeFromSuperview()
|
||||
// }
|
||||
//
|
||||
//
|
||||
// let d = DesignnGradientView(frame: bounds)
|
||||
// d.backgroundColor = .clear
|
||||
// d.tag = 44
|
||||
// d.fillColor = .clear
|
||||
// d.brWidth = brWidth
|
||||
// d.brColor = brColor
|
||||
// d.grColor1 = grColor1
|
||||
// d.grColor2 = grColor2
|
||||
// d.grColor3 = grColor3
|
||||
// d.grStartPoint = grStartPoint
|
||||
// d.grEndPoint = grEndPoint
|
||||
// d.layoutSubviews()
|
||||
//
|
||||
//
|
||||
// let g = DesignnGraphOnlyView(frame: bounds)
|
||||
// g.backgroundColor = .clear
|
||||
// g.tag = 44
|
||||
// g.fillColor = .clear
|
||||
// g.brWidth = brWidth
|
||||
// g.brColor = brColor
|
||||
// g.arrStr = arrStr
|
||||
// g.layoutSubviews()
|
||||
|
||||
|
||||
// let path = quadCurvedPath()
|
||||
// brColor.setStroke()
|
||||
// path.lineWidth = brWidth
|
||||
// path.stroke()
|
||||
|
||||
// var colors: [CGColor] = []
|
||||
// if let c = grColor1 { colors.append(c.cgColor) }
|
||||
// if let c = grColor2 { colors.append(c.cgColor) }
|
||||
// if let c = grColor3 { colors.append(c.cgColor) }
|
||||
//
|
||||
// let gradient = CAGradientLayer()
|
||||
// gradient.frame = path.bounds
|
||||
// gradient.colors = colors
|
||||
//
|
||||
// let shapeMask = CAShapeLayer()
|
||||
// shapeMask.path = path.cgPath
|
||||
//
|
||||
// gradient.mask = shapeMask
|
||||
// self.layer.addSublayer(gradient)
|
||||
|
||||
|
||||
// let newPath = convert(path, from: self)
|
||||
|
||||
|
||||
|
||||
// UIColor.orange.setFill()
|
||||
// newPath.fill()
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
func gradientCurve(points: [CGPoint]) {
|
||||
// Gradient for the chart colors
|
||||
let gradient = CAGradientLayer()
|
||||
|
||||
var colors: [CGColor] = []
|
||||
if let c = grColor1 { colors.append(c.cgColor) }
|
||||
if let c = grColor2 { colors.append(c.cgColor) }
|
||||
if let c = grColor3 { colors.append(c.cgColor) }
|
||||
gradient.colors = colors
|
||||
|
||||
|
||||
gradient.startPoint = grEndPoint
|
||||
gradient.endPoint = grStartPoint
|
||||
|
||||
gradient.frame = bounds
|
||||
layer.addSublayer(gradient)
|
||||
|
||||
// Random points
|
||||
let graph = CAShapeLayer()
|
||||
let path = CGMutablePath()
|
||||
// var y: CGFloat = 150
|
||||
// let points: [CGPoint] = stride(from: CGFloat.zero, to: 300, by: 2).map {
|
||||
// let change = CGFloat.random(in: -20...20)
|
||||
// var newY = y + change
|
||||
// newY = max(10, newY)
|
||||
// newY = min(newY, 300)
|
||||
// y = newY
|
||||
// return CGPoint(x: $0, y: y)
|
||||
// }
|
||||
path.addLines(between: points)
|
||||
graph.path = path
|
||||
graph.fillColor = nil
|
||||
graph.strokeColor = UIColor.black.cgColor
|
||||
graph.lineWidth = brWidth
|
||||
graph.lineJoin = .round
|
||||
graph.lineCap = .round
|
||||
graph.frame = bounds
|
||||
|
||||
// Only show the gradient where the line is
|
||||
gradient.mask = graph
|
||||
}
|
||||
|
||||
func convert(_ path: UIBezierPath, from view: UIView) -> UIBezierPath {
|
||||
path.apply(view.transform)
|
||||
// we now have a path in view's superview's coordinates. Let's adjust by the origin.
|
||||
let viewTransform = CGAffineTransform(translationX: view.frame.origin.x, y: view.frame.origin.y)
|
||||
path.apply(viewTransform)
|
||||
|
||||
// now the path is adjusted by view's origin. Next we need to subtract self's origin
|
||||
let selfTranslationTransform = CGAffineTransform(translationX: -self.frame.origin.x, y: -self.frame.origin.y)
|
||||
path.apply(selfTranslationTransform)
|
||||
|
||||
// now adjust by self's transform
|
||||
path.apply(self.transform.inverted())
|
||||
return path
|
||||
}
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
|
||||
setup()
|
||||
// self.layer.cornerRadius = cornerRadius
|
||||
// self.layer.backgroundColor = fillColor?.cgColor
|
||||
// self.clipsToBounds = true
|
||||
//
|
||||
//
|
||||
// let bezier = rectangle(rect: bounds, radius: cornerRadius)
|
||||
//
|
||||
//// addFill(bezier: bezier)
|
||||
////
|
||||
//// addGradient(bezier: bezier)
|
||||
//
|
||||
//
|
||||
// let path = quadCurvedPath()
|
||||
//
|
||||
//
|
||||
// var colors: [CGColor] = []
|
||||
// if let c = grColor1 { colors.append(c.cgColor) }
|
||||
// if let c = grColor2 { colors.append(c.cgColor) }
|
||||
// if let c = grColor3 { colors.append(c.cgColor) }
|
||||
//
|
||||
// let gradient = CAGradientLayer()
|
||||
// gradient.frame = path.bounds
|
||||
// gradient.colors = colors
|
||||
//
|
||||
// let shapeMask = CAShapeLayer()
|
||||
// shapeMask.path = path.cgPath
|
||||
//
|
||||
// gradient.mask = shapeMask
|
||||
// self.layer.addSublayer(gradient)
|
||||
|
||||
// brColor.setStroke()
|
||||
// path.lineWidth = brWidth
|
||||
// path.stroke()
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
func getText(_ text: String, size: CGFloat = 12, position: CGPoint) -> CATextLayer {
|
||||
let textlayer = CATextLayer()
|
||||
textlayer.frame = CGRect(x: position.x, y: position.y, width: 30, height: 18)
|
||||
textlayer.fontSize = size
|
||||
textlayer.alignmentMode = .center
|
||||
textlayer.string = text
|
||||
textlayer.isWrapped = true
|
||||
textlayer.truncationMode = .end
|
||||
textlayer.backgroundColor = UIColor.clear.cgColor
|
||||
textlayer.foregroundColor = UIColor.black.cgColor
|
||||
return textlayer
|
||||
}
|
||||
|
||||
func getRect() -> CGSize {
|
||||
.init(width: bounds.width - (padding * 2), height: bounds.height - (padding * 2))
|
||||
}
|
||||
|
||||
func quadCurvedPath() -> (UIBezierPath, [CGPoint]) {
|
||||
|
||||
var arrPoints: [CGPoint] = []
|
||||
|
||||
let path = UIBezierPath()
|
||||
let step = (getRect().width) / CGFloat(data.count - 1)
|
||||
|
||||
var p1 = CGPoint(x: 0 + padding, y: coordYFor(index: 0) + padding)
|
||||
arrPoints.append(p1)
|
||||
path.move(to: p1)
|
||||
|
||||
if addPoints { drawPoint(point: p1, color: UIColor.red, radius: 3) }
|
||||
|
||||
if (data.count == 2) {
|
||||
let pp = CGPoint(x: step + padding, y: coordYFor(index: 1) + padding)
|
||||
arrPoints.append(pp)
|
||||
path.addLine(to: pp)
|
||||
return (path, arrPoints)
|
||||
}
|
||||
|
||||
var oldControlP: CGPoint?
|
||||
|
||||
for i in 1..<data.count {
|
||||
let p2 = CGPoint(x: (step * CGFloat(i)) + padding, y: coordYFor(index: i) + padding)
|
||||
if addPoints { drawPoint(point: p2, color: UIColor.red, radius: 3) }
|
||||
var p3: CGPoint?
|
||||
if i < data.count - 1 {
|
||||
p3 = CGPoint(x: (step * CGFloat(i + 1)) + padding, y: (coordYFor(index: i + 1)) + padding)
|
||||
}
|
||||
|
||||
let newControlP = controlPointForPoints(p1: p1, p2: p2, next: p3)
|
||||
|
||||
|
||||
arrPoints.append(p2)
|
||||
path.addCurve(to: p2, controlPoint1: oldControlP ?? p1, controlPoint2: newControlP ?? p2)
|
||||
|
||||
p1 = p2
|
||||
oldControlP = antipodalFor(point: newControlP, center: p2)
|
||||
}
|
||||
|
||||
|
||||
path.addLine(to: .init(x: getRect().width, y: getRect().height))
|
||||
path.addLine(to: .init(x: 0, y: getRect().height))
|
||||
|
||||
if arrPoints.count > 0 {
|
||||
path.addLine(to: arrPoints[0])
|
||||
}
|
||||
// path.close()
|
||||
|
||||
// arrPoints.reverse()
|
||||
//
|
||||
// var old: CGPoint = oldControlP ?? p1
|
||||
// arrPoints.forEach {
|
||||
// let new: CGPoint = .init(x: $0.x + 0.5, y: $0.y + 0.5)
|
||||
// path.addCurve(to: new, controlPoint1: old, controlPoint2: new)
|
||||
// old = new
|
||||
// }
|
||||
|
||||
|
||||
|
||||
return (path, arrPoints);
|
||||
}
|
||||
|
||||
/// located on the opposite side from the center point
|
||||
func antipodalFor(point: CGPoint?, center: CGPoint?) -> CGPoint? {
|
||||
guard let p1 = point, let center = center else {
|
||||
return nil
|
||||
}
|
||||
let newX = 2 * center.x - p1.x
|
||||
let diffY = abs(p1.y - center.y)
|
||||
let newY = center.y + diffY * (p1.y < center.y ? 1 : -1)
|
||||
|
||||
return CGPoint(x: newX, y: newY)
|
||||
}
|
||||
|
||||
/// halfway of two points
|
||||
func midPointForPoints(p1: CGPoint, p2: CGPoint) -> CGPoint {
|
||||
return CGPoint(x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2);
|
||||
}
|
||||
|
||||
/// Find controlPoint2 for addCurve
|
||||
/// - Parameters:
|
||||
/// - p1: first point of curve
|
||||
/// - p2: second point of curve whose control point we are looking for
|
||||
/// - next: predicted next point which will use antipodal control point for finded
|
||||
func controlPointForPoints(p1: CGPoint, p2: CGPoint, next p3: CGPoint?) -> CGPoint? {
|
||||
guard let p3 = p3 else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let leftMidPoint = midPointForPoints(p1: p1, p2: p2)
|
||||
let rightMidPoint = midPointForPoints(p1: p2, p2: p3)
|
||||
|
||||
var controlPoint = midPointForPoints(p1: leftMidPoint, p2: antipodalFor(point: rightMidPoint, center: p2)!)
|
||||
|
||||
if p1.y.between(a: p2.y, b: controlPoint.y) {
|
||||
controlPoint.y = p1.y
|
||||
} else if p2.y.between(a: p1.y, b: controlPoint.y) {
|
||||
controlPoint.y = p2.y
|
||||
}
|
||||
|
||||
|
||||
let imaginContol = antipodalFor(point: controlPoint, center: p2)!
|
||||
if p2.y.between(a: p3.y, b: imaginContol.y) {
|
||||
controlPoint.y = p2.y
|
||||
}
|
||||
if p3.y.between(a: p2.y, b: imaginContol.y) {
|
||||
let diffY = abs(p2.y - p3.y)
|
||||
controlPoint.y = p2.y + diffY * (p3.y < p2.y ? 1 : -1)
|
||||
}
|
||||
|
||||
// make lines easier
|
||||
controlPoint.x += (p2.x - p1.x) * 0.1
|
||||
|
||||
return controlPoint
|
||||
}
|
||||
|
||||
func coordYFor(index: Int) -> CGFloat {
|
||||
return getRect().height - getRect().height * data[index] / (data.max() ?? 0)
|
||||
}
|
||||
|
||||
func drawPoint(point: CGPoint, color: UIColor, radius: CGFloat) {
|
||||
let ovalPath = UIBezierPath(ovalIn: CGRect(x: point.x - radius, y: point.y - radius, width: radius * 2, height: radius * 2))
|
||||
color.setFill()
|
||||
ovalPath.fill()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension CGFloat {
|
||||
func between(a: CGFloat, b: CGFloat) -> Bool {
|
||||
return self >= Swift.min(a, b) && self <= Swift.max(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
extension UIView {
|
||||
|
||||
func rectanglee(rect: CGRect, radius: CGFloat) -> UIBezierPath {
|
||||
|
||||
let r = self.cornerRadius(radius)
|
||||
let w = rect.width
|
||||
let h = rect.height
|
||||
|
||||
let path = UIBezierPath()
|
||||
path.move(to: CGPoint(x: r, y: 0.0))
|
||||
|
||||
path.addLine(to: CGPoint(x: w - r, y: 0.0))
|
||||
path.addArc(withCenter: CGPoint(x: w - r, y: r),
|
||||
radius: r,
|
||||
startAngle: 3.0 * .pi / 2.0,
|
||||
endAngle: 2 * .pi,
|
||||
clockwise: true)
|
||||
|
||||
path.addLine(to: CGPoint(x: w, y: h - r))
|
||||
path.addArc(withCenter: CGPoint(x: w - r, y: h - r),
|
||||
radius: r,
|
||||
startAngle: 0.0,
|
||||
endAngle: .pi / 2.0,
|
||||
clockwise: true)
|
||||
|
||||
path.addLine(to: CGPoint(x: r, y: h))
|
||||
path.addArc(withCenter: CGPoint(x: r, y: h - r),
|
||||
radius: r,
|
||||
startAngle: .pi / 2.0,
|
||||
endAngle: .pi,
|
||||
clockwise: true)
|
||||
|
||||
path.addLine(to: CGPoint(x: 0.0, y: r))
|
||||
path.addArc(withCenter: CGPoint(x: r, y: r),
|
||||
radius: r,
|
||||
startAngle: .pi,
|
||||
endAngle: 3.0 * .pi / 2.0,
|
||||
clockwise: true)
|
||||
|
||||
path.close()
|
||||
return path
|
||||
}
|
||||
|
||||
|
||||
func drawLinearGradient(inside path:UIBezierPath, start:CGPoint, end:CGPoint, colors:[UIColor])
|
||||
{
|
||||
guard let ctx = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
ctx.saveGState()
|
||||
defer { ctx.restoreGState() } // clean up graphics state changes when the method returns
|
||||
|
||||
path.addClip() // use the path as the clipping region
|
||||
|
||||
let cgColors = colors.map({ $0.cgColor })
|
||||
guard let gradient = CGGradient(colorsSpace: nil, colors: cgColors as CFArray, locations: nil)
|
||||
else { return }
|
||||
|
||||
ctx.drawLinearGradient(gradient, start: start, end: end, options: [])
|
||||
}
|
||||
}
|
||||
|
||||
extension DesignnGraphView {
|
||||
|
||||
//MARK: - Gradient
|
||||
|
||||
private func addGradient(
|
||||
bezier: UIBezierPath,
|
||||
grColor1: UIColor?,
|
||||
grColor2: UIColor?,
|
||||
grColor3: UIColor?,
|
||||
grStartPoint: CGPoint,
|
||||
grEndPoint: CGPoint,
|
||||
grBlendMode: Int = 0
|
||||
) {
|
||||
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
var colors: [CGColor] = []
|
||||
|
||||
if let c = grColor1 { colors.append(c.cgColor) }
|
||||
if let c = grColor2 { colors.append(c.cgColor) }
|
||||
if let c = grColor3 { colors.append(c.cgColor) }
|
||||
// if let c = grColor4 { colors.append(c.cgColor) }
|
||||
// if let c = grColor5 { colors.append(c.cgColor) }
|
||||
// if let c = grColor6 { colors.append(c.cgColor) }
|
||||
|
||||
if colors.count < 2 {
|
||||
colors.append(UIColor.clear.cgColor)
|
||||
colors.append(UIColor.clear.cgColor)
|
||||
} else if colors.count < 1 {
|
||||
if grColor1 != nil {
|
||||
colors.append(UIColor.clear.cgColor)
|
||||
} else {
|
||||
colors.insert(UIColor.clear.cgColor, at: 0)
|
||||
}
|
||||
}
|
||||
|
||||
guard let gradient = CGGradient(colorsSpace: nil,
|
||||
colors: colors as CFArray,
|
||||
locations: nil) else { return }
|
||||
let grDrawsOptions: Bool = true
|
||||
let grPointPercent: Bool = true
|
||||
|
||||
let bMode = CGBlendMode(rawValue: CGBlendMode.RawValue(grBlendMode)) ?? CGBlendMode.sourceAtop
|
||||
|
||||
// bMode = CGBlendMode.screen
|
||||
|
||||
context.setBlendMode(bMode)
|
||||
|
||||
let options: CGGradientDrawingOptions =
|
||||
grDrawsOptions ? [ .drawsBeforeStartLocation, .drawsAfterEndLocation ] : [ ]
|
||||
|
||||
var grEndPointR: CGPoint = grEndPoint
|
||||
var grStartPointR: CGPoint = grStartPoint
|
||||
if grPointPercent {
|
||||
grEndPointR = CGPoint(x: (grEndPoint.x * frame.width), y: (grEndPoint.y * frame.height))
|
||||
grStartPointR = CGPoint(x: (grStartPoint.x * frame.width), y: (grStartPoint.y * frame.height))
|
||||
}
|
||||
|
||||
bezier.close()
|
||||
context.saveGState()
|
||||
bezier.addClip()
|
||||
|
||||
if grRadial {
|
||||
|
||||
let x: CGFloat = (grEndPointR.x - grStartPointR.x)
|
||||
let y: CGFloat = (grEndPointR.y - grStartPointR.y)
|
||||
let distance: CGFloat = sqrt((x * x) + (y * y))
|
||||
|
||||
context.drawRadialGradient(gradient,
|
||||
startCenter: grStartPointR,
|
||||
startRadius: 0,
|
||||
endCenter: grStartPointR,
|
||||
endRadius: distance,
|
||||
options: options)
|
||||
} else {
|
||||
|
||||
context.drawLinearGradient(gradient,
|
||||
start: grStartPointR,
|
||||
end: grEndPointR,
|
||||
options: options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension DesignnGraphView {
|
||||
|
||||
func addInfoLabels() {
|
||||
|
||||
let mmaax = Int(data.max() ?? 0)
|
||||
|
||||
self.layer.addSublayer(getText("0" ,size: 13, position: .init(x: 0, y: bounds.height - 18 )))
|
||||
self.layer.addSublayer(getText("\(mmaax)" ,size: 13, position: .init(x: 0, y: 0 )))
|
||||
self.layer.addSublayer(getText("\(data.count)" ,size: 13, position: .init(x: bounds.width - 30, y: bounds.height - 18 )))
|
||||
|
||||
var start = false
|
||||
var half = false
|
||||
var end = false
|
||||
|
||||
for i in 0..<mmaax {
|
||||
|
||||
|
||||
let y = (( CGFloat(i) / CGFloat(mmaax) ) * (bounds.height - 18))
|
||||
|
||||
let percent = Int((y / bounds.height) * 100)
|
||||
|
||||
var str = "\(100 - percent )%"
|
||||
str = "--"
|
||||
|
||||
if percent >= 25 && !start {
|
||||
start = true
|
||||
self.layer.addSublayer(getText( str ,size: 10, position: .init(x: 0 , y: y - 9 )))
|
||||
self.layer.addSublayer(getText( str ,size: 10, position: .init(x: bounds.width - 30 , y: y - 9 )))
|
||||
}
|
||||
|
||||
if percent >= 50 && !half {
|
||||
half = true
|
||||
str = "=--"
|
||||
|
||||
self.layer.addSublayer(getText(str,size: 10, position: .init(x: 0 , y: y - 9 )))
|
||||
str = "--="
|
||||
self.layer.addSublayer(getText( str ,size: 10, position: .init(x: bounds.width - 30 , y: y - 9 )))
|
||||
}
|
||||
|
||||
|
||||
if percent >= 75 && !end {
|
||||
end = true
|
||||
self.layer.addSublayer(getText(str,size: 10, position: .init(x:0, y:y - 9)))
|
||||
self.layer.addSublayer(getText( str ,size: 10, position: .init(x: bounds.width - 30 , y: y - 9 )))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
start = false
|
||||
half = false
|
||||
end = false
|
||||
|
||||
for i in 0..<data.count {
|
||||
|
||||
let x = (( CGFloat(i) / CGFloat(data.count) ) * (bounds.width - 30))
|
||||
|
||||
let percent = Int((x / bounds.width) * 100)
|
||||
|
||||
var str = "\(percent)%"
|
||||
str = "!"
|
||||
|
||||
if percent >= 25 && !start {
|
||||
start = true
|
||||
self.layer.addSublayer(getText(str,size: 10, position: .init(x: x - 15 , y: bounds.height - 18 )))
|
||||
self.layer.addSublayer(getText(str,size: 10, position: .init(x: x - 15 , y: 5 )))
|
||||
}
|
||||
|
||||
if percent >= 50 && !half {
|
||||
half = true
|
||||
str = ".|."
|
||||
self.layer.addSublayer(getText(str,size: 10, position: .init(x: x - 15 , y: bounds.height - 18 )))
|
||||
str = "'|'"
|
||||
self.layer.addSublayer(getText(str,size: 10, position: .init(x: x - 15 , y: 5 )))
|
||||
}
|
||||
|
||||
|
||||
if percent >= 75 && !end {
|
||||
end = true
|
||||
self.layer.addSublayer(getText(str,size: 10, position: .init(x: x - 15, y: bounds.height - 18 )))
|
||||
self.layer.addSublayer(getText(str,size: 10, position: .init(x: x - 15 , y: 5 )))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UIView {
|
||||
|
||||
func addFill(bezier: UIBezierPath, fillColor: UIColor?) {
|
||||
|
||||
guard let fillColor = fillColor else { return }
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
bezier.close()
|
||||
context.saveGState()
|
||||
fillColor.setFill()
|
||||
bezier.fill()
|
||||
context.restoreGState()
|
||||
}
|
||||
|
||||
}
|
||||
-193
@@ -1,193 +0,0 @@
|
||||
//
|
||||
// DesignnGraphViewLegacy.swift
|
||||
// ContainerControllerSwift_Example
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 04.09.2024.
|
||||
// Copyright © 2024 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@IBDesignable
|
||||
class DesignnGraphViewOld: UIView {
|
||||
|
||||
@IBInspectable var maxValue: Int = 100
|
||||
@IBInspectable var minValue: Int = 0
|
||||
|
||||
@IBInspectable var padding: Int = 10
|
||||
|
||||
@IBInspectable var arrStr: String = ""
|
||||
|
||||
var arrData: [Int] = [10,5,50,70,80,40,35,55,60,62,20,40,70,60,50,90,95]
|
||||
|
||||
|
||||
@IBInspectable var cornerRadius: CGFloat = 0.0
|
||||
@IBInspectable var fillColor: UIColor?
|
||||
@IBInspectable var brColor: UIColor = .clear
|
||||
@IBInspectable var brWidth: CGFloat = 0.0
|
||||
@IBInspectable var brDash: Int = 0
|
||||
|
||||
|
||||
func addFill(bezier: UIBezierPath) {
|
||||
|
||||
guard let fillColor = fillColor else { return }
|
||||
guard let context = UIGraphicsGetCurrentContext() else { return }
|
||||
|
||||
bezier.close()
|
||||
context.saveGState()
|
||||
fillColor.setFill()
|
||||
bezier.fill()
|
||||
context.restoreGState()
|
||||
}
|
||||
|
||||
override func draw(_ rect: CGRect) {
|
||||
super.draw(rect)
|
||||
|
||||
// layer.backgroundColor = fillColor?.cgColor
|
||||
|
||||
let context = UIGraphicsGetCurrentContext()!
|
||||
|
||||
let oval = UIBezierPath(ovalIn: rect)
|
||||
addFill(bezier: oval)
|
||||
|
||||
|
||||
UIColor.green.setStroke()
|
||||
|
||||
oval.lineWidth = 2 * 2
|
||||
oval.stroke()
|
||||
|
||||
//// Color Declarations
|
||||
let gradientColor = UIColor(red: 0.039, green: 0.839, blue: 0.361, alpha: 0.140)
|
||||
let gradientColor2 = UIColor(red: 0.039, green: 0.841, blue: 0.362, alpha: 0.000)
|
||||
let gradientColor3 = UIColor.green
|
||||
let color = UIColor.red
|
||||
|
||||
//// Gradient Declarations
|
||||
// let gradient = CGGradient(colorsSpace: nil, colors: [ gradientColor.cgColor, gradientColor2.cgColor] as CFArray, locations: [0, 1])!
|
||||
//// Rectangle Drawing
|
||||
// let rectanglePath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 70, height: 70))
|
||||
// color.setFill()
|
||||
// rectanglePath.fill()
|
||||
|
||||
|
||||
//// Bezier Drawing
|
||||
let bezierPath = UIBezierPath ()
|
||||
|
||||
UIColor.green.setStroke()
|
||||
bezierPath.lineWidth = 2 * 2
|
||||
|
||||
|
||||
// let result = arrStr.components(separatedBy: ",")
|
||||
//
|
||||
// let newResult = result.map {
|
||||
// Int($0) ?? 0
|
||||
// }
|
||||
|
||||
|
||||
arrData.enumerated().forEach { index, item in
|
||||
let widht = ( (rect.width) - ( CGFloat(padding) * 2))
|
||||
let height = ( (rect.height) - (CGFloat(padding) * 2))
|
||||
|
||||
|
||||
let y = ((( CGFloat(index) / CGFloat(arrData.count) ) * widht) + CGFloat(padding))
|
||||
|
||||
let maxHeight = CGFloat(arrData.max() ?? 0)
|
||||
|
||||
let x = ((( CGFloat(item) / maxHeight) * height) + CGFloat(padding))
|
||||
|
||||
|
||||
bezierPath.move(to: CGPoint(x: x, y: y))
|
||||
}
|
||||
|
||||
|
||||
// bezierPath.move(to: CGPoint(x: 4, y: 34.64))
|
||||
// bezierPath.addLine(to: CGPoint(x: 8.4, y: 34.64))
|
||||
// bezierPath.addLine(to: CGPoint(x: 11.04, y: 32.04))
|
||||
// bezierPath.addLine(to: CGPoint(x: 15.44, y: 32.04))
|
||||
// bezierPath.addLine(to: CGPoint(x: 18.53, y: 29.01))
|
||||
// bezierPath.addLine(to: CGPoint(x: 22.49, y: 29.01))
|
||||
// bezierPath.addLine(to: CGPoint(x: 26.01, y: 34.64))
|
||||
// bezierPath.addLine(to: CGPoint(x: 29.53, y: 37.89))
|
||||
// bezierPath.addLine(to: CGPoint(x: 32.61, y: 37.89))
|
||||
// bezierPath.addLine(to: CGPoint(x: 34.81, y: 34.64))
|
||||
// bezierPath.addLine(to: CGPoint(x: 38.55, y: 34.64))
|
||||
// bezierPath.addLine(to: CGPoint(x: 42.95, y: 25.55))
|
||||
// bezierPath.addLine(to: CGPoint(x: 53.08, y: 25.55))
|
||||
// bezierPath.addLine(to: CGPoint(x: 55.5, y: 21))
|
||||
// bezierPath.addLine(to: CGPoint(x: 61, y: 21))
|
||||
// bezierPath.addLine(to: CGPoint(x: 61, y: 42))
|
||||
// bezierPath.addLine(to: CGPoint(x: 4, y: 42))
|
||||
// bezierPath.addLine(to: CGPoint(x: 4, y: 34.64))
|
||||
|
||||
bezierPath.stroke()
|
||||
// bezierPath.stroke()
|
||||
|
||||
context.restoreGState()
|
||||
// context.restoreGState()
|
||||
|
||||
|
||||
// bezierPath.close()
|
||||
// context.saveGState()
|
||||
// context.restoreGState()
|
||||
|
||||
// bezierPath.close ()
|
||||
// context.saveGState ()
|
||||
// bezierPath.addClip()
|
||||
// context.drawLinearGradient(gradient, start: CGPoint(x: 362.5, y: 84), end: CGPoint(x: 362.5, y: 105), options: [])
|
||||
// context.restoreGState()
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
func getPoints() {
|
||||
|
||||
var arr: [CGPoint] = []
|
||||
|
||||
print(" getPoints width: \(self.width) height: \(self.height)")
|
||||
arrData.enumerated().forEach { index, item in
|
||||
|
||||
let widht = ( (self.width) - ( CGFloat(padding) * 2))
|
||||
let height = ( (self.height) - (CGFloat(padding) * 2))
|
||||
|
||||
|
||||
let y = ((( CGFloat(index) / CGFloat(arrData.count) ) * widht) + CGFloat(padding))
|
||||
|
||||
let maxHeight = CGFloat(arrData.max() ?? 0)
|
||||
|
||||
let x = ((( CGFloat(item) / maxHeight) * height) + CGFloat(padding))
|
||||
|
||||
print(" getPoints ( width: \(widht) height: \(height) maxHeight \(maxHeight)) index: \(index), x: \(x) y: \(y)")
|
||||
|
||||
arr.append(CGPoint(x: x, y: y))
|
||||
// bezierPath.move(to: CGPoint(x: x, y: y))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// func setup() {
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// if let foundView = viewWithTag(55) {
|
||||
// foundView.removeFromSuperview()
|
||||
// }
|
||||
//
|
||||
// let d = DesignFigure_(frame: bounds)
|
||||
// d.backgroundColor = .clear
|
||||
// d.tag = 55
|
||||
// d.cornerRadius = cornerRadius
|
||||
// // d.blur = blur
|
||||
// // d.image = image
|
||||
// // d.imageMode = imageMode
|
||||
// d.fillColor = fillColor
|
||||
// d.brWidth = brWidth
|
||||
// d.brColor = brColor
|
||||
// d.brDash = brDash
|
||||
// insertSubview(d, at: 0)
|
||||
//
|
||||
// }
|
||||
|
||||
// override func layoutSubviews() { setup() }
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
//
|
||||
// DesignnImageView.swift
|
||||
// ContainerControllerSwift_Example
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 04.09.2024.
|
||||
// Copyright © 2024 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@IBDesignable
|
||||
class DesignnImageView: UIView {
|
||||
|
||||
@IBInspectable var cornerRadius: CGFloat = 0.0
|
||||
|
||||
@IBInspectable var fillColor: UIColor?
|
||||
@IBInspectable var image: UIImage?
|
||||
@IBInspectable var imageMode: Int = 1
|
||||
@IBInspectable var blur: CGFloat = 0.0
|
||||
|
||||
|
||||
@IBInspectable var brColor: UIColor = .clear
|
||||
@IBInspectable var brWidth: CGFloat = 0.0
|
||||
@IBInspectable var brDash: Int = 0
|
||||
|
||||
func setup() {
|
||||
|
||||
if let foundView = viewWithTag(55) {
|
||||
foundView.removeFromSuperview()
|
||||
}
|
||||
|
||||
let d = DesignFigure_(frame: bounds)
|
||||
d.backgroundColor = .clear
|
||||
d.tag = 55
|
||||
d.cornerRadius = cornerRadius
|
||||
d.blur = blur
|
||||
d.image = image
|
||||
d.imageMode = imageMode
|
||||
d.fillColor = fillColor
|
||||
d.brWidth = brWidth
|
||||
d.brColor = brColor
|
||||
d.brDash = brDash
|
||||
insertSubview(d, at: 0)
|
||||
|
||||
}
|
||||
|
||||
override func layoutSubviews() { setup() }
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
//
|
||||
// DesignnShadowView.swift
|
||||
// ContainerControllerSwift_Example
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 04.09.2024.
|
||||
// Copyright © 2024 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@IBDesignable
|
||||
class DesignnShadowView: UIView {
|
||||
|
||||
@IBInspectable var cornerRadius: CGFloat = 0.0
|
||||
|
||||
@IBInspectable var fillColor: UIColor?
|
||||
|
||||
|
||||
@IBInspectable var brColor: UIColor = .clear
|
||||
@IBInspectable var brWidth: CGFloat = 0.0
|
||||
@IBInspectable var brDash: Int = 0
|
||||
|
||||
@IBInspectable var shColor: UIColor = .clear
|
||||
@IBInspectable var shRadius: CGFloat = 0.0
|
||||
@IBInspectable var shOffset: CGSize = .zero
|
||||
|
||||
|
||||
func setup() {
|
||||
|
||||
if let foundView = viewWithTag(55) {
|
||||
foundView.removeFromSuperview()
|
||||
}
|
||||
|
||||
let d = DesignFigure_(frame: bounds)
|
||||
d.backgroundColor = .clear
|
||||
d.tag = 55
|
||||
d.cornerRadius = cornerRadius
|
||||
// d.blur = blur
|
||||
// d.image = image
|
||||
// d.imageMode = imageMode
|
||||
d.fillColor = fillColor
|
||||
d.brWidth = brWidth
|
||||
d.brColor = brColor
|
||||
d.brDash = brDash
|
||||
|
||||
|
||||
d.shColor = shColor
|
||||
d.shRadius = shRadius
|
||||
d.shOffset = shOffset
|
||||
insertSubview(d, at: 0)
|
||||
|
||||
}
|
||||
|
||||
override func layoutSubviews() { setup() }
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
//
|
||||
// DesignnView.swift
|
||||
// ContainerControllerSwift_Example
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 04.09.2024.
|
||||
// Copyright © 2024 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@IBDesignable
|
||||
class DesignnView: UIView {
|
||||
|
||||
@IBInspectable var cornerRadius: CGFloat = 0.0
|
||||
|
||||
@IBInspectable var fillColor: UIColor?
|
||||
|
||||
|
||||
@IBInspectable var brColor: UIColor = .clear
|
||||
@IBInspectable var brWidth: CGFloat = 0.0
|
||||
@IBInspectable var brDash: Int = 0
|
||||
|
||||
func setup() {
|
||||
|
||||
if let foundView = viewWithTag(55) {
|
||||
foundView.removeFromSuperview()
|
||||
}
|
||||
|
||||
let d = DesignFigure_(frame: bounds)
|
||||
d.backgroundColor = .clear
|
||||
d.tag = 55
|
||||
d.cornerRadius = cornerRadius
|
||||
// d.blur = blur
|
||||
// d.image = image
|
||||
// d.imageMode = imageMode
|
||||
d.fillColor = fillColor
|
||||
d.brWidth = brWidth
|
||||
d.brColor = brColor
|
||||
d.brDash = brDash
|
||||
insertSubview(d, at: 0)
|
||||
|
||||
}
|
||||
|
||||
// override func layoutSubviews() { setup() }
|
||||
|
||||
}
|
||||
|
||||
-200
@@ -1,200 +0,0 @@
|
||||
//
|
||||
// DesignViewExtentions.swift
|
||||
// FigmaConvertXib
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 20.07.2020.
|
||||
// Copyright © 2020 mrusta. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIView {
|
||||
func add(shadow radius: CGFloat, offset: CGSize, color: UIColor) {
|
||||
layer.shadowOpacity = 1.0
|
||||
layer.shadowColor = color.cgColor
|
||||
layer.shadowOffset = offset
|
||||
layer.shadowRadius = radius
|
||||
}
|
||||
|
||||
func add(border width: CGFloat, color: UIColor) {
|
||||
layer.borderColor = color.cgColor
|
||||
layer.borderWidth = width
|
||||
}
|
||||
|
||||
//MARK: - Blur
|
||||
|
||||
func add(blur: CGFloat, rect: CGRect? = nil, clearCallback: (() -> Void)? = nil) {
|
||||
|
||||
guard blur > 0 else { return }
|
||||
|
||||
layer.shadowOpacity = 0.0
|
||||
var fr = bounds
|
||||
if let rect = rect {
|
||||
fr = CGRect(x: 0, y: 0, width: rect.width, height: rect.height)
|
||||
}
|
||||
|
||||
UIGraphicsBeginImageContext(fr.size)
|
||||
layer.render(in: UIGraphicsGetCurrentContext()!)
|
||||
guard let imgC = UIGraphicsGetImageFromCurrentImageContext() else { return }
|
||||
UIGraphicsEndImageContext()
|
||||
|
||||
self.blur(screen: imgC, blur: blur, clearCallback: clearCallback)
|
||||
}
|
||||
|
||||
func blur(screen: UIImage, blur: CGFloat, clearCallback: (() -> Void)? = nil) {
|
||||
|
||||
guard let ciscreen: CIImage = CIImage(image: screen) else { return }
|
||||
|
||||
guard let filter: CIFilter = CIFilter(name: "CIGaussianBlur") else { return }
|
||||
filter.setDefaults()
|
||||
filter.setValue(ciscreen, forKey: kCIInputImageKey)
|
||||
filter.setValue(blur, forKey: kCIInputRadiusKey)
|
||||
|
||||
let bl2 = ((blur * 2) * -1)
|
||||
let bl4 = (blur * 4)
|
||||
|
||||
let ofW = (layer.shadowOffset.width * 1) * -1
|
||||
let ofH = (layer.shadowOffset.height * 1) * -1
|
||||
|
||||
let ofW2 = (layer.shadowOffset.width * 2)
|
||||
let ofH2 = (layer.shadowOffset.height * 2)
|
||||
|
||||
let contextFrame = CGRect(x: bl2 + ofW,
|
||||
y: bl2 + ofH,
|
||||
width: frame.width + bl4 + ofW2,
|
||||
height: frame.height + bl4 + ofH2)
|
||||
|
||||
let ciContext = CIContext(options: nil)
|
||||
guard let r = filter.value(forKey: kCIOutputImageKey) as? CIImage else { return }
|
||||
guard let cImg = ciContext.createCGImage(r, from: contextFrame) else { return }
|
||||
|
||||
let finalImage = UIImage(cgImage: cImg)
|
||||
|
||||
let imageFrame = CGRect(x: bl2 + ofW,
|
||||
y: bl2 + ofH,
|
||||
width: frame.width + bl4 + ofW2,
|
||||
height: frame.height + bl4 + ofH2)
|
||||
|
||||
let blurImageView = UIImageView(frame: imageFrame)
|
||||
blurImageView.image = finalImage
|
||||
blurImageView.contentMode = .scaleAspectFit
|
||||
|
||||
clearAllFills()
|
||||
|
||||
clearCallback?()
|
||||
|
||||
addSubview(blurImageView)
|
||||
|
||||
}
|
||||
|
||||
//MARK: - Blur Clear All
|
||||
|
||||
func clearAllFills() {
|
||||
|
||||
if let sublayers = layer.sublayers {
|
||||
for layer in sublayers {
|
||||
|
||||
layer.backgroundColor = UIColor.clear.cgColor
|
||||
if let gradientLayer = layer as? CAGradientLayer {
|
||||
gradientLayer.removeFromSuperlayer()
|
||||
} else if layer.name == "InnerShadow" {
|
||||
layer.removeFromSuperlayer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
layer.backgroundColor = UIColor.clear.cgColor
|
||||
|
||||
func clearShadow() {
|
||||
layer.shadowOffset = .zero
|
||||
layer.shadowOpacity = 0.0
|
||||
layer.shadowRadius = 0.0
|
||||
layer.shadowColor = UIColor.clear.cgColor
|
||||
}
|
||||
|
||||
func clearBorder() {
|
||||
layer.borderColor = UIColor.clear.cgColor
|
||||
layer.borderWidth = 0.0
|
||||
}
|
||||
|
||||
clearBorder()
|
||||
}
|
||||
|
||||
//MARK: - Inner Shadow
|
||||
|
||||
func addInnerShadow(color: UIColor,
|
||||
radius: CGFloat,
|
||||
offset: CGSize,
|
||||
cornerRadius: CGFloat,
|
||||
alpha: Float = 1.0) {
|
||||
|
||||
let cornerRadius = self.cornerRadius(cornerRadius)
|
||||
|
||||
let innerShadow = CALayer()
|
||||
innerShadow.name = "InnerShadow"
|
||||
innerShadow.frame = bounds
|
||||
|
||||
let path = UIBezierPath(roundedRect: innerShadow.bounds.insetBy(dx: -bounds.width, dy: -bounds.height), cornerRadius:cornerRadius)
|
||||
let cutout = UIBezierPath(roundedRect: innerShadow.bounds, cornerRadius:cornerRadius).reversing()
|
||||
|
||||
path.append(cutout)
|
||||
innerShadow.shadowPath = path.cgPath
|
||||
innerShadow.masksToBounds = true
|
||||
|
||||
innerShadow.shadowColor = color.cgColor
|
||||
innerShadow.shadowOffset = offset
|
||||
innerShadow.shadowRadius = radius
|
||||
innerShadow.cornerRadius = cornerRadius
|
||||
innerShadow.shadowOpacity = alpha
|
||||
layer.addSublayer(innerShadow)
|
||||
}
|
||||
|
||||
func add(gradient
|
||||
color1: UIColor? = nil,
|
||||
color2: UIColor? = nil,
|
||||
color3: UIColor? = nil,
|
||||
color4: UIColor? = nil,
|
||||
color5: UIColor? = nil,
|
||||
color6: UIColor? = nil,
|
||||
pointStart: CGPoint,
|
||||
pointEnd: CGPoint,
|
||||
cornerRadius: CGFloat) -> CAGradientLayer? {
|
||||
|
||||
if color1 != nil || color2 != nil || color3 != nil || color4 != nil || color5 != nil || color6 != nil {
|
||||
|
||||
var colors: [CGColor] = []
|
||||
// colors.append(fillColor.cgColor)
|
||||
if let color1 = color1 { colors.append(color1.cgColor) }
|
||||
if let color2 = color2 { colors.append(color2.cgColor) }
|
||||
if let color3 = color3 { colors.append(color3.cgColor) }
|
||||
if let color4 = color4 { colors.append(color4.cgColor) }
|
||||
if let color5 = color5 { colors.append(color5.cgColor) }
|
||||
if let color6 = color6 { colors.append(color6.cgColor) }
|
||||
|
||||
let glayer = CAGradientLayer()
|
||||
glayer.name = "Gradient"
|
||||
glayer.frame = bounds
|
||||
glayer.colors = colors
|
||||
glayer.startPoint = pointStart
|
||||
glayer.endPoint = pointEnd
|
||||
glayer.cornerRadius = self.cornerRadius(cornerRadius)
|
||||
layer.insertSublayer(glayer, at: 0)
|
||||
|
||||
layer.backgroundColor = UIColor.clear.cgColor
|
||||
|
||||
return glayer
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
//MARK: - Check CornerRadius
|
||||
|
||||
func cornerRadius(_ cornerRadius: CGFloat) -> CGFloat {
|
||||
let minSize = min(frame.size.width, frame.size.height)
|
||||
let minSizeRadius = (minSize / 2)
|
||||
let radius = ((cornerRadius < 0) || (minSizeRadius < cornerRadius) ? minSizeRadius : cornerRadius)
|
||||
return radius
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
//
|
||||
// Device.swift
|
||||
// Inferential Futures
|
||||
//
|
||||
// Created by Valentin on 22.10.2020.
|
||||
// Copyright © 2020 Valentin Titov. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
fileprivate let kIPad = "iPad"
|
||||
fileprivate let kIPhone = "iPhone"
|
||||
|
||||
enum DeviceType {
|
||||
case iPhoneSE, iPhoneMedium, iPhoneDefault, iPhoneMax, iPhoneX, iPhoneXMax, simulator, iPad97, iPad105, iPad129
|
||||
}
|
||||
|
||||
enum DeviceModel:String {
|
||||
case iPodTouch5, iPodTouch6,
|
||||
iPhone4, iPhone4s, iPhone5, iPhone5c, iPhone5s, iPhoneSE, iPhoneSE2ndGen,
|
||||
iPhone6, iPhone6s, iPhone7, iPhone8,
|
||||
iPhone6Plus, iPhone6sPlus, iPhone7Plus, iPhone8Plus, iPhoneX, iPhoneXS, iPhoneXSMax, iPhoneXR, iPhone11, iPhone11Pro, iPhone11ProMax,
|
||||
iPhone12Mini, iPhone12, iPhone12Pro, iPhone12ProMax,
|
||||
iPadMini, iPadMini2, iPadMini3, iPadMini4, iPadMini5,
|
||||
iPad2, iPad3, iPad4, iPadAir, iPadAir2, iPadPro, iPad5, iPadPro10, iPad2018,
|
||||
iPadPro12Inch, iPadPro12Inch2, iPadPro11,iPadPro12Inch3,
|
||||
appleTV, simulator, unknown
|
||||
}
|
||||
|
||||
open class Device {
|
||||
|
||||
// MARK: - Type
|
||||
|
||||
static public let isIpad = UIDevice.current.userInterfaceIdiom == .pad
|
||||
static public let isIphone = UIDevice.current.userInterfaceIdiom == .phone
|
||||
static public let isRetina = UIScreen.main.scale >= 2.0
|
||||
|
||||
class public var isBigIphone: Bool { get { (isIphone && ScreenSize.screenMax > 568.0) } }
|
||||
class public var isIphoneX: Bool { get { (isIphone && ScreenSize.screenMax > 736.0) } }
|
||||
class public var is12ProMax: Bool { get { (isIphone && ScreenSize.screenMax > 926.0) } }
|
||||
class public var SE: Bool { get { !isBigIphone } }
|
||||
|
||||
static public var isSimulator: Bool { return UIDevice.device == .simulator }
|
||||
}
|
||||
|
||||
extension UIDevice {
|
||||
|
||||
// MARK: - Device Model
|
||||
|
||||
static var modelName: DeviceModel {
|
||||
var systemInfo = utsname()
|
||||
uname(&systemInfo)
|
||||
let machineMirror = Mirror(reflecting: systemInfo.machine)
|
||||
let identifier = machineMirror.children.reduce(String.empty) { identifier, element in
|
||||
guard let value = element.value as? Int8 , value != 0 else { return identifier }
|
||||
return identifier + String(UnicodeScalar(UInt8(value)))
|
||||
}
|
||||
|
||||
switch identifier {
|
||||
case "iPod5,1": return .iPodTouch5
|
||||
case "iPod7,1": return .iPodTouch6
|
||||
case "iPhone3,1", "iPhone3,2", "iPhone3,3": return .iPhone4
|
||||
case "iPhone4,1": return .iPhone4s
|
||||
case "iPhone5,1", "iPhone5,2": return .iPhone5
|
||||
case "iPhone5,3", "iPhone5,4": return .iPhone5c
|
||||
case "iPhone6,1", "iPhone6,2": return .iPhone5s
|
||||
case "iPhone7,2": return .iPhone6
|
||||
case "iPhone7,1": return .iPhone6Plus
|
||||
case "iPhone8,1": return .iPhone6s
|
||||
case "iPhone8,2": return .iPhone6sPlus
|
||||
case "iPhone8,4": return .iPhoneSE
|
||||
case "iPhone9,1", "iPhone9,3": return .iPhone7
|
||||
case "iPhone9,2", "iPhone9,4": return .iPhone7Plus
|
||||
case "iPhone10,1", "iPhone10,3": return .iPhone8
|
||||
case "iPhone10,2", "iPhone10,4": return .iPhone8Plus
|
||||
case "iPhone10,5", "iPhone10,6": return .iPhoneX
|
||||
case "iPhone11,2": return .iPhoneXS
|
||||
case "iPhone11,4", "iPhone11,6": return .iPhoneXSMax
|
||||
case "iPhone11,8": return .iPhoneXR
|
||||
case "iPhone12,1": return .iPhone11
|
||||
case "iPhone12,3": return .iPhone11Pro
|
||||
case "iPhone12,5": return .iPhone11ProMax
|
||||
case "iPhone12,8": return .iPhoneSE2ndGen
|
||||
case "iPhone13,1": return .iPhone12Mini
|
||||
case "iPhone13,2": return .iPhone12
|
||||
case "iPhone13,3": return .iPhone12Pro
|
||||
case "iPhone13,4": return .iPhone12ProMax
|
||||
case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return .iPad2
|
||||
case "iPad3,1", "iPad3,2", "iPad3,3": return .iPad3
|
||||
case "iPad3,4", "iPad3,5", "iPad3,6": return .iPad4
|
||||
case "iPad4,1", "iPad4,2", "iPad4,3": return .iPadAir
|
||||
case "iPad5,3", "iPad5,4": return .iPadAir2
|
||||
case "iPad2,5", "iPad2,6", "iPad2,7": return .iPadMini
|
||||
case "iPad4,4", "iPad4,5", "iPad4,6": return .iPadMini2
|
||||
case "iPad4,7", "iPad4,8", "iPad4,9": return .iPadMini3
|
||||
case "iPad5,1", "iPad5,2": return .iPadMini4
|
||||
case "iPad11,1", "iPad11,2": return .iPadMini5
|
||||
case "iPad6,3", "iPad6,4": return .iPadPro
|
||||
case "iPad6,7", "iPad6,8": return .iPadPro12Inch
|
||||
case "iPad6,11","iPad6,12": return .iPad5
|
||||
case "iPad7,1", "iPad7,2": return .iPadPro12Inch2
|
||||
case "iPad7,3", "iPad7,4": return .iPadPro10
|
||||
case "iPad7,5", "iPad7,6": return .iPad2018
|
||||
case "iPad8,1", "iPad8,2", "iPad8,3", "iPad8,4":return .iPadPro11
|
||||
case "iPad8,5", "iPad8,6", "iPad8,7", "iPad8,8":return .iPadPro12Inch3
|
||||
case "AppleTV1,1","AppleTV2,1","AppleTV3,1",
|
||||
"AppleTV3,2","AppleTV5,3","AppleTV6,2": return .appleTV
|
||||
case "i386", "x86_64", "arm64": return .simulator
|
||||
default: return .unknown
|
||||
}
|
||||
}
|
||||
|
||||
static var idiom: UIUserInterfaceIdiom {
|
||||
get { return UIDevice.current.userInterfaceIdiom }
|
||||
}
|
||||
|
||||
// MARK: - Device Type
|
||||
|
||||
static var device:DeviceType {
|
||||
switch UIDevice.current.userInterfaceIdiom {
|
||||
case .pad:
|
||||
let screenSize = UIScreen.main.bounds.size
|
||||
let height = max(screenSize.width, screenSize.height)
|
||||
switch height {
|
||||
case 1024: return .iPad97
|
||||
case 1112: return .iPad105
|
||||
case 1366: return .iPad129
|
||||
default: return .iPad97
|
||||
}
|
||||
case .phone:
|
||||
switch modelName {
|
||||
case .iPhone5,.iPhone5c,.iPhone5s,.iPhoneSE: return .iPhoneSE
|
||||
case .iPhone6, .iPhone7, .iPhone8, .iPhoneSE2ndGen, .iPhone12Mini: return .iPhoneMedium
|
||||
case .iPhone6Plus, .iPhone6sPlus, .iPhone7Plus, .iPhone8Plus: return .iPhoneMax
|
||||
case .iPhoneX, .iPhoneXS, .iPhone11Pro, .iPhone12Pro: return .iPhoneX
|
||||
case .iPhoneXR,.iPhoneXSMax, .iPhone11, .iPhone11ProMax, .iPhone12, .iPhone12ProMax: return .iPhoneXMax
|
||||
case .simulator : return .simulator
|
||||
default: return .iPhoneDefault
|
||||
}
|
||||
default: return .iPhoneDefault
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
//
|
||||
// Screen.swift
|
||||
// Realme
|
||||
//
|
||||
// Created by Valentin Titov on 04.01.2021.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
// Common screen constants
|
||||
var offset: CGFloat = 16
|
||||
|
||||
var lastNavBarHeight: CGFloat = 0
|
||||
|
||||
struct ScreenSize {
|
||||
static var size:CGSize { get { return UIScreen.main.bounds.size }}
|
||||
static var bounds:CGRect { get { return CGRect(origin: .zero, size: size) }}
|
||||
static var width:CGFloat { get { return size.width }}
|
||||
static var height:CGFloat { get { return size.height }}
|
||||
// static var aspectRatio: CGFloat { get { return size.aspectRatio }}
|
||||
static var screenMax:CGFloat { get { max(width, height) } }
|
||||
static var screenMin:CGFloat { get { min(width, height) } }
|
||||
|
||||
// MARK: - X Padding
|
||||
|
||||
static var isIphoneXTop: CGFloat { get { ( Device.isIphoneX ? 24.0 : 0.0) } }
|
||||
static var isIphoneXBottom: CGFloat { get { ( Device.isIphoneX ? 34.0 : 0.0) } }
|
||||
|
||||
}
|
||||
|
||||
extension UIViewController {
|
||||
|
||||
func getStatusBarHeight() -> CGFloat {
|
||||
var statusBarHeight: CGFloat = 0
|
||||
if #available(iOS 13.0, *) {
|
||||
let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
|
||||
statusBarHeight = window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
|
||||
} else {
|
||||
statusBarHeight = UIApplication.shared.statusBarFrame.height
|
||||
}
|
||||
return statusBarHeight
|
||||
}
|
||||
|
||||
var topbarHeight: CGFloat {
|
||||
|
||||
let statusHeight = getStatusBarHeight()
|
||||
let navHeight = self.navigationController?.navigationBar.frame.height ?? 0.0
|
||||
|
||||
let height: CGFloat = statusHeight + navHeight
|
||||
lastNavBarHeight = height
|
||||
|
||||
return height
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
//
|
||||
// UIView+Round.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Valentin Titov on 07.02.2021.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
//MARK: - Round
|
||||
extension UIView {
|
||||
|
||||
/**
|
||||
Rounds the given set of corners to the specified radius
|
||||
|
||||
- parameter corners: Corners to round
|
||||
- parameter radius: Radius to round to
|
||||
*/
|
||||
func roundRadius(corners: UIRectCorner,
|
||||
radius: CGFloat) {
|
||||
_ = _roundRadius(corners: corners, radius: radius)
|
||||
}
|
||||
|
||||
/**
|
||||
Rounds the given set of corners to the specified radius with a border
|
||||
- parameter corners: Corners to round
|
||||
- parameter radius: Radius to round to
|
||||
- parameter borderColor: The border color
|
||||
- parameter borderWidth: The border width
|
||||
*/
|
||||
func roundRadius(corners: UIRectCorner,
|
||||
radius: CGFloat,
|
||||
borderColor: UIColor,
|
||||
borderWidth: CGFloat) {
|
||||
let mask = _roundRadius(corners: corners, radius: radius)
|
||||
addBorder(mask: mask, borderColor: borderColor, borderWidth: borderWidth)
|
||||
}
|
||||
|
||||
/**
|
||||
Fully rounds an autolayout view (e.g. one with no known frame) with the given diameter and border
|
||||
|
||||
- parameter diameter: The view's diameter
|
||||
- parameter borderColor: The border color
|
||||
- parameter borderWidth: The border width
|
||||
*/
|
||||
func fullyRound(diameter: CGFloat,
|
||||
borderColor: UIColor,
|
||||
borderWidth: CGFloat) {
|
||||
layer.masksToBounds = true
|
||||
layer.cornerRadius = diameter / 2
|
||||
layer.borderWidth = borderWidth
|
||||
layer.borderColor = borderColor.cgColor;
|
||||
}
|
||||
|
||||
@discardableResult func _roundRadius(corners: UIRectCorner,
|
||||
radius: CGFloat) -> CAShapeLayer {
|
||||
let path = UIBezierPath(roundedRect: bounds,
|
||||
byRoundingCorners: corners,
|
||||
cornerRadii: CGSize(width: radius, height: radius))
|
||||
let mask = CAShapeLayer()
|
||||
mask.path = path.cgPath
|
||||
self.layer.mask = mask
|
||||
return mask
|
||||
}
|
||||
|
||||
func addBorder(mask: CAShapeLayer,
|
||||
borderColor: UIColor,
|
||||
borderWidth: CGFloat) {
|
||||
let borderLayer = CAShapeLayer()
|
||||
borderLayer.path = mask.path
|
||||
borderLayer.fillColor = UIColor.clear.cgColor
|
||||
borderLayer.strokeColor = borderColor.cgColor
|
||||
borderLayer.lineWidth = borderWidth
|
||||
borderLayer.frame = bounds
|
||||
layer.addSublayer(borderLayer)
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
//
|
||||
// Alpha.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Valentin Titov on 05.02.2021.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
enum Alpha: CGFloat {
|
||||
case invisible = 0.0
|
||||
case halfTransluent = 0.5
|
||||
case visible = 1.0
|
||||
}
|
||||
|
||||
extension UIView {
|
||||
func setAlpha(_ alpha: Alpha) {
|
||||
self.alpha = alpha.rawValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
//
|
||||
// AutoresizingMask.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 30.05.2021.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIView {
|
||||
|
||||
func maskAll() {
|
||||
self.autoresizingMask = [ .flexibleTopMargin,
|
||||
.flexibleBottomMargin,
|
||||
.flexibleLeftMargin,
|
||||
.flexibleRightMargin,
|
||||
.flexibleWidth,
|
||||
.flexibleHeight,]
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
//
|
||||
// Blur.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 21.05.2021.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Blurberry
|
||||
|
||||
protocol AppSceneProtocol {
|
||||
var window: UIWindow? { get set }
|
||||
}
|
||||
|
||||
private let overBlurTag: Int = 9036164
|
||||
|
||||
//MARK: - OverBlurView
|
||||
extension AppSceneProtocol {
|
||||
|
||||
public func appearOverBlurView() {
|
||||
|
||||
let effect = UIBlurEffect(style: .light)
|
||||
let view = UIVisualEffectView(effect: nil)
|
||||
view.blur.radius = 5.0
|
||||
view.blur.tintColor = .clear
|
||||
view.frame = window!.frame
|
||||
view.tag = overBlurTag
|
||||
|
||||
UIView.animate(withDuration: Speed.ms100.rawValue) {
|
||||
view.effect = effect
|
||||
}
|
||||
|
||||
self.window?.addSubview(view)
|
||||
}
|
||||
|
||||
public func dissappearOverBlurView() {
|
||||
|
||||
mainAsync(delay: Speed.ms100.rawValue) {
|
||||
|
||||
guard let view = self.window?.viewWithTag(overBlurTag) as? UIVisualEffectView else { return }
|
||||
|
||||
UIView.animate(withDuration: Speed.ms100.rawValue,
|
||||
animations: {
|
||||
view.effect = nil
|
||||
}, completion: { _ in
|
||||
view.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
//
|
||||
// Bundle.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Valentin Titov on 02.03.2021.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Bundle {
|
||||
static var appName: String {
|
||||
return Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ?? "KvantMobile"
|
||||
}
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
//
|
||||
// BindableGestureRecognizer.swift
|
||||
// ButtonLayersClickStyle
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 09.03.2022.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
final class BindableGestureRecognizer: UITapGestureRecognizer {
|
||||
private var action: (UITapGestureRecognizer) -> Void
|
||||
|
||||
init(action: @escaping (UITapGestureRecognizer) -> Void) {
|
||||
self.action = action
|
||||
super.init(target: nil, action: nil)
|
||||
self.addTarget(self, action: #selector(execute(_:)))
|
||||
}
|
||||
|
||||
@objc private func execute(_ sender: UITapGestureRecognizer) {
|
||||
action(sender)
|
||||
}
|
||||
}
|
||||
|
||||
-253
@@ -1,253 +0,0 @@
|
||||
//
|
||||
// ButtonAnimationView.swift
|
||||
// ButtonLayersClickStyle
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 09.03.2022.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension CGFloat {
|
||||
static func random() -> CGFloat {
|
||||
return CGFloat(arc4random()) / CGFloat(UInt32.max)
|
||||
}
|
||||
}
|
||||
|
||||
extension UIColor {
|
||||
static func random() -> UIColor {
|
||||
return UIColor(
|
||||
red: .random(),
|
||||
green: .random(),
|
||||
blue: .random(),
|
||||
alpha: 1.0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@IBDesignable
|
||||
class ButtonAnimationView: UIView {
|
||||
|
||||
@IBInspectable var cornerRadius: CGFloat = 0.0
|
||||
@IBInspectable var animationType: Int = 0
|
||||
var animationTypeValue: CGFloat?
|
||||
@IBInspectable var allSubviews: Bool = false
|
||||
@IBInspectable var startClick: Bool = false
|
||||
|
||||
|
||||
var addViews: [UIView]?
|
||||
|
||||
var setupDone = false
|
||||
|
||||
public var type: UIButton.TapType = .alpha(0.5)
|
||||
private var subviewsAnimation = false
|
||||
public var button: UIButton?
|
||||
// public var mainView: UIView?
|
||||
|
||||
|
||||
// override func draw(_ rect: CGRect) {
|
||||
// super.draw(rect)
|
||||
//
|
||||
// updateSubviews()
|
||||
// }
|
||||
|
||||
// MARK: - Initialize
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
// updateSubviews()
|
||||
}
|
||||
|
||||
// public init() {
|
||||
// super.init(frame: .zero)
|
||||
// updateSubviews()
|
||||
// }
|
||||
|
||||
|
||||
|
||||
public init(
|
||||
frame: CGRect,
|
||||
radius: CGFloat = 0.0,
|
||||
animation: Int = 0,
|
||||
value: CGFloat? = nil,
|
||||
addViews: [UIView]? = nil,
|
||||
startClick: Bool = false
|
||||
) {
|
||||
super.init(frame: frame)
|
||||
self.cornerRadius = radius
|
||||
self.animationType = animation
|
||||
self.animationTypeValue = value
|
||||
self.addViews = addViews
|
||||
self.startClick = startClick
|
||||
// updateSubviews()
|
||||
}
|
||||
|
||||
|
||||
// MARK: - layout subViews Update
|
||||
|
||||
override func layoutSubviews() {
|
||||
updateSubviews()
|
||||
}
|
||||
|
||||
public func updateSubviews() {
|
||||
|
||||
if setupDone {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if button == nil {
|
||||
createButton()
|
||||
}
|
||||
// if animationType == 9 {
|
||||
// createMainViewCopy()
|
||||
// }
|
||||
|
||||
if animationType != 0 {
|
||||
|
||||
let type: UIButton.TapType = {
|
||||
switch animationType {
|
||||
case 1: return .alpha(animationTypeValue ?? 0.5)
|
||||
case 2: return .layerGray(animationTypeValue ?? 0.22)
|
||||
case 3: return .pulsate(new: false)
|
||||
case 4: return .pulsate(new: true)
|
||||
case 5: return .shake(new: false)
|
||||
case 6: return .shake(new: true)
|
||||
case 7: return .flash
|
||||
case 8: return .color(value: UIColor.random())
|
||||
case 9: return .androidClickable(dark: false)
|
||||
case 10: return .androidClickable(dark: true)
|
||||
default: return .alpha(0.5)
|
||||
}
|
||||
}()
|
||||
|
||||
setAnimation(type: type)
|
||||
|
||||
if startClick {
|
||||
startClick = false
|
||||
|
||||
let nviews = getViews()
|
||||
button?.onClick(views: nviews, radius: cornerRadius, type: type)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
setupDone = true
|
||||
}
|
||||
|
||||
func getType(value: CGFloat? = nil) -> UIButton.TapType {
|
||||
|
||||
let type: UIButton.TapType = {
|
||||
switch animationType {
|
||||
case 1: return .alpha(value ?? 0.5)
|
||||
case 2: return .layerGray(value ?? 0.22)
|
||||
case 3: return .pulsate(new: false)
|
||||
case 4: return .pulsate(new: true)
|
||||
case 5: return .shake(new: false)
|
||||
case 6: return .shake(new: true)
|
||||
case 7: return .flash
|
||||
case 8: return .color(value: UIColor.random())
|
||||
case 9: return .androidClickable(dark: false)
|
||||
case 10: return .androidClickable(dark: true)
|
||||
default: return .alpha(0.5)
|
||||
}
|
||||
}()
|
||||
return type
|
||||
}
|
||||
|
||||
public func onClick() {
|
||||
button?.onClick(views: getViews(), radius: cornerRadius, type: getType())
|
||||
}
|
||||
|
||||
// public func createMainViewCopy() {
|
||||
// let view = UIView(frame: bounds)
|
||||
// view.backgroundColor = .clear
|
||||
// view.layer.cornerRadius = cornerRadius
|
||||
// view.maskAll()
|
||||
// addSubview(view)
|
||||
// self.mainView = view
|
||||
// }
|
||||
|
||||
public func createButton() {
|
||||
var fr: CGRect = bounds
|
||||
if subviews.count != 0 {
|
||||
let mainView = subviews[0]
|
||||
fr = mainView.frame
|
||||
}
|
||||
|
||||
let btn = UIButton(type: .system)
|
||||
btn.frame = fr
|
||||
btn.backgroundColor = .clear
|
||||
btn.setTitle(nil, for: .normal)
|
||||
|
||||
// btn.contentVerticalAlignment = .center
|
||||
btn.layer.cornerRadius = cornerRadius
|
||||
btn.clipsToBounds = true
|
||||
// btn.maskAll()
|
||||
addSubview(btn)
|
||||
self.button = btn
|
||||
}
|
||||
|
||||
func getViews(views: [UIView]? = nil) -> [UIView] {
|
||||
|
||||
var nviews: [UIView] = []
|
||||
if let views = views {
|
||||
nviews = views
|
||||
} else {
|
||||
if allSubviews {
|
||||
nviews.append(self)
|
||||
subviews.forEach {
|
||||
nviews.append($0)
|
||||
}
|
||||
} else {
|
||||
|
||||
|
||||
|
||||
|
||||
if animationType == 8, let v = button {
|
||||
nviews.append(v)
|
||||
} else if ((animationType == 9) || (animationType == 10)), let v = button {
|
||||
nviews.append(v)
|
||||
} else if subviews.count != 0 {
|
||||
|
||||
if let addViews = addViews {
|
||||
|
||||
nviews = addViews
|
||||
|
||||
// if let tagsID = viewsTagsID {
|
||||
// let tags = tagsID.components(separatedBy: ",")
|
||||
// for str in tags {
|
||||
// let tagNumb = Int(str) ?? 0
|
||||
// for viww in subviews {
|
||||
// if viww.tag == tagNumb {
|
||||
// nviews.append(viww)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
} else {
|
||||
let mainView = subviews[0]
|
||||
nviews.append(mainView)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nviews
|
||||
}
|
||||
|
||||
public func setAnimation(type: UIButton.TapType, views: [UIView]? = nil) {
|
||||
self.type = type
|
||||
// updateSubviews()
|
||||
|
||||
layer.cornerRadius = cornerRadius
|
||||
|
||||
let nviews = getViews(views: views)
|
||||
|
||||
button?.tapHideAnimation(views: nviews, radius: cornerRadius, type: type, callback: { type in
|
||||
if type == .touchUpInside {
|
||||
|
||||
}
|
||||
})
|
||||
subviewsAnimation = true
|
||||
}
|
||||
|
||||
}
|
||||
-70
@@ -1,70 +0,0 @@
|
||||
//
|
||||
// PulseAnimation.swift
|
||||
// ButtonLayersClickStyle
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 09.03.2022.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class PulseAnimation: CALayer {
|
||||
|
||||
var animationGroup = CAAnimationGroup()
|
||||
var animationDuration: TimeInterval = 1.5
|
||||
var radius: CGFloat = 200
|
||||
var numebrOfPulse: Float = Float.infinity
|
||||
|
||||
override init(layer: Any) {
|
||||
super.init(layer: layer)
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
init(numberOfPulse: Float = Float.infinity, radius: CGFloat, postion: CGPoint){
|
||||
super.init()
|
||||
self.backgroundColor = UIColor.black.cgColor
|
||||
self.contentsScale = UIScreen.main.scale
|
||||
self.opacity = 0
|
||||
self.radius = radius
|
||||
self.numebrOfPulse = numberOfPulse
|
||||
self.position = postion
|
||||
|
||||
self.bounds = CGRect(x: 0, y: 0, width: radius*2, height: radius*2)
|
||||
self.cornerRadius = radius
|
||||
|
||||
DispatchQueue.global(qos: .default).async {
|
||||
self.setupAnimationGroup()
|
||||
DispatchQueue.main.async {
|
||||
self.add(self.animationGroup, forKey: "pulse")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func scaleAnimation() -> CABasicAnimation {
|
||||
let scaleAnimaton = CABasicAnimation(keyPath: "transform.scale.xy")
|
||||
scaleAnimaton.fromValue = NSNumber(value: 0)
|
||||
scaleAnimaton.toValue = NSNumber(value: 1)
|
||||
scaleAnimaton.duration = animationDuration
|
||||
return scaleAnimaton
|
||||
}
|
||||
|
||||
func createOpacityAnimation() -> CAKeyframeAnimation {
|
||||
let opacityAnimiation = CAKeyframeAnimation(keyPath: "opacity")
|
||||
opacityAnimiation.duration = animationDuration
|
||||
opacityAnimiation.values = [0.4,0.8,0]
|
||||
opacityAnimiation.keyTimes = [0,0.3,1]
|
||||
return opacityAnimiation
|
||||
}
|
||||
|
||||
func setupAnimationGroup() {
|
||||
self.animationGroup.duration = animationDuration
|
||||
self.animationGroup.repeatCount = numebrOfPulse
|
||||
let defaultCurve = CAMediaTimingFunction(name: CAMediaTimingFunctionName.default)
|
||||
self.animationGroup.timingFunction = defaultCurve
|
||||
self.animationGroup.animations = [scaleAnimation(),createOpacityAnimation()]
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
-255
@@ -1,255 +0,0 @@
|
||||
//
|
||||
// UIButton+AllAnimations.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 20.08.2021.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
// MARK: Animations
|
||||
|
||||
extension UIColor {
|
||||
var inverted: UIColor {
|
||||
var r: CGFloat = 0.0, g: CGFloat = 0.0, b: CGFloat = 0.0, a: CGFloat = 0.0
|
||||
self.getRed(&r, green: &g, blue: &b, alpha: &a)
|
||||
return UIColor(red: (1 - r), green: (1 - g), blue: (1 - b), alpha: a) // Assuming you want the same alpha value.
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - Button extension
|
||||
|
||||
extension UIButton {
|
||||
|
||||
// MARK: - Alpha
|
||||
|
||||
func updateChangeAlpha(with views: [UIView], visible: Alpha, value: CGFloat, duration: Speed?) {
|
||||
|
||||
var alpha: CGFloat = 1.0
|
||||
if visible != .visible {
|
||||
alpha = value
|
||||
}
|
||||
|
||||
if let duration = duration {
|
||||
UIView.animate(with: duration) {
|
||||
for view in views {
|
||||
view.alpha = alpha
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for view in views {
|
||||
view.alpha = alpha
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Layer Gray
|
||||
|
||||
func updateLayerGray(with views: [UIView], cornRadius: CGFloat? = nil, visible: Alpha, value: CGFloat, duration: Speed?) {
|
||||
|
||||
// let filterViews = views
|
||||
let filterViews = views.filter { !(($0 is UIButton) || ($0 is UILabel)) }
|
||||
|
||||
guard let mainView = filterViews.last else { return }
|
||||
let shTag = 31
|
||||
let spechialColor = UIColor(red: 10.0 / 255.0, green: 13.0 / 255.0, blue: 38.0 / 255.0, alpha: value)
|
||||
|
||||
if visible == .visible {
|
||||
|
||||
for v in mainView.subviews {
|
||||
|
||||
if v.tag == shTag {
|
||||
if let duration = duration {
|
||||
UIView.animate(
|
||||
with: duration,
|
||||
animations: {
|
||||
v.alpha = 0
|
||||
},
|
||||
completion: { fin in
|
||||
v.removeFromSuperview()
|
||||
}
|
||||
)
|
||||
} else {
|
||||
v.alpha = 0
|
||||
v.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if mainView.viewWithTag(shTag) == nil {
|
||||
|
||||
var radius = cornRadius ?? mainView.layer.cornerRadius
|
||||
if radius == 0 {
|
||||
for sv in mainView.subviews {
|
||||
if sv.layer.cornerRadius != 0 {
|
||||
radius = mainView.layer.cornerRadius
|
||||
}
|
||||
if let desFig = mainView as? DesignFigure {
|
||||
radius = desFig.cornerRadius
|
||||
if radius == -1 {
|
||||
let minSize = min(mainView.frame.width, mainView.bounds.height)
|
||||
radius = minSize / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if mainView.viewWithTag(shTag) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
let shadowView = UIView(frame: mainView.bounds)
|
||||
shadowView.tag = shTag
|
||||
shadowView.backgroundColor = spechialColor
|
||||
shadowView.layer.cornerRadius = radius
|
||||
mainView.addSubview(shadowView)
|
||||
shadowView.alpha = ((duration == nil) ? 1 : 0)
|
||||
if let duration = duration {
|
||||
if duration == .zero {
|
||||
shadowView.alpha = 1
|
||||
} else {
|
||||
UIView.animate(with: duration) {
|
||||
shadowView.alpha = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - View extension
|
||||
|
||||
extension UIView {
|
||||
|
||||
// MARK: - Flash
|
||||
|
||||
func flash(duration: Speed = .ms200) {
|
||||
|
||||
let flash = CABasicAnimation(keyPath: "opacity")
|
||||
flash.duration = duration.rawValue
|
||||
flash.fromValue = 1
|
||||
flash.toValue = 0.1
|
||||
flash.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
|
||||
flash.autoreverses = true
|
||||
flash.repeatCount = 3
|
||||
|
||||
layer.add(flash, forKey: nil)
|
||||
}
|
||||
|
||||
|
||||
func inversionColor(duration: Speed = .ms300, cornRadius: CGFloat? = nil, value: UIColor) { // .s1
|
||||
|
||||
let v = UIView(frame: frame)
|
||||
v.backgroundColor = value.inverted
|
||||
v.layer.compositingFilter = "differenceBlendMode"
|
||||
addSubview(v)
|
||||
}
|
||||
|
||||
// MARK: - Change Color
|
||||
|
||||
func animationColor(duration: Speed = .ms300, cornRadius: CGFloat? = nil, value: UIColor) { // .s1
|
||||
|
||||
let color = CABasicAnimation(keyPath: "backgroundColor")
|
||||
let fromColor = backgroundColor ?? .clear
|
||||
color.fromValue = value.cgColor //UIColor.white.cgColor
|
||||
color.toValue = fromColor.cgColor
|
||||
color.duration = duration.rawValue
|
||||
color.beginTime = CACurrentMediaTime() + 0.1
|
||||
color.autoreverses = false
|
||||
|
||||
// if let r = cornRadius {
|
||||
// layer.cornerRadius = r
|
||||
// }
|
||||
|
||||
|
||||
layer.add(color, forKey: "animationColor")
|
||||
}
|
||||
|
||||
// MARK: - Pulsate
|
||||
|
||||
func pulsate(duration: Speed = .ms200) {
|
||||
|
||||
let pulse = CASpringAnimation(keyPath: "transform.scale")
|
||||
pulse.duration = duration.rawValue
|
||||
pulse.fromValue = 1.0
|
||||
pulse.toValue = 0.85
|
||||
pulse.autoreverses = true
|
||||
pulse.repeatCount = 2
|
||||
pulse.initialVelocity = 0.5
|
||||
|
||||
|
||||
layer.add(pulse, forKey: "pulse")
|
||||
}
|
||||
|
||||
// MARK: - Pulsate 2
|
||||
|
||||
func pulsateNew(visible: Alpha) {
|
||||
if visible == .visible {
|
||||
animate(self, transform: .identity)
|
||||
} else {
|
||||
animate(self, transform: CGAffineTransform.identity.scaledBy(x: 0.85, y: 0.85))
|
||||
}
|
||||
}
|
||||
|
||||
private func animate(_ view: UIView, transform: CGAffineTransform) {
|
||||
UIView.animate(withDuration: 0.4,
|
||||
delay: 0,
|
||||
usingSpringWithDamping: 0.5,
|
||||
initialSpringVelocity: 3,
|
||||
options: [.curveEaseInOut],
|
||||
animations: {
|
||||
view.transform = transform
|
||||
}, completion: nil)
|
||||
}
|
||||
|
||||
// MARK: - Shake
|
||||
|
||||
func shake() {
|
||||
let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
|
||||
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
|
||||
animation.duration = 0.6
|
||||
animation.values = [-20.0, 20.0, -20.0, 20.0, -10.0, 10.0, -5.0, 5.0, 0.0 ]
|
||||
layer.add(animation, forKey: "shake")
|
||||
}
|
||||
|
||||
// MARK: - Shake 2
|
||||
|
||||
func shakeNew(duration: Speed = .ms50) {
|
||||
|
||||
let shake = CABasicAnimation(keyPath: "position")
|
||||
shake.duration = duration.rawValue
|
||||
shake.repeatCount = 2
|
||||
shake.autoreverses = true
|
||||
|
||||
let fromPoint = CGPoint(x: center.x - 5, y: center.y)
|
||||
let fromValue = NSValue(cgPoint: fromPoint)
|
||||
|
||||
let toPoint = CGPoint(x: center.x + 5, y: center.y)
|
||||
let toValue = NSValue(cgPoint: toPoint)
|
||||
|
||||
shake.fromValue = fromValue
|
||||
shake.toValue = toValue
|
||||
|
||||
layer.add(shake, forKey: "position")
|
||||
}
|
||||
|
||||
// MARK: - Android Pulse
|
||||
|
||||
func androidPulseAnimation(duration: Speed = .ms1, dark: Bool, value: CGFloat? = nil, position: CGPoint) {
|
||||
|
||||
var color = dark ? #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0.2786076018) : #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
|
||||
if let alpha = value {
|
||||
color = color.withAlphaComponent(alpha)
|
||||
}
|
||||
|
||||
let pulse = PulseAnimation(numberOfPulse: 1, radius: 200, postion: position)
|
||||
pulse.animationDuration = duration.rawValue
|
||||
pulse.backgroundColor = color.cgColor// #colorLiteral(red: 0.05282949957, green: 0.5737867104, blue: 1, alpha: 1)
|
||||
layer.insertSublayer(pulse, below: layer)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-206
@@ -1,206 +0,0 @@
|
||||
//
|
||||
// ViewAnimationSelect.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 22.06.2021.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIButton {
|
||||
|
||||
// MARK: Tap Animation Type
|
||||
|
||||
static let setTag = 963
|
||||
|
||||
enum TapType {
|
||||
case alpha(_ value: CGFloat) // 0.5
|
||||
case layerGray(_ value: CGFloat = 0.1845) // 0.1845 add black shadow
|
||||
case pulsate(new: Bool = false)
|
||||
case shake(new: Bool = false)
|
||||
case flash
|
||||
case color(value: UIColor = .red)
|
||||
case androidClickable(dark: Bool = false)
|
||||
}
|
||||
|
||||
// MARK: Set
|
||||
|
||||
func tapHideAnimation(
|
||||
view: UIView?,
|
||||
type: TapType = .alpha(0.0),
|
||||
hideSpeed: Speed? = .ms100,
|
||||
callback: ((UIControl.Event) -> Void)? = nil
|
||||
) {
|
||||
guard let view = view else { return }
|
||||
tapHideAnimation(views: [view], type: type, callback: callback)
|
||||
}
|
||||
|
||||
func tapHideAnimation(
|
||||
views: [UIView],
|
||||
radius: CGFloat? = nil,
|
||||
type: TapType = .alpha(0.0),
|
||||
hideSpeed: Speed? = .ms100,
|
||||
callback: ((UIControl.Event) -> Void)? = nil
|
||||
) {
|
||||
|
||||
switch type {
|
||||
case .androidClickable(let dark): do {
|
||||
guard let mainView = views.last else { return }
|
||||
|
||||
var tapAdded: Bool = false
|
||||
gestureRecognizers?.forEach {
|
||||
if $0 is UITapGestureRecognizer {
|
||||
tapAdded = true
|
||||
}
|
||||
}
|
||||
if !tapAdded {
|
||||
let tap = BindableGestureRecognizer { [weak self] sender in
|
||||
|
||||
let touchPoint = sender.location(in: mainView)
|
||||
|
||||
guard let dur: Speed = self?.defaultDuration(type: .androidClickable(dark: dark)) else { return }
|
||||
self?.androidPulseAnimation(duration: dur, dark: dark, position: touchPoint)
|
||||
|
||||
}
|
||||
mainView.addGestureRecognizer(tap)
|
||||
}
|
||||
}
|
||||
default: break
|
||||
}
|
||||
|
||||
|
||||
// if tag != UIButton.setTag { return }
|
||||
// tag = UIButton.setTag
|
||||
|
||||
tap(for: .touchDown) { [weak self] in
|
||||
callback?(.touchDown)
|
||||
Logs.add(".touchDown")
|
||||
self?.hideAnimation(with: views, radius: radius, type: type, event: .touchDown, duration: hideSpeed)
|
||||
}
|
||||
tap(for: .touchUpInside) { [weak self] in
|
||||
callback?(.touchUpInside)
|
||||
Logs.add(".touchUpInside")
|
||||
self?.hideAnimation(with: views, radius: radius, visible: .visible, type: type, event: .touchUpInside)
|
||||
}
|
||||
tap(for: .touchUpOutside) { [weak self] in
|
||||
callback?(.touchUpOutside)
|
||||
Logs.add(".touchUpOutside")
|
||||
self?.hideAnimation(with: views, radius: radius, visible: .visible, type: type, event: .touchUpOutside)
|
||||
}
|
||||
tap(for: .touchCancel) { [weak self] in
|
||||
callback?(.touchCancel)
|
||||
Logs.add(".touchCancel")
|
||||
self?.hideAnimation(with: views, radius: radius, visible: .visible, type: type, event: .touchCancel)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - onClick
|
||||
|
||||
func onClick(
|
||||
views: [UIView],
|
||||
radius: CGFloat? = nil,
|
||||
type: TapType = .alpha(0.0),
|
||||
hideSpeed: Speed? = .ms100,
|
||||
callback: ((UIControl.Event) -> Void)? = nil
|
||||
) {
|
||||
main(delay: 0.1) { [weak self] in
|
||||
self?.hideAnimation(with: views, radius: radius, type: type, event: .touchDown, duration: hideSpeed)
|
||||
main(delay: 0.35) { [weak self] in
|
||||
self?.hideAnimation(with: views, radius: radius, visible: .visible, type: type, event: .touchUpInside)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@objc func handleTap(_ sender: UITapGestureRecognizer? = nil) {
|
||||
guard let touchPoint = sender?.location(in: superview) else { return }
|
||||
|
||||
let dur: Speed = defaultDuration(type: .androidClickable(dark: false))
|
||||
androidPulseAnimation(duration: dur, dark: false, position: touchPoint)
|
||||
}
|
||||
|
||||
// MARK: - De-Select
|
||||
|
||||
func deselected(_ views: [UIView]) {
|
||||
hideAnimation(
|
||||
with: views,
|
||||
visible: .visible
|
||||
)
|
||||
}
|
||||
|
||||
func defaultDuration(type: TapType) -> Speed {
|
||||
switch type {
|
||||
case .alpha(_), .layerGray(_): return .ms300
|
||||
case .pulsate(_), .flash: return .ms200
|
||||
case .shake(_): return .ms50
|
||||
case .color(_): return .ms300
|
||||
case .androidClickable(_): return .s1
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Animation Filter
|
||||
|
||||
func hideAnimation(
|
||||
with views: [UIView],
|
||||
radius: CGFloat? = nil,
|
||||
visible: Alpha = .invisible,
|
||||
type: TapType = .alpha(0.0),
|
||||
event: UIControl.Event = .touchUpInside,
|
||||
duration: Speed? = nil
|
||||
) {
|
||||
|
||||
let dur: Speed = defaultDuration(type: type)
|
||||
switch type {
|
||||
case .alpha(let value):
|
||||
updateChangeAlpha(with: views, visible: visible, value: value, duration: dur)
|
||||
case .layerGray(let value):
|
||||
if event == .touchDown {
|
||||
updateLayerGray(with: views, cornRadius: radius, visible: .invisible, value: value, duration: nil)
|
||||
} else {
|
||||
updateLayerGray(with: views, cornRadius: radius, visible: .visible, value: value, duration: dur)
|
||||
}
|
||||
default: break
|
||||
}
|
||||
|
||||
views.forEach {
|
||||
switch type {
|
||||
case .flash: $0.flash(duration: dur)
|
||||
case .color(let value):
|
||||
if event == .touchDown
|
||||
,$0 is UIButton
|
||||
// ,!(($0 is UIButton) || ($0 is UILabel))
|
||||
{
|
||||
$0.animationColor(duration: dur, cornRadius: radius, value: value)
|
||||
}
|
||||
case .pulsate(let new):
|
||||
if new { $0.pulsateNew(visible: visible) }
|
||||
else { if event == .touchDown { $0.pulsate(duration: dur) } }
|
||||
case .shake(let new):
|
||||
if new { $0.shake() }
|
||||
else { $0.shakeNew(duration: dur) }
|
||||
// case .androidClickable:
|
||||
// androidPulseAnimation(duration: dur)
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension UIControl.Event {
|
||||
|
||||
func strName() -> String {
|
||||
return enevtName(self)
|
||||
}
|
||||
|
||||
func enevtName(_ event: UIControl.Event) -> String {
|
||||
switch event {
|
||||
case .touchDown: return "touch.Down"
|
||||
case .touchCancel: return "touch.Cancel"
|
||||
case .touchUpOutside: return "touch.Up.Outside"
|
||||
case .touchUpInside: return "touch.Up.Inside"
|
||||
default: return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
//
|
||||
// CALayer+Animate.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Valentin Titov on 04.02.2021.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension CALayer {
|
||||
|
||||
public func animate() -> CALayerAnimate {
|
||||
return CALayerAnimate(layer: self)
|
||||
}
|
||||
}
|
||||
|
||||
public class CALayerAnimate {
|
||||
|
||||
private var animations: [String: CAAnimation]
|
||||
private var duration: CFTimeInterval
|
||||
let layer: CALayer
|
||||
|
||||
init(layer: CALayer) {
|
||||
self.animations = [String: CAAnimation]()
|
||||
self.duration = 0.25 // second
|
||||
self.layer = layer
|
||||
}
|
||||
|
||||
public func shadowOpacity(shadowOpacity: Float) -> CALayerAnimate {
|
||||
let key = "shadowOpacity"
|
||||
let animation = CABasicAnimation(keyPath: key)
|
||||
animation.fromValue = layer.shadowOpacity
|
||||
animation.toValue = shadowOpacity
|
||||
animation.isRemovedOnCompletion = false
|
||||
animation.fillMode = .forwards
|
||||
animations[key] = animation
|
||||
return self
|
||||
}
|
||||
|
||||
public func shadowRadius(shadowRadius: CGFloat) -> CALayerAnimate {
|
||||
let key = "shadowRadius"
|
||||
let animation = CABasicAnimation(keyPath: key)
|
||||
animation.fromValue = layer.shadowRadius
|
||||
animation.toValue = shadowRadius
|
||||
animation.isRemovedOnCompletion = false
|
||||
animation.fillMode = CAMediaTimingFillMode.forwards
|
||||
animations[key] = animation
|
||||
return self
|
||||
}
|
||||
|
||||
public func shadowOffsetX(shadowOffsetX: CGFloat) -> CALayerAnimate {
|
||||
let key = "shadowOffset"
|
||||
|
||||
var toValue: CGSize
|
||||
if let currentAnimation = animations[key] as? CABasicAnimation, let currentValue = currentAnimation.toValue {
|
||||
toValue = (currentValue as AnyObject).cgSizeValue
|
||||
} else {
|
||||
toValue = .zero
|
||||
}
|
||||
toValue.width = shadowOffsetX
|
||||
|
||||
let animation = CABasicAnimation(keyPath: key)
|
||||
animation.fromValue = NSValue(cgSize: layer.shadowOffset)
|
||||
animation.toValue = NSValue(cgSize: toValue)
|
||||
animation.isRemovedOnCompletion = false
|
||||
animation.fillMode = CAMediaTimingFillMode.forwards
|
||||
animations[key] = animation
|
||||
return self
|
||||
}
|
||||
|
||||
public func shadowOffsetY(shadowOffsetY: CGFloat) -> CALayerAnimate {
|
||||
let key = "shadowOffset"
|
||||
|
||||
var toValue: CGSize
|
||||
if let currentAnimation = animations[key] as? CABasicAnimation, let currentValue = currentAnimation.toValue {
|
||||
toValue = (currentValue as AnyObject).cgSizeValue
|
||||
} else {
|
||||
toValue = .zero
|
||||
}
|
||||
toValue.height = shadowOffsetY
|
||||
|
||||
let animation = CABasicAnimation(keyPath: key)
|
||||
animation.fromValue = NSValue(cgSize: layer.shadowOffset)
|
||||
animation.toValue = NSValue(cgSize: toValue)
|
||||
animation.isRemovedOnCompletion = false
|
||||
animation.fillMode = CAMediaTimingFillMode.forwards
|
||||
animations[key] = animation
|
||||
return self
|
||||
}
|
||||
|
||||
public func duration(duration: CFTimeInterval) -> CALayerAnimate {
|
||||
self.duration = duration
|
||||
return self
|
||||
}
|
||||
|
||||
public func start() {
|
||||
for (key, animation) in animations {
|
||||
animation.duration = duration
|
||||
layer.removeAnimation(forKey: key)
|
||||
layer.add(animation, forKey: key)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
//
|
||||
// CallPhone.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 24.05.2021.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
class CallPhone {
|
||||
|
||||
class func call(phoneNumber:String) {
|
||||
let cleanPhoneNumber = phoneNumber.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "")
|
||||
let urlString:String = "tel://\(cleanPhoneNumber)"
|
||||
if let phoneCallURL = URL(string: urlString) {
|
||||
if (UIApplication.shared.canOpenURL(phoneCallURL)) {
|
||||
UIApplication.shared.open(phoneCallURL, options: [:], completionHandler: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
//
|
||||
// Cell.swift
|
||||
// FigmaConvertXib
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 08.08.2020.
|
||||
// Copyright © 2020 mrusta. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UITableViewCell {
|
||||
|
||||
func separator(hide: Bool) {
|
||||
separatorInset = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: hide ? CGFloat(Double.greatestFiniteMagnitude) : 0.0)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
//
|
||||
// Colors.swift
|
||||
// Dieta
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 23.01.2022.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
extension UIColor {
|
||||
|
||||
// 16진수로 컬러값 세팅
|
||||
convenience init(hex: Int, alpha: CGFloat = 1.0) {
|
||||
let newRed = CGFloat((hex >> 16) & 0xff) / 255
|
||||
let newGreen = CGFloat((hex >> 08) & 0xff) / 255
|
||||
let newBlue = CGFloat((hex >> 00) & 0xff) / 255
|
||||
|
||||
self.init(red:newRed, green:newGreen, blue:newBlue, alpha:alpha)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
//
|
||||
// Date.swift
|
||||
// CarLoan
|
||||
//
|
||||
// Created by Valentin Titov on 28/11/2019.
|
||||
// Copyright © 2019 Valentin Titov. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum DateFormatType: String {
|
||||
case shortSlash = "dd/MM/yyyy"
|
||||
case shortDot = "dd.MM.yyyy"
|
||||
case shortHyphen = "yyyy-MM-dd"
|
||||
case utc = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
|
||||
case dayMonth = "d MMMM"
|
||||
}
|
||||
|
||||
extension Date {
|
||||
func formatted(by type: DateFormatType) -> String {
|
||||
return toString(with: type.rawValue)
|
||||
}
|
||||
|
||||
func toString(with dateFormat: String, ru: Bool = false) -> String {
|
||||
let formatter = DateFormatter()
|
||||
if ru { formatter.locale = Locale(identifier: "ru_RU") }
|
||||
formatter.dateFormat = dateFormat
|
||||
return formatter.string(from: self)
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
func localDateAsString(with dateFormat: DateFormatType = .shortHyphen) -> String {
|
||||
if let date = localDate(dateFormat: dateFormat) {
|
||||
return date.toString(with: dateFormat.rawValue)
|
||||
}
|
||||
return .empty
|
||||
}
|
||||
|
||||
func localDate(dateFormat: DateFormatType = .shortHyphen) -> Date? {
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.dateFormat = dateFormat.rawValue
|
||||
dateFormatter.timeZone = TimeZone.init(abbreviation: "UTC")
|
||||
let date = dateFormatter.date(from: self)
|
||||
return date
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
//
|
||||
// Device.swift
|
||||
// Inferential Futures
|
||||
//
|
||||
// Created by Valentin on 22.10.2020.
|
||||
// Copyright © 2020 Valentin Titov. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
fileprivate let kIPad = "iPad"
|
||||
fileprivate let kIPhone = "iPhone"
|
||||
|
||||
enum DeviceType {
|
||||
case iPhoneSE, iPhoneMedium, iPhoneDefault, iPhoneMax, iPhoneX, iPhoneXMax, simulator, iPad97, iPad105, iPad129
|
||||
}
|
||||
|
||||
enum DeviceModel:String {
|
||||
case iPodTouch5, iPodTouch6,
|
||||
iPhone4, iPhone4s, iPhone5, iPhone5c, iPhone5s, iPhoneSE, iPhoneSE2ndGen,
|
||||
iPhone6, iPhone6s, iPhone7, iPhone8,
|
||||
iPhone6Plus, iPhone6sPlus, iPhone7Plus, iPhone8Plus, iPhoneX, iPhoneXS, iPhoneXSMax, iPhoneXR, iPhone11, iPhone11Pro, iPhone11ProMax,
|
||||
iPhone12Mini, iPhone12, iPhone12Pro, iPhone12ProMax,
|
||||
iPadMini, iPadMini2, iPadMini3, iPadMini4, iPadMini5,
|
||||
iPad2, iPad3, iPad4, iPadAir, iPadAir2, iPadPro, iPad5, iPadPro10, iPad2018,
|
||||
iPadPro12Inch, iPadPro12Inch2, iPadPro11,iPadPro12Inch3,
|
||||
appleTV, simulator, unknown
|
||||
}
|
||||
|
||||
open class Device {
|
||||
|
||||
// MARK: - Type
|
||||
|
||||
static public let isIpad = UIDevice.current.userInterfaceIdiom == .pad
|
||||
static public let isIphone = UIDevice.current.userInterfaceIdiom == .phone
|
||||
static public let isRetina = UIScreen.main.scale >= 2.0
|
||||
|
||||
class public var isBigIphone: Bool { get { (isIphone && ScreenSize.screenMax > 568.0) } }
|
||||
class public var isIphoneX: Bool { get { (isIphone && ScreenSize.screenMax > 736.0) } }
|
||||
class public var is12ProMax: Bool { get { (isIphone && ScreenSize.screenMax > 926.0) } }
|
||||
class public var SE: Bool { get { !isBigIphone } }
|
||||
|
||||
static public var isSimulator: Bool { return UIDevice.device == .simulator }
|
||||
}
|
||||
|
||||
extension UIDevice {
|
||||
|
||||
// MARK: - Device Model
|
||||
|
||||
static var modelName: DeviceModel {
|
||||
var systemInfo = utsname()
|
||||
uname(&systemInfo)
|
||||
let machineMirror = Mirror(reflecting: systemInfo.machine)
|
||||
let identifier = machineMirror.children.reduce(String.empty) { identifier, element in
|
||||
guard let value = element.value as? Int8 , value != 0 else { return identifier }
|
||||
return identifier + String(UnicodeScalar(UInt8(value)))
|
||||
}
|
||||
|
||||
switch identifier {
|
||||
case "iPod5,1": return .iPodTouch5
|
||||
case "iPod7,1": return .iPodTouch6
|
||||
case "iPhone3,1", "iPhone3,2", "iPhone3,3": return .iPhone4
|
||||
case "iPhone4,1": return .iPhone4s
|
||||
case "iPhone5,1", "iPhone5,2": return .iPhone5
|
||||
case "iPhone5,3", "iPhone5,4": return .iPhone5c
|
||||
case "iPhone6,1", "iPhone6,2": return .iPhone5s
|
||||
case "iPhone7,2": return .iPhone6
|
||||
case "iPhone7,1": return .iPhone6Plus
|
||||
case "iPhone8,1": return .iPhone6s
|
||||
case "iPhone8,2": return .iPhone6sPlus
|
||||
case "iPhone8,4": return .iPhoneSE
|
||||
case "iPhone9,1", "iPhone9,3": return .iPhone7
|
||||
case "iPhone9,2", "iPhone9,4": return .iPhone7Plus
|
||||
case "iPhone10,1", "iPhone10,3": return .iPhone8
|
||||
case "iPhone10,2", "iPhone10,4": return .iPhone8Plus
|
||||
case "iPhone10,5", "iPhone10,6": return .iPhoneX
|
||||
case "iPhone11,2": return .iPhoneXS
|
||||
case "iPhone11,4", "iPhone11,6": return .iPhoneXSMax
|
||||
case "iPhone11,8": return .iPhoneXR
|
||||
case "iPhone12,1": return .iPhone11
|
||||
case "iPhone12,3": return .iPhone11Pro
|
||||
case "iPhone12,5": return .iPhone11ProMax
|
||||
case "iPhone12,8": return .iPhoneSE2ndGen
|
||||
case "iPhone13,1": return .iPhone12Mini
|
||||
case "iPhone13,2": return .iPhone12
|
||||
case "iPhone13,3": return .iPhone12Pro
|
||||
case "iPhone13,4": return .iPhone12ProMax
|
||||
case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return .iPad2
|
||||
case "iPad3,1", "iPad3,2", "iPad3,3": return .iPad3
|
||||
case "iPad3,4", "iPad3,5", "iPad3,6": return .iPad4
|
||||
case "iPad4,1", "iPad4,2", "iPad4,3": return .iPadAir
|
||||
case "iPad5,3", "iPad5,4": return .iPadAir2
|
||||
case "iPad2,5", "iPad2,6", "iPad2,7": return .iPadMini
|
||||
case "iPad4,4", "iPad4,5", "iPad4,6": return .iPadMini2
|
||||
case "iPad4,7", "iPad4,8", "iPad4,9": return .iPadMini3
|
||||
case "iPad5,1", "iPad5,2": return .iPadMini4
|
||||
case "iPad11,1", "iPad11,2": return .iPadMini5
|
||||
case "iPad6,3", "iPad6,4": return .iPadPro
|
||||
case "iPad6,7", "iPad6,8": return .iPadPro12Inch
|
||||
case "iPad6,11","iPad6,12": return .iPad5
|
||||
case "iPad7,1", "iPad7,2": return .iPadPro12Inch2
|
||||
case "iPad7,3", "iPad7,4": return .iPadPro10
|
||||
case "iPad7,5", "iPad7,6": return .iPad2018
|
||||
case "iPad8,1", "iPad8,2", "iPad8,3", "iPad8,4":return .iPadPro11
|
||||
case "iPad8,5", "iPad8,6", "iPad8,7", "iPad8,8":return .iPadPro12Inch3
|
||||
case "AppleTV1,1","AppleTV2,1","AppleTV3,1",
|
||||
"AppleTV3,2","AppleTV5,3","AppleTV6,2": return .appleTV
|
||||
case "i386", "x86_64", "arm64": return .simulator
|
||||
default: return .unknown
|
||||
}
|
||||
}
|
||||
|
||||
static var idiom: UIUserInterfaceIdiom {
|
||||
get { return UIDevice.current.userInterfaceIdiom }
|
||||
}
|
||||
|
||||
// MARK: - Device Type
|
||||
|
||||
static var device:DeviceType {
|
||||
switch UIDevice.current.userInterfaceIdiom {
|
||||
case .pad:
|
||||
let screenSize = UIScreen.main.bounds.size
|
||||
let height = max(screenSize.width, screenSize.height)
|
||||
switch height {
|
||||
case 1024: return .iPad97
|
||||
case 1112: return .iPad105
|
||||
case 1366: return .iPad129
|
||||
default: return .iPad97
|
||||
}
|
||||
case .phone:
|
||||
switch modelName {
|
||||
case .iPhone5,.iPhone5c,.iPhone5s,.iPhoneSE: return .iPhoneSE
|
||||
case .iPhone6, .iPhone7, .iPhone8, .iPhoneSE2ndGen, .iPhone12Mini: return .iPhoneMedium
|
||||
case .iPhone6Plus, .iPhone6sPlus, .iPhone7Plus, .iPhone8Plus: return .iPhoneMax
|
||||
case .iPhoneX, .iPhoneXS, .iPhone11Pro, .iPhone12Pro: return .iPhoneX
|
||||
case .iPhoneXR,.iPhoneXSMax, .iPhone11, .iPhone11ProMax, .iPhone12, .iPhone12ProMax: return .iPhoneXMax
|
||||
case .simulator : return .simulator
|
||||
default: return .iPhoneDefault
|
||||
}
|
||||
default: return .iPhoneDefault
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
//
|
||||
// Screen.swift
|
||||
// Realme
|
||||
//
|
||||
// Created by Valentin Titov on 04.01.2021.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
// Common screen constants
|
||||
var offset: CGFloat = 16
|
||||
|
||||
var lastNavBarHeight: CGFloat = 0
|
||||
|
||||
struct ScreenSize {
|
||||
static var size:CGSize { get { return UIScreen.main.bounds.size }}
|
||||
static var bounds:CGRect { get { return CGRect(origin: .zero, size: size) }}
|
||||
static var width:CGFloat { get { return size.width }}
|
||||
static var height:CGFloat { get { return size.height }}
|
||||
static var aspectRatio: CGFloat { get { return size.aspectRatio }}
|
||||
static var screenMax:CGFloat { get { max(width, height) } }
|
||||
static var screenMin:CGFloat { get { min(width, height) } }
|
||||
|
||||
// MARK: - X Padding
|
||||
|
||||
static var isIphoneXTop: CGFloat { get { ( Device.isIphoneX ? 24.0 : 0.0) } }
|
||||
static var isIphoneXBottom: CGFloat { get { ( Device.isIphoneX ? 34.0 : 0.0) } }
|
||||
|
||||
}
|
||||
|
||||
extension UIViewController {
|
||||
|
||||
func getStatusBarHeight() -> CGFloat {
|
||||
var statusBarHeight: CGFloat = 0
|
||||
if #available(iOS 13.0, *) {
|
||||
let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
|
||||
statusBarHeight = window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
|
||||
} else {
|
||||
statusBarHeight = UIApplication.shared.statusBarFrame.height
|
||||
}
|
||||
return statusBarHeight
|
||||
}
|
||||
|
||||
var topbarHeight: CGFloat {
|
||||
|
||||
let statusHeight = getStatusBarHeight()
|
||||
let navHeight = self.navigationController?.navigationBar.frame.height ?? 0.0
|
||||
|
||||
let height: CGFloat = statusHeight + navHeight
|
||||
lastNavBarHeight = height
|
||||
|
||||
return height
|
||||
}
|
||||
}
|
||||
|
||||
-248
@@ -1,248 +0,0 @@
|
||||
//
|
||||
// UIView+Round.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Valentin Titov on 07.02.2021.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
//MARK: - Round
|
||||
extension UIView {
|
||||
|
||||
func set(x:CGFloat) {
|
||||
var frame:CGRect = self.frame
|
||||
frame.origin.x = x
|
||||
self.frame = frame
|
||||
}
|
||||
|
||||
func set(y:CGFloat) {
|
||||
var frame:CGRect = self.frame
|
||||
frame.origin.y = y
|
||||
self.frame = frame
|
||||
}
|
||||
|
||||
func set(width:CGFloat) {
|
||||
var frame:CGRect = self.frame
|
||||
frame.size.width = width
|
||||
self.frame = frame
|
||||
}
|
||||
|
||||
func set(height:CGFloat) {
|
||||
var frame:CGRect = self.frame
|
||||
frame.size.height = height
|
||||
self.frame = frame
|
||||
}
|
||||
}
|
||||
|
||||
extension CALayer {
|
||||
|
||||
func set(x:CGFloat) {
|
||||
var frame:CGRect = self.frame
|
||||
frame.origin.x = x
|
||||
self.frame = frame
|
||||
}
|
||||
|
||||
func set(y:CGFloat) {
|
||||
var frame:CGRect = self.frame
|
||||
frame.origin.y = y
|
||||
self.frame = frame
|
||||
}
|
||||
|
||||
func set(width:CGFloat) {
|
||||
var frame:CGRect = self.frame
|
||||
frame.size.width = width
|
||||
self.frame = frame
|
||||
}
|
||||
|
||||
func set(height:CGFloat) {
|
||||
var frame:CGRect = self.frame
|
||||
frame.size.height = height
|
||||
self.frame = frame
|
||||
}
|
||||
}
|
||||
|
||||
public extension UIView {
|
||||
|
||||
// MARK: - Basic Properties
|
||||
|
||||
/// X Axis value of UIView.
|
||||
var x: CGFloat {
|
||||
set { self.frame = CGRect(x: _pixelIntegral(newValue),
|
||||
y: self.y,
|
||||
width: self.width,
|
||||
height: self.height)
|
||||
}
|
||||
get { return self.frame.origin.x }
|
||||
}
|
||||
|
||||
/// Y Axis value of UIView.
|
||||
var y: CGFloat {
|
||||
set { self.frame = CGRect(x: self.x,
|
||||
y: _pixelIntegral(newValue),
|
||||
width: self.width,
|
||||
height: self.height)
|
||||
}
|
||||
get { return self.frame.origin.y }
|
||||
}
|
||||
|
||||
/// Width of view.
|
||||
var width: CGFloat {
|
||||
set { self.frame = CGRect(x: self.x,
|
||||
y: self.y,
|
||||
width: _pixelIntegral(newValue),
|
||||
height: self.height)
|
||||
}
|
||||
get { return self.frame.size.width }
|
||||
}
|
||||
|
||||
/// Height of view.
|
||||
var height: CGFloat {
|
||||
set { self.frame = CGRect(x: self.x,
|
||||
y: self.y,
|
||||
width: self.width,
|
||||
height: _pixelIntegral(newValue))
|
||||
}
|
||||
get { return self.frame.size.height }
|
||||
}
|
||||
|
||||
// MARK: - Origin and Size
|
||||
|
||||
/// View's Origin point.
|
||||
var origin: CGPoint {
|
||||
set { self.frame = CGRect(x: _pixelIntegral(newValue.x),
|
||||
y: _pixelIntegral(newValue.y),
|
||||
width: self.width,
|
||||
height: self.height)
|
||||
}
|
||||
get { return self.frame.origin }
|
||||
}
|
||||
|
||||
/// View's size.
|
||||
var size: CGSize {
|
||||
set { self.frame = CGRect(x: self.x,
|
||||
y: self.y,
|
||||
width: _pixelIntegral(newValue.width),
|
||||
height: _pixelIntegral(newValue.height))
|
||||
}
|
||||
get { return self.frame.size }
|
||||
}
|
||||
|
||||
// MARK: - Extra Properties
|
||||
|
||||
/// View's right side (x + width).
|
||||
var right: CGFloat {
|
||||
set { self.x = newValue - self.width }
|
||||
get { return self.x + self.width }
|
||||
}
|
||||
|
||||
/// View's bottom (y + height).
|
||||
var bottom: CGFloat {
|
||||
set { self.y = newValue - self.height }
|
||||
get { return self.y + self.height }
|
||||
}
|
||||
|
||||
/// View's top (y).
|
||||
var top: CGFloat {
|
||||
set { self.y = newValue }
|
||||
get { return self.y }
|
||||
}
|
||||
|
||||
/// View's left side (x).
|
||||
var left: CGFloat {
|
||||
set { self.x = newValue }
|
||||
get { return self.x }
|
||||
}
|
||||
|
||||
/// View's center X value (center.x).
|
||||
var centerX: CGFloat {
|
||||
set { self.center = CGPoint(x: newValue, y: self.centerY) }
|
||||
get { return self.center.x }
|
||||
}
|
||||
|
||||
/// View's center Y value (center.y).
|
||||
var centerY: CGFloat {
|
||||
set { self.center = CGPoint(x: self.centerX, y: newValue) }
|
||||
get { return self.center.y }
|
||||
}
|
||||
|
||||
/// Last subview on X Axis.
|
||||
var lastSubviewOnX: UIView? {
|
||||
return self.subviews.reduce(UIView(frame: .zero)) {
|
||||
return $1.x > $0.x ? $1 : $0
|
||||
}
|
||||
}
|
||||
|
||||
/// Last subview on Y Axis.
|
||||
var lastSubviewOnY: UIView? {
|
||||
return self.subviews.reduce(UIView(frame: .zero)) {
|
||||
return $1.y > $0.y ? $1 : $0
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Bounds Methods
|
||||
|
||||
/// X value of bounds (bounds.origin.x).
|
||||
var boundsX: CGFloat {
|
||||
set { self.bounds = CGRect(x: _pixelIntegral(newValue),
|
||||
y: self.boundsY,
|
||||
width: self.boundsWidth,
|
||||
height: self.boundsHeight)
|
||||
}
|
||||
get { return self.bounds.origin.x }
|
||||
}
|
||||
|
||||
/// Y value of bounds (bounds.origin.y).
|
||||
var boundsY: CGFloat {
|
||||
set { self.frame = CGRect(x: self.boundsX,
|
||||
y: _pixelIntegral(newValue),
|
||||
width: self.boundsWidth,
|
||||
height: self.boundsHeight)
|
||||
}
|
||||
get { return self.bounds.origin.y }
|
||||
}
|
||||
|
||||
/// Width of bounds (bounds.size.width).
|
||||
var boundsWidth: CGFloat {
|
||||
set { self.frame = CGRect(x: self.boundsX,
|
||||
y: self.boundsY,
|
||||
width: _pixelIntegral(newValue),
|
||||
height: self.boundsHeight)
|
||||
}
|
||||
get { return self.bounds.size.width }
|
||||
}
|
||||
|
||||
/// Height of bounds (bounds.size.height).
|
||||
var boundsHeight: CGFloat {
|
||||
set { self.frame = CGRect(x: self.boundsX,
|
||||
y: self.boundsY,
|
||||
width: self.boundsWidth,
|
||||
height: _pixelIntegral(newValue))
|
||||
}
|
||||
get { return self.bounds.size.height }
|
||||
}
|
||||
|
||||
// MARK: - Useful Methods
|
||||
|
||||
/// Center view to it's parent view.
|
||||
// func centerToParent() {
|
||||
// guard let superview = self.superview else { return }
|
||||
//
|
||||
// switch UIApplication.shared.statusBarOrientation {
|
||||
// case .landscapeLeft, .landscapeRight:
|
||||
// self.origin = CGPoint(x: (superview.height / 2) - (self.width / 2),
|
||||
// y: (superview.width / 2) - (self.height / 2))
|
||||
// case .portrait, .portraitUpsideDown:
|
||||
// self.origin = CGPoint(x: (superview.width / 2) - (self.width / 2),
|
||||
// y: (superview.height / 2) - (self.height / 2))
|
||||
// case .unknown:
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
|
||||
// MARK: - Private Methods
|
||||
fileprivate func _pixelIntegral(_ pointValue: CGFloat) -> CGFloat {
|
||||
let scale = UIScreen.main.scale
|
||||
return (round(pointValue * scale) / scale)
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
//
|
||||
// UIView+Round.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Valentin Titov on 07.02.2021.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
//MARK: - Round
|
||||
extension UIView {
|
||||
|
||||
/**
|
||||
Rounds the given set of corners to the specified radius
|
||||
|
||||
- parameter corners: Corners to round
|
||||
- parameter radius: Radius to round to
|
||||
*/
|
||||
func roundRadius(corners: UIRectCorner,
|
||||
radius: CGFloat) {
|
||||
_ = _roundRadius(corners: corners, radius: radius)
|
||||
}
|
||||
|
||||
/**
|
||||
Rounds the given set of corners to the specified radius with a border
|
||||
- parameter corners: Corners to round
|
||||
- parameter radius: Radius to round to
|
||||
- parameter borderColor: The border color
|
||||
- parameter borderWidth: The border width
|
||||
*/
|
||||
func roundRadius(corners: UIRectCorner,
|
||||
radius: CGFloat,
|
||||
borderColor: UIColor,
|
||||
borderWidth: CGFloat) {
|
||||
let mask = _roundRadius(corners: corners, radius: radius)
|
||||
addBorder(mask: mask, borderColor: borderColor, borderWidth: borderWidth)
|
||||
}
|
||||
|
||||
/**
|
||||
Fully rounds an autolayout view (e.g. one with no known frame) with the given diameter and border
|
||||
|
||||
- parameter diameter: The view's diameter
|
||||
- parameter borderColor: The border color
|
||||
- parameter borderWidth: The border width
|
||||
*/
|
||||
func fullyRound(diameter: CGFloat,
|
||||
borderColor: UIColor,
|
||||
borderWidth: CGFloat) {
|
||||
layer.masksToBounds = true
|
||||
layer.cornerRadius = diameter / 2
|
||||
layer.borderWidth = borderWidth
|
||||
layer.borderColor = borderColor.cgColor;
|
||||
}
|
||||
|
||||
@discardableResult func _roundRadius(corners: UIRectCorner,
|
||||
radius: CGFloat) -> CAShapeLayer {
|
||||
let path = UIBezierPath(roundedRect: bounds,
|
||||
byRoundingCorners: corners,
|
||||
cornerRadii: CGSize(width: radius, height: radius))
|
||||
let mask = CAShapeLayer()
|
||||
mask.path = path.cgPath
|
||||
self.layer.mask = mask
|
||||
return mask
|
||||
}
|
||||
|
||||
func addBorder(mask: CAShapeLayer,
|
||||
borderColor: UIColor,
|
||||
borderWidth: CGFloat) {
|
||||
let borderLayer = CAShapeLayer()
|
||||
borderLayer.path = mask.path
|
||||
borderLayer.fillColor = UIColor.clear.cgColor
|
||||
borderLayer.strokeColor = borderColor.cgColor
|
||||
borderLayer.lineWidth = borderWidth
|
||||
borderLayer.frame = bounds
|
||||
layer.addSublayer(borderLayer)
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
|
||||
|
||||
import Foundation
|
||||
|
||||
public func background(work: @escaping () -> Void) {
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
work()
|
||||
}
|
||||
}
|
||||
|
||||
public func main(work: @escaping () -> Void) {
|
||||
DispatchQueue.main.async {
|
||||
work()
|
||||
}
|
||||
}
|
||||
|
||||
public func mainAsync(delay: Double, work: @escaping () -> Void) {
|
||||
main(delay: delay, work: work)
|
||||
}
|
||||
|
||||
public func main(delay: Double, work: @escaping () -> Void) {
|
||||
let deadline = DispatchTime.now() + delay
|
||||
DispatchQueue.main.asyncAfter(deadline: deadline) {
|
||||
work()
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
//
|
||||
// TextField.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 17.02.2021.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UITextField {
|
||||
@IBInspectable var placeHolderColor: UIColor? {
|
||||
get {
|
||||
return self.placeHolderColor
|
||||
}
|
||||
set {
|
||||
self.attributedPlaceholder = NSAttributedString(string:self.placeholder != nil ? self.placeholder! : "", attributes:[NSAttributedString.Key.foregroundColor: newValue!])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
//
|
||||
// Jailbreak.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 20.05.2021.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
class JailbreakCheck {
|
||||
|
||||
public static func jailbroken() -> Bool {
|
||||
guard let cydiaUrlScheme = URL(string: "cydia://package/com.example.package") else { return isJailbroken() }
|
||||
return UIApplication.shared.canOpenURL(cydiaUrlScheme) || isJailbroken()
|
||||
}
|
||||
|
||||
static func isJailbroken() -> Bool {
|
||||
|
||||
if Device.isSimulator {
|
||||
return false
|
||||
}
|
||||
|
||||
let fileManager = FileManager.default
|
||||
if fileManager.fileExists(atPath: "/Applications/Cydia.app") ||
|
||||
fileManager.fileExists(atPath: "/Library/MobileSubstrate/MobileSubstrate.dylib") ||
|
||||
fileManager.fileExists(atPath: "/bin/bash") ||
|
||||
fileManager.fileExists(atPath: "/usr/sbin/sshd") ||
|
||||
fileManager.fileExists(atPath: "/etc/apt") ||
|
||||
fileManager.fileExists(atPath: "/usr/bin/ssh") {
|
||||
return true
|
||||
}
|
||||
|
||||
if canOpen("/Applications/Cydia.app") ||
|
||||
canOpen("/Library/MobileSubstrate/MobileSubstrate.dylib") ||
|
||||
canOpen("/bin/bash") ||
|
||||
canOpen("/usr/sbin/sshd") ||
|
||||
canOpen("/etc/apt") ||
|
||||
canOpen("/usr/bin/ssh") {
|
||||
return true
|
||||
}
|
||||
|
||||
let path = "/private/" + UUID().uuidString
|
||||
do {
|
||||
try "anyString".write(toFile: path, atomically: true, encoding: .utf8)
|
||||
try fileManager.removeItem(atPath: path)
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
static func canOpen(_ path: String) -> Bool {
|
||||
let file = fopen(path, "r")
|
||||
guard file != nil else { return false }
|
||||
fclose(file)
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
//
|
||||
// LayoutConstraint.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 30.05.2021.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
|
||||
extension NSLayoutConstraint {
|
||||
/**
|
||||
Change multiplier constraint
|
||||
|
||||
- parameter multiplier: CGFloat
|
||||
- returns: NSLayoutConstraint
|
||||
*/
|
||||
func multiplier(_ value: CGFloat) -> NSLayoutConstraint {
|
||||
|
||||
guard let firstItem = firstItem else { return self }
|
||||
|
||||
NSLayoutConstraint.deactivate([self])
|
||||
|
||||
let newConstraint = NSLayoutConstraint(
|
||||
item: firstItem,
|
||||
attribute: firstAttribute,
|
||||
relatedBy: relation,
|
||||
toItem: secondItem,
|
||||
attribute: secondAttribute,
|
||||
multiplier: value,
|
||||
constant: constant
|
||||
)
|
||||
|
||||
newConstraint.priority = priority
|
||||
newConstraint.shouldBeArchived = self.shouldBeArchived
|
||||
newConstraint.identifier = self.identifier
|
||||
|
||||
NSLayoutConstraint.activate([newConstraint])
|
||||
return newConstraint
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
//
|
||||
// NSData+JsonRu.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 08.06.2021.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// MARK: - Convert Json RU
|
||||
|
||||
func convertJsonRU(to data: Data, encoding: String.Encoding = .utf8) -> String {
|
||||
|
||||
guard let temp: String = String(data: data as Data, encoding: encoding) else { return "" }
|
||||
|
||||
let arr = Array(temp)
|
||||
|
||||
var tab = 0
|
||||
var findLeft = false
|
||||
var findRight = false
|
||||
var findNote = false
|
||||
// var array = false
|
||||
|
||||
var result: [Character] = []
|
||||
let count = arr.count
|
||||
let countMinus = count-1
|
||||
for i in 0..<count {
|
||||
|
||||
let charr = arr[i]
|
||||
var nextChar: Character = " "
|
||||
let y = (i + 1)
|
||||
if y < count {
|
||||
nextChar = arr[y]
|
||||
}
|
||||
|
||||
if (charr != "\"") {
|
||||
|
||||
if ((charr == "{") && (i == 0)) ||
|
||||
((charr == "{") && (nextChar == "\"")) ||
|
||||
((charr == "[") && (nextChar == "\"")) ||
|
||||
((charr == "[") && (nextChar == "{" )) ||
|
||||
((charr == "[") && (nextChar == "]" )) {
|
||||
tab += 1
|
||||
findLeft = true
|
||||
result.append(charr)
|
||||
if (charr == "[") {
|
||||
// array = true
|
||||
result += (" " + "🔢 " + "A" + "r" + "r" + "a" + "y")
|
||||
}
|
||||
}
|
||||
else if ((charr == "}") && (i == countMinus)) ||
|
||||
((charr == "}") && (nextChar == ",")) ||
|
||||
((charr == "}") && (nextChar == "}")) ||
|
||||
((charr == "}") && (nextChar == "]")) ||
|
||||
((charr == "]") && (nextChar == ",")) ||
|
||||
((charr == "]") && (nextChar == "}")) {
|
||||
if 0 < tab {
|
||||
tab -= 1
|
||||
}
|
||||
findRight = true
|
||||
if (charr == "]") {
|
||||
// array = false
|
||||
}
|
||||
}
|
||||
else if (charr == ",") {
|
||||
findNote = true
|
||||
result.append(charr)
|
||||
} else if (charr == ":") {
|
||||
result.append(" ")
|
||||
result.append(charr)
|
||||
result.append(" ")
|
||||
//result.append("👉")
|
||||
// result.append("〰️")
|
||||
// result.append("〰️")
|
||||
// result.append("➰")
|
||||
} else {
|
||||
result.append(charr)
|
||||
}
|
||||
|
||||
if findLeft || findRight || findNote {
|
||||
|
||||
let tabb = " "
|
||||
var t = ""
|
||||
for _ in 0..<tab {
|
||||
t += tabb
|
||||
}
|
||||
|
||||
result.append("🔴")
|
||||
for _ in 0..<t.count {
|
||||
result.append(" ")
|
||||
}
|
||||
// result.append("|")
|
||||
|
||||
findLeft = false
|
||||
findNote = false
|
||||
|
||||
if findRight {
|
||||
result.append(charr)
|
||||
findRight = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var str = String(result)
|
||||
str = str.replacingOccurrences(of: "🔴", with: "\n | ")
|
||||
str = str.replacingOccurrences(of: "false", with: " ❌")
|
||||
str = str.replacingOccurrences(of: "true", with: " ✅")
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
//
|
||||
// Bool.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Valentin Titov on 03.03.2021.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
extension Bool {
|
||||
static func from(string: String) -> Bool {
|
||||
if string == "true" { return true }
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
extension Bool: Stringable {
|
||||
var stringValue: String {
|
||||
if self { return "true" }
|
||||
return "false"
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
//
|
||||
// Decimal.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Valentin Titov on 03.03.2021.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Decimal {
|
||||
var intValue: Int {
|
||||
return (self as NSDecimalNumber).intValue
|
||||
}
|
||||
|
||||
var doubleValue: Double {
|
||||
return (self as NSDecimalNumber).doubleValue
|
||||
}
|
||||
|
||||
func formatWith(currency: CurrencyType) -> String {
|
||||
currencyFormatted(currency)
|
||||
}
|
||||
}
|
||||
|
||||
extension Decimal {
|
||||
|
||||
func currencyFormatted(_ currency: CurrencyType) -> String {
|
||||
let value = self * 100.0
|
||||
let floatValue = (value as NSDecimalNumber).floatValue
|
||||
let intValue = Int(floatValue)
|
||||
var stringValue: String = String(intValue)
|
||||
while stringValue.count < 3 {
|
||||
stringValue.insert("0", at: stringValue.startIndex)
|
||||
}
|
||||
var result: String = currency.symbol
|
||||
result.insert(" ", at: result.startIndex)
|
||||
var cents: String = String(stringValue.removeLast())
|
||||
cents.insert(stringValue.removeLast(), at: cents.startIndex)
|
||||
result = cents + result
|
||||
result.insert(",", at: result.startIndex)
|
||||
let characters: [Character] = Array(stringValue) as [Character]
|
||||
var j = 1
|
||||
for i in (0..<characters.count).reversed() {
|
||||
let character = characters[i]
|
||||
result.insert(character, at: result.startIndex)
|
||||
if j%3 == 0, i != 0 {result.insert(" ", at: result.startIndex)}
|
||||
j += 1
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
var decimalValue: Decimal? {
|
||||
let formattedStr =
|
||||
replacingOccurrences(of: " ", with: "")
|
||||
.replacingOccurrences(of: ",", with: ".")
|
||||
return Decimal(string: formattedStr)
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
//
|
||||
// Double.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Valentin Titov on 03.03.2021.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Double {
|
||||
func decimalValue() -> Decimal? {
|
||||
return Decimal(self)
|
||||
}
|
||||
|
||||
func currencyFormatted(_ currency: CurrencyType) -> String {
|
||||
let intValue = Int(self * 100.0)
|
||||
var stringValue: String = String(intValue)
|
||||
while stringValue.count < 3 {
|
||||
stringValue.insert("0", at: stringValue.startIndex)
|
||||
}
|
||||
var result: String = currency.symbol
|
||||
result.insert(" ", at: result.startIndex)
|
||||
var cents: String = String(stringValue.removeLast())
|
||||
cents.insert(stringValue.removeLast(), at: cents.startIndex)
|
||||
result = cents + result
|
||||
result.insert(",", at: result.startIndex)
|
||||
let characters: [Character] = Array(stringValue) as [Character]
|
||||
var j = 1
|
||||
for i in (0..<characters.count).reversed() {
|
||||
let character = characters[i]
|
||||
result.insert(character, at: result.startIndex)
|
||||
if j%3 == 0, i != 0 {result.insert(" ", at: result.startIndex)}
|
||||
j += 1
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
//
|
||||
// Int.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Valentin Titov on 03.03.2021.
|
||||
//
|
||||
|
||||
import CoreGraphics
|
||||
|
||||
extension Int {
|
||||
static var zero: Int { get {return 0 }}
|
||||
mutating func next() { self += 1 }
|
||||
mutating func increase() { self += 1 }
|
||||
mutating func previous() { self -= 1 }
|
||||
mutating func decrease() { self -= 1 }
|
||||
|
||||
func percentToCGFloat() -> CGFloat {
|
||||
return CGFloat(self)/CGFloat(100.0)
|
||||
}
|
||||
}
|
||||
|
||||
extension UInt8 {
|
||||
public init(_ boolean: BooleanLiteralType) {
|
||||
self = boolean ? 1 : 0
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
//
|
||||
// Number.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Valentin Titov on 03.02.2021.
|
||||
//
|
||||
|
||||
import CoreGraphics
|
||||
|
||||
extension CGFloat {
|
||||
static var zero: CGFloat { get {return 0.0 }}
|
||||
var half:CGFloat { get { return self/2 } }
|
||||
var double:CGFloat { get { return self*2 } }
|
||||
var toPercent: CGFloat { get { return self*100.0 } }
|
||||
var syncSize: CGFloat { get { return self * sizeAspect.rawValue }}
|
||||
var syncFont: CGFloat { get { return self * fontAspect.rawValue }}
|
||||
|
||||
//Pi Constants
|
||||
static let π = CGFloat(Double.pi)
|
||||
static let π2 = CGFloat(2 * Double.pi)
|
||||
static let π_2 = CGFloat(Double.pi/2)
|
||||
|
||||
var radians: CGFloat {
|
||||
return (self*CGFloat.pi)/180.0
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// ScrollView.swift
|
||||
// PlusBank
|
||||
//
|
||||
// Created by Рустам Мотыгуллин on 07.04.2021.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIScrollView {
|
||||
|
||||
public func scrollingBottom(animated: Bool = true) {
|
||||
let deadline = DispatchTime.now() + 0.5
|
||||
DispatchQueue.main.asyncAfter(deadline: deadline) {
|
||||
let bottomOffset = CGPoint(x: 0, y: self.contentSize.height - self.bounds.height + self.contentInset.bottom)
|
||||
self.setContentOffset(bottomOffset, animated: animated)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UITextView {
|
||||
|
||||
func scrollTextToBottom() {
|
||||
if text.count != 0 {
|
||||
let a = (text.count - 1)
|
||||
let bottom: NSRange = NSRange(location: a, length: 1) // a..<1
|
||||
scrollRangeToVisible(bottom)
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user