├── .gitignore
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── .travis.yml
├── BSZoomGridScrollView.podspec
├── BSZoomGridScrollView
├── Assets
│ └── .gitkeep
└── Classes
│ ├── .gitkeep
│ ├── BSZoomGridScrollView.swift
│ ├── BSZoomGridScrollView
│ ├── Extension
│ │ ├── UIControl+Extension.swift
│ │ ├── UIImage+Extension.swift
│ │ └── UIViewController+Extension.swift
│ ├── Function
│ │ └── Functions.swift
│ └── UIKit
│ │ ├── BSZoomGridBaseViewController.swift
│ │ └── BSZoomGridUIScrollView.swift
│ ├── BSZoomGridScrollViewController.swift
│ └── Enumeration.swift
├── Example
├── BSZoomGridScrollView.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ ├── BSZoomGridScrollView-Example.xcscheme
│ │ └── SwiftUIExample.xcscheme
├── BSZoomGridScrollView.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── BSZoomGridScrollView
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ ├── s0.imageset
│ │ │ ├── Contents.json
│ │ │ └── s0.jpeg
│ │ ├── s1.imageset
│ │ │ ├── Contents.json
│ │ │ └── s1.jpeg
│ │ ├── s10.imageset
│ │ │ ├── Contents.json
│ │ │ └── s10.jpeg
│ │ ├── s11.imageset
│ │ │ ├── Contents.json
│ │ │ └── s11.jpeg
│ │ ├── s12.imageset
│ │ │ ├── Contents.json
│ │ │ └── s12.jpeg
│ │ ├── s13.imageset
│ │ │ ├── Contents.json
│ │ │ └── s13.jpeg
│ │ ├── s14.imageset
│ │ │ ├── Contents.json
│ │ │ └── s14.jpeg
│ │ ├── s15.imageset
│ │ │ ├── Contents.json
│ │ │ └── s15.jpeg
│ │ ├── s16.imageset
│ │ │ ├── Contents.json
│ │ │ └── s16.jpeg
│ │ ├── s17.imageset
│ │ │ ├── Contents.json
│ │ │ └── s17.jpeg
│ │ ├── s18.imageset
│ │ │ ├── Contents.json
│ │ │ └── s18.jpeg
│ │ ├── s19.imageset
│ │ │ ├── Contents.json
│ │ │ └── s19.jpeg
│ │ ├── s2.imageset
│ │ │ ├── Contents.json
│ │ │ └── s2.jpeg
│ │ ├── s20.imageset
│ │ │ ├── Contents.json
│ │ │ └── s20.jpeg
│ │ ├── s21.imageset
│ │ │ ├── Contents.json
│ │ │ └── s21.jpeg
│ │ ├── s22.imageset
│ │ │ ├── Contents.json
│ │ │ └── s22.jpeg
│ │ ├── s23.imageset
│ │ │ ├── Contents.json
│ │ │ └── s23.jpeg
│ │ ├── s24.imageset
│ │ │ ├── Contents.json
│ │ │ └── s24.jpeg
│ │ ├── s25.imageset
│ │ │ ├── Contents.json
│ │ │ └── s25.jpg
│ │ ├── s26.imageset
│ │ │ ├── Contents.json
│ │ │ └── s26.JPG
│ │ ├── s27.imageset
│ │ │ ├── Contents.json
│ │ │ └── s27.jpg
│ │ ├── s28.imageset
│ │ │ ├── Contents.json
│ │ │ └── s28.jpg
│ │ ├── s29.imageset
│ │ │ ├── Contents.json
│ │ │ └── s29.jpg
│ │ ├── s3.imageset
│ │ │ ├── Contents.json
│ │ │ └── s3.jpeg
│ │ ├── s4.imageset
│ │ │ ├── Contents.json
│ │ │ └── s4.jpeg
│ │ ├── s5.imageset
│ │ │ ├── Contents.json
│ │ │ └── s5.jpeg
│ │ ├── s6.imageset
│ │ │ ├── Contents.json
│ │ │ └── s6.jpeg
│ │ ├── s7.imageset
│ │ │ ├── Contents.json
│ │ │ └── s7.jpeg
│ │ ├── s8.imageset
│ │ │ ├── Contents.json
│ │ │ └── s8.jpeg
│ │ └── s9.imageset
│ │ │ ├── Contents.json
│ │ │ └── s9.jpeg
│ ├── Base.lproj
│ │ ├── LaunchScreen.xib
│ │ └── Main.storyboard
│ ├── ContentView.swift
│ ├── Info.plist
│ ├── ShowingSelectedImageView.swift
│ └── ViewController.swift
├── Podfile
├── Podfile.lock
├── Pods
│ ├── Local Podspecs
│ │ └── BSZoomGridScrollView.podspec.json
│ ├── Manifest.lock
│ ├── Pods.xcodeproj
│ │ ├── project.pbxproj
│ │ └── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── Target Support Files
│ │ ├── BSZoomGridScrollView
│ │ ├── BSZoomGridScrollView-Info.plist
│ │ ├── BSZoomGridScrollView-dummy.m
│ │ ├── BSZoomGridScrollView-prefix.pch
│ │ ├── BSZoomGridScrollView-umbrella.h
│ │ ├── BSZoomGridScrollView.modulemap
│ │ └── BSZoomGridScrollView.xcconfig
│ │ ├── Pods-BSZoomGridScrollView_Example
│ │ ├── Pods-BSZoomGridScrollView_Example-Info.plist
│ │ ├── Pods-BSZoomGridScrollView_Example-acknowledgements.markdown
│ │ ├── Pods-BSZoomGridScrollView_Example-acknowledgements.plist
│ │ ├── Pods-BSZoomGridScrollView_Example-dummy.m
│ │ ├── Pods-BSZoomGridScrollView_Example-frameworks.sh
│ │ ├── Pods-BSZoomGridScrollView_Example-umbrella.h
│ │ ├── Pods-BSZoomGridScrollView_Example.debug.xcconfig
│ │ ├── Pods-BSZoomGridScrollView_Example.modulemap
│ │ └── Pods-BSZoomGridScrollView_Example.release.xcconfig
│ │ └── Pods-SwiftUIExample
│ │ ├── Pods-SwiftUIExample-Info.plist
│ │ ├── Pods-SwiftUIExample-acknowledgements.markdown
│ │ ├── Pods-SwiftUIExample-acknowledgements.plist
│ │ ├── Pods-SwiftUIExample-dummy.m
│ │ ├── Pods-SwiftUIExample-frameworks.sh
│ │ ├── Pods-SwiftUIExample-umbrella.h
│ │ ├── Pods-SwiftUIExample.debug.xcconfig
│ │ ├── Pods-SwiftUIExample.modulemap
│ │ └── Pods-SwiftUIExample.release.xcconfig
├── SwiftUIExample
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ ├── iconBeerList.imageset
│ │ │ ├── Contents.json
│ │ │ └── iconBeerList.png
│ │ ├── iconRandom.imageset
│ │ │ ├── Contents.json
│ │ │ └── iconRandom.png
│ │ ├── iconSearchID.imageset
│ │ │ ├── Contents.json
│ │ │ └── iconSearchID.png
│ │ └── placeHolderNoBeer.imageset
│ │ │ ├── Contents.json
│ │ │ └── placeHolderNoBeer.png
│ ├── Base.lproj
│ │ └── LaunchScreen.storyboard
│ ├── CombineNetworkError.swift
│ ├── Common
│ │ ├── DataStructure
│ │ │ └── OrderedSet.swift
│ │ ├── ImageLoader
│ │ │ └── ImageLoader.swift
│ │ ├── Network
│ │ │ └── CombineNetwork.swift
│ │ ├── Protocol
│ │ │ ├── FetchItemUrlMakeable.swift
│ │ │ ├── Fetchable.swift
│ │ │ └── ImageLoadable.swift
│ │ └── UIImage+Extension.swift
│ ├── Components
│ │ ├── Grid
│ │ │ └── GridView.swift
│ │ └── ItemList
│ │ │ ├── Model
│ │ │ └── ItemListModel.swift
│ │ │ ├── View
│ │ │ ├── ItemList.swift
│ │ │ └── ItemRow.swift
│ │ │ └── ViewModel
│ │ │ └── ItemListViewModel.swift
│ ├── ContentView.swift
│ ├── Functions.swift
│ ├── GenericItem.swift
│ ├── Info.plist
│ ├── Photo.swift
│ ├── Preview Content
│ │ └── Preview Assets.xcassets
│ │ │ └── Contents.json
│ ├── SceneDelegate.swift
│ └── URL+Extension.swift
├── SwiftUIExampleTests
│ ├── Info.plist
│ └── SwiftUIExampleTests.swift
├── SwiftUIExampleUITests
│ ├── Info.plist
│ └── SwiftUIExampleUITests.swift
├── Tests
│ ├── Info.plist
│ └── Tests.swift
└── build
│ └── XCBuildData
│ ├── 0c29229faba1b04b484d4f36d61eb1b6-desc.xcbuild
│ ├── 0c29229faba1b04b484d4f36d61eb1b6-manifest.xcbuild
│ └── BuildDescriptionCacheIndex-73dec89a04f8f8ce5460e588f22190f8
├── LICENSE
├── Package.swift
├── README.md
├── Sources
└── BSZoomGridScrollView
│ └── Classes
│ ├── .gitkeep
│ ├── BSZoomGridScrollView.swift
│ ├── BSZoomGridScrollView
│ ├── Extension
│ │ ├── UIControl+Extension.swift
│ │ ├── UIImage+Extension.swift
│ │ └── UIViewController+Extension.swift
│ ├── Function
│ │ └── Functions.swift
│ └── UIKit
│ │ ├── BSZoomGridBaseViewController.swift
│ │ └── BSZoomGridUIScrollView.swift
│ ├── BSZoomGridScrollViewController.swift
│ └── Enumeration.swift
├── Tests
├── BSZoomGridScrollViewTests
│ ├── BSZoomGridScrollViewTests.swift
│ └── XCTestManifests.swift
└── LinuxMain.swift
└── _Pods.xcodeproj
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 | xcuserdata/
6 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # references:
2 | # * https://www.objc.io/issues/6-build-tools/travis-ci/
3 | # * https://github.com/supermarin/xcpretty#usage
4 |
5 | osx_image: xcode7.3
6 | language: objective-c
7 | # cache: cocoapods
8 | # podfile: Example/Podfile
9 | # before_install:
10 | # - gem install cocoapods # Since Travis is not always on latest version
11 | # - pod install --project-directory=Example
12 | script:
13 | - set -o pipefail && xcodebuild test -enableCodeCoverage YES -workspace Example/BSZoomGridScrollView.xcworkspace -scheme BSZoomGridScrollView-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty
14 | - pod lib lint
15 |
--------------------------------------------------------------------------------
/BSZoomGridScrollView.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod lib lint BSZoomGridScrollView.podspec' to ensure this is a
3 | # valid spec before submitting.
4 | #
5 | # Any lines starting with a # are optional, but their use is encouraged
6 | # To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html
7 | #
8 |
9 | Pod::Spec.new do |s|
10 | s.name = 'BSZoomGridScrollView'
11 | s.version = '0.2.0'
12 | s.summary = 'Tracking your touch, BSZoomGridScrollView zooms in subviews in the grid-style UIScrollView'
13 |
14 | s.description = 'Boooooring grid-scrollview that is only good at zooming series of views continuously, tracking your touch..'
15 |
16 | s.homepage = 'https://github.com/boraseoksoon/BSZoomGridScrollView'
17 | # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
18 | s.license = { :type => 'MIT', :file => 'LICENSE' }
19 | s.author = { 'boraseoksoon' => 'boraseoksoon@gmail.com' }
20 | s.source = { :git => 'https://github.com/boraseoksoon/BSZoomGridScrollView.git', :tag => s.version.to_s }
21 |
22 | s.social_media_url = 'https://twitter.com/boraseoksoon'
23 |
24 | s.swift_version = '5.1'
25 |
26 | s.ios.deployment_target = '13.0'
27 |
28 | s.source_files = 'BSZoomGridScrollView/Classes/**/*'
29 |
30 | s.frameworks = 'UIKit'
31 | end
32 |
--------------------------------------------------------------------------------
/BSZoomGridScrollView/Assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/BSZoomGridScrollView/Assets/.gitkeep
--------------------------------------------------------------------------------
/BSZoomGridScrollView/Classes/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/BSZoomGridScrollView/Classes/.gitkeep
--------------------------------------------------------------------------------
/BSZoomGridScrollView/Classes/BSZoomGridScrollView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BSZoomGridScrollView.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by Jang seoksoon on 2019/11/19.
6 | //
7 | // Copyright (c) 2019 Jang seoksoon
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | #if os(iOS)
28 | import SwiftUI
29 | import UIKit
30 |
31 | ///
32 | /// UIKit -> SwiftUI Coordinator
33 | ///
34 | public struct BSZoomGridScrollView {
35 | // MARK: - Initializer
36 | ///
37 | public init(itemsToZoom: [Any],
38 | powerOfZoomBounce: ZoomBounceRatio,
39 | numberOfColumns: Int = 0,
40 | numberOfRows: Int = 0,
41 | scrollEnableButtonTintColor: UIColor = .black,
42 | scrollEnableButtonBackgroundColor: UIColor = .white,
43 | isBeingDraggingOnItem: ((_: UIImage) -> Void)?,
44 | didTapOnItem: ((_: UIImage) -> Void)?,
45 | didLongPressItem: ((_: UIImage) -> Void)?,
46 | didFinishDraggingOnItem: ((_: UIImage) -> Void)?) {
47 | self.didTapOnItem = didTapOnItem
48 | self.didLongPressItem = didLongPressItem
49 | self.didFinishDraggingOnItem = didFinishDraggingOnItem
50 | self.isBeingDraggingOnItem = isBeingDraggingOnItem
51 |
52 | self.itemsToZoom = itemsToZoom
53 | self.powerOfZoomBounce = powerOfZoomBounce
54 | self.scrollEnableButtonTintColor = scrollEnableButtonTintColor
55 | self.scrollEnableButtonBackgroundColor = scrollEnableButtonBackgroundColor
56 |
57 | self.numberOfColumns = numberOfColumns
58 | self.numberOfRows = numberOfRows
59 | }
60 |
61 | // MARK: - Instance Variables
62 | ///
63 | private let itemsToZoom: [Any]
64 | private let powerOfZoomBounce: ZoomBounceRatio
65 | private let numberOfColumns: Int
66 | private let numberOfRows: Int
67 | private let scrollEnableButtonTintColor: UIColor
68 | private let scrollEnableButtonBackgroundColor: UIColor
69 | private let isBeingDraggingOnItem: ((_: UIImage) -> Void)?
70 | private let didTapOnItem: ((_: UIImage) -> Void)?
71 | private let didLongPressItem: ((_: UIImage) -> Void)?
72 | private let didFinishDraggingOnItem: ((_: UIImage) -> Void)?
73 | }
74 |
75 | // MARK: - Public Methods
76 | ///
77 | extension BSZoomGridScrollView: UIViewControllerRepresentable {
78 |
79 | public func makeCoordinator() -> Coordinator {
80 | Coordinator(self)
81 | }
82 |
83 | public func makeUIViewController(context: Context) -> BSZoomGridScrollViewController {
84 | let scrollViewController = BSZoomGridScrollViewController(itemsToZoom: itemsToZoom,
85 | powerOfZoomBounce: self.powerOfZoomBounce,
86 | numberOfColumns: self.numberOfColumns,
87 | numberOfRows: self.numberOfRows,
88 | scrollEnableButtonTintColor: self.scrollEnableButtonTintColor,
89 | scrollEnableButtonBackgroundColor: self.scrollEnableButtonBackgroundColor,
90 | isBeingDraggingOnItem: self.isBeingDraggingOnItem,
91 | didTapOnItem:self.didTapOnItem,
92 | didLongPressItem:self.didLongPressItem,
93 | didFinishDraggingOnItem:self.didFinishDraggingOnItem)
94 | return scrollViewController
95 | }
96 |
97 | public func updateUIViewController(_ vc: BSZoomGridScrollViewController, context: Context) {
98 | vc.refresh(self.itemsToZoom)
99 | }
100 |
101 | public class Coordinator: NSObject {
102 | private var parent: BSZoomGridScrollView
103 |
104 | public init(_ pageViewController: BSZoomGridScrollView) {
105 | self.parent = pageViewController
106 | }
107 | }
108 | }
109 |
110 | #endif
111 |
--------------------------------------------------------------------------------
/BSZoomGridScrollView/Classes/BSZoomGridScrollView/Extension/UIControl+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIButton.swift
3 | // BSZoomGridScrollViewSwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/11/19.
6 | // Copyright © 2019 Seoksoon Jang. All rights reserved.
7 | //
8 |
9 | #if os(iOS)
10 | import UIKit
11 |
12 | @objc private class ClosureBox: NSObject {
13 | let closure: ()->()
14 |
15 | init (_ closure: @escaping ()->()) {
16 | self.closure = closure
17 | }
18 |
19 | @objc func invoke () {
20 | closure()
21 | }
22 | }
23 |
24 | extension UIControl {
25 | func take(for controlEvents: UIControl.Event = .touchUpInside, _ closure: @escaping ()->()) {
26 | let container = ClosureBox(closure)
27 | addTarget(container, action: #selector(ClosureBox.invoke), for: controlEvents)
28 | objc_setAssociatedObject(self, "[\(arc4random())]", container, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
29 | }
30 | }
31 |
32 | #endif
33 |
--------------------------------------------------------------------------------
/BSZoomGridScrollView/Classes/BSZoomGridScrollView/Extension/UIImage+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+Extension.swift
3 | // BSZoomGridScrollViewSwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/11/18.
6 | // Copyright © 2019 Seoksoon Jang. All rights reserved.
7 | //
8 |
9 | #if os(iOS)
10 | import UIKit
11 |
12 | extension UIImage {
13 | func resized(to size: CGSize) -> UIImage {
14 | return UIGraphicsImageRenderer(size: size).image { _ in
15 | draw(in: CGRect(origin: .zero, size: size))
16 | }
17 | }
18 | }
19 |
20 | #endif
21 |
--------------------------------------------------------------------------------
/BSZoomGridScrollView/Classes/BSZoomGridScrollView/Extension/UIViewController+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+Extension.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by Seoksoon Jang on 2019/11/19.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIViewController {
11 | func showToast(message : String, font: UIFont) {
12 | let toast = UILabel(frame: CGRect(x: self.view.frame.size.width/2 - 75,
13 | y: self.view.frame.size.height-(self.view.frame.size.height * 0.3),
14 | width: 150,
15 | height: 50))
16 | toast.backgroundColor = UIColor.black.withAlphaComponent(0.8)
17 | toast.textColor = UIColor.white
18 | toast.font = font
19 | toast.textAlignment = .center;
20 | toast.text = message
21 | toast.alpha = 1.0
22 | toast.layer.cornerRadius = 15;
23 | toast.clipsToBounds = true
24 |
25 | self.view.addSubview(toast)
26 |
27 | UIView.animate(withDuration: 4.0, delay: 0.1, options: .curveEaseOut, animations: {
28 | toast.alpha = 0.0
29 | }, completion: { isCompleted in
30 | if isCompleted {
31 | toast.removeFromSuperview()
32 | }
33 | })
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/BSZoomGridScrollView/Classes/BSZoomGridScrollView/Function/Functions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Functions.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by Jang seoksoon on 2019/11/19.
6 | //
7 | // Copyright (c) 2019 Jang seoksoon
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 |
30 | // MARK: - Grand Central Dispatch Wrapper -
31 | func MainQ(completion: @escaping () -> Void) {
32 | DispatchQueue.main.async {
33 | completion()
34 | }
35 | }
36 |
37 | func GlobalQ(threadName: String = Bundle.main.bundleIdentifier ?? "BSZoomGridScrollView",
38 | completion: @escaping () -> Void) {
39 | DispatchQueue.global().async {
40 | completion()
41 | }
42 | }
43 |
44 | let serialQueue = DispatchQueue(label: Bundle.main.bundleIdentifier ?? "BSZoomGridScrollView")
45 | func SerialQ(completion: @escaping () -> Void) {
46 | serialQueue.async {
47 | completion()
48 | }
49 | }
50 |
51 | func Delay(_ delaySeconds: Double, completion: @escaping () -> Void) -> Void {
52 | DispatchQueue.main.asyncAfter(deadline: .now() + delaySeconds) {
53 | completion()
54 | }
55 | }
56 |
57 | #if os(iOS)
58 | import UIKit
59 | // MARK: - Utility
60 | ///
61 | func GetRootViewController() -> UIViewController? {
62 | let keyWindow = UIApplication.shared.connectedScenes
63 | .filter({$0.activationState == .foregroundActive})
64 | .map({$0 as? UIWindowScene})
65 | .compactMap({$0})
66 | .first?.windows
67 | .filter({$0.isKeyWindow}).first
68 | return keyWindow?.rootViewController
69 | }
70 |
71 | func RandomEmoji() -> String {
72 | let range = 0x1F300...0x1F3F0
73 | let index = Int(arc4random_uniform(UInt32(range.count)))
74 | let ord = range.lowerBound + index
75 | guard let scalar = UnicodeScalar(ord) else { return "❓" }
76 | return String(scalar)
77 | }
78 |
79 | #endif
80 |
--------------------------------------------------------------------------------
/BSZoomGridScrollView/Classes/BSZoomGridScrollView/UIKit/BSZoomGridBaseViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BSZoomGridBaseViewController.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by Jang seoksoon on 2019/11/19.
6 | //
7 | // Copyright (c) 2019 Jang seoksoon
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | #if os(iOS)
28 | import UIKit
29 |
30 | public class BSZoomGridBaseViewController: UIViewController {
31 | // MARK: - Initializers
32 | /// Using constuctor Dependency Injection, all initialization should be done in the constructor.
33 | ///
34 | /// - Parameters:
35 | /// - parentView: a parent view to add scrollView as subview
36 | /// - itemsToZoom: item array in grid to be displayed such as [UIImage]
37 | /// if item numbers are not enough to fill the grid, it will be repeated until grid is fully drawn.
38 | /// - powerOfZoomBounce: a value to be able to choose from enum four enumeration types
39 | /// - numberOfRows: number of row to be applied in a row.
40 | /// - didLongPressItem: closure that will indicates which UIImage is decided to be chosen, by a long touch.
41 | /// - didFinishDraggingOnItem: closure that will indicates
42 | /// which UIImage is decided to be chosen, by a end of pan gesture touch.
43 | /// - Returns: Initializer
44 | public init(itemsToZoom: [Any],
45 | powerOfZoomBounce: ZoomBounceRatio,
46 | numberOfColumns: Int = 0,
47 | numberOfRows: Int = 0,
48 | scrollEnableButtonTintColor: UIColor = .black,
49 | scrollEnableButtonBackgroundColor: UIColor = .white,
50 | isBeingDraggingOnItem: ((_: UIImage) -> Void)?,
51 | didTapOnItem: ((_: UIImage) -> Void)?,
52 | didLongPressItem: ((_: UIImage) -> Void)?,
53 | didFinishDraggingOnItem: ((_: UIImage) -> Void)?) {
54 | /// Closures
55 | self.didTapOnItem = didTapOnItem
56 | self.didLongPressItem = didLongPressItem
57 | self.didFinishDraggingOnItem = didFinishDraggingOnItem
58 | self.isBeingDraggingOnItem = isBeingDraggingOnItem
59 |
60 | self.itemsToZoom = itemsToZoom
61 | self.powerOfZoomBounce = powerOfZoomBounce
62 |
63 | super.init(nibName: nil, bundle: nil)
64 |
65 | self.numberOfColumns = numberOfColumns
66 | self.numberOfRows = numberOfRows
67 | self.scrollEnableButtonTintColor = scrollEnableButtonTintColor
68 | self.scrollEnableButtonBackgroundColor = scrollEnableButtonBackgroundColor
69 | }
70 |
71 | required public init?(coder: NSCoder) {
72 | fatalError("""
73 | init(coder:) has not been implemented.\n
74 | Creating BSZoomGridScrollViewController programmatically is only allowed.
75 | """)
76 | }
77 |
78 | // MARK: - Private Instance Variables
79 | /// private accessor goes here.
80 | internal private(set) var didLongPressItem: ((_: UIImage) -> Void)?
81 | internal private(set) var didFinishDraggingOnItem: ((_: UIImage) -> Void)?
82 | internal private(set) var didTapOnItem: ((_: UIImage) -> Void)?
83 | internal private(set) var isBeingDraggingOnItem: ((_: UIImage) -> Void)?
84 |
85 | internal private(set) var itemsToZoom: [Any]
86 |
87 | internal private(set) var powerOfZoomBounce: ZoomBounceRatio
88 |
89 | private var _scrollEnableButtonBackgroundColor: UIColor = .black
90 | internal var scrollEnableButtonBackgroundColor: UIColor {
91 | get {
92 | return _scrollEnableButtonBackgroundColor
93 | }
94 | set {
95 | _scrollEnableButtonBackgroundColor = newValue
96 | }
97 | }
98 |
99 | private var _scrollEnableButtonTintColor: UIColor = .black
100 | internal var scrollEnableButtonTintColor: UIColor {
101 | get {
102 | return _scrollEnableButtonTintColor
103 | }
104 | set {
105 | _scrollEnableButtonTintColor = newValue
106 | }
107 | }
108 |
109 | private var _numberOfColumns: CGFloat = 70.0
110 | internal private(set) var numberOfColumns: Int {
111 | get {
112 | return Int(_numberOfColumns)
113 | }
114 | set {
115 | _numberOfColumns = CGFloat(newValue)
116 | }
117 | }
118 |
119 | private var _numberOfRows: CGFloat = 30.0
120 | internal private(set) var numberOfRows: Int {
121 | get {
122 | return Int(_numberOfRows)
123 | }
124 | set {
125 | _numberOfRows = CGFloat(newValue)
126 | }
127 | }
128 | }
129 | #endif
130 |
--------------------------------------------------------------------------------
/BSZoomGridScrollView/Classes/BSZoomGridScrollViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BSZoomGridScrollViewController.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by Jang seoksoon on 2019/11/19.
6 | //
7 | // Copyright (c) 2019 Jang seoksoon
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | #if os(iOS)
28 | import UIKit
29 |
30 | ///
31 | /// 😁 #Step1: Inherits BSZoomGridBaseViewController in order to inject constructor including instances variables,
32 | /// Actually, it does not do any important tasks.
33 | /// So, you can ignore inheritance. By doing so, however, currently you can't change configuration.
34 | public final class BSZoomGridScrollViewController: BSZoomGridBaseViewController {
35 | ///
36 | /// 🤔 #Step2: These buttons are not a mandatory,
37 | /// but it will help us scroll up and down in the grid scroll view.
38 |
39 | // MARK: - Instance Variables
40 | ///
41 |
42 | /// To programmtically disable scroll view,
43 | /// target & action is wrapped by closure.
44 | /// FYI: UIControl+Extension
45 | private lazy var disableOrNotButton: UIButton = { [unowned self] in
46 | let b = UIButton()
47 | b.frame = CGRect(x: UIScreen.main.bounds.width - (UIScreen.main.bounds.width * 0.25),
48 | y: UIScreen.main.bounds.height - (UIScreen.main.bounds.height * 0.25),
49 | width: BSZoomGridUIScrollView.ICON_WIDTH,
50 | height: BSZoomGridUIScrollView.ICON_WIDTH)
51 |
52 | b.setBackgroundImage(UIImage(systemName: "circle"),
53 | for: .normal)
54 |
55 | b.setBackgroundImage(UIImage(systemName: "circle.fill"),
56 | for: .highlighted)
57 |
58 | b.tintColor = self.scrollEnableButtonTintColor
59 | b.backgroundColor = self.scrollEnableButtonBackgroundColor
60 |
61 | b.layer.cornerRadius = b.frame.size.width / 2.0
62 | b.clipsToBounds = true
63 |
64 | b.take(for: .touchUpInside) { [unowned self] in
65 | self.zoomGridScrollView.isScrollEnabled = !self.zoomGridScrollView.isScrollEnabled
66 |
67 | self.showToast(
68 | message: self.zoomGridScrollView.isScrollEnabled
69 | ? "Scroll enabled. \(RandomEmoji())" : "Scroll locked. \(RandomEmoji())",
70 | font: .boldSystemFont(ofSize: 16)
71 | )
72 | }
73 |
74 | return b
75 | }()
76 |
77 | ///
78 | /// 😊 #Step3: Init BSZoomGridUIScrollView, ready to use!
79 | private lazy var zoomGridScrollView: BSZoomGridUIScrollView = { [unowned self] in
80 | return BSZoomGridUIScrollView(parentView: self.view,
81 | itemsToZoom: self.itemsToZoom,
82 | powerOfZoomBounce: self.powerOfZoomBounce,
83 | numberOfColumns: self.numberOfColumns,
84 | numberOfRows: self.numberOfRows,
85 | isBeingDraggingOnItem: self.isBeingDraggingOnItem,
86 | didTapOnItem: self.didTapOnItem,
87 | didLongPressItem: self.didLongPressItem,
88 | didFinishDraggingOnItem: self.didFinishDraggingOnItem)
89 | }()
90 |
91 | // MARK: - View LifeCycle Methods
92 | ///
93 | override public func viewDidLoad() {
94 | super.viewDidLoad()
95 |
96 | ///
97 | /// 😎 # Step4: That's it. well done!
98 | /// Add all views created so far.
99 | self.view.addSubview(self.zoomGridScrollView)
100 | self.view.addSubview(self.disableOrNotButton)
101 | }
102 |
103 | }
104 |
105 | // MARK: - Public Methods
106 | ///
107 | extension BSZoomGridScrollViewController {
108 | /// Refresh and redraw array items in the grid
109 | ///
110 | /// - Parameters:
111 | /// - compositingOperation: The compositing operation of creating image.
112 | /// - alpha: The alpha should be used for image.
113 | /// - backgroundColor: The background color for the output image.
114 | /// - Returns: An image with compositing operation applied.
115 | ///
116 | /// - Note: This method only works for CG-based image. For any non-CG-based image, `base` itself is returned.
117 |
118 | public func refresh(_ itemsToZoom: [Any]) -> Void {
119 | self.zoomGridScrollView.refresh(itemsToZoom)
120 | }
121 | }
122 | #endif
123 |
--------------------------------------------------------------------------------
/BSZoomGridScrollView/Classes/Enumeration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Enumeration.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by Jang seoksoon on 2019/11/19.
6 | //
7 | // Copyright (c) 2019 Jang seoksoon
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 | // MARK: - Enumeration
30 | /// it will decide bounce animation ratio. it should be only used and injected in the constructor.
31 | public enum ZoomBounceRatio {
32 | case weak
33 | case regular
34 | case strong
35 | case crazy
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView.xcodeproj/xcshareddata/xcschemes/BSZoomGridScrollView-Example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
51 |
52 |
53 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
76 |
78 |
84 |
85 |
86 |
87 |
93 |
95 |
101 |
102 |
103 |
104 |
106 |
107 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView.xcodeproj/xcshareddata/xcschemes/SwiftUIExample.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
43 |
49 |
50 |
51 |
52 |
53 |
63 |
65 |
71 |
72 |
73 |
74 |
80 |
82 |
88 |
89 |
90 |
91 |
93 |
94 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by boraseoksoon on 11/18/2019.
6 | // Copyright (c) 2019 boraseoksoon. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s0.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s0.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s0.imageset/s0.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s0.imageset/s0.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s1.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s1.imageset/s1.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s1.imageset/s1.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s10.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s10.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s10.imageset/s10.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s10.imageset/s10.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s11.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s11.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s11.imageset/s11.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s11.imageset/s11.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s12.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s12.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s12.imageset/s12.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s12.imageset/s12.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s13.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s13.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s13.imageset/s13.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s13.imageset/s13.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s14.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s14.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s14.imageset/s14.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s14.imageset/s14.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s15.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s15.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s15.imageset/s15.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s15.imageset/s15.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s16.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s16.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s16.imageset/s16.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s16.imageset/s16.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s17.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s17.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s17.imageset/s17.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s17.imageset/s17.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s18.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s18.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s18.imageset/s18.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s18.imageset/s18.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s19.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s19.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s19.imageset/s19.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s19.imageset/s19.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s2.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s2.imageset/s2.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s2.imageset/s2.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s20.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s20.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s20.imageset/s20.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s20.imageset/s20.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s21.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s21.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s21.imageset/s21.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s21.imageset/s21.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s22.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s22.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s22.imageset/s22.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s22.imageset/s22.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s23.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s23.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s23.imageset/s23.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s23.imageset/s23.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s24.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s24.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s24.imageset/s24.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s24.imageset/s24.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s25.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s25.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s25.imageset/s25.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s25.imageset/s25.jpg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s26.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s26.JPG",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s26.imageset/s26.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s26.imageset/s26.JPG
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s27.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s27.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s27.imageset/s27.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s27.imageset/s27.jpg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s28.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s28.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s28.imageset/s28.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s28.imageset/s28.jpg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s29.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s29.jpg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s29.imageset/s29.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s29.imageset/s29.jpg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s3.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s3.imageset/s3.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s3.imageset/s3.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s4.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s4.imageset/s4.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s4.imageset/s4.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s5.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s5.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s5.imageset/s5.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s5.imageset/s5.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s6.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s6.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s6.imageset/s6.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s6.imageset/s6.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s7.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s7.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s7.imageset/s7.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s7.imageset/s7.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s8.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s8.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s8.imageset/s8.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s8.imageset/s8.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s9.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "s9.jpeg",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Assets.xcassets/s9.imageset/s9.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/BSZoomGridScrollView/Assets.xcassets/s9.imageset/s9.jpeg
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // BSZoomGridScrollViewSwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/11/18.
6 | // Copyright © 2019 Seoksoon Jang. All rights reserved.
7 | //
8 |
9 | /// To use BSZoomGridScrollView in a SwiftUI project,
10 | /// Please, Follow steps written in the comments with Icon that will help you pay attention like 😀.
11 |
12 | import SwiftUI
13 |
14 | /// 🥳 # Step1: let's import!
15 | import BSZoomGridScrollView
16 |
17 | struct ContentView: View {
18 | @State var showSelectedImageView = false
19 | @State var selectedImage: UIImage?
20 |
21 | var itemsToZoom: [Any] = {
22 | var images = [UIImage]()
23 | for i in 0...29 {
24 | images.append(UIImage(named: "s\(i)") ?? UIImage())
25 | }
26 | return images
27 | }()
28 |
29 | var body: some View {
30 | /// 😊 # Step2. That's it. completed!
31 | BSZoomGridScrollView(itemsToZoom: itemsToZoom,
32 | powerOfZoomBounce: .regular,
33 | scrollEnableButtonTintColor: .blue,
34 | scrollEnableButtonBackgroundColor: .black,
35 | isBeingDraggingOnItem:{ selectedImage in
36 | ///
37 | },
38 | didTapOnItem: { tapImage in
39 | ///
40 | },
41 | didLongPressItem: { selectedImage in
42 | /// Grab an image user end up choosing.
43 | print("on long press : ", selectedImage)
44 | self.selectedImage = selectedImage
45 |
46 | /// Present!
47 | self.showSelectedImageView.toggle()
48 | },
49 | didFinishDraggingOnItem: { selectedImage in
50 | /// Grab an image user end up choosing.
51 | print("on drag finish : ", selectedImage)
52 | })
53 | .edgesIgnoringSafeArea(.all)
54 | .sheet(isPresented:self.$showSelectedImageView) {
55 | /// The example view showing a picked up image.
56 | ShowingSelectedImageView(selectedImage: self.selectedImage)
57 | }
58 | }
59 | }
60 |
61 | struct ContentView_Previews: PreviewProvider {
62 | static var previews: some View {
63 | ContentView()
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/ShowingSelectedImageView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ShowingSelectedImageView.swift
3 | // BSZoomGridScrollViewSwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/11/19.
6 | // Copyright © 2019 Seoksoon Jang. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct ShowingSelectedImageView: View {
12 | @State var selectedImage: UIImage?
13 | var body: some View {
14 | ZStack {
15 | Rectangle()
16 | .foregroundColor(Color.black)
17 | .frame(width: UIScreen.main.bounds.width,
18 | height: UIScreen.main.bounds.height)
19 |
20 | Spacer()
21 |
22 | Image(uiImage: selectedImage ?? UIImage())
23 | .edgesIgnoringSafeArea(.all)
24 |
25 | Spacer()
26 | }
27 | }
28 | }
29 |
30 | struct ShowingSelectedImageView_Previews: PreviewProvider {
31 | static var previews: some View {
32 | ShowingSelectedImageView(selectedImage: UIImage())
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Example/BSZoomGridScrollView/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by boraseoksoon on 11/18/2019.
6 | // Copyright (c) 2019 boraseoksoon. All rights reserved.
7 | //
8 |
9 | ///
10 | /// To use BSZoomGridScrollView,
11 | /// Please, Follow steps written in the comments with icon like 😀.
12 | ///
13 |
14 | import SwiftUI
15 | import UIKit
16 |
17 | ///
18 | // 😚 #Step1: import BSZoomGridScrollView!
19 | ///
20 | import BSZoomGridScrollView
21 |
22 | class ViewController: UIViewController {
23 | ///
24 | // prepare any item array to feed to BSZoomGridScrollViewController.
25 | ///
26 | private var itemsToZoom: [Any] = {
27 | return (0...1500).compactMap { _ in UIImage(systemName: "smiley") }
28 | }()
29 |
30 |
31 | ///
32 | // 😋 #Step2: declare BSZoomGridScrollView
33 | ///
34 | private lazy var zoomGridScrollViewController: BSZoomGridScrollViewController = { [unowned self] in
35 | ///
36 | /// It can be used on both SwiftUI and UIKit.
37 | /// To see how it works on SwiftUI,
38 | /// please refer to comments in SwiftUI directory -> ContentView.swift
39 | ///
40 | return BSZoomGridScrollViewController(itemsToZoom: self.itemsToZoom,
41 | powerOfZoomBounce: .regular,
42 | scrollEnableButtonTintColor: .black,
43 | scrollEnableButtonBackgroundColor: .white,
44 | isBeingDraggingOnItem:{ [unowned self] selectedImage in
45 | ///
46 | },
47 | didTapOnItem: { [unowned self] tapImage in
48 | ///
49 | },
50 | didLongPressItem: { [unowned self] selectedImage in
51 | ///
52 | },
53 | didFinishDraggingOnItem: { [unowned self] selectedImage in
54 | ///
55 | })
56 | }()
57 |
58 | ///
59 | // 😁 #Step3: Present it!
60 | ///
61 | @IBAction func goToBSZoomGridScrollView(_ sender: Any) {
62 | ///
63 | // 😎 That's all. well done.
64 | ///
65 |
66 | self.present(UINavigationController(rootViewController: zoomGridScrollViewController),
67 | animated: true,
68 | completion: nil)
69 | }
70 |
71 | ///
72 | // MARK: - ViewController LifeCycle Methods
73 | ///
74 | override func viewDidLoad() {
75 | super.viewDidLoad()
76 | }
77 |
78 | override func didReceiveMemoryWarning() {
79 | super.didReceiveMemoryWarning()
80 | }
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/Example/Podfile:
--------------------------------------------------------------------------------
1 | use_frameworks!
2 |
3 | target 'BSZoomGridScrollView_Example' do
4 | platform :ios, '13.0'
5 | pod 'BSZoomGridScrollView', :path => '../'
6 |
7 | end
8 |
9 |
10 | target 'SwiftUIExample' do
11 | platform :ios, '13.0'
12 | pod 'BSZoomGridScrollView', :path => '../'
13 |
14 | end
15 |
--------------------------------------------------------------------------------
/Example/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - BSZoomGridScrollView (0.1.4)
3 |
4 | DEPENDENCIES:
5 | - BSZoomGridScrollView (from `../`)
6 |
7 | EXTERNAL SOURCES:
8 | BSZoomGridScrollView:
9 | :path: "../"
10 |
11 | SPEC CHECKSUMS:
12 | BSZoomGridScrollView: 2ad694576a0e12dafa0e35c2f23e897ae591535a
13 |
14 | PODFILE CHECKSUM: a0b49d6ddff3a37ca5d2ad80461a1f49ed496298
15 |
16 | COCOAPODS: 1.8.4
17 |
--------------------------------------------------------------------------------
/Example/Pods/Local Podspecs/BSZoomGridScrollView.podspec.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "BSZoomGridScrollView",
3 | "version": "0.1.4",
4 | "summary": "Tracking your touch, BSZoomGridScrollView zooms in subviews in the grid-style UIScrollView",
5 | "description": "Boooooring grid-scrollview that is only good at zooming series of views continuously, tracking your touch..",
6 | "homepage": "https://github.com/boraseoksoon/BSZoomGridScrollView",
7 | "license": {
8 | "type": "MIT",
9 | "file": "LICENSE"
10 | },
11 | "authors": {
12 | "boraseoksoon": "boraseoksoon@gmail.com"
13 | },
14 | "source": {
15 | "git": "https://github.com/boraseoksoon/BSZoomGridScrollView.git",
16 | "tag": "0.1.4"
17 | },
18 | "social_media_url": "https://twitter.com/boraseoksoon",
19 | "swift_versions": "5.1",
20 | "platforms": {
21 | "ios": "13.0"
22 | },
23 | "source_files": "BSZoomGridScrollView/Classes/**/*",
24 | "frameworks": "UIKit",
25 | "swift_version": "5.1"
26 | }
27 |
--------------------------------------------------------------------------------
/Example/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - BSZoomGridScrollView (0.1.4)
3 |
4 | DEPENDENCIES:
5 | - BSZoomGridScrollView (from `../`)
6 |
7 | EXTERNAL SOURCES:
8 | BSZoomGridScrollView:
9 | :path: "../"
10 |
11 | SPEC CHECKSUMS:
12 | BSZoomGridScrollView: 2ad694576a0e12dafa0e35c2f23e897ae591535a
13 |
14 | PODFILE CHECKSUM: a0b49d6ddff3a37ca5d2ad80461a1f49ed496298
15 |
16 | COCOAPODS: 1.8.4
17 |
--------------------------------------------------------------------------------
/Example/Pods/Pods.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/Pods/Pods.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/BSZoomGridScrollView/BSZoomGridScrollView-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 0.1.4
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/BSZoomGridScrollView/BSZoomGridScrollView-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_BSZoomGridScrollView : NSObject
3 | @end
4 | @implementation PodsDummy_BSZoomGridScrollView
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/BSZoomGridScrollView/BSZoomGridScrollView-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/BSZoomGridScrollView/BSZoomGridScrollView-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double BSZoomGridScrollViewVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char BSZoomGridScrollViewVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/BSZoomGridScrollView/BSZoomGridScrollView.modulemap:
--------------------------------------------------------------------------------
1 | framework module BSZoomGridScrollView {
2 | umbrella header "BSZoomGridScrollView-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/BSZoomGridScrollView/BSZoomGridScrollView.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/BSZoomGridScrollView
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | OTHER_LDFLAGS = $(inherited) -framework "UIKit"
4 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
5 | PODS_BUILD_DIR = ${BUILD_DIR}
6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_ROOT = ${SRCROOT}
8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
10 | SKIP_INSTALL = YES
11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
12 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-BSZoomGridScrollView_Example/Pods-BSZoomGridScrollView_Example-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-BSZoomGridScrollView_Example/Pods-BSZoomGridScrollView_Example-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## BSZoomGridScrollView
5 |
6 | Copyright (c) 2019 boraseoksoon
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | Generated by CocoaPods - https://cocoapods.org
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-BSZoomGridScrollView_Example/Pods-BSZoomGridScrollView_Example-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | Copyright (c) 2019 boraseoksoon <boraseoksoon@gmail.com>
18 |
19 | Permission is hereby granted, free of charge, to any person obtaining a copy
20 | of this software and associated documentation files (the "Software"), to deal
21 | in the Software without restriction, including without limitation the rights
22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 | copies of the Software, and to permit persons to whom the Software is
24 | furnished to do so, subject to the following conditions:
25 |
26 | The above copyright notice and this permission notice shall be included in
27 | all copies or substantial portions of the Software.
28 |
29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 | THE SOFTWARE.
36 |
37 | License
38 | MIT
39 | Title
40 | BSZoomGridScrollView
41 | Type
42 | PSGroupSpecifier
43 |
44 |
45 | FooterText
46 | Generated by CocoaPods - https://cocoapods.org
47 | Title
48 |
49 | Type
50 | PSGroupSpecifier
51 |
52 |
53 | StringsTable
54 | Acknowledgements
55 | Title
56 | Acknowledgements
57 |
58 |
59 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-BSZoomGridScrollView_Example/Pods-BSZoomGridScrollView_Example-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_BSZoomGridScrollView_Example : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_BSZoomGridScrollView_Example
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-BSZoomGridScrollView_Example/Pods-BSZoomGridScrollView_Example-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | function on_error {
7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
8 | }
9 | trap 'on_error $LINENO' ERR
10 |
11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
13 | # frameworks to, so exit 0 (signalling the script phase was successful).
14 | exit 0
15 | fi
16 |
17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
19 |
20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
22 |
23 | # Used as a return value for each invocation of `strip_invalid_archs` function.
24 | STRIP_BINARY_RETVAL=0
25 |
26 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
27 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
28 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
29 |
30 | # Copies and strips a vendored framework
31 | install_framework()
32 | {
33 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
34 | local source="${BUILT_PRODUCTS_DIR}/$1"
35 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
36 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
37 | elif [ -r "$1" ]; then
38 | local source="$1"
39 | fi
40 |
41 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
42 |
43 | if [ -L "${source}" ]; then
44 | echo "Symlinked..."
45 | source="$(readlink "${source}")"
46 | fi
47 |
48 | # Use filter instead of exclude so missing patterns don't throw errors.
49 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
50 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
51 |
52 | local basename
53 | basename="$(basename -s .framework "$1")"
54 | binary="${destination}/${basename}.framework/${basename}"
55 |
56 | if ! [ -r "$binary" ]; then
57 | binary="${destination}/${basename}"
58 | elif [ -L "${binary}" ]; then
59 | echo "Destination binary is symlinked..."
60 | dirname="$(dirname "${binary}")"
61 | binary="${dirname}/$(readlink "${binary}")"
62 | fi
63 |
64 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
65 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
66 | strip_invalid_archs "$binary"
67 | fi
68 |
69 | # Resign the code if required by the build settings to avoid unstable apps
70 | code_sign_if_enabled "${destination}/$(basename "$1")"
71 |
72 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
73 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
74 | local swift_runtime_libs
75 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)
76 | for lib in $swift_runtime_libs; do
77 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
78 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
79 | code_sign_if_enabled "${destination}/${lib}"
80 | done
81 | fi
82 | }
83 |
84 | # Copies and strips a vendored dSYM
85 | install_dsym() {
86 | local source="$1"
87 | if [ -r "$source" ]; then
88 | # Copy the dSYM into a the targets temp dir.
89 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
90 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
91 |
92 | local basename
93 | basename="$(basename -s .framework.dSYM "$source")"
94 | binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}"
95 |
96 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
97 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
98 | strip_invalid_archs "$binary"
99 | fi
100 |
101 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
102 | # Move the stripped file into its final destination.
103 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
104 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
105 | else
106 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
107 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM"
108 | fi
109 | fi
110 | }
111 |
112 | # Copies the bcsymbolmap files of a vendored framework
113 | install_bcsymbolmap() {
114 | local bcsymbolmap_path="$1"
115 | local destination="${BUILT_PRODUCTS_DIR}"
116 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
117 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
118 | }
119 |
120 | # Signs a framework with the provided identity
121 | code_sign_if_enabled() {
122 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
123 | # Use the current code_sign_identity
124 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
125 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
126 |
127 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
128 | code_sign_cmd="$code_sign_cmd &"
129 | fi
130 | echo "$code_sign_cmd"
131 | eval "$code_sign_cmd"
132 | fi
133 | }
134 |
135 | # Strip invalid architectures
136 | strip_invalid_archs() {
137 | binary="$1"
138 | # Get architectures for current target binary
139 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
140 | # Intersect them with the architectures we are building for
141 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
142 | # If there are no archs supported by this binary then warn the user
143 | if [[ -z "$intersected_archs" ]]; then
144 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
145 | STRIP_BINARY_RETVAL=0
146 | return
147 | fi
148 | stripped=""
149 | for arch in $binary_archs; do
150 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then
151 | # Strip non-valid architectures in-place
152 | lipo -remove "$arch" -output "$binary" "$binary"
153 | stripped="$stripped $arch"
154 | fi
155 | done
156 | if [[ "$stripped" ]]; then
157 | echo "Stripped $binary of architectures:$stripped"
158 | fi
159 | STRIP_BINARY_RETVAL=1
160 | }
161 |
162 |
163 | if [[ "$CONFIGURATION" == "Debug" ]]; then
164 | install_framework "${BUILT_PRODUCTS_DIR}/BSZoomGridScrollView/BSZoomGridScrollView.framework"
165 | fi
166 | if [[ "$CONFIGURATION" == "Release" ]]; then
167 | install_framework "${BUILT_PRODUCTS_DIR}/BSZoomGridScrollView/BSZoomGridScrollView.framework"
168 | fi
169 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
170 | wait
171 | fi
172 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-BSZoomGridScrollView_Example/Pods-BSZoomGridScrollView_Example-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_BSZoomGridScrollView_ExampleVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_BSZoomGridScrollView_ExampleVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-BSZoomGridScrollView_Example/Pods-BSZoomGridScrollView_Example.debug.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BSZoomGridScrollView"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BSZoomGridScrollView/BSZoomGridScrollView.framework/Headers"
5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
6 | OTHER_LDFLAGS = $(inherited) -framework "BSZoomGridScrollView" -framework "UIKit"
7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
8 | PODS_BUILD_DIR = ${BUILD_DIR}
9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
13 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-BSZoomGridScrollView_Example/Pods-BSZoomGridScrollView_Example.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_BSZoomGridScrollView_Example {
2 | umbrella header "Pods-BSZoomGridScrollView_Example-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-BSZoomGridScrollView_Example/Pods-BSZoomGridScrollView_Example.release.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BSZoomGridScrollView"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BSZoomGridScrollView/BSZoomGridScrollView.framework/Headers"
5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
6 | OTHER_LDFLAGS = $(inherited) -framework "BSZoomGridScrollView" -framework "UIKit"
7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
8 | PODS_BUILD_DIR = ${BUILD_DIR}
9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
13 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-SwiftUIExample/Pods-SwiftUIExample-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-SwiftUIExample/Pods-SwiftUIExample-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## BSZoomGridScrollView
5 |
6 | Copyright (c) 2019 boraseoksoon
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | Generated by CocoaPods - https://cocoapods.org
27 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-SwiftUIExample/Pods-SwiftUIExample-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | Copyright (c) 2019 boraseoksoon <boraseoksoon@gmail.com>
18 |
19 | Permission is hereby granted, free of charge, to any person obtaining a copy
20 | of this software and associated documentation files (the "Software"), to deal
21 | in the Software without restriction, including without limitation the rights
22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 | copies of the Software, and to permit persons to whom the Software is
24 | furnished to do so, subject to the following conditions:
25 |
26 | The above copyright notice and this permission notice shall be included in
27 | all copies or substantial portions of the Software.
28 |
29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 | THE SOFTWARE.
36 |
37 | License
38 | MIT
39 | Title
40 | BSZoomGridScrollView
41 | Type
42 | PSGroupSpecifier
43 |
44 |
45 | FooterText
46 | Generated by CocoaPods - https://cocoapods.org
47 | Title
48 |
49 | Type
50 | PSGroupSpecifier
51 |
52 |
53 | StringsTable
54 | Acknowledgements
55 | Title
56 | Acknowledgements
57 |
58 |
59 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-SwiftUIExample/Pods-SwiftUIExample-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_SwiftUIExample : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_SwiftUIExample
5 | @end
6 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-SwiftUIExample/Pods-SwiftUIExample-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | function on_error {
7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
8 | }
9 | trap 'on_error $LINENO' ERR
10 |
11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
13 | # frameworks to, so exit 0 (signalling the script phase was successful).
14 | exit 0
15 | fi
16 |
17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
19 |
20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
22 |
23 | # Used as a return value for each invocation of `strip_invalid_archs` function.
24 | STRIP_BINARY_RETVAL=0
25 |
26 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
27 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
28 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
29 |
30 | # Copies and strips a vendored framework
31 | install_framework()
32 | {
33 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
34 | local source="${BUILT_PRODUCTS_DIR}/$1"
35 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
36 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
37 | elif [ -r "$1" ]; then
38 | local source="$1"
39 | fi
40 |
41 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
42 |
43 | if [ -L "${source}" ]; then
44 | echo "Symlinked..."
45 | source="$(readlink "${source}")"
46 | fi
47 |
48 | # Use filter instead of exclude so missing patterns don't throw errors.
49 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
50 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
51 |
52 | local basename
53 | basename="$(basename -s .framework "$1")"
54 | binary="${destination}/${basename}.framework/${basename}"
55 |
56 | if ! [ -r "$binary" ]; then
57 | binary="${destination}/${basename}"
58 | elif [ -L "${binary}" ]; then
59 | echo "Destination binary is symlinked..."
60 | dirname="$(dirname "${binary}")"
61 | binary="${dirname}/$(readlink "${binary}")"
62 | fi
63 |
64 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
65 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
66 | strip_invalid_archs "$binary"
67 | fi
68 |
69 | # Resign the code if required by the build settings to avoid unstable apps
70 | code_sign_if_enabled "${destination}/$(basename "$1")"
71 |
72 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
73 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
74 | local swift_runtime_libs
75 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)
76 | for lib in $swift_runtime_libs; do
77 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
78 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
79 | code_sign_if_enabled "${destination}/${lib}"
80 | done
81 | fi
82 | }
83 |
84 | # Copies and strips a vendored dSYM
85 | install_dsym() {
86 | local source="$1"
87 | if [ -r "$source" ]; then
88 | # Copy the dSYM into a the targets temp dir.
89 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
90 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
91 |
92 | local basename
93 | basename="$(basename -s .framework.dSYM "$source")"
94 | binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}"
95 |
96 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
97 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
98 | strip_invalid_archs "$binary"
99 | fi
100 |
101 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
102 | # Move the stripped file into its final destination.
103 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
104 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
105 | else
106 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
107 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM"
108 | fi
109 | fi
110 | }
111 |
112 | # Copies the bcsymbolmap files of a vendored framework
113 | install_bcsymbolmap() {
114 | local bcsymbolmap_path="$1"
115 | local destination="${BUILT_PRODUCTS_DIR}"
116 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
117 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
118 | }
119 |
120 | # Signs a framework with the provided identity
121 | code_sign_if_enabled() {
122 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
123 | # Use the current code_sign_identity
124 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
125 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
126 |
127 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
128 | code_sign_cmd="$code_sign_cmd &"
129 | fi
130 | echo "$code_sign_cmd"
131 | eval "$code_sign_cmd"
132 | fi
133 | }
134 |
135 | # Strip invalid architectures
136 | strip_invalid_archs() {
137 | binary="$1"
138 | # Get architectures for current target binary
139 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
140 | # Intersect them with the architectures we are building for
141 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
142 | # If there are no archs supported by this binary then warn the user
143 | if [[ -z "$intersected_archs" ]]; then
144 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
145 | STRIP_BINARY_RETVAL=0
146 | return
147 | fi
148 | stripped=""
149 | for arch in $binary_archs; do
150 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then
151 | # Strip non-valid architectures in-place
152 | lipo -remove "$arch" -output "$binary" "$binary"
153 | stripped="$stripped $arch"
154 | fi
155 | done
156 | if [[ "$stripped" ]]; then
157 | echo "Stripped $binary of architectures:$stripped"
158 | fi
159 | STRIP_BINARY_RETVAL=1
160 | }
161 |
162 |
163 | if [[ "$CONFIGURATION" == "Debug" ]]; then
164 | install_framework "${BUILT_PRODUCTS_DIR}/BSZoomGridScrollView/BSZoomGridScrollView.framework"
165 | fi
166 | if [[ "$CONFIGURATION" == "Release" ]]; then
167 | install_framework "${BUILT_PRODUCTS_DIR}/BSZoomGridScrollView/BSZoomGridScrollView.framework"
168 | fi
169 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
170 | wait
171 | fi
172 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-SwiftUIExample/Pods-SwiftUIExample-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_SwiftUIExampleVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_SwiftUIExampleVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-SwiftUIExample/Pods-SwiftUIExample.debug.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BSZoomGridScrollView"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BSZoomGridScrollView/BSZoomGridScrollView.framework/Headers"
5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
6 | OTHER_LDFLAGS = $(inherited) -framework "BSZoomGridScrollView" -framework "UIKit"
7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
8 | PODS_BUILD_DIR = ${BUILD_DIR}
9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
13 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-SwiftUIExample/Pods-SwiftUIExample.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_SwiftUIExample {
2 | umbrella header "Pods-SwiftUIExample-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Example/Pods/Target Support Files/Pods-SwiftUIExample/Pods-SwiftUIExample.release.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BSZoomGridScrollView"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BSZoomGridScrollView/BSZoomGridScrollView.framework/Headers"
5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
6 | OTHER_LDFLAGS = $(inherited) -framework "BSZoomGridScrollView" -framework "UIKit"
7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
8 | PODS_BUILD_DIR = ${BUILD_DIR}
9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
11 | PODS_ROOT = ${SRCROOT}/Pods
12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
13 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // SwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/12/02.
6 | // Copyright © 2019 CocoaPods. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 |
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17 | // Override point for customization after application launch.
18 | return true
19 | }
20 |
21 | // MARK: UISceneSession Lifecycle
22 |
23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
24 | // Called when a new scene session is being created.
25 | // Use this method to select a configuration to create the new scene with.
26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
27 | }
28 |
29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
30 | // Called when the user discards a scene session.
31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
33 | }
34 |
35 |
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Assets.xcassets/iconBeerList.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "universal",
13 | "filename" : "iconBeerList.png",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Assets.xcassets/iconBeerList.imageset/iconBeerList.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/SwiftUIExample/Assets.xcassets/iconBeerList.imageset/iconBeerList.png
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Assets.xcassets/iconRandom.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "universal",
13 | "filename" : "iconRandom.png",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Assets.xcassets/iconRandom.imageset/iconRandom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/SwiftUIExample/Assets.xcassets/iconRandom.imageset/iconRandom.png
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Assets.xcassets/iconSearchID.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "universal",
13 | "filename" : "iconSearchID.png",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Assets.xcassets/iconSearchID.imageset/iconSearchID.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/SwiftUIExample/Assets.xcassets/iconSearchID.imageset/iconSearchID.png
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Assets.xcassets/placeHolderNoBeer.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "universal",
13 | "filename" : "placeHolderNoBeer.png",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Assets.xcassets/placeHolderNoBeer.imageset/placeHolderNoBeer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/SwiftUIExample/Assets.xcassets/placeHolderNoBeer.imageset/placeHolderNoBeer.png
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/CombineNetworkError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CombineNetworkError.swift
3 | // SwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/12/02.
6 | // Copyright © 2019 CocoaPods. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | enum CombineNetworkError: Error {
12 | case error(String)
13 | case unknown(String)
14 |
15 | var message: String? {
16 | switch self {
17 | case .error(let msg):
18 | return msg
19 | case let .unknown(msg):
20 | return msg
21 | }
22 | }
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Common/DataStructure/OrderedSet.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OrderedSet.swift
3 | // SwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/12/02.
6 | // Copyright © 2019 CocoaPods. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// An ordered set is an ordered collection of instances of `Element` in which
12 | /// uniqueness of the objects is guaranteed.
13 | public struct OrderedSet: Equatable, Collection {
14 | public typealias Element = E
15 | public typealias Index = Int
16 |
17 | #if swift(>=4.1.50)
18 | public typealias Indices = Range
19 | #else
20 | public typealias Indices = CountableRange
21 | #endif
22 |
23 | private var array: [Element]
24 | private var set: Set
25 |
26 | /// Creates an empty ordered set.
27 | public init() {
28 | self.array = []
29 | self.set = Set()
30 | }
31 |
32 | /// Creates an ordered set with the contents of `array`.
33 | ///
34 | /// If an element occurs more than once in `element`, only the first one
35 | /// will be included.
36 | public init(_ array: [Element]) {
37 | self.init()
38 | for element in array {
39 | append(element)
40 | }
41 | }
42 |
43 | // MARK: Working with an ordered set
44 | /// The number of elements the ordered set stores.
45 | public var count: Int { return array.count }
46 |
47 | /// Returns `true` if the set is empty.
48 | public var isEmpty: Bool { return array.isEmpty }
49 |
50 | /// Returns the contents of the set as an array.
51 | public var contents: [Element] { return array }
52 |
53 | /// Returns `true` if the ordered set contains `member`.
54 | public func contains(_ member: Element) -> Bool {
55 | return set.contains(member)
56 | }
57 |
58 | /// Adds an element to the ordered set.
59 | ///
60 | /// If it already contains the element, then the set is unchanged.
61 | ///
62 | /// - returns: True if the item was inserted.
63 | @discardableResult
64 | public mutating func append(_ newElement: Element) -> Bool {
65 | let inserted = set.insert(newElement).inserted
66 | if inserted {
67 | array.append(newElement)
68 | }
69 | return inserted
70 | }
71 |
72 | /// Remove and return the element at the beginning of the ordered set.
73 | public mutating func removeFirst() -> Element {
74 | let firstElement = array.removeFirst()
75 | set.remove(firstElement)
76 | return firstElement
77 | }
78 |
79 | /// Remove and return the element at the end of the ordered set.
80 | public mutating func removeLast() -> Element {
81 | let lastElement = array.removeLast()
82 | set.remove(lastElement)
83 | return lastElement
84 | }
85 |
86 | /// Remove all elements.
87 | public mutating func removeAll(keepingCapacity keepCapacity: Bool) {
88 | array.removeAll(keepingCapacity: keepCapacity)
89 | set.removeAll(keepingCapacity: keepCapacity)
90 | }
91 | }
92 |
93 | extension OrderedSet: ExpressibleByArrayLiteral {
94 | /// Create an instance initialized with `elements`.
95 | ///
96 | /// If an element occurs more than once in `element`, only the first one
97 | /// will be included.
98 | public init(arrayLiteral elements: Element...) {
99 | self.init(elements)
100 | }
101 | }
102 |
103 | extension OrderedSet: RandomAccessCollection {
104 | public var startIndex: Int { return contents.startIndex }
105 | public var endIndex: Int { return contents.endIndex }
106 | public subscript(index: Int) -> Element {
107 | return contents[index]
108 | }
109 | }
110 |
111 | public func == (lhs: OrderedSet, rhs: OrderedSet) -> Bool {
112 | return lhs.contents == rhs.contents
113 | }
114 |
115 | extension OrderedSet: Hashable where Element: Hashable { }
116 |
117 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Common/ImageLoader/ImageLoader.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageLoader.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by boraseoksoon on 11/18/2019.
6 | // Copyright (c) 2019 boraseoksoon. All rights reserved.
7 | //
8 |
9 | import Combine
10 | import SwiftUI
11 |
12 | final class ImageLoader: ObservableObject {
13 | @Published private(set) var image: UIImage? = nil
14 |
15 | public lazy var objectWillChange: AnyPublisher = {
16 | Empty().eraseToAnyPublisher()
17 | }()
18 |
19 | private let loadable: ImageLoadable
20 | private var cancellable: AnyCancellable?
21 |
22 | init(loadable: ImageLoadable, id: Int) {
23 | self.loadable = loadable
24 |
25 | self.objectWillChange = $image.handleEvents(
26 | receiveSubscription: { [weak self] sub in
27 | self?.load(id: id)
28 | },
29 | receiveCancel: { [weak self] in
30 | self?.cancellable?.cancel()
31 | }
32 | ).eraseToAnyPublisher()
33 | }
34 | }
35 |
36 | // MARK: - Private methods
37 | extension ImageLoader {
38 | private func load(id: Int) {
39 | guard image == nil else {
40 | return
41 | }
42 |
43 | cancellable = loadable
44 | .loadImage(id: id)
45 | .receive(on: DispatchQueue.main)
46 | .sink(
47 | receiveCompletion: { _ in },
48 | receiveValue: { [weak self] image in
49 | self?.image = image
50 | }
51 | )
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Common/Network/CombineNetwork.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Network.swift
3 | // SwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/12/02.
6 | // Copyright © 2019 CocoaPods. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Combine
11 |
12 | class CombineNetwork {
13 | private let session: URLSession
14 |
15 | init(session: URLSession = .shared) {
16 | self.session = session
17 | }
18 | }
19 |
20 | // MARK: - Fetchable
21 | extension CombineNetwork: Fetchable {
22 | func fetchItems(page: Int?) -> AnyPublisher<[Photo], CombineNetworkError> {
23 | guard let url = makeFetchItemsComponents(page: page).url else {
24 | return makeErrorPublisher(msg: "invalid Url")
25 | }
26 |
27 | return session.dataTaskPublisher(for: URLRequest(url: url))
28 | .mapError { .error($0.localizedDescription) }
29 | .flatMap { response in
30 | Just(response.data)
31 | .decode(type: [Photo].self, decoder: JSONDecoder())
32 | .mapError { .error($0.localizedDescription) }
33 | }
34 | .eraseToAnyPublisher()
35 | }
36 | }
37 |
38 | // MARK: - FetchItemUrlMakeable
39 | extension CombineNetwork: FetchItemUrlMakeable {
40 | struct apiUrl {
41 | static let scheme = "https"
42 | static let host = "picsum.photos"
43 | static let path = "/v2/list"
44 | }
45 |
46 | func makeFetchItemsComponents(page: Int?) -> URLComponents {
47 | var components = URLComponents()
48 | components.scheme = apiUrl.scheme
49 | components.host = apiUrl.host
50 | components.path = apiUrl.path
51 |
52 | if let page = page {
53 | components.queryItems = [
54 | URLQueryItem(name: "page", value: "\(page)"),
55 | URLQueryItem(name: "limit", value: "200")
56 | ]
57 | } else {
58 | components.queryItems = [
59 | URLQueryItem(name: "limit", value: "200")
60 | ]
61 | }
62 |
63 | return components
64 | }
65 | }
66 |
67 | // MARK: - Private Methods
68 | extension CombineNetwork {
69 | private func makeErrorPublisher(msg: String) -> AnyPublisher<[Photo], CombineNetworkError> {
70 | Fail(error: CombineNetworkError.error(msg)).eraseToAnyPublisher()
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Common/Protocol/FetchItemUrlMakeable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FetchItemUrlMakeable.swift
3 | // SwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/12/02.
6 | // Copyright © 2019 CocoaPods. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Combine
11 |
12 | protocol FetchItemUrlMakeable {
13 | func makeFetchItemsComponents(page: Int?) -> URLComponents
14 | }
15 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Common/Protocol/Fetchable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Fetchable.swift
3 | // SwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/12/02.
6 | // Copyright © 2019 CocoaPods. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Combine
11 |
12 | protocol Fetchable {
13 | func fetchItems(page: Int?) -> AnyPublisher<[Photo], CombineNetworkError>
14 | }
15 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Common/Protocol/ImageLoadable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageLoadable.swift
3 | // SwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/12/02.
6 | // Copyright © 2019 CocoaPods. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Foundation
11 | import Combine
12 |
13 | protocol ImageLoadable {
14 | func loadImage(id: Int) -> AnyPublisher
15 | }
16 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Common/UIImage+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+Extension.swift
3 | // SwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/12/02.
6 | // Copyright © 2019 CocoaPods. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Foundation
11 | import Combine
12 |
13 | extension UIImage: ImageLoadable {
14 | func loadImage(id: Int) -> AnyPublisher {
15 | return Just(self)
16 | .setFailureType(to: Error.self)
17 | .eraseToAnyPublisher()
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Components/Grid/GridView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GridView.swift
3 | // SwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/12/02.
6 | // Copyright © 2019 CocoaPods. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 | /// 🥳 # Step1: let's import!
11 | import BSZoomGridScrollView
12 |
13 | struct GridView: View {
14 | @ObservedObject var viewModel: ItemListViewModel
15 |
16 | @State var showSelectedImageView = false
17 | @State var selectedImage: UIImage?
18 |
19 | init(viewModel: ItemListViewModel) {
20 | self.viewModel = viewModel
21 | }
22 |
23 | /// from VM
24 | func itemsToZoom() -> [UIImage] {
25 | return self.viewModel.images
26 | }
27 |
28 | // generated static images
29 | var itemsToZoom2: [Any] = {
30 | var images = [UIImage]()
31 | for i in 0...1000 {
32 | images.append(UIImage(systemName: "smiley") ?? UIImage())
33 | }
34 | return images
35 | }()
36 |
37 | var body: some View {
38 | /// 😊 # Step2. That's it. completed!
39 | BSZoomGridScrollView(itemsToZoom: itemsToZoom(),
40 | powerOfZoomBounce: .regular,
41 | scrollEnableButtonTintColor: .blue,
42 | scrollEnableButtonBackgroundColor: .black,
43 | isBeingDraggingOnItem:{ draggingImage in
44 | ///
45 | },
46 | didTapOnItem: { tapImage in
47 | ///
48 | },
49 | didLongPressItem: { longPressedImage in
50 | ///
51 | },
52 | didFinishDraggingOnItem: { draggedFinalImage in
53 | ///
54 | })
55 | .edgesIgnoringSafeArea(.all)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Components/ItemList/Model/ItemListModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ItemListModel.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by boraseoksoon on 11/18/2019.
6 | // Copyright (c) 2019 boraseoksoon. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Combine
11 |
12 | struct ItemListModel {
13 | let network: Fetchable
14 |
15 | init(network: Fetchable) {
16 | self.network = network
17 | }
18 | }
19 |
20 | // MARK: - Public Methods
21 | extension ItemListModel {
22 | func fetchItems(page: Int?) -> AnyPublisher<[Photo], CombineNetworkError> {
23 | return network.fetchItems(page: page)
24 | }
25 |
26 | func getPage(items: [Photo], id: Int?) -> Int? {
27 | let lastRowCount = items.count
28 | let lastIndex = items.firstIndex { id == Int($0.id) }
29 | let page = lastRowCount / 75 + 1
30 |
31 | guard (74...) ~= lastRowCount,
32 | lastRowCount - 1 == lastIndex else {
33 | return nil
34 | }
35 |
36 | return page
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Components/ItemList/View/ItemList.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ItemList.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by boraseoksoon on 11/18/2019.
6 | // Copyright (c) 2019 boraseoksoon. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct ItemList: View {
12 | @ObservedObject var viewModel: ItemListViewModel
13 |
14 | init(viewModel: ItemListViewModel) {
15 | self.viewModel = viewModel
16 | }
17 |
18 | var body: some View {
19 | NavigationView {
20 | listView
21 | }
22 | .alert(isPresented: $viewModel.showingAlert) {
23 | Alert(title: Text(viewModel.errorMessage))
24 | }
25 | }
26 | }
27 |
28 | // MARK: - Views
29 | extension ItemList {
30 | var listView: some View {
31 | List(viewModel.items, id: \.id) { item in
32 | ItemRow(item: item).onAppear {
33 | self.viewModel.appearItem(id:item.id)
34 | }
35 | }
36 | .navigationBarTitle(Text("Photos"))
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Components/ItemList/View/ItemRow.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ItemRow.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by boraseoksoon on 11/18/2019.
6 | // Copyright (c) 2019 boraseoksoon. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 | import Combine
11 |
12 | struct ItemRow: View {
13 | var item: Photo
14 | @ObservedObject var imageLoader: ImageLoader
15 |
16 | init(item: Photo) {
17 | self.item = item
18 |
19 | self.imageLoader = ImageLoader(
20 | loadable: URL(string: item.imageURL ?? "") ?? UIImage(systemName: "xmark") ?? UIImage(),
21 | id: item.id
22 | )
23 | }
24 |
25 | var body: some View {
26 | VStack {
27 | itemRow
28 | }
29 | }
30 | }
31 |
32 | // MARK: - Views
33 | extension ItemRow {
34 | var itemRow: some View {
35 | HStack {
36 | Image(uiImage: imageLoader.image ?? UIImage(systemName: "xmark") ?? UIImage())
37 | .resizable()
38 | .clipShape(Circle())
39 | .frame(width: 120.0, height: 120.0, alignment: .center)
40 | .overlay(Circle().stroke(Color.white,lineWidth:2).shadow(radius: 10))
41 |
42 | VStack(alignment: .leading) {
43 | Text("Author: \(item.name ?? "unknown author")")
44 | .font(Font.system(size: 14, weight: .regular, design: .default))
45 | .foregroundColor(.blue)
46 | .padding([.bottom], 10)
47 |
48 | Text("Size: \(item.description ?? "")")
49 | .font(Font.system(size: 12, weight: .light, design: .default))
50 | .foregroundColor(.gray)
51 | .lineLimit(3)
52 | }
53 | .padding([.leading], 5)
54 | }
55 | .padding([.top, .bottom], 20)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Components/ItemList/ViewModel/ItemListViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ItemListViewModel.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by boraseoksoon on 11/18/2019.
6 | // Copyright (c) 2019 boraseoksoon. All rights reserved.
7 | //
8 |
9 | import Combine
10 | import SwiftUI
11 |
12 | class ItemListViewModel: ObservableObject {
13 | @Published var items: [Photo] = []
14 | @Published var showingAlert: Bool = false
15 | @Published var errorMessage: String = ""
16 |
17 | private let itemId = PassthroughSubject()
18 | private var cancellables = Set()
19 |
20 | private var _images: [UIImage] = []
21 | public var images: [UIImage] {
22 | get {
23 | return _images
24 | }
25 | set {
26 | _images = newValue
27 | }
28 | }
29 |
30 | init(model: ItemListModel = ItemListModel(network: CombineNetwork())) {
31 | self.bind(to: model)
32 | }
33 | }
34 |
35 | // MARK: - Public methods
36 | extension ItemListViewModel {
37 | public func appearItem(id: Int?) -> Void {
38 | guard let id = id else { return }
39 | self.itemId.send(id)
40 | }
41 | }
42 |
43 | // MARK: - Private methods
44 | extension ItemListViewModel {
45 | private func bind(to model: ItemListModel) {
46 | itemId
47 | .map { model.getPage(items: self.items, id: $0) }
48 | .filter { $0 != nil }
49 | .eraseToAnyPublisher()
50 | .prepend(nil)
51 | .flatMap(model.fetchItems)
52 | .receive(on: DispatchQueue.main)
53 | .sink(
54 | receiveCompletion: {
55 | guard case .failure(let error) = $0 else { return }
56 | self.items = []
57 | self.showingAlert = true
58 | self.errorMessage = error.message ?? "Unknown error"
59 | },
60 | receiveValue: { items in
61 | self.items += items
62 |
63 | self.downloadImages(from:items)
64 | }
65 | )
66 | .store(in: &cancellables)
67 | }
68 |
69 | private func downloadImages(from items: [Photo]) -> Void {
70 | DispatchQueue.global().async {
71 | items.forEach { item in
72 | URL(string: item.imageURL ?? "")?
73 | .loadImage(id: item.id)
74 | .receive(on: DispatchQueue.main)
75 | .sink(
76 | receiveCompletion: { _ in },
77 | receiveValue: { [weak self] image in
78 | DispatchQueue.main.async {
79 | self?.images.append(image)
80 | }
81 | }
82 | )
83 | .store(in: &self.cancellables)
84 | }
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // SwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/12/02.
6 | // Copyright © 2019 CocoaPods. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 | import Combine
11 |
12 | struct ContentView: View {
13 | @ObservedObject var ItemListViewModel: ItemListViewModel
14 |
15 | init(ItemListViewModel: ItemListViewModel) {
16 | self.ItemListViewModel = ItemListViewModel
17 | }
18 |
19 | var body: some View {
20 | TabView {
21 | ItemList(viewModel: ItemListViewModel)
22 | .tabItem {
23 | Image(systemName:"safari")
24 | Text("Photos")
25 | }
26 |
27 | GridView(viewModel: ItemListViewModel)
28 | .tabItem {
29 | Image(systemName: "grid")
30 | Text("Grid")
31 | }
32 | }
33 | .edgesIgnoringSafeArea(.top)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Functions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Functions.swift
3 | // SwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/12/02.
6 | // Copyright © 2019 CocoaPods. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Combine
11 |
12 | func ReplaceUrlResolution(from url: String,
13 | targetWidth: String,
14 | targetHeight: String) -> String {
15 | var copyUrl = url
16 | let components = copyUrl
17 | .components(separatedBy: "id/")
18 |
19 | if components.count > 1 {
20 | let subComponents = components[1]
21 | .components(separatedBy:"/")
22 |
23 | if subComponents.count >= 3 {
24 | let sourceWidth = subComponents[1]
25 | let sourceHeight = subComponents[2]
26 |
27 | copyUrl = copyUrl
28 | .replacingOccurrences(of: sourceWidth,
29 | with: targetWidth)
30 | copyUrl = copyUrl
31 | .replacingOccurrences(of: sourceHeight,
32 | with: targetHeight)
33 |
34 | } else {
35 | return url
36 | }
37 | } else {
38 | return url
39 | }
40 |
41 | return copyUrl
42 | }
43 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/GenericItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GenericItem.swift
3 | // SwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/12/02.
6 | // Copyright © 2019 CocoaPods. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol GenericItem {
12 | var id: Int { get }
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 |
37 |
38 |
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UISupportedInterfaceOrientations~ipad
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationPortraitUpsideDown
56 | UIInterfaceOrientationLandscapeLeft
57 | UIInterfaceOrientationLandscapeRight
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Photo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Photo.swift
3 | // SwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/12/02.
6 | // Copyright © 2019 CocoaPods. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Combine
11 |
12 | struct Photo: GenericItem, Codable, Identifiable {
13 | let id: Int
14 | let author: String
15 | let width: Int
16 | let height: Int
17 | let url: String
18 | let download_url: String
19 |
20 | let name: String?
21 | let imageURL: String?
22 | let description: String?
23 |
24 | enum CodingKeys: String, CodingKey {
25 | case id, author, width, height, url, download_url
26 | }
27 |
28 | init(from decoder: Decoder) throws {
29 | let values = try decoder.container(keyedBy: CodingKeys.self)
30 |
31 | let id = try values.decode(String.self, forKey: .id)
32 | self.id = Int(id) ?? -1
33 |
34 | self.author = try values.decode(String.self, forKey: .author)
35 | self.width = try values.decode(Int.self, forKey: .width)
36 | self.height = try values.decode(Int.self, forKey: .height)
37 | self.url = try values.decode(String.self, forKey: .url)
38 | self.download_url = try values.decode(String.self, forKey: .download_url)
39 |
40 | self.name = self.author
41 | self.imageURL = ReplaceUrlResolution(from: self.download_url,
42 | targetWidth: "120",
43 | targetHeight: "120")
44 |
45 | self.description = "\(String(self.width)) * \(String(self.height))"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Example/SwiftUIExample/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // SwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/12/02.
6 | // Copyright © 2019 CocoaPods. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SwiftUI
11 |
12 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
13 |
14 | var window: UIWindow?
15 |
16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
17 | guard let windowScene = scene as? UIWindowScene else { return }
18 |
19 | let contentView = ContentView(
20 | ItemListViewModel: ItemListViewModel()
21 | )
22 |
23 | // Use a UIHostingController as window root view controller
24 | let window = UIWindow(windowScene: windowScene)
25 | window.rootViewController = UIHostingController(rootView: contentView)
26 | window.makeKeyAndVisible()
27 | self.window = window
28 | }
29 |
30 |
31 | func sceneDidDisconnect(_ scene: UIScene) {
32 | // Called as the scene is being released by the system.
33 | // This occurs shortly after the scene enters the background, or when its session is discarded.
34 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
35 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
36 | }
37 |
38 | func sceneDidBecomeActive(_ scene: UIScene) {
39 | // Called when the scene has moved from an inactive state to an active state.
40 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
41 | }
42 |
43 | func sceneWillResignActive(_ scene: UIScene) {
44 | // Called when the scene will move from an active state to an inactive state.
45 | // This may occur due to temporary interruptions (ex. an incoming phone call).
46 | }
47 |
48 | func sceneWillEnterForeground(_ scene: UIScene) {
49 | // Called as the scene transitions from the background to the foreground.
50 | // Use this method to undo the changes made on entering the background.
51 | }
52 |
53 | func sceneDidEnterBackground(_ scene: UIScene) {
54 | // Called as the scene transitions from the foreground to the background.
55 | // Use this method to save data, release shared resources, and store enough scene-specific state information
56 | // to restore the scene back to its current state.
57 | }
58 |
59 |
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/Example/SwiftUIExample/URL+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URL+Extension.swift
3 | // SwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/12/02.
6 | // Copyright © 2019 CocoaPods. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Foundation
11 | import Combine
12 |
13 | extension URL: ImageLoadable {
14 | enum ImageLoadingError: Error {
15 | case incorrectData
16 | }
17 |
18 | func loadImage(id: Int) -> AnyPublisher {
19 | if let retrieveImage = self.retrieveImage(forKey: "\(id)") {
20 | return retrieveImage.loadImage(id: id)
21 | }
22 |
23 | return URLSession
24 | .shared
25 | .dataTaskPublisher(for: self)
26 | .tryMap { data, _ in
27 | guard let image = UIImage(data: data) else {
28 | throw ImageLoadingError.incorrectData
29 | }
30 |
31 | self.store(image: image, forKey: "\(id)")
32 | return image
33 | }
34 | .eraseToAnyPublisher()
35 | }
36 |
37 | private func store(image: UIImage, forKey key: String) {
38 | if let pngRepresentation = image.pngData() {
39 | UserDefaults.standard.set(pngRepresentation, forKey: key)
40 | }
41 | }
42 |
43 | private func retrieveImage(forKey key: String) -> UIImage? {
44 | guard let imageData = UserDefaults.standard.object(forKey: key) as? Data,
45 | let image = UIImage(data: imageData) else {
46 | return nil
47 | }
48 | return image
49 | }
50 | }
51 |
52 |
--------------------------------------------------------------------------------
/Example/SwiftUIExampleTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Example/SwiftUIExampleTests/SwiftUIExampleTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftUIExampleTests.swift
3 | // SwiftUIExampleTests
4 | //
5 | // Created by Seoksoon Jang on 2019/12/02.
6 | // Copyright © 2019 CocoaPods. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import SwiftUIExample
11 |
12 | class SwiftUIExampleTests: XCTestCase {
13 |
14 | override func setUp() {
15 | // Put setup code here. This method is called before the invocation of each test method in the class.
16 | }
17 |
18 | override func tearDown() {
19 | // Put teardown code here. This method is called after the invocation of each test method in the class.
20 | }
21 |
22 | func testExample() {
23 | // This is an example of a functional test case.
24 | // Use XCTAssert and related functions to verify your tests produce the correct results.
25 | }
26 |
27 | func testPerformanceExample() {
28 | // This is an example of a performance test case.
29 | self.measure {
30 | // Put the code you want to measure the time of here.
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/Example/SwiftUIExampleUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Example/SwiftUIExampleUITests/SwiftUIExampleUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftUIExampleUITests.swift
3 | // SwiftUIExampleUITests
4 | //
5 | // Created by Seoksoon Jang on 2019/12/02.
6 | // Copyright © 2019 CocoaPods. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class SwiftUIExampleUITests: XCTestCase {
12 |
13 | override func setUp() {
14 | // Put setup code here. This method is called before the invocation of each test method in the class.
15 |
16 | // In UI tests it is usually best to stop immediately when a failure occurs.
17 | continueAfterFailure = false
18 |
19 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
20 | }
21 |
22 | override func tearDown() {
23 | // Put teardown code here. This method is called after the invocation of each test method in the class.
24 | }
25 |
26 | func testExample() {
27 | // UI tests must launch the application that they test.
28 | let app = XCUIApplication()
29 | app.launch()
30 |
31 | // Use recording to get started writing UI tests.
32 | // Use XCTAssert and related functions to verify your tests produce the correct results.
33 | }
34 |
35 | func testLaunchPerformance() {
36 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) {
37 | // This measures how long it takes to launch your application.
38 | measure(metrics: [XCTOSSignpostMetric.applicationLaunch]) {
39 | XCUIApplication().launch()
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Example/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Example/Tests/Tests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import BSZoomGridScrollView
3 |
4 | class Tests: XCTestCase {
5 |
6 | override func setUp() {
7 | super.setUp()
8 | // Put setup code here. This method is called before the invocation of each test method in the class.
9 | }
10 |
11 | override func tearDown() {
12 | // Put teardown code here. This method is called after the invocation of each test method in the class.
13 | super.tearDown()
14 | }
15 |
16 | func testExample() {
17 | // This is an example of a functional test case.
18 | XCTAssert(true, "Pass")
19 | }
20 |
21 | func testPerformanceExample() {
22 | // This is an example of a performance test case.
23 | self.measure() {
24 | // Put the code you want to measure the time of here.
25 | }
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/Example/build/XCBuildData/0c29229faba1b04b484d4f36d61eb1b6-desc.xcbuild:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/build/XCBuildData/0c29229faba1b04b484d4f36d61eb1b6-desc.xcbuild
--------------------------------------------------------------------------------
/Example/build/XCBuildData/BuildDescriptionCacheIndex-73dec89a04f8f8ce5460e588f22190f8:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Example/build/XCBuildData/BuildDescriptionCacheIndex-73dec89a04f8f8ce5460e588f22190f8
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2019 boraseoksoon
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.1
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 |
5 | import PackageDescription
6 |
7 | let package = Package(
8 | name: "BSZoomGridScrollView",
9 | platforms: [
10 | .iOS(.v13),
11 | ],
12 |
13 | products: [
14 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
15 | .library(
16 | name: "BSZoomGridScrollView",
17 | targets: ["BSZoomGridScrollView"]),
18 | ],
19 | dependencies: [
20 | // Dependencies declare other packages that this package depends on.
21 | // .package(url: /* package url */, from: "1.0.0"),
22 | ],
23 | targets: [
24 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
25 | // Targets can depend on other targets in this package, and on products in packages which this package depends on.
26 | .target(
27 | name: "BSZoomGridScrollView",
28 | dependencies: []),
29 | .testTarget(
30 | name: "BSZoomGridScrollViewTests",
31 | dependencies: ["BSZoomGridScrollView"]),
32 | ]
33 | )
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BSZoomGridScrollView
2 |
3 | BSZoomGridScrollView is a powerful, pure swift iOS UI framework that provides the awesome grid scrollview containing your image array that are able to zoom, tracking your touch area.
4 |
5 | Screenshots
6 | -----------
7 |
8 | [Click to watch how it works in youtube](https://youtu.be/QTB7GqZL-L8)
9 |
10 |
11 |
12 | 
13 |
14 | 
15 |
16 |
17 | At a Glance
18 | -----------
19 |
20 | ```swift
21 |
22 | var body: some View {
23 | /// 😊 That's it.
24 | BSZoomGridScrollView(imagesToZoom: imagesToZoom,
25 | powerOfZoomBounce: .regular,
26 | numberOfColumns: 200,
27 | numberOfRows: 10,
28 | didLongPressItem: { selectedImage in
29 | print("on long press : ", selectedImage)
30 | /// Grab an image user end up choosing.
31 | self.selectedImage = selectedImage
32 |
33 | /// Present!
34 | self.showSelectedImageView.toggle()
35 | },
36 | didFinishDraggingOnItem: { selectedImage in
37 | print("on drag finish : ", selectedImage)
38 | })
39 | .edgesIgnoringSafeArea(.all)
40 | .sheet(isPresented:self.$showSelectedImageView) {
41 | /// The example view showing a picked up image.
42 | ShowingSelectedImageView(selectedImage: self.selectedImage)
43 | }
44 | }
45 | ```
46 |
47 | ## Features
48 |
49 | - [x] Designed for SwiftUI, SwiftUI 100% is supported.
50 | - [x] Complex grid ScrollView UI is provided out of box.
51 | - [x] Tracking user touch area on the grid scrollview, Zooming items is done out of box.
52 | - [x] BSZoomGridScrollView will return an image selected by a user, detected by the internal long press and pan gesture inside out of box.
53 | - [x] Grid UI can be styled for number of columns, rows, zoom effect and images you would like to input to show in the grid.
54 |
55 |
56 |
57 | ## Example
58 |
59 | To run the example project, clone the repo, and run `pod install` from the Example directory first.
60 | It includes examples for UIKit as well as SwiftUI.
61 |
62 | ## Requirements
63 |
64 | - iOS 13.0 or later
65 | - Swift 5.0 or later
66 | - Xcode 11.0 or later
67 |
68 |
69 | Getting Started
70 | ---------------
71 |
72 | * SwiftUI
73 |
74 | ```Swift
75 | import SwiftUI
76 |
77 | /// 🥳 # Step1: let's import!
78 | import BSZoomGridScrollView
79 |
80 | struct ContentView: View {
81 | var itemsToZoom: [UIImage] = {
82 | var images = [UIImage]()
83 | for i in 0...29 {
84 | images.append(UIImage(named: "yourImage\(i)") ?? UIImage())
85 | }
86 | return images
87 | }()
88 |
89 | var body: some View {
90 | /// 😊 # Step2. That's it. completed!
91 | BSZoomGridScrollView(itemsToZoom: itemsToZoom,
92 | powerOfZoomBounce: .regular,
93 | isBeingDraggingOnItem:{ selectedImage in
94 | ///
95 | },
96 | didLongPressItem: { selectedImage in
97 | /// Grab an image user ends up choosing.
98 | },
99 | didFinishDraggingOnItem: { selectedImage in
100 | /// Grab an image user ends up choosing.
101 | })
102 | .edgesIgnoringSafeArea(.all)
103 | }
104 | }
105 | ```
106 |
107 | * UIKit
108 | ```Swift
109 | ///
110 | /// To use BSZoomGridScrollView,
111 | /// Please, Follow steps written in the comments with icon like 😀.
112 | ///
113 |
114 | import SwiftUI
115 | import UIKit
116 |
117 | ///
118 | // 😚 #Step1: import BSZoomGridScrollView!
119 | ///
120 | import BSZoomGridScrollView
121 |
122 | class ViewController: UIViewController {
123 |
124 | ///
125 | // 😋 #Step2: declare BSZoomGridScrollView
126 | ///
127 | private lazy var zoomGridScrollViewController: BSZoomGridScrollViewController = { [unowned self] in
128 | ///
129 | /// It can be used on both SwiftUI and UIKit.
130 | /// To see how it works on SwiftUI,
131 | /// please refer to comments in SwiftUI directory -> ContentView.swift
132 | ///
133 | return BSZoomGridScrollViewController(itemsToZoom: self.itemsToZoom,
134 | powerOfZoomBounce: .regular,
135 | scrollEnableButtonTintColor: .black,
136 | scrollEnableButtonBackgroundColor: .white,
137 | isBeingDraggingOnItem:{ [unowned self] selectedImage in
138 | ///
139 | },
140 | didLongPressItem: { [unowned self] selectedImage in
141 | /// Grab an image user end up choosing.
142 | },
143 | didFinishDraggingOnItem: { [unowned self] selectedImage in
144 | /// on drag finished
145 | })
146 | }()
147 |
148 | ///
149 | // prepare any item array to feed to BSZoomGridScrollViewController.
150 | ///
151 | private var itemsToZoom: [Any] = {
152 | var images = [UIImage]()
153 | for i in 0...29 {
154 | images.append(UIImage(named: "s\(i)") ?? UIImage())
155 | }
156 | return images
157 | }()
158 |
159 | ///
160 | // 😁 #Step3: Present it!
161 | ///
162 | @IBAction func goToBSZoomGridScrollView(_ sender: Any) {
163 | ///
164 | // 😎 That's all. well done.
165 | ///
166 |
167 | self.present(UINavigationController(rootViewController: zoomGridScrollViewController),
168 | animated: true,
169 | completion: nil)
170 | }
171 |
172 | ///
173 | // MARK: - ViewController LifeCycle Methods
174 | ///
175 | override func viewDidLoad() {
176 | super.viewDidLoad()
177 | }
178 |
179 | override func didReceiveMemoryWarning() {
180 | super.didReceiveMemoryWarning()
181 | }
182 | }
183 |
184 | ```
185 |
186 | ## Installation
187 |
188 | There are four ways to use BSZoomGridScrollView in your project:
189 | - using CocoaPods
190 | - using Swift Package Manager
191 | - manual install (build frameworks or embed Xcode Project)
192 |
193 | ### Installation with CocoaPods
194 |
195 | [CocoaPods](http://cocoapods.org/) is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries in your projects. See the [Get Started](http://cocoapods.org/#get_started) section for more details.
196 |
197 | #### Podfile
198 |
199 | First,
200 | ```ruby
201 | pod 'BSZoomGridScrollView'
202 | ```
203 | then in your root project,
204 | ```ruby
205 | pod install
206 | ```
207 |
208 | ### Installation with Swift Package Manager (Xcode 11+)
209 |
210 | [Swift Package Manager](https://swift.org/package-manager/) (SwiftPM) is a tool for managing the distribution of Swift code as well as C-family dependency. From Xcode 11, SwiftPM got natively integrated with Xcode.
211 |
212 | BSZoomGridScrollView support SwiftPM from version 5.1.0. To use SwiftPM, you should use Xcode 11 to open your project. Click `File` -> `Swift Packages` -> `Add Package Dependency`, enter [BSZoomGridScrollView repo's URL](https://github.com/boraseoksoon/BSZoomGridScrollView). Or you can login Xcode with your GitHub account and just type `BSZoomGridScrollView` to search.
213 |
214 | After select the package, you can choose the dependency type (tagged version, branch or commit). Then Xcode will setup all the stuff for you.
215 |
216 | If you're a framework author and use BSZoomGridScrollView as a dependency, update your `Package.swift` file:
217 |
218 | ```swift
219 | let package = Package(
220 | dependencies: [
221 | .package(url: "https://github.com/boraseoksoon/BSZoomGridScrollView", from: "0.1.1")
222 | ],
223 | // ...
224 | )
225 | ```
226 | ## Disclamer
227 |
228 | It was done for my fun.
229 |
230 | ## Author
231 |
232 | boraseoksoon@gmail.com
233 |
234 | ## License
235 |
236 | BSZoomGridScrollView is available under the MIT license. See the LICENSE file for more info.
237 |
238 |
239 | ## References
240 |
241 | [Observable](https://apps.apple.com/us/app/observable/id1488022000?ls=1) :
242 | Photos browsing iOS app where you can download the photos for free as you like.
243 |
244 |
245 |
246 |
247 |
--------------------------------------------------------------------------------
/Sources/BSZoomGridScrollView/Classes/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/boraseoksoon/BSZoomGridScrollView/11f2b1de1882bd7f41fc0128db8e0bbbff0ab5f5/Sources/BSZoomGridScrollView/Classes/.gitkeep
--------------------------------------------------------------------------------
/Sources/BSZoomGridScrollView/Classes/BSZoomGridScrollView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BSZoomGridScrollView.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by Jang seoksoon on 2019/11/19.
6 | //
7 | // Copyright (c) 2019 Jang seoksoon
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | #if os(iOS)
28 | import SwiftUI
29 | import UIKit
30 |
31 | ///
32 | /// UIKit -> SwiftUI Coordinator
33 | ///
34 | public struct BSZoomGridScrollView {
35 | // MARK: - Initializer
36 | ///
37 | public init(itemsToZoom: [Any],
38 | powerOfZoomBounce: ZoomBounceRatio,
39 | numberOfColumns: Int = 0,
40 | numberOfRows: Int = 0,
41 | scrollEnableButtonTintColor: UIColor = .black,
42 | scrollEnableButtonBackgroundColor: UIColor = .white,
43 | isBeingDraggingOnItem: ((_: UIImage) -> Void)?,
44 | didTapOnItem: ((_: UIImage) -> Void)?,
45 | didLongPressItem: ((_: UIImage) -> Void)?,
46 | didFinishDraggingOnItem: ((_: UIImage) -> Void)?) {
47 | self.didTapOnItem = didTapOnItem
48 | self.didLongPressItem = didLongPressItem
49 | self.didFinishDraggingOnItem = didFinishDraggingOnItem
50 | self.isBeingDraggingOnItem = isBeingDraggingOnItem
51 |
52 | self.itemsToZoom = itemsToZoom
53 | self.powerOfZoomBounce = powerOfZoomBounce
54 | self.scrollEnableButtonTintColor = scrollEnableButtonTintColor
55 | self.scrollEnableButtonBackgroundColor = scrollEnableButtonBackgroundColor
56 |
57 | self.numberOfColumns = numberOfColumns
58 | self.numberOfRows = numberOfRows
59 | }
60 |
61 | // MARK: - Instance Variables
62 | ///
63 | private let itemsToZoom: [Any]
64 | private let powerOfZoomBounce: ZoomBounceRatio
65 | private let numberOfColumns: Int
66 | private let numberOfRows: Int
67 | private let scrollEnableButtonTintColor: UIColor
68 | private let scrollEnableButtonBackgroundColor: UIColor
69 | private let isBeingDraggingOnItem: ((_: UIImage) -> Void)?
70 | private let didTapOnItem: ((_: UIImage) -> Void)?
71 | private let didLongPressItem: ((_: UIImage) -> Void)?
72 | private let didFinishDraggingOnItem: ((_: UIImage) -> Void)?
73 | }
74 |
75 | // MARK: - Public Methods
76 | ///
77 | extension BSZoomGridScrollView: UIViewControllerRepresentable {
78 |
79 | public func makeCoordinator() -> Coordinator {
80 | Coordinator(self)
81 | }
82 |
83 | public func makeUIViewController(context: Context) -> BSZoomGridScrollViewController {
84 | let scrollViewController = BSZoomGridScrollViewController(itemsToZoom: itemsToZoom,
85 | powerOfZoomBounce: self.powerOfZoomBounce,
86 | numberOfColumns: self.numberOfColumns,
87 | numberOfRows: self.numberOfRows,
88 | scrollEnableButtonTintColor: self.scrollEnableButtonTintColor,
89 | scrollEnableButtonBackgroundColor: self.scrollEnableButtonBackgroundColor,
90 | isBeingDraggingOnItem: self.isBeingDraggingOnItem,
91 | didTapOnItem:self.didTapOnItem,
92 | didLongPressItem:self.didLongPressItem,
93 | didFinishDraggingOnItem:self.didFinishDraggingOnItem)
94 | return scrollViewController
95 | }
96 |
97 | public func updateUIViewController(_ vc: BSZoomGridScrollViewController, context: Context) {
98 | vc.refresh(self.itemsToZoom)
99 | }
100 |
101 | public class Coordinator: NSObject {
102 | private var parent: BSZoomGridScrollView
103 |
104 | public init(_ pageViewController: BSZoomGridScrollView) {
105 | self.parent = pageViewController
106 | }
107 | }
108 | }
109 |
110 | #endif
111 |
--------------------------------------------------------------------------------
/Sources/BSZoomGridScrollView/Classes/BSZoomGridScrollView/Extension/UIControl+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIButton.swift
3 | // BSZoomGridScrollViewSwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/11/19.
6 | // Copyright © 2019 Seoksoon Jang. All rights reserved.
7 | //
8 |
9 | #if os(iOS)
10 | import UIKit
11 |
12 | @objc private class ClosureBox: NSObject {
13 | let closure: ()->()
14 |
15 | init (_ closure: @escaping ()->()) {
16 | self.closure = closure
17 | }
18 |
19 | @objc func invoke () {
20 | closure()
21 | }
22 | }
23 |
24 | extension UIControl {
25 | func take(for controlEvents: UIControl.Event = .touchUpInside, _ closure: @escaping ()->()) {
26 | let container = ClosureBox(closure)
27 | addTarget(container, action: #selector(ClosureBox.invoke), for: controlEvents)
28 | objc_setAssociatedObject(self, "[\(arc4random())]", container, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
29 | }
30 | }
31 |
32 | #endif
33 |
--------------------------------------------------------------------------------
/Sources/BSZoomGridScrollView/Classes/BSZoomGridScrollView/Extension/UIImage+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+Extension.swift
3 | // BSZoomGridScrollViewSwiftUIExample
4 | //
5 | // Created by Seoksoon Jang on 2019/11/18.
6 | // Copyright © 2019 Seoksoon Jang. All rights reserved.
7 | //
8 |
9 | #if os(iOS)
10 | import UIKit
11 |
12 | extension UIImage {
13 | func resized(to size: CGSize) -> UIImage {
14 | return UIGraphicsImageRenderer(size: size).image { _ in
15 | draw(in: CGRect(origin: .zero, size: size))
16 | }
17 | }
18 | }
19 |
20 | #endif
21 |
--------------------------------------------------------------------------------
/Sources/BSZoomGridScrollView/Classes/BSZoomGridScrollView/Extension/UIViewController+Extension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+Extension.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by Seoksoon Jang on 2019/11/19.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIViewController {
11 | func showToast(message : String, font: UIFont) {
12 | let toast = UILabel(frame: CGRect(x: self.view.frame.size.width/2 - 75,
13 | y: self.view.frame.size.height-(self.view.frame.size.height * 0.3),
14 | width: 150,
15 | height: 50))
16 | toast.backgroundColor = UIColor.black.withAlphaComponent(0.8)
17 | toast.textColor = UIColor.white
18 | toast.font = font
19 | toast.textAlignment = .center;
20 | toast.text = message
21 | toast.alpha = 1.0
22 | toast.layer.cornerRadius = 15;
23 | toast.clipsToBounds = true
24 |
25 | self.view.addSubview(toast)
26 |
27 | UIView.animate(withDuration: 4.0, delay: 0.1, options: .curveEaseOut, animations: {
28 | toast.alpha = 0.0
29 | }, completion: { isCompleted in
30 | if isCompleted {
31 | toast.removeFromSuperview()
32 | }
33 | })
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Sources/BSZoomGridScrollView/Classes/BSZoomGridScrollView/Function/Functions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Functions.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by Jang seoksoon on 2019/11/19.
6 | //
7 | // Copyright (c) 2019 Jang seoksoon
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 |
30 | // MARK: - Grand Central Dispatch Wrapper -
31 | func MainQ(completion: @escaping () -> Void) {
32 | DispatchQueue.main.async {
33 | completion()
34 | }
35 | }
36 |
37 | func GlobalQ(threadName: String = Bundle.main.bundleIdentifier ?? "BSZoomGridScrollView",
38 | completion: @escaping () -> Void) {
39 | DispatchQueue.global().async {
40 | completion()
41 | }
42 | }
43 |
44 | let serialQueue = DispatchQueue(label: Bundle.main.bundleIdentifier ?? "BSZoomGridScrollView")
45 | func SerialQ(completion: @escaping () -> Void) {
46 | serialQueue.async {
47 | completion()
48 | }
49 | }
50 |
51 | func Delay(_ delaySeconds: Double, completion: @escaping () -> Void) -> Void {
52 | DispatchQueue.main.asyncAfter(deadline: .now() + delaySeconds) {
53 | completion()
54 | }
55 | }
56 |
57 | #if os(iOS)
58 | import UIKit
59 | // MARK: - Utility
60 | ///
61 | func GetRootViewController() -> UIViewController? {
62 | let keyWindow = UIApplication.shared.connectedScenes
63 | .filter({$0.activationState == .foregroundActive})
64 | .map({$0 as? UIWindowScene})
65 | .compactMap({$0})
66 | .first?.windows
67 | .filter({$0.isKeyWindow}).first
68 | return keyWindow?.rootViewController
69 | }
70 |
71 | func RandomEmoji() -> String {
72 | let range = 0x1F300...0x1F3F0
73 | let index = Int(arc4random_uniform(UInt32(range.count)))
74 | let ord = range.lowerBound + index
75 | guard let scalar = UnicodeScalar(ord) else { return "❓" }
76 | return String(scalar)
77 | }
78 |
79 | #endif
80 |
--------------------------------------------------------------------------------
/Sources/BSZoomGridScrollView/Classes/BSZoomGridScrollView/UIKit/BSZoomGridBaseViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BSZoomGridBaseViewController.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by Jang seoksoon on 2019/11/19.
6 | //
7 | // Copyright (c) 2019 Jang seoksoon
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | #if os(iOS)
28 | import UIKit
29 |
30 | public class BSZoomGridBaseViewController: UIViewController {
31 | // MARK: - Initializers
32 | /// Using constuctor Dependency Injection, all initialization should be done in the constructor.
33 | ///
34 | /// - Parameters:
35 | /// - parentView: a parent view to add scrollView as subview
36 | /// - itemsToZoom: item array in grid to be displayed such as [UIImage]
37 | /// if item numbers are not enough to fill the grid, it will be repeated until grid is fully drawn.
38 | /// - powerOfZoomBounce: a value to be able to choose from enum four enumeration types
39 | /// - numberOfRows: number of row to be applied in a row.
40 | /// - didLongPressItem: closure that will indicates which UIImage is decided to be chosen, by a long touch.
41 | /// - didFinishDraggingOnItem: closure that will indicates
42 | /// which UIImage is decided to be chosen, by a end of pan gesture touch.
43 | /// - Returns: Initializer
44 | public init(itemsToZoom: [Any],
45 | powerOfZoomBounce: ZoomBounceRatio,
46 | numberOfColumns: Int = 0,
47 | numberOfRows: Int = 0,
48 | scrollEnableButtonTintColor: UIColor = .black,
49 | scrollEnableButtonBackgroundColor: UIColor = .white,
50 | isBeingDraggingOnItem: ((_: UIImage) -> Void)?,
51 | didTapOnItem: ((_: UIImage) -> Void)?,
52 | didLongPressItem: ((_: UIImage) -> Void)?,
53 | didFinishDraggingOnItem: ((_: UIImage) -> Void)?) {
54 | /// Closures
55 | self.didTapOnItem = didTapOnItem
56 | self.didLongPressItem = didLongPressItem
57 | self.didFinishDraggingOnItem = didFinishDraggingOnItem
58 | self.isBeingDraggingOnItem = isBeingDraggingOnItem
59 |
60 | self.itemsToZoom = itemsToZoom
61 | self.powerOfZoomBounce = powerOfZoomBounce
62 |
63 | super.init(nibName: nil, bundle: nil)
64 |
65 | self.numberOfColumns = numberOfColumns
66 | self.numberOfRows = numberOfRows
67 | self.scrollEnableButtonTintColor = scrollEnableButtonTintColor
68 | self.scrollEnableButtonBackgroundColor = scrollEnableButtonBackgroundColor
69 | }
70 |
71 | required public init?(coder: NSCoder) {
72 | fatalError("""
73 | init(coder:) has not been implemented.\n
74 | Creating BSZoomGridScrollViewController programmatically is only allowed.
75 | """)
76 | }
77 |
78 | // MARK: - Private Instance Variables
79 | /// private accessor goes here.
80 | internal private(set) var didLongPressItem: ((_: UIImage) -> Void)?
81 | internal private(set) var didFinishDraggingOnItem: ((_: UIImage) -> Void)?
82 | internal private(set) var didTapOnItem: ((_: UIImage) -> Void)?
83 | internal private(set) var isBeingDraggingOnItem: ((_: UIImage) -> Void)?
84 |
85 | internal private(set) var itemsToZoom: [Any]
86 |
87 | internal private(set) var powerOfZoomBounce: ZoomBounceRatio
88 |
89 | private var _scrollEnableButtonBackgroundColor: UIColor = .black
90 | internal var scrollEnableButtonBackgroundColor: UIColor {
91 | get {
92 | return _scrollEnableButtonBackgroundColor
93 | }
94 | set {
95 | _scrollEnableButtonBackgroundColor = newValue
96 | }
97 | }
98 |
99 | private var _scrollEnableButtonTintColor: UIColor = .black
100 | internal var scrollEnableButtonTintColor: UIColor {
101 | get {
102 | return _scrollEnableButtonTintColor
103 | }
104 | set {
105 | _scrollEnableButtonTintColor = newValue
106 | }
107 | }
108 |
109 | private var _numberOfColumns: CGFloat = 70.0
110 | internal private(set) var numberOfColumns: Int {
111 | get {
112 | return Int(_numberOfColumns)
113 | }
114 | set {
115 | _numberOfColumns = CGFloat(newValue)
116 | }
117 | }
118 |
119 | private var _numberOfRows: CGFloat = 30.0
120 | internal private(set) var numberOfRows: Int {
121 | get {
122 | return Int(_numberOfRows)
123 | }
124 | set {
125 | _numberOfRows = CGFloat(newValue)
126 | }
127 | }
128 | }
129 | #endif
130 |
--------------------------------------------------------------------------------
/Sources/BSZoomGridScrollView/Classes/BSZoomGridScrollViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BSZoomGridScrollViewController.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by Jang seoksoon on 2019/11/19.
6 | //
7 | // Copyright (c) 2019 Jang seoksoon
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | #if os(iOS)
28 | import UIKit
29 |
30 | ///
31 | /// 😁 #Step1: Inherits BSZoomGridBaseViewController in order to inject constructor including instances variables,
32 | /// Actually, it does not do any important tasks.
33 | /// So, you can ignore inheritance. By doing so, however, currently you can't change configuration.
34 | public final class BSZoomGridScrollViewController: BSZoomGridBaseViewController {
35 | ///
36 | /// 🤔 #Step2: These buttons are not a mandatory,
37 | /// but it will help us scroll up and down in the grid scroll view.
38 |
39 | // MARK: - Instance Variables
40 | ///
41 |
42 | /// To programmtically disable scroll view,
43 | /// target & action is wrapped by closure.
44 | /// FYI: UIControl+Extension
45 | private lazy var disableOrNotButton: UIButton = { [unowned self] in
46 | let b = UIButton()
47 | b.frame = CGRect(x: UIScreen.main.bounds.width - (UIScreen.main.bounds.width * 0.25),
48 | y: UIScreen.main.bounds.height - (UIScreen.main.bounds.height * 0.25),
49 | width: BSZoomGridUIScrollView.ICON_WIDTH,
50 | height: BSZoomGridUIScrollView.ICON_WIDTH)
51 |
52 | b.setBackgroundImage(UIImage(systemName: "circle"),
53 | for: .normal)
54 |
55 | b.setBackgroundImage(UIImage(systemName: "circle.fill"),
56 | for: .highlighted)
57 |
58 | b.tintColor = self.scrollEnableButtonTintColor
59 | b.backgroundColor = self.scrollEnableButtonBackgroundColor
60 |
61 | b.layer.cornerRadius = b.frame.size.width / 2.0
62 | b.clipsToBounds = true
63 |
64 | b.take(for: .touchUpInside) { [unowned self] in
65 | self.zoomGridScrollView.isScrollEnabled = !self.zoomGridScrollView.isScrollEnabled
66 |
67 | self.showToast(
68 | message: self.zoomGridScrollView.isScrollEnabled
69 | ? "Scroll enabled. \(RandomEmoji())" : "Scroll locked. \(RandomEmoji())",
70 | font: .boldSystemFont(ofSize: 16)
71 | )
72 | }
73 |
74 | return b
75 | }()
76 |
77 | ///
78 | /// 😊 #Step3: Init BSZoomGridUIScrollView, ready to use!
79 | private lazy var zoomGridScrollView: BSZoomGridUIScrollView = { [unowned self] in
80 | return BSZoomGridUIScrollView(parentView: self.view,
81 | itemsToZoom: self.itemsToZoom,
82 | powerOfZoomBounce: self.powerOfZoomBounce,
83 | numberOfColumns: self.numberOfColumns,
84 | numberOfRows: self.numberOfRows,
85 | isBeingDraggingOnItem: self.isBeingDraggingOnItem,
86 | didTapOnItem: self.didTapOnItem,
87 | didLongPressItem: self.didLongPressItem,
88 | didFinishDraggingOnItem: self.didFinishDraggingOnItem)
89 | }()
90 |
91 | // MARK: - View LifeCycle Methods
92 | ///
93 | override public func viewDidLoad() {
94 | super.viewDidLoad()
95 |
96 | ///
97 | /// 😎 # Step4: That's it. well done!
98 | /// Add all views created so far.
99 | self.view.addSubview(self.zoomGridScrollView)
100 | self.view.addSubview(self.disableOrNotButton)
101 | }
102 |
103 | }
104 |
105 | // MARK: - Public Methods
106 | ///
107 | extension BSZoomGridScrollViewController {
108 | /// Refresh and redraw array items in the grid
109 | ///
110 | /// - Parameters:
111 | /// - compositingOperation: The compositing operation of creating image.
112 | /// - alpha: The alpha should be used for image.
113 | /// - backgroundColor: The background color for the output image.
114 | /// - Returns: An image with compositing operation applied.
115 | ///
116 | /// - Note: This method only works for CG-based image. For any non-CG-based image, `base` itself is returned.
117 |
118 | public func refresh(_ itemsToZoom: [Any]) -> Void {
119 | self.zoomGridScrollView.refresh(itemsToZoom)
120 | }
121 | }
122 | #endif
123 |
--------------------------------------------------------------------------------
/Sources/BSZoomGridScrollView/Classes/Enumeration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Enumeration.swift
3 | // BSZoomGridScrollView
4 | //
5 | // Created by Jang seoksoon on 2019/11/19.
6 | //
7 | // Copyright (c) 2019 Jang seoksoon
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 | // MARK: - Enumeration
30 | /// it will decide bounce animation ratio. it should be only used and injected in the constructor.
31 | public enum ZoomBounceRatio {
32 | case weak
33 | case regular
34 | case strong
35 | case crazy
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/Tests/BSZoomGridScrollViewTests/BSZoomGridScrollViewTests.swift:
--------------------------------------------------------------------------------
1 | //import XCTest
2 | //@testable import BSZoomGridScrollView
3 | //
4 | //final class BSZoomGridScrollViewTests: XCTestCase {
5 | // func testExample() {
6 | // // This is an example of a functional test case.
7 | // // Use XCTAssert and related functions to verify your tests produce the correct
8 | // // results.
9 | // XCTAssertEqual(BSZoomGridScrollView().text, "Hello, World!")
10 | // }
11 | //
12 | // static var allTests = [
13 | // ("testExample", testExample),
14 | // ]
15 | //}
16 |
--------------------------------------------------------------------------------
/Tests/BSZoomGridScrollViewTests/XCTestManifests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | #if !canImport(ObjectiveC)
4 | public func allTests() -> [XCTestCaseEntry] {
5 | return [
6 | testCase(BSZoomGridScrollViewTests.allTests),
7 | ]
8 | }
9 | #endif
10 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | import BSZoomGridScrollViewTests
4 |
5 | var tests = [XCTestCaseEntry]()
6 | tests += BSZoomGridScrollViewTests.allTests()
7 | XCTMain(tests)
8 |
--------------------------------------------------------------------------------
/_Pods.xcodeproj:
--------------------------------------------------------------------------------
1 | Example/Pods/Pods.xcodeproj
--------------------------------------------------------------------------------