├── .swift-version ├── gifs ├── mmsharesheet_1.gif ├── mmsharesheet_2.gif ├── mmsharesheet_3.gif └── mmsharesheet_4.gif ├── swiftui ├── Assets.xcassets │ ├── Contents.json │ ├── qq.imageset │ │ ├── qq.png │ │ └── Contents.json │ ├── icon.imageset │ │ ├── icon.png │ │ └── Contents.json │ ├── sina.imageset │ │ ├── sina.png │ │ └── Contents.json │ ├── jubao.imageset │ │ ├── jubao.png │ │ └── Contents.json │ ├── airpay.imageset │ │ ├── airpay.png │ │ └── Contents.json │ ├── moment.imageset │ │ ├── moment.png │ │ └── Contents.json │ ├── safari.imageset │ │ ├── safari.png │ │ └── Contents.json │ ├── wechat.imageset │ │ ├── wechat.png │ │ └── Contents.json │ ├── copy_link.imageset │ │ ├── copy_link.png │ │ └── Contents.json │ ├── collection.imageset │ │ ├── collection.png │ │ └── Contents.json │ ├── refresh_icon.imageset │ │ ├── refresh_icon.png │ │ └── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── AppDelegate.swift └── Base.lproj │ └── LaunchScreen.storyboard ├── swiftui.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── project.pbxproj ├── .gitignore ├── MMShareSheet.podspec ├── LICENSE ├── Components ├── MMCardItem.swift └── MMShareSheet.swift ├── README.md ├── Example ├── ExampleShareSheetVC.swift └── Example.storyboard └── Tools └── SwiftNotice.swift /.swift-version: -------------------------------------------------------------------------------- 1 | 3.0 2 | -------------------------------------------------------------------------------- /gifs/mmsharesheet_1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MinMao-Hub/MMShareSheet/HEAD/gifs/mmsharesheet_1.gif -------------------------------------------------------------------------------- /gifs/mmsharesheet_2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MinMao-Hub/MMShareSheet/HEAD/gifs/mmsharesheet_2.gif -------------------------------------------------------------------------------- /gifs/mmsharesheet_3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MinMao-Hub/MMShareSheet/HEAD/gifs/mmsharesheet_3.gif -------------------------------------------------------------------------------- /gifs/mmsharesheet_4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MinMao-Hub/MMShareSheet/HEAD/gifs/mmsharesheet_4.gif -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/qq.imageset/qq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MinMao-Hub/MMShareSheet/HEAD/swiftui/Assets.xcassets/qq.imageset/qq.png -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/icon.imageset/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MinMao-Hub/MMShareSheet/HEAD/swiftui/Assets.xcassets/icon.imageset/icon.png -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/sina.imageset/sina.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MinMao-Hub/MMShareSheet/HEAD/swiftui/Assets.xcassets/sina.imageset/sina.png -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/jubao.imageset/jubao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MinMao-Hub/MMShareSheet/HEAD/swiftui/Assets.xcassets/jubao.imageset/jubao.png -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/airpay.imageset/airpay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MinMao-Hub/MMShareSheet/HEAD/swiftui/Assets.xcassets/airpay.imageset/airpay.png -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/moment.imageset/moment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MinMao-Hub/MMShareSheet/HEAD/swiftui/Assets.xcassets/moment.imageset/moment.png -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/safari.imageset/safari.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MinMao-Hub/MMShareSheet/HEAD/swiftui/Assets.xcassets/safari.imageset/safari.png -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/wechat.imageset/wechat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MinMao-Hub/MMShareSheet/HEAD/swiftui/Assets.xcassets/wechat.imageset/wechat.png -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/copy_link.imageset/copy_link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MinMao-Hub/MMShareSheet/HEAD/swiftui/Assets.xcassets/copy_link.imageset/copy_link.png -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/collection.imageset/collection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MinMao-Hub/MMShareSheet/HEAD/swiftui/Assets.xcassets/collection.imageset/collection.png -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/refresh_icon.imageset/refresh_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MinMao-Hub/MMShareSheet/HEAD/swiftui/Assets.xcassets/refresh_icon.imageset/refresh_icon.png -------------------------------------------------------------------------------- /swiftui.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | swiftui.xcodeproj/project.xcworkspace/xcuserdata 3 | swiftui.xcodeproj/project.xcworkspace/xcshareddata 4 | swiftui.xcworkspace/xcuserdata/ 5 | swiftui.xcworkspace/xcshareddata/ 6 | swiftui.xcodeproj/xcshareddata/ 7 | swiftui.xcodeproj/xcuserdata/ 8 | -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "icon.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/qq.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "qq.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/sina.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "sina.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/airpay.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "airpay.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/jubao.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "jubao.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/moment.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "moment.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/safari.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "safari.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/wechat.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "wechat.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/copy_link.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "copy_link.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/collection.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "collection.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /swiftui/Assets.xcassets/refresh_icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "refresh_icon.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /MMShareSheet.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "MMShareSheet" 4 | s.version = "0.0.3" 5 | s.summary = "MMShareSheet is an simple pop-up selection box(ShareSheet) written in pure Swift" 6 | s.homepage = "https://github.com/MinMao-Hub" 7 | s.license = "MIT" 8 | s.author = { "gyh" => "m12860gyh@gmail.com" } 9 | s.platform = :ios, "8.0" 10 | s.source = { :git => "https://github.com/MinMao-Hub/MMShareSheet.git", :tag => "#{s.version}" } 11 | s.source_files = "Components" 12 | end 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 小冒 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /swiftui/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 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Example 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | NSAppTransportSecurity 45 | 46 | NSAllowsArbitraryLoads 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /swiftui/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 | } -------------------------------------------------------------------------------- /swiftui/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // swiftui 4 | // 5 | // Created by 郭永红 on 2017/10/12. 6 | // Copyright © 2017年 keeponrunning. 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: [UIApplicationLaunchOptionsKey: 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 invalidate graphics rendering callbacks. 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 active 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 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Components/MMCardItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MMCardItem.swift 3 | // swiftui 4 | // 5 | // Created by 郭永红 on 2017/10/12. 6 | // Copyright © 2017年 keeponrunning. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | let mm_itemWidth:CGFloat = 60.0 * ss_mmscreenWidth / 375 /* item的宽高 */ 12 | let mm_itemPadding:CGFloat = 8.0 * ss_mmscreenWidth / 375 /* item距离顶部的距离 */ 13 | let mm_titlePadding:CGFloat = 5.0 * ss_mmscreenWidth / 375 /* item距离顶部的距离 */ 14 | public class MMCardItem: UIView { 15 | 16 | var icon: String? 17 | var title: String? 18 | var handler: String? 19 | var callBack:ItemClickBlock? 20 | 21 | public override init(frame: CGRect) { 22 | super.init(frame: frame) 23 | } 24 | 25 | required public init?(coder aDecoder: NSCoder) { 26 | fatalError("init(coder:) has not been implemented") 27 | } 28 | 29 | convenience public init(frame: CGRect,props: Dictionary?, callback: @escaping ItemClickBlock) { 30 | self.init(frame: frame) 31 | self.title = props?["title"] ?? "" 32 | self.icon = props?["icon"] ?? "" 33 | self.handler = props?["handler"] ?? "" 34 | self.callBack = callback 35 | initUI() 36 | 37 | } 38 | 39 | func initUI() { 40 | 41 | let button = UIButton.init(type: .custom) 42 | button.frame = CGRect.init(x: (self.bounds.size.width - mm_itemWidth) / 2, y: mm_itemPadding, width: mm_itemWidth, height: mm_itemWidth) 43 | 44 | var imageNormal:UIImage? = nil 45 | 46 | DispatchQueue.global().async { 47 | if self.icon != "" { 48 | if (self.icon?.hasPrefix("http"))! { 49 | do { 50 | let imgData = try Data.init(contentsOf: URL.init(string: self.icon!)!) 51 | imageNormal = UIImage.init(data: imgData, scale: UIScreen.main.scale) 52 | } catch { 53 | //Handle exception 54 | } 55 | } else { 56 | imageNormal = UIImage.init(named: self.icon!) 57 | } 58 | } 59 | 60 | DispatchQueue.main.async { 61 | button.setBackgroundImage(imageNormal, for: .normal) 62 | } 63 | } 64 | 65 | button.addTarget(self, action: #selector(self.itemClick), for: .touchUpInside) 66 | 67 | self.addSubview(button) 68 | 69 | if (self.title != nil && self.title != "") { 70 | let titlelabel = UILabel.init(frame: CGRect.init(x: 0, y: mm_itemWidth + mm_itemPadding + mm_titlePadding, width: self.bounds.size.width, height: 20)) 71 | titlelabel.text = self.title 72 | titlelabel.textAlignment = .center 73 | titlelabel.textColor = UIColor(red: 0.365, green: 0.361, blue: 0.357, alpha: 1.00) 74 | titlelabel.font = UIFont.systemFont(ofSize: 12) 75 | titlelabel.backgroundColor = UIColor(red: 0.937, green: 0.937, blue: 0.941, alpha: 0.00) 76 | titlelabel.adjustsFontSizeToFitWidth = true 77 | self.addSubview(titlelabel) 78 | } 79 | } 80 | 81 | @objc func itemClick(button:UIButton) { 82 | if (self.callBack != nil) { 83 | self.callBack!(self.handler!) 84 | } 85 | } 86 | 87 | public override func layoutSubviews() { 88 | super.layoutSubviews() 89 | 90 | self.backgroundColor = UIColor(red: 0.937, green: 0.937, blue: 0.941, alpha: 0.90).withAlphaComponent(0.0) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /swiftui/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | MarkerFelt-Wide 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## MMShareSheet 3 | 4 | 5 | [![Building](https://img.shields.io/wercker/ci/wercker/docs.svg?style=flat)](https://cocoapods.org/pods/MMShareSheet) 6 | [![Language](https://img.shields.io/badge/language-Swift-orange.svg?style=flat)](https://github.com/MinMao-Hub/MMShareSheet) 7 | [![CocoaPods compatible](https://img.shields.io/badge/pod-v1.3.1-blue.svg?style=flat)](https://cocoapods.org/pods/MMShareSheet) 8 | [![Platform](https://img.shields.io/badge/platform-ios-lightgrey.svg?style=flat)](https://github.com/MinMao-Hub/MMShareSheet) 9 | [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](http://opensource.org/licenses/MIT) 10 | 11 | ### Introduction 12 | 13 | MMShareSheet 是一个简单的弹出选择框,使用纯swift编写,类似于微信(或支付宝)里面的分享(朋友圈打开网页右上角分享)控件 14 | 15 | MMShareSheet is an simple pop-up selection box(ShareSheet) written in pure Swift. Similar to the wechat(or airpay) actionsheet share-UIKit 16 | 17 | ### Rquirements 18 | 19 | * iOS 8.0+ 20 | * Xcode 9 (swift 4) 21 | * Xcode 8 (swift 3) 22 | * If you want to run demo in swift3, please switch branch to swift3.0 23 | 24 | ### Installation 25 | 26 | 27 | #### Install with Cocoapods 28 | 29 | * `pod 'MMShareSheet', '~> 0.0'` 30 | * `import MMShareSheet ` in you code 31 | 32 | 33 | #### Copy code into project 34 | 35 | [克隆代码](https://github.com/MinMao-Hub/MMShareSheet.git),然后将components文件夹下面的两个文件 `MMShareSheet.swift` 和 `MMCardItem.swift`加入到你的项目中即可。 36 | 37 | Just clone and add `MMShareSheet.swift`, `MMCardItem.swift` to your project. 38 | 39 | ### Example 40 | 41 | > 1. 【类似于微信分享】- Similar to WeChat share 42 | > 43 | > 2. 【单组cards】- Single group cards(显示组数完全取决于传入的cards数组) 44 | > 45 | > 3. 【多组cards】- Multi group cards 46 | > 47 | > 4. 【支持远程icon】- Support remote Icon 48 | 49 |
50 | 51 | 52 |
53 |
54 | 55 | 56 |
57 | 58 | 59 | ### Usage 60 | 61 | ```swift 62 | let cards = [ 63 | [ 64 | [ 65 | "title": "微信好友", 66 | "icon": "wechat", 67 | "handler": "wxfriend" 68 | ],[ 69 | "title": "微信朋友圈", 70 | "icon": "moment", 71 | "handler": "wxmoment" 72 | ],[ 73 | "title": "QQ好友", 74 | "icon": "qq", 75 | "handler": "qqfriend", 76 | ],[ 77 | "title": "支付宝", 78 | "icon": "airpay", 79 | "handler": "airpay", 80 | ],[ 81 | "title": "新浪微博", 82 | "icon": "sina", 83 | "handler": "sinawb", 84 | ] 85 | ],[ 86 | [ 87 | "title": "拷贝", 88 | "icon": "copy_link", 89 | "handler": "copy" 90 | ],[ 91 | "title": "在Safari中打开", 92 | "icon": "safari", 93 | "handler": "safari" 94 | ],[ 95 | "title": "收藏", 96 | "icon": "collection", 97 | "handler": "collect", 98 | ],[ 99 | "title": "刷新", 100 | "icon": "refresh_icon", 101 | "handler": "refresh", 102 | ],[ 103 | "title": "举报", 104 | "icon": "jubao", 105 | "handler": "report", 106 | ] 107 | ] 108 | ] 109 | 110 | let cancelBtn = [ 111 | "title": "取消", 112 | "handler": "cancel", 113 | "type": "default", 114 | ] 115 | let mmShareSheet = MMShareSheet.init(title: "此网页由wx.keeponrunning.com提供", cards: cards, duration: nil, cancelBtn: cancelBtn) 116 | mmShareSheet.callBack = { (handler) ->() in 117 | print(handler) 118 | } 119 | mmShareSheet.present() 120 | 121 | ``` 122 | 123 | *PS:注释* 124 | 125 | * create sharesheet && init 【创建并初始化】 126 | 127 | `MMShareSheet.init(title: "此网页由wx.keeponrunning.com提供", cards: cards, duration: nil, cancelBtn: cancelBtn)` 128 | 129 | * argument【参数描述】 130 | 131 | * `title` 头部标题 132 | * `cards ` 事件按钮数组,类型为`Array>>`,里面包含每一行卡片组`Array>`,每一行卡片里面又包含item>: 133 | 134 | ``` 135 | [ 136 | "title": "拍照", 137 | "icon": "wechat" 138 | "handler": "camera", 139 | ] 140 | ``` 141 | * `title` item标题 142 | * `icon ` item图标,可以是本地图片名或者远程图片链接 143 | * `handler` item事件唯一标识,回调的时候根据该值区别处理事件 144 | * `duration ` 动画时长 145 | * `cancelBtn ` 取消按钮属性,类型为``;若设置为`nil`则无该按钮, 必须要设置某一个属性,默认值为`[ 146 | "title": "取消", "handler": "cancel","type": "default"]` 147 | * callback【回调】 148 | 149 | ``` 150 | mmShareSheet.callBack = { (handler) ->() in 151 | print(handler) 152 | } 153 | ``` 154 | `handler` 该handler即为cards里面item的`handler`,对应的回调过来 155 | 156 | * present【弹出sharesheet】 157 | 158 | `mmShareSheet.present()` 159 | 160 | ### Contribution 161 | 162 | You are welcome to fork and submit pull requests. 163 | 164 | ### License 165 | 166 | MMShareSheet is open-sourced software licensed under the MIT license. 167 | -------------------------------------------------------------------------------- /Example/ExampleShareSheetVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleShareSheetVC.swift 3 | // swiftui 4 | // 5 | // Created by 郭永红 on 2017/10/12. 6 | // Copyright © 2017年 keeponrunning. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ExampleShareSheetVC: UIViewController { 12 | override func viewDidLoad() { 13 | super.viewDidLoad() 14 | 15 | self.view.backgroundColor = UIColor.white 16 | // Do any additional setup after loading the view. 17 | } 18 | 19 | @IBAction func presentActionSheet(_ sender: Any) { 20 | let cards = [ 21 | [ 22 | [ 23 | "title": "微信好友", 24 | "icon": "wechat", 25 | "handler": "wxfriend" 26 | ],[ 27 | "title": "微信朋友圈", 28 | "icon": "moment", 29 | "handler": "wxmoment" 30 | ],[ 31 | "title": "QQ好友", 32 | "icon": "qq", 33 | "handler": "qqfriend", 34 | ],[ 35 | "title": "支付宝", 36 | "icon": "airpay", 37 | "handler": "airpay", 38 | ],[ 39 | "title": "新浪微博", 40 | "icon": "sina", 41 | "handler": "sinawb", 42 | ],[ 43 | "title": "微信好友", 44 | "icon": "wechat", 45 | "handler": "wxfriend" 46 | ],[ 47 | "title": "微信朋友圈", 48 | "icon": "moment", 49 | "handler": "wxmoment" 50 | ] 51 | ],[ 52 | [ 53 | "title": "拷贝", 54 | "icon": "copy_link", 55 | "handler": "copy" 56 | ],[ 57 | "title": "在Safari中打开", 58 | "icon": "safari", 59 | "handler": "safari" 60 | ],[ 61 | "title": "收藏", 62 | "icon": "collection", 63 | "handler": "collect", 64 | ],[ 65 | "title": "刷新", 66 | "icon": "refresh_icon", 67 | "handler": "refresh", 68 | ],[ 69 | "title": "举报", 70 | "icon": "jubao", 71 | "handler": "report", 72 | ] 73 | ] 74 | ] 75 | 76 | let cancelBtn = [ 77 | "title": "取消", 78 | ] 79 | let mmShareSheet = MMShareSheet.init(title: "此网页由wx.keeponrunning.com提供", cards: cards, duration: nil, cancelBtn: cancelBtn) 80 | mmShareSheet.callBack = { (handler) ->() in 81 | self.noticeOnlyText(handler) 82 | } 83 | mmShareSheet.present() 84 | } 85 | 86 | 87 | @IBAction func singleLineShareSheet(_ sender: Any) { 88 | let cards = [ 89 | [ 90 | [ 91 | "title": "微信好友", 92 | "icon": "wechat", 93 | "handler": "wxfriend" 94 | ],[ 95 | "title": "微信朋友圈", 96 | "icon": "moment", 97 | "handler": "wxmoment" 98 | ],[ 99 | "title": "QQ好友", 100 | "icon": "qq", 101 | "handler": "qqfriend", 102 | ],[ 103 | "title": "支付宝", 104 | "icon": "airpay", 105 | "handler": "airpay", 106 | ] 107 | ] 108 | ] 109 | 110 | let cancelBtn = [ 111 | "title": "取消", 112 | "type": "danger" 113 | ] 114 | let mmShareSheet = MMShareSheet.init(title: "分 享", cards: cards, duration: nil, cancelBtn: cancelBtn) 115 | mmShareSheet.callBack = { (handler) ->() in 116 | self.noticeOnlyText(handler) 117 | } 118 | mmShareSheet.present() 119 | 120 | } 121 | 122 | 123 | @IBAction func mutableLineShareSheet(_ sender: Any) { 124 | 125 | let cards = [ 126 | [ 127 | [ 128 | "title": "微信好友", 129 | "icon": "wechat", 130 | "handler": "wxfriend" 131 | ],[ 132 | "title": "微信朋友圈", 133 | "icon": "moment", 134 | "handler": "wxmoment" 135 | ],[ 136 | "title": "QQ好友", 137 | "icon": "qq", 138 | "handler": "qqfriend", 139 | ],[ 140 | "title": "支付宝", 141 | "icon": "airpay", 142 | "handler": "airpay", 143 | ],[ 144 | "title": "新浪微博", 145 | "icon": "sina", 146 | "handler": "sinawb", 147 | ],[ 148 | "title": "微信好友", 149 | "icon": "wechat", 150 | "handler": "wxfriend" 151 | ],[ 152 | "title": "微信朋友圈", 153 | "icon": "moment", 154 | "handler": "wxmoment" 155 | ] 156 | ],[ 157 | [ 158 | "title": "拷贝", 159 | "icon": "copy_link", 160 | "handler": "copy" 161 | ],[ 162 | "title": "在Safari中打开", 163 | "icon": "safari", 164 | "handler": "safari" 165 | ],[ 166 | "title": "收藏", 167 | "icon": "collection", 168 | "handler": "collect", 169 | ],[ 170 | "title": "刷新", 171 | "icon": "refresh_icon", 172 | "handler": "refresh", 173 | ],[ 174 | "title": "举报", 175 | "icon": "jubao", 176 | "handler": "report", 177 | ] 178 | ], 179 | [ 180 | [ 181 | "title": "微信好友", 182 | "icon": "wechat", 183 | "handler": "wxfriend" 184 | ],[ 185 | "title": "微信朋友圈", 186 | "icon": "moment", 187 | "handler": "wxmoment" 188 | ],[ 189 | "title": "QQ好友", 190 | "icon": "qq", 191 | "handler": "qqfriend", 192 | ],[ 193 | "title": "支付宝", 194 | "icon": "airpay", 195 | "handler": "airpay", 196 | ],[ 197 | "title": "新浪微博", 198 | "icon": "sina", 199 | "handler": "sinawb", 200 | ],[ 201 | "title": "微信好友", 202 | "icon": "wechat", 203 | "handler": "wxfriend" 204 | ],[ 205 | "title": "微信朋友圈", 206 | "icon": "moment", 207 | "handler": "wxmoment" 208 | ] 209 | ] 210 | ] 211 | 212 | let cancelBtn = [ 213 | "title": "取消", 214 | "type": "blue" 215 | ] 216 | let mmShareSheet = MMShareSheet.init(title: "分 享", cards: cards, duration: nil, cancelBtn: cancelBtn) 217 | mmShareSheet.callBack = { (handler) ->() in 218 | self.noticeOnlyText(handler) 219 | } 220 | mmShareSheet.present() 221 | } 222 | 223 | 224 | @IBAction func remoteIconShareSheet(_ sender: Any) { 225 | let cards = [ 226 | [ 227 | [ 228 | "title": "银行卡管理", 229 | "icon": "http://dsposweb.oss-cn-hangzhou.aliyuncs.com/Image/wd_1.png", 230 | "handler": "bankCard" 231 | ],[ 232 | "title": "信用卡管理", 233 | "icon": "http://dsposweb.oss-cn-hangzhou.aliyuncs.com/Image/wd_5.png", 234 | "handler": "creditCard" 235 | ],[ 236 | "title": "微信", 237 | "icon": "http://dsposweb.oss-cn-hangzhou.aliyuncs.com/Image/wd_2.png", 238 | "handler": "weChat", 239 | ],[ 240 | "title": "安全中心", 241 | "icon": "http://dsposweb.oss-cn-hangzhou.aliyuncs.com/Image/wd_6.png", 242 | "handler": "securityCenter", 243 | ] 244 | ] 245 | ] 246 | 247 | let cancelBtn = [ 248 | "title": "取消", 249 | "type": "danger" 250 | ] 251 | let mmShareSheet = MMShareSheet.init(title: "远程icon测试", cards: cards, duration: nil, cancelBtn: cancelBtn) 252 | mmShareSheet.callBack = { (handler) ->() in 253 | self.noticeOnlyText(handler) 254 | } 255 | mmShareSheet.present() 256 | 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /Components/MMShareSheet.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DDShareSheet.swift 3 | // swiftui 4 | // 5 | // Created by 郭永红 on 2017/10/12. 6 | // Copyright © 2017年 keeponrunning. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | //常量 12 | let ss_mmdivideLineHeight:CGFloat = 1 /* 按钮与按钮之间的分割线高度 */ 13 | let ss_mmscreenBounds = UIScreen.main.bounds /* 屏幕Bounds */ 14 | let ss_mmscreenSize = ss_mmscreenBounds.size /* 屏幕大小 */ 15 | let ss_mmscreenWidth = ss_mmscreenSize.width /* 屏幕宽度 */ 16 | let ss_mmscreenHeight = ss_mmscreenSize.height /* 屏幕高度 */ 17 | let ss_mmbuttonHeight:CGFloat = 48.0 * ss_mmscreenWidth / 375 /* button高度 */ 18 | let ss_mmtitleHeight:CGFloat = 35.0 * ss_mmscreenWidth / 375 /* 标题的高度 */ 19 | let ss_mmbtnPadding:CGFloat = 5 * ss_mmscreenWidth / 375 /* 取消按钮与其他按钮之间的间距 */ 20 | let ss_mmdefaultDuration = 0.3 21 | let ss_mmcardHeight:CGFloat = 120.0 * ss_mmscreenWidth / 375 /* 单行card的高度 */ 22 | let ss_mmitemHeight:CGFloat = 100.0 * ss_mmscreenWidth / 375 /* 单个item的高度 */ 23 | let ss_mmitemwidth:CGFloat = 93.75 * ss_mmscreenWidth / 375 /* 单个item的宽度 */ 24 | 25 | 26 | public typealias ItemClickBlock = (String) ->() 27 | 28 | public class MMShareSheet: UIView { 29 | var title:String? //标题 30 | var cards:Array>>? //按钮组 31 | var duration: Double? //动画时长 32 | var cancelButton: Dictionary? //取消按钮 33 | 34 | //适配iphoneX 35 | var paddng_bottom:CGFloat = ss_mmscreenHeight == 812.0 ? 34.0 : 0.0 36 | 37 | var shareSheetHeight:CGFloat = 0 38 | public var shareSheetView:UIView = UIView() 39 | 40 | public var callBack:ItemClickBlock? 41 | 42 | override init(frame: CGRect) { 43 | super.init(frame: frame) 44 | } 45 | 46 | required public init?(coder aDecoder: NSCoder) { 47 | fatalError("init(coder:) has not been implemented") 48 | } 49 | 50 | 51 | /// 初始化 52 | /// 53 | /// - Parameters: 54 | /// - title: 标题 55 | /// - buttons: 按钮数组 56 | /// - duration: 动画时长 57 | /// - cancel: 是否需要取消按钮 58 | convenience public init(title: String?, cards: Array>>?, duration: Double?, cancelBtn: Dictionary?) { 59 | 60 | //半透明背景 61 | self.init(frame: ss_mmscreenBounds) 62 | self.title = title ?? "" 63 | self.cards = cards ?? [] 64 | let btnCount = self.cards?.count ?? 0 65 | self.duration = duration ?? (ss_mmdefaultDuration + ss_mmdefaultDuration * Double(btnCount/30)) 66 | self.cancelButton = cancelBtn ?? [:] 67 | //添加单击事件,隐藏sheet 68 | let singleTap = UITapGestureRecognizer.init(target: self, action: #selector(self.singleTapDismiss)) 69 | singleTap.delegate = self 70 | self.addGestureRecognizer(singleTap) 71 | 72 | //shareSheet 73 | initShareSheet() 74 | //初始化UI 75 | initUI() 76 | } 77 | 78 | func initShareSheet() { 79 | let btnCount = self.cards?.count ?? 0 80 | var tHeight:CGFloat = 0.0 81 | if (self.title != nil && self.title != "") { 82 | tHeight = ss_mmtitleHeight 83 | } 84 | 85 | var cancelHeight:CGFloat = 0.0 86 | if self.cancelButton! != [:] { 87 | cancelHeight = ss_mmbuttonHeight + ss_mmbtnPadding 88 | } 89 | 90 | shareSheetHeight = CGFloat(btnCount) * ss_mmcardHeight + tHeight + cancelHeight + CGFloat(btnCount) * ss_mmdivideLineHeight + paddng_bottom 91 | let aFrame:CGRect = CGRect.init(x: 0, y: ss_mmscreenHeight, width: ss_mmscreenWidth, height: shareSheetHeight) 92 | self.shareSheetView.frame = aFrame 93 | self.addSubview(self.shareSheetView) 94 | } 95 | 96 | func initUI() { 97 | 98 | //标题不为空,则添加标题 99 | if (self.title != nil && self.title != "") { 100 | let titlelabel = UILabel.init(frame: CGRect.init(x: 0, y: 0, width: ss_mmscreenWidth, height: ss_mmtitleHeight)) 101 | titlelabel.text = self.title 102 | titlelabel.textAlignment = .center 103 | titlelabel.textColor = UIColor(red: 0.361, green: 0.361, blue: 0.361, alpha: 1.00) 104 | titlelabel.font = UIFont.systemFont(ofSize: 12) 105 | titlelabel.backgroundColor = UIColor(red: 0.937, green: 0.937, blue: 0.941, alpha: 0.90) 106 | titlelabel.adjustsFontSizeToFitWidth = true 107 | self.shareSheetView.addSubview(titlelabel) 108 | } 109 | 110 | //事件按钮组 111 | let cardsCount = self.cards?.count ?? 0 112 | for index in 0.. 3 {break} 114 | let card = self.cards![index] 115 | 116 | var tHeight:CGFloat = 0.0 117 | if (self.title != nil && self.title != "") { 118 | tHeight = ss_mmtitleHeight 119 | } 120 | 121 | let origin_y = tHeight + ss_mmcardHeight * CGFloat(index) + ss_mmdivideLineHeight * CGFloat(index) 122 | 123 | let scroller = UIScrollView.init(frame: CGRect.init(x: 0.0, y: origin_y, width: ss_mmscreenWidth, height: ss_mmcardHeight)) 124 | scroller.backgroundColor = UIColor(red: 1.000, green: 1.000, blue: 1.000, alpha: 0.80) 125 | scroller.showsHorizontalScrollIndicator = false 126 | scroller.showsVerticalScrollIndicator = false 127 | let contentSizeWidth = CGFloat(card.count) * ss_mmitemwidth > ss_mmscreenWidth ? CGFloat(card.count) * ss_mmitemwidth : (ss_mmscreenWidth + 1.0) 128 | scroller.contentSize = CGSize.init(width: contentSizeWidth, height: ss_mmcardHeight) 129 | let itemsCount = card.count 130 | for subIdx in 0..UIImage{ 229 | let rect = CGRect(x:0, y:0, width: size.width, height: size.height) 230 | UIGraphicsBeginImageContext(rect.size) 231 | let context = UIGraphicsGetCurrentContext() 232 | context!.setFillColor(color.cgColor) 233 | context!.fill(rect) 234 | let image = UIGraphicsGetImageFromCurrentImageContext() 235 | UIGraphicsEndImageContext() 236 | return image! 237 | } 238 | } 239 | 240 | extension MMShareSheet: UIGestureRecognizerDelegate { 241 | public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { 242 | if touch.view == self { 243 | return true 244 | } 245 | return false 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /Example/Example.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 | 43 | 62 | 81 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /swiftui.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 194CBE151F8DBA99002729E2 /* SwiftNotice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 194CBE141F8DB963002729E2 /* SwiftNotice.swift */; }; 11 | 1986B1601F8C3F2B00CBC6AE /* Example.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1986B15F1F8C3F2B00CBC6AE /* Example.storyboard */; }; 12 | 19A29C391F8E0978004FBA48 /* MMShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A29C381F8E0978004FBA48 /* MMShareSheet.swift */; }; 13 | 19A5B11A1F8F417900E5B593 /* MMCardItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A5B1191F8F417900E5B593 /* MMCardItem.swift */; }; 14 | 19A84DF81F8AF08400475BEB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19A84DF71F8AF08400475BEB /* AppDelegate.swift */; }; 15 | 19A84DFF1F8AF08400475BEB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 19A84DFE1F8AF08400475BEB /* Assets.xcassets */; }; 16 | 19A84E021F8AF08400475BEB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 19A84E001F8AF08400475BEB /* LaunchScreen.storyboard */; }; 17 | 19C6410E1F8B5B1C005C0E3B /* ExampleShareSheetVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19C6410D1F8B5B1C005C0E3B /* ExampleShareSheetVC.swift */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXFileReference section */ 21 | 194CBE141F8DB963002729E2 /* SwiftNotice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftNotice.swift; sourceTree = ""; }; 22 | 1986B15F1F8C3F2B00CBC6AE /* Example.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Example.storyboard; sourceTree = ""; }; 23 | 19A29C381F8E0978004FBA48 /* MMShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MMShareSheet.swift; sourceTree = ""; }; 24 | 19A5B1191F8F417900E5B593 /* MMCardItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MMCardItem.swift; sourceTree = ""; }; 25 | 19A84DF41F8AF08400475BEB /* swiftui.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = swiftui.app; sourceTree = BUILT_PRODUCTS_DIR; }; 26 | 19A84DF71F8AF08400475BEB /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 27 | 19A84DFE1F8AF08400475BEB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 28 | 19A84E011F8AF08400475BEB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 29 | 19A84E031F8AF08400475BEB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 30 | 19C6410D1F8B5B1C005C0E3B /* ExampleShareSheetVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleShareSheetVC.swift; sourceTree = ""; }; 31 | /* End PBXFileReference section */ 32 | 33 | /* Begin PBXFrameworksBuildPhase section */ 34 | 19A84DF11F8AF08400475BEB /* Frameworks */ = { 35 | isa = PBXFrameworksBuildPhase; 36 | buildActionMask = 2147483647; 37 | files = ( 38 | ); 39 | runOnlyForDeploymentPostprocessing = 0; 40 | }; 41 | /* End PBXFrameworksBuildPhase section */ 42 | 43 | /* Begin PBXGroup section */ 44 | 1900C6BC1F8B0E5000DD81B5 /* Example */ = { 45 | isa = PBXGroup; 46 | children = ( 47 | 19C6410D1F8B5B1C005C0E3B /* ExampleShareSheetVC.swift */, 48 | 1986B15F1F8C3F2B00CBC6AE /* Example.storyboard */, 49 | ); 50 | path = Example; 51 | sourceTree = ""; 52 | }; 53 | 194CBE131F8DB94B002729E2 /* Tools */ = { 54 | isa = PBXGroup; 55 | children = ( 56 | 194CBE141F8DB963002729E2 /* SwiftNotice.swift */, 57 | ); 58 | path = Tools; 59 | sourceTree = ""; 60 | }; 61 | 19A84DEB1F8AF08400475BEB = { 62 | isa = PBXGroup; 63 | children = ( 64 | 1900C6BC1F8B0E5000DD81B5 /* Example */, 65 | 19F72E7F1F8AF42D001B1EF7 /* Components */, 66 | 19A84DF61F8AF08400475BEB /* swiftui */, 67 | 194CBE131F8DB94B002729E2 /* Tools */, 68 | 19A84DF51F8AF08400475BEB /* Products */, 69 | ); 70 | sourceTree = ""; 71 | }; 72 | 19A84DF51F8AF08400475BEB /* Products */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | 19A84DF41F8AF08400475BEB /* swiftui.app */, 76 | ); 77 | name = Products; 78 | sourceTree = ""; 79 | }; 80 | 19A84DF61F8AF08400475BEB /* swiftui */ = { 81 | isa = PBXGroup; 82 | children = ( 83 | 19A84DF71F8AF08400475BEB /* AppDelegate.swift */, 84 | 19A84DFE1F8AF08400475BEB /* Assets.xcassets */, 85 | 19A84E001F8AF08400475BEB /* LaunchScreen.storyboard */, 86 | 19A84E031F8AF08400475BEB /* Info.plist */, 87 | ); 88 | path = swiftui; 89 | sourceTree = ""; 90 | }; 91 | 19F72E7F1F8AF42D001B1EF7 /* Components */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 19A29C381F8E0978004FBA48 /* MMShareSheet.swift */, 95 | 19A5B1191F8F417900E5B593 /* MMCardItem.swift */, 96 | ); 97 | path = Components; 98 | sourceTree = ""; 99 | }; 100 | /* End PBXGroup section */ 101 | 102 | /* Begin PBXNativeTarget section */ 103 | 19A84DF31F8AF08400475BEB /* swiftui */ = { 104 | isa = PBXNativeTarget; 105 | buildConfigurationList = 19A84E061F8AF08400475BEB /* Build configuration list for PBXNativeTarget "swiftui" */; 106 | buildPhases = ( 107 | 19A84DF01F8AF08400475BEB /* Sources */, 108 | 19A84DF11F8AF08400475BEB /* Frameworks */, 109 | 19A84DF21F8AF08400475BEB /* Resources */, 110 | ); 111 | buildRules = ( 112 | ); 113 | dependencies = ( 114 | ); 115 | name = swiftui; 116 | productName = swiftui; 117 | productReference = 19A84DF41F8AF08400475BEB /* swiftui.app */; 118 | productType = "com.apple.product-type.application"; 119 | }; 120 | /* End PBXNativeTarget section */ 121 | 122 | /* Begin PBXProject section */ 123 | 19A84DEC1F8AF08400475BEB /* Project object */ = { 124 | isa = PBXProject; 125 | attributes = { 126 | LastSwiftUpdateCheck = 0830; 127 | LastUpgradeCheck = 0900; 128 | ORGANIZATIONNAME = keeponrunning; 129 | TargetAttributes = { 130 | 19A84DF31F8AF08400475BEB = { 131 | CreatedOnToolsVersion = 8.3.3; 132 | DevelopmentTeam = Q5N6EB6624; 133 | LastSwiftMigration = 0900; 134 | ProvisioningStyle = Automatic; 135 | }; 136 | }; 137 | }; 138 | buildConfigurationList = 19A84DEF1F8AF08400475BEB /* Build configuration list for PBXProject "swiftui" */; 139 | compatibilityVersion = "Xcode 3.2"; 140 | developmentRegion = English; 141 | hasScannedForEncodings = 0; 142 | knownRegions = ( 143 | en, 144 | Base, 145 | ); 146 | mainGroup = 19A84DEB1F8AF08400475BEB; 147 | productRefGroup = 19A84DF51F8AF08400475BEB /* Products */; 148 | projectDirPath = ""; 149 | projectRoot = ""; 150 | targets = ( 151 | 19A84DF31F8AF08400475BEB /* swiftui */, 152 | ); 153 | }; 154 | /* End PBXProject section */ 155 | 156 | /* Begin PBXResourcesBuildPhase section */ 157 | 19A84DF21F8AF08400475BEB /* Resources */ = { 158 | isa = PBXResourcesBuildPhase; 159 | buildActionMask = 2147483647; 160 | files = ( 161 | 19A84E021F8AF08400475BEB /* LaunchScreen.storyboard in Resources */, 162 | 19A84DFF1F8AF08400475BEB /* Assets.xcassets in Resources */, 163 | 1986B1601F8C3F2B00CBC6AE /* Example.storyboard in Resources */, 164 | ); 165 | runOnlyForDeploymentPostprocessing = 0; 166 | }; 167 | /* End PBXResourcesBuildPhase section */ 168 | 169 | /* Begin PBXSourcesBuildPhase section */ 170 | 19A84DF01F8AF08400475BEB /* Sources */ = { 171 | isa = PBXSourcesBuildPhase; 172 | buildActionMask = 2147483647; 173 | files = ( 174 | 19A5B11A1F8F417900E5B593 /* MMCardItem.swift in Sources */, 175 | 194CBE151F8DBA99002729E2 /* SwiftNotice.swift in Sources */, 176 | 19C6410E1F8B5B1C005C0E3B /* ExampleShareSheetVC.swift in Sources */, 177 | 19A84DF81F8AF08400475BEB /* AppDelegate.swift in Sources */, 178 | 19A29C391F8E0978004FBA48 /* MMShareSheet.swift in Sources */, 179 | ); 180 | runOnlyForDeploymentPostprocessing = 0; 181 | }; 182 | /* End PBXSourcesBuildPhase section */ 183 | 184 | /* Begin PBXVariantGroup section */ 185 | 19A84E001F8AF08400475BEB /* LaunchScreen.storyboard */ = { 186 | isa = PBXVariantGroup; 187 | children = ( 188 | 19A84E011F8AF08400475BEB /* Base */, 189 | ); 190 | name = LaunchScreen.storyboard; 191 | sourceTree = ""; 192 | }; 193 | /* End PBXVariantGroup section */ 194 | 195 | /* Begin XCBuildConfiguration section */ 196 | 19A84E041F8AF08400475BEB /* Debug */ = { 197 | isa = XCBuildConfiguration; 198 | buildSettings = { 199 | ALWAYS_SEARCH_USER_PATHS = NO; 200 | CLANG_ANALYZER_NONNULL = YES; 201 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 202 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 203 | CLANG_CXX_LIBRARY = "libc++"; 204 | CLANG_ENABLE_MODULES = YES; 205 | CLANG_ENABLE_OBJC_ARC = YES; 206 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 207 | CLANG_WARN_BOOL_CONVERSION = YES; 208 | CLANG_WARN_COMMA = YES; 209 | CLANG_WARN_CONSTANT_CONVERSION = YES; 210 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 211 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 212 | CLANG_WARN_EMPTY_BODY = YES; 213 | CLANG_WARN_ENUM_CONVERSION = YES; 214 | CLANG_WARN_INFINITE_RECURSION = YES; 215 | CLANG_WARN_INT_CONVERSION = YES; 216 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 217 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 218 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 219 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 220 | CLANG_WARN_STRICT_PROTOTYPES = YES; 221 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 222 | CLANG_WARN_UNREACHABLE_CODE = YES; 223 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 224 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 225 | COPY_PHASE_STRIP = NO; 226 | DEBUG_INFORMATION_FORMAT = dwarf; 227 | ENABLE_STRICT_OBJC_MSGSEND = YES; 228 | ENABLE_TESTABILITY = YES; 229 | GCC_C_LANGUAGE_STANDARD = gnu99; 230 | GCC_DYNAMIC_NO_PIC = NO; 231 | GCC_NO_COMMON_BLOCKS = YES; 232 | GCC_OPTIMIZATION_LEVEL = 0; 233 | GCC_PREPROCESSOR_DEFINITIONS = ( 234 | "DEBUG=1", 235 | "$(inherited)", 236 | ); 237 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 238 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 239 | GCC_WARN_UNDECLARED_SELECTOR = YES; 240 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 241 | GCC_WARN_UNUSED_FUNCTION = YES; 242 | GCC_WARN_UNUSED_VARIABLE = YES; 243 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 244 | MTL_ENABLE_DEBUG_INFO = YES; 245 | ONLY_ACTIVE_ARCH = YES; 246 | SDKROOT = iphoneos; 247 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 248 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 249 | TARGETED_DEVICE_FAMILY = "1,2"; 250 | }; 251 | name = Debug; 252 | }; 253 | 19A84E051F8AF08400475BEB /* Release */ = { 254 | isa = XCBuildConfiguration; 255 | buildSettings = { 256 | ALWAYS_SEARCH_USER_PATHS = NO; 257 | CLANG_ANALYZER_NONNULL = YES; 258 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 259 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 260 | CLANG_CXX_LIBRARY = "libc++"; 261 | CLANG_ENABLE_MODULES = YES; 262 | CLANG_ENABLE_OBJC_ARC = YES; 263 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 264 | CLANG_WARN_BOOL_CONVERSION = YES; 265 | CLANG_WARN_COMMA = YES; 266 | CLANG_WARN_CONSTANT_CONVERSION = YES; 267 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 268 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 269 | CLANG_WARN_EMPTY_BODY = YES; 270 | CLANG_WARN_ENUM_CONVERSION = YES; 271 | CLANG_WARN_INFINITE_RECURSION = YES; 272 | CLANG_WARN_INT_CONVERSION = YES; 273 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 274 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 275 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 276 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 277 | CLANG_WARN_STRICT_PROTOTYPES = YES; 278 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 279 | CLANG_WARN_UNREACHABLE_CODE = YES; 280 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 281 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 282 | COPY_PHASE_STRIP = NO; 283 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 284 | ENABLE_NS_ASSERTIONS = NO; 285 | ENABLE_STRICT_OBJC_MSGSEND = YES; 286 | GCC_C_LANGUAGE_STANDARD = gnu99; 287 | GCC_NO_COMMON_BLOCKS = YES; 288 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 289 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 290 | GCC_WARN_UNDECLARED_SELECTOR = YES; 291 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 292 | GCC_WARN_UNUSED_FUNCTION = YES; 293 | GCC_WARN_UNUSED_VARIABLE = YES; 294 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 295 | MTL_ENABLE_DEBUG_INFO = NO; 296 | SDKROOT = iphoneos; 297 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 298 | TARGETED_DEVICE_FAMILY = "1,2"; 299 | VALIDATE_PRODUCT = YES; 300 | }; 301 | name = Release; 302 | }; 303 | 19A84E071F8AF08400475BEB /* Debug */ = { 304 | isa = XCBuildConfiguration; 305 | buildSettings = { 306 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 307 | DEVELOPMENT_TEAM = Q5N6EB6624; 308 | INFOPLIST_FILE = swiftui/Info.plist; 309 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 310 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 311 | PRODUCT_BUNDLE_IDENTIFIER = com.keeponrunning.swiftui; 312 | PRODUCT_NAME = "$(TARGET_NAME)"; 313 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 314 | SWIFT_VERSION = 4.0; 315 | }; 316 | name = Debug; 317 | }; 318 | 19A84E081F8AF08400475BEB /* Release */ = { 319 | isa = XCBuildConfiguration; 320 | buildSettings = { 321 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 322 | DEVELOPMENT_TEAM = Q5N6EB6624; 323 | INFOPLIST_FILE = swiftui/Info.plist; 324 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 325 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 326 | PRODUCT_BUNDLE_IDENTIFIER = com.keeponrunning.swiftui; 327 | PRODUCT_NAME = "$(TARGET_NAME)"; 328 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 329 | SWIFT_VERSION = 4.0; 330 | }; 331 | name = Release; 332 | }; 333 | /* End XCBuildConfiguration section */ 334 | 335 | /* Begin XCConfigurationList section */ 336 | 19A84DEF1F8AF08400475BEB /* Build configuration list for PBXProject "swiftui" */ = { 337 | isa = XCConfigurationList; 338 | buildConfigurations = ( 339 | 19A84E041F8AF08400475BEB /* Debug */, 340 | 19A84E051F8AF08400475BEB /* Release */, 341 | ); 342 | defaultConfigurationIsVisible = 0; 343 | defaultConfigurationName = Release; 344 | }; 345 | 19A84E061F8AF08400475BEB /* Build configuration list for PBXNativeTarget "swiftui" */ = { 346 | isa = XCConfigurationList; 347 | buildConfigurations = ( 348 | 19A84E071F8AF08400475BEB /* Debug */, 349 | 19A84E081F8AF08400475BEB /* Release */, 350 | ); 351 | defaultConfigurationIsVisible = 0; 352 | defaultConfigurationName = Release; 353 | }; 354 | /* End XCConfigurationList section */ 355 | }; 356 | rootObject = 19A84DEC1F8AF08400475BEB /* Project object */; 357 | } 358 | -------------------------------------------------------------------------------- /Tools/SwiftNotice.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftNotice.swift 3 | // SwiftNotice 4 | // 5 | // Created by JohnLui on 15/4/15. 6 | // Copyright (c) 2015年 com.lvwenhan. All rights reserved. 7 | // https://github.com/johnlui/SwiftNotice 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | private let sn_topBar: Int = 1001 13 | 14 | extension UIResponder { 15 | /// wait with your own animated images 16 | @discardableResult 17 | func pleaseWaitWithImages(_ imageNames: Array, timeInterval: Int) -> UIWindow{ 18 | return SwiftNotice.wait(imageNames, timeInterval: timeInterval) 19 | } 20 | // api changed from v3.3 21 | @discardableResult 22 | func noticeTop(_ text: String, autoClear: Bool = true, autoClearTime: Int = 1) -> UIWindow{ 23 | return SwiftNotice.noticeOnStatusBar(text, autoClear: autoClear, autoClearTime: autoClearTime) 24 | } 25 | 26 | // new apis from v3.3 27 | @discardableResult 28 | func noticeSuccess(_ text: String, autoClear: Bool = false, autoClearTime: Int = 3) -> UIWindow{ 29 | return SwiftNotice.showNoticeWithText(NoticeType.success, text: text, autoClear: autoClear, autoClearTime: autoClearTime) 30 | } 31 | @discardableResult 32 | func noticeError(_ text: String, autoClear: Bool = false, autoClearTime: Int = 3) -> UIWindow{ 33 | return SwiftNotice.showNoticeWithText(NoticeType.error, text: text, autoClear: autoClear, autoClearTime: autoClearTime) 34 | } 35 | @discardableResult 36 | func noticeInfo(_ text: String, autoClear: Bool = false, autoClearTime: Int = 3) -> UIWindow{ 37 | return SwiftNotice.showNoticeWithText(NoticeType.info, text: text, autoClear: autoClear, autoClearTime: autoClearTime) 38 | } 39 | 40 | // old apis 41 | @discardableResult 42 | func successNotice(_ text: String, autoClear: Bool = true) -> UIWindow{ 43 | return SwiftNotice.showNoticeWithText(NoticeType.success, text: text, autoClear: autoClear, autoClearTime: 3) 44 | } 45 | @discardableResult 46 | func errorNotice(_ text: String, autoClear: Bool = true) -> UIWindow{ 47 | return SwiftNotice.showNoticeWithText(NoticeType.error, text: text, autoClear: autoClear, autoClearTime: 3) 48 | } 49 | @discardableResult 50 | func infoNotice(_ text: String, autoClear: Bool = true) -> UIWindow{ 51 | return SwiftNotice.showNoticeWithText(NoticeType.info, text: text, autoClear: autoClear, autoClearTime: 3) 52 | } 53 | @discardableResult 54 | func notice(_ text: String, type: NoticeType, autoClear: Bool, autoClearTime: Int = 3) -> UIWindow{ 55 | return SwiftNotice.showNoticeWithText(type, text: text, autoClear: autoClear, autoClearTime: autoClearTime) 56 | } 57 | @discardableResult 58 | func pleaseWait() -> UIWindow{ 59 | return SwiftNotice.wait() 60 | } 61 | @discardableResult 62 | func noticeOnlyText(_ text: String) -> UIWindow{ 63 | return SwiftNotice.showText(text) 64 | } 65 | func clearAllNotice() { 66 | SwiftNotice.clear() 67 | } 68 | } 69 | 70 | enum NoticeType{ 71 | case success 72 | case error 73 | case info 74 | } 75 | 76 | class SwiftNotice: NSObject { 77 | 78 | static var windows = Array() 79 | static let rv = UIApplication.shared.keyWindow?.subviews.first as UIView! 80 | static var timer: DispatchSource! 81 | static var timerTimes = 0 82 | 83 | /* just for iOS 8 84 | */ 85 | static var degree: Double { 86 | get { 87 | return [0, 0, 180, 270, 90][UIApplication.shared.statusBarOrientation.hashValue] as Double 88 | } 89 | } 90 | 91 | // fix https://github.com/johnlui/SwiftNotice/issues/2 92 | // thanks broccolii(https://github.com/broccolii) and his PR https://github.com/johnlui/SwiftNotice/pull/5 93 | static func clear() { 94 | self.cancelPreviousPerformRequests(withTarget: self) 95 | if let _ = timer { 96 | timer.cancel() 97 | timer = nil 98 | timerTimes = 0 99 | } 100 | windows.removeAll(keepingCapacity: false) 101 | } 102 | 103 | @discardableResult 104 | static func noticeOnStatusBar(_ text: String, autoClear: Bool, autoClearTime: Int) -> UIWindow{ 105 | let frame = UIApplication.shared.statusBarFrame 106 | let window = UIWindow() 107 | window.backgroundColor = UIColor.clear 108 | let view = UIView() 109 | view.backgroundColor = UIColor(red: 0x6a/0x100, green: 0xb4/0x100, blue: 0x9f/0x100, alpha: 1) 110 | 111 | let label = UILabel(frame: frame) 112 | label.textAlignment = NSTextAlignment.center 113 | label.font = UIFont.systemFont(ofSize: 12) 114 | label.textColor = UIColor.white 115 | label.text = text 116 | view.addSubview(label) 117 | 118 | window.frame = frame 119 | view.frame = frame 120 | 121 | if let version = Double(UIDevice.current.systemVersion), 122 | version < 9.0 { 123 | // change center 124 | var array = [UIScreen.main.bounds.width, UIScreen.main.bounds.height] 125 | array = array.sorted(by: <) 126 | let screenWidth = array[0] 127 | let screenHeight = array[1] 128 | let x = [0, screenWidth/2, screenWidth/2, 10, screenWidth-10][UIApplication.shared.statusBarOrientation.hashValue] as CGFloat 129 | let y = [0, 10, screenHeight-10, screenHeight/2, screenHeight/2][UIApplication.shared.statusBarOrientation.hashValue] as CGFloat 130 | window.center = CGPoint(x: x, y: y) 131 | 132 | // change direction 133 | window.transform = CGAffineTransform(rotationAngle: CGFloat(degree * Double.pi / 180)) 134 | } 135 | 136 | window.windowLevel = UIWindowLevelStatusBar 137 | window.isHidden = false 138 | window.addSubview(view) 139 | windows.append(window) 140 | 141 | var origPoint = view.frame.origin 142 | origPoint.y = -(view.frame.size.height) 143 | let destPoint = view.frame.origin 144 | view.tag = sn_topBar 145 | 146 | view.frame = CGRect(origin: origPoint, size: view.frame.size) 147 | UIView.animate(withDuration: 0.3, animations: { 148 | view.frame = CGRect(origin: destPoint, size: view.frame.size) 149 | }, completion: { b in 150 | if autoClear { 151 | let selector = #selector(SwiftNotice.hideNotice(_:)) 152 | self.perform(selector, with: window, afterDelay: TimeInterval(autoClearTime)) 153 | } 154 | }) 155 | return window 156 | } 157 | 158 | @discardableResult 159 | static func wait(_ imageNames: Array = Array(), timeInterval: Int = 0) -> UIWindow { 160 | let frame = CGRect(x: 0, y: 0, width: 78, height: 78) 161 | let window = UIWindow() 162 | window.backgroundColor = UIColor.clear 163 | let mainView = UIView() 164 | mainView.layer.cornerRadius = 12 165 | mainView.backgroundColor = UIColor(red:0, green:0, blue:0, alpha: 0.8) 166 | 167 | if imageNames.count > 0 { 168 | if imageNames.count > timerTimes { 169 | let iv = UIImageView(frame: frame) 170 | iv.image = imageNames.first! 171 | iv.contentMode = UIViewContentMode.scaleAspectFit 172 | mainView.addSubview(iv) 173 | timer = DispatchSource.makeTimerSource(flags: DispatchSource.TimerFlags(rawValue: UInt(0)), queue: DispatchQueue.main) as! DispatchSource 174 | timer.schedule(deadline: DispatchTime.now(), repeating: DispatchTimeInterval.milliseconds(timeInterval)) 175 | timer.setEventHandler(handler: { () -> Void in 176 | let name = imageNames[timerTimes % imageNames.count] 177 | iv.image = name 178 | timerTimes += 1 179 | }) 180 | timer.resume() 181 | } 182 | } else { 183 | let ai = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.whiteLarge) 184 | ai.frame = CGRect(x: 21, y: 21, width: 36, height: 36) 185 | ai.startAnimating() 186 | mainView.addSubview(ai) 187 | } 188 | 189 | window.frame = frame 190 | mainView.frame = frame 191 | window.center = rv!.center 192 | 193 | if let version = Double(UIDevice.current.systemVersion), 194 | version < 9.0 { 195 | // change center 196 | window.center = getRealCenter() 197 | // change direction 198 | window.transform = CGAffineTransform(rotationAngle: CGFloat(degree * Double.pi / 180)) 199 | } 200 | 201 | window.windowLevel = UIWindowLevelAlert 202 | window.isHidden = false 203 | window.addSubview(mainView) 204 | windows.append(window) 205 | 206 | mainView.alpha = 0.0 207 | UIView.animate(withDuration: 0.2, animations: { 208 | mainView.alpha = 1 209 | }) 210 | return window 211 | } 212 | 213 | @discardableResult 214 | static func showText(_ text: String, autoClear: Bool=true, autoClearTime: Int=2) -> UIWindow { 215 | let window = UIWindow() 216 | window.backgroundColor = UIColor.clear 217 | let mainView = UIView() 218 | mainView.layer.cornerRadius = 12 219 | mainView.backgroundColor = UIColor(red:0, green:0, blue:0, alpha: 0.8) 220 | 221 | let label = UILabel() 222 | label.text = text 223 | label.numberOfLines = 0 224 | label.font = UIFont.systemFont(ofSize: 13) 225 | label.textAlignment = NSTextAlignment.center 226 | label.textColor = UIColor.white 227 | let size = label.sizeThatFits(CGSize(width: UIScreen.main.bounds.width-82, height: CGFloat.greatestFiniteMagnitude)) 228 | label.bounds = CGRect(x: 0, y: 0, width: size.width, height: size.height) 229 | mainView.addSubview(label) 230 | 231 | let superFrame = CGRect(x: 0, y: 0, width: label.frame.width + 50 , height: label.frame.height + 30) 232 | window.frame = superFrame 233 | mainView.frame = superFrame 234 | 235 | label.center = mainView.center 236 | window.center = rv!.center 237 | 238 | if let version = Double(UIDevice.current.systemVersion), 239 | version < 9.0 { 240 | // change center 241 | window.center = getRealCenter() 242 | // change direction 243 | window.transform = CGAffineTransform(rotationAngle: CGFloat(degree * Double.pi / 180)) 244 | } 245 | 246 | window.windowLevel = UIWindowLevelAlert 247 | window.isHidden = false 248 | window.addSubview(mainView) 249 | windows.append(window) 250 | 251 | if autoClear { 252 | let selector = #selector(SwiftNotice.hideNotice(_:)) 253 | self.perform(selector, with: window, afterDelay: TimeInterval(autoClearTime)) 254 | } 255 | return window 256 | } 257 | 258 | @discardableResult 259 | static func showNoticeWithText(_ type: NoticeType,text: String, autoClear: Bool, autoClearTime: Int) -> UIWindow { 260 | let frame = CGRect(x: 0, y: 0, width: 90, height: 90) 261 | let window = UIWindow() 262 | window.backgroundColor = UIColor.clear 263 | let mainView = UIView() 264 | mainView.layer.cornerRadius = 10 265 | mainView.backgroundColor = UIColor(red:0, green:0, blue:0, alpha: 0.7) 266 | 267 | var image = UIImage() 268 | switch type { 269 | case .success: 270 | image = SwiftNoticeSDK.imageOfCheckmark 271 | case .error: 272 | image = SwiftNoticeSDK.imageOfCross 273 | case .info: 274 | image = SwiftNoticeSDK.imageOfInfo 275 | } 276 | let checkmarkView = UIImageView(image: image) 277 | checkmarkView.frame = CGRect(x: 27, y: 15, width: 36, height: 36) 278 | mainView.addSubview(checkmarkView) 279 | 280 | let label = UILabel(frame: CGRect(x: 0, y: 60, width: 90, height: 16)) 281 | label.font = UIFont.systemFont(ofSize: 13) 282 | label.textColor = UIColor.white 283 | label.text = text 284 | label.textAlignment = NSTextAlignment.center 285 | mainView.addSubview(label) 286 | 287 | window.frame = frame 288 | mainView.frame = frame 289 | window.center = rv!.center 290 | 291 | if let version = Double(UIDevice.current.systemVersion), 292 | version < 9.0 { 293 | // change center 294 | window.center = getRealCenter() 295 | // change direction 296 | window.transform = CGAffineTransform(rotationAngle: CGFloat(degree * Double.pi / 180)) 297 | } 298 | 299 | window.windowLevel = UIWindowLevelAlert 300 | window.center = rv!.center 301 | window.isHidden = false 302 | window.addSubview(mainView) 303 | windows.append(window) 304 | 305 | mainView.alpha = 0.0 306 | UIView.animate(withDuration: 0.2, animations: { 307 | mainView.alpha = 1 308 | }) 309 | 310 | if autoClear { 311 | let selector = #selector(SwiftNotice.hideNotice(_:)) 312 | self.perform(selector, with: window, afterDelay: TimeInterval(autoClearTime)) 313 | } 314 | return window 315 | } 316 | 317 | // fix https://github.com/johnlui/SwiftNotice/issues/2 318 | @objc static func hideNotice(_ sender: AnyObject) { 319 | if let window = sender as? UIWindow { 320 | 321 | if let v = window.subviews.first { 322 | UIView.animate(withDuration: 0.2, animations: { 323 | 324 | if v.tag == sn_topBar { 325 | v.frame = CGRect(x: 0, y: -v.frame.height, width: v.frame.width, height: v.frame.height) 326 | } 327 | v.alpha = 0 328 | }, completion: { b in 329 | 330 | if let index = windows.index(where: { (item) -> Bool in 331 | return item == window 332 | }) { 333 | windows.remove(at: index) 334 | } 335 | }) 336 | } 337 | 338 | } 339 | } 340 | 341 | // just for iOS 8 342 | static func getRealCenter() -> CGPoint { 343 | if UIApplication.shared.statusBarOrientation.hashValue >= 3 { 344 | return CGPoint(x: rv!.center.y, y: rv!.center.x) 345 | } else { 346 | return rv!.center 347 | } 348 | } 349 | } 350 | 351 | class SwiftNoticeSDK { 352 | struct Cache { 353 | static var imageOfCheckmark: UIImage? 354 | static var imageOfCross: UIImage? 355 | static var imageOfInfo: UIImage? 356 | } 357 | class func draw(_ type: NoticeType) { 358 | let checkmarkShapePath = UIBezierPath() 359 | 360 | // draw circle 361 | checkmarkShapePath.move(to: CGPoint(x: 36, y: 18)) 362 | checkmarkShapePath.addArc(withCenter: CGPoint(x: 18, y: 18), radius: 17.5, startAngle: 0, endAngle: CGFloat(Double.pi*2), clockwise: true) 363 | checkmarkShapePath.close() 364 | 365 | switch type { 366 | case .success: // draw checkmark 367 | checkmarkShapePath.move(to: CGPoint(x: 10, y: 18)) 368 | checkmarkShapePath.addLine(to: CGPoint(x: 16, y: 24)) 369 | checkmarkShapePath.addLine(to: CGPoint(x: 27, y: 13)) 370 | checkmarkShapePath.move(to: CGPoint(x: 10, y: 18)) 371 | checkmarkShapePath.close() 372 | case .error: // draw X 373 | checkmarkShapePath.move(to: CGPoint(x: 10, y: 10)) 374 | checkmarkShapePath.addLine(to: CGPoint(x: 26, y: 26)) 375 | checkmarkShapePath.move(to: CGPoint(x: 10, y: 26)) 376 | checkmarkShapePath.addLine(to: CGPoint(x: 26, y: 10)) 377 | checkmarkShapePath.move(to: CGPoint(x: 10, y: 10)) 378 | checkmarkShapePath.close() 379 | case .info: 380 | checkmarkShapePath.move(to: CGPoint(x: 18, y: 6)) 381 | checkmarkShapePath.addLine(to: CGPoint(x: 18, y: 22)) 382 | checkmarkShapePath.move(to: CGPoint(x: 18, y: 6)) 383 | checkmarkShapePath.close() 384 | 385 | UIColor.white.setStroke() 386 | checkmarkShapePath.stroke() 387 | 388 | let checkmarkShapePath = UIBezierPath() 389 | checkmarkShapePath.move(to: CGPoint(x: 18, y: 27)) 390 | checkmarkShapePath.addArc(withCenter: CGPoint(x: 18, y: 27), radius: 1, startAngle: 0, endAngle: CGFloat(Double.pi*2), clockwise: true) 391 | checkmarkShapePath.close() 392 | 393 | UIColor.white.setFill() 394 | checkmarkShapePath.fill() 395 | } 396 | 397 | UIColor.white.setStroke() 398 | checkmarkShapePath.stroke() 399 | } 400 | class var imageOfCheckmark: UIImage { 401 | if (Cache.imageOfCheckmark != nil) { 402 | return Cache.imageOfCheckmark! 403 | } 404 | UIGraphicsBeginImageContextWithOptions(CGSize(width: 36, height: 36), false, 0) 405 | 406 | SwiftNoticeSDK.draw(NoticeType.success) 407 | 408 | Cache.imageOfCheckmark = UIGraphicsGetImageFromCurrentImageContext() 409 | UIGraphicsEndImageContext() 410 | return Cache.imageOfCheckmark! 411 | } 412 | class var imageOfCross: UIImage { 413 | if (Cache.imageOfCross != nil) { 414 | return Cache.imageOfCross! 415 | } 416 | UIGraphicsBeginImageContextWithOptions(CGSize(width: 36, height: 36), false, 0) 417 | 418 | SwiftNoticeSDK.draw(NoticeType.error) 419 | 420 | Cache.imageOfCross = UIGraphicsGetImageFromCurrentImageContext() 421 | UIGraphicsEndImageContext() 422 | return Cache.imageOfCross! 423 | } 424 | class var imageOfInfo: UIImage { 425 | if (Cache.imageOfInfo != nil) { 426 | return Cache.imageOfInfo! 427 | } 428 | UIGraphicsBeginImageContextWithOptions(CGSize(width: 36, height: 36), false, 0) 429 | 430 | SwiftNoticeSDK.draw(NoticeType.info) 431 | 432 | Cache.imageOfInfo = UIGraphicsGetImageFromCurrentImageContext() 433 | UIGraphicsEndImageContext() 434 | return Cache.imageOfInfo! 435 | } 436 | } 437 | 438 | extension UIWindow{ 439 | func hide(){ 440 | SwiftNotice.hideNotice(self) 441 | } 442 | } 443 | --------------------------------------------------------------------------------