This commit is contained in:
xaoxuu 2019-08-12 17:59:40 +08:00
parent ca6c36650b
commit 9431c715f5
25 changed files with 618 additions and 243 deletions

View File

@ -8,8 +8,11 @@
/* Begin PBXBuildFile section */
33E2B6CF0D9BD11D8C027DE6 /* Pods_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB925B38880FB296AF5D219F /* Pods_Example.framework */; };
CD10F0DA211582580077CAFF /* header.gif in Resources */ = {isa = PBXBuildFile; fileRef = CD10F0D9211582580077CAFF /* header.gif */; };
CD95D26F22E732CE007559A3 /* TestA.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD95D26E22E732CE007559A3 /* TestA.swift */; };
CD8BFF1823014850001E08DD /* TestToastVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD8BFF1723014850001E08DD /* TestToastVC.swift */; };
CD8BFF1A2301485E001E08DD /* TestAlertVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD8BFF192301485E001E08DD /* TestAlertVC.swift */; };
CD8BFF1C23014867001E08DD /* TestGuardVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD8BFF1B23014867001E08DD /* TestGuardVC.swift */; };
CD8BFF1E230148DD001E08DD /* BaseListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD8BFF1D230148DD001E08DD /* BaseListVC.swift */; };
CD8BFF2023014CB5001E08DD /* EmptyVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD8BFF1F23014CB5001E08DD /* EmptyVC.swift */; };
CDA4E03C20D3935B00CD2A0C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA4E03B20D3935B00CD2A0C /* AppDelegate.swift */; };
CDA4E03E20D3935B00CD2A0C /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA4E03D20D3935B00CD2A0C /* ViewController.swift */; };
CDA4E04120D3935B00CD2A0C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CDA4E03F20D3935B00CD2A0C /* Main.storyboard */; };
@ -21,9 +24,12 @@
AB925B38880FB296AF5D219F /* Pods_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BA1A6035F1B9A658B3BB225C /* Pods-Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig"; sourceTree = "<group>"; };
CA1298266BE89D7950DE99F2 /* Pods-Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig"; sourceTree = "<group>"; };
CD10F0D9211582580077CAFF /* header.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = header.gif; sourceTree = "<group>"; };
CD59584620E36DA8000F6427 /* Example-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Example-Bridging-Header.h"; sourceTree = "<group>"; };
CD95D26E22E732CE007559A3 /* TestA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestA.swift; sourceTree = "<group>"; };
CD8BFF1723014850001E08DD /* TestToastVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestToastVC.swift; sourceTree = "<group>"; };
CD8BFF192301485E001E08DD /* TestAlertVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestAlertVC.swift; sourceTree = "<group>"; };
CD8BFF1B23014867001E08DD /* TestGuardVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestGuardVC.swift; sourceTree = "<group>"; };
CD8BFF1D230148DD001E08DD /* BaseListVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseListVC.swift; sourceTree = "<group>"; };
CD8BFF1F23014CB5001E08DD /* EmptyVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyVC.swift; sourceTree = "<group>"; };
CDA4E03820D3935B00CD2A0C /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
CDA4E03B20D3935B00CD2A0C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
CDA4E03D20D3935B00CD2A0C /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
@ -84,11 +90,14 @@
isa = PBXGroup;
children = (
CDA4E03B20D3935B00CD2A0C /* AppDelegate.swift */,
CD8BFF1D230148DD001E08DD /* BaseListVC.swift */,
CD8BFF1F23014CB5001E08DD /* EmptyVC.swift */,
CDA4E03D20D3935B00CD2A0C /* ViewController.swift */,
CD95D26E22E732CE007559A3 /* TestA.swift */,
CD8BFF1723014850001E08DD /* TestToastVC.swift */,
CD8BFF192301485E001E08DD /* TestAlertVC.swift */,
CD8BFF1B23014867001E08DD /* TestGuardVC.swift */,
CDA4E03F20D3935B00CD2A0C /* Main.storyboard */,
CDA4E04220D3935C00CD2A0C /* Assets.xcassets */,
CD10F0D9211582580077CAFF /* header.gif */,
CDA4E04420D3935C00CD2A0C /* LaunchScreen.storyboard */,
CDA4E04720D3935C00CD2A0C /* Info.plist */,
CD59584620E36DA8000F6427 /* Example-Bridging-Header.h */,
@ -161,7 +170,6 @@
CDA4E04620D3935C00CD2A0C /* LaunchScreen.storyboard in Resources */,
CDA4E04320D3935C00CD2A0C /* Assets.xcassets in Resources */,
CDA4E04120D3935B00CD2A0C /* Main.storyboard in Resources */,
CD10F0DA211582580077CAFF /* header.gif in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -230,9 +238,13 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
CD8BFF1823014850001E08DD /* TestToastVC.swift in Sources */,
CDA4E03E20D3935B00CD2A0C /* ViewController.swift in Sources */,
CD8BFF2023014CB5001E08DD /* EmptyVC.swift in Sources */,
CD8BFF1A2301485E001E08DD /* TestAlertVC.swift in Sources */,
CDA4E03C20D3935B00CD2A0C /* AppDelegate.swift in Sources */,
CD95D26F22E732CE007559A3 /* TestA.swift in Sources */,
CD8BFF1C23014867001E08DD /* TestGuardVC.swift in Sources */,
CD8BFF1E230148DD001E08DD /* BaseListVC.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -1,25 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "alert-circle.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "alert-circle (1).png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 961 B

View File

@ -1,22 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "header_center@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "header_center@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14835.7" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14835.7" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="ttk-4w-IeX">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
@ -8,42 +8,39 @@
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<!--ProHUD-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="Example" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" image="bg" translatesAutoresizingMaskIntoConstraints="NO" id="0oA-CL-uZS">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
</imageView>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="PcH-Px-Vql">
<rect key="frame" x="51" y="120" width="46" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="Button"/>
<connections>
<action selector="test:" destination="BYZ-38-t0r" eventType="touchUpInside" id="mff-h5-exz"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="0oA-CL-uZS" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="5mO-PC-le4"/>
<constraint firstItem="0oA-CL-uZS" firstAttribute="top" secondItem="8bC-Xf-vdC" secondAttribute="top" id="Fay-dw-LvJ"/>
<constraint firstAttribute="bottom" secondItem="0oA-CL-uZS" secondAttribute="bottom" id="TC7-O2-j1c"/>
<constraint firstAttribute="trailing" secondItem="0oA-CL-uZS" secondAttribute="trailing" id="U3A-8b-rnZ"/>
</constraints>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
<navigationItem key="navigationItem" title="ProHUD" id="Yzl-Q6-9v7"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="142" y="134"/>
<point key="canvasLocation" x="1050.7246376811595" y="133.92857142857142"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="HjC-hd-4PZ">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="ttk-4w-IeX" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="juX-kz-8Ti">
<rect key="frame" x="0.0" y="44" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="BYZ-38-t0r" kind="relationship" relationship="rootViewController" id="gyV-fc-5FK"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Lg9-xW-IRh" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="140.57971014492756" y="133.92857142857142"/>
</scene>
</scenes>
<resources>
<image name="bg" width="414" height="896"/>
</resources>
</document>

View File

@ -0,0 +1,55 @@
//
// BaseListVC.swift
// Example
//
// Created by xaoxuu on 2019/8/12.
// Copyright © 2019 Titan Studio. All rights reserved.
//
import UIKit
class BaseListVC: UIViewController {
lazy var tableView: UITableView = {
let tv = UITableView()
return tv
}()
var titles: [String] {
return ["Toast", "Alert", "Guard"]
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(tableView)
tableView.dataSource = self
tableView.delegate = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.snp.makeConstraints { (mk) in
mk.edges.equalToSuperview()
}
}
}
extension BaseListVC: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return titles.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = titles[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}

View File

@ -0,0 +1,57 @@
//
// EmptyVC.swift
// Example
//
// Created by xaoxuu on 2019/8/12.
// Copyright © 2019 Titan Studio. All rights reserved.
//
import UIKit
import SnapKit
import Inspire
class EmptyVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(white: 0.95, alpha: 1)
// Do any additional setup after loading the view.
let lb = UILabel()
lb.numberOfLines = 0
lb.text = title
lb.font = .regular(40)
view.addSubview(lb)
lb.snp.makeConstraints { (mk) in
mk.center.equalToSuperview()
mk.leading.greaterThanOrEqualToSuperview().offset(16)
mk.trailing.lessThanOrEqualToSuperview().offset(-16)
}
let btn = UIButton(type: .system)
btn.titleLabel?.font = .bold(20)
btn.setTitle("Dismiss", for: .normal)
btn.addTarget(self, action: #selector(didTappedDismiss(_:)), for: .touchUpInside)
view.addSubview(btn)
btn.snp.makeConstraints { (mk) in
mk.top.equalToSuperview().offset(Inspire.current.layout.safeAreaInsets(for: self).top)
mk.trailing.equalToSuperview().offset(-16)
mk.height.equalTo(44)
}
}
@objc func didTappedDismiss(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
}
}
extension UIViewController {
func presentEmptyVC(title: String?) {
let vc = EmptyVC()
vc.title = title
present(vc, animated: true, completion: nil)
}
}

View File

@ -1,49 +0,0 @@
//
// TestA.swift
// ProHUDExample
//
// Created by xaoxuu on 2019/7/23.
// Copyright © 2019 Titan Studio. All rights reserved.
//
import UIKit
public class TestA: NSObject {
class func test1() {
print(self, "test1")
}
class func test2() {
print(self, "test2")
}
}
open class TestB: NSObject {
class func test1() {
print(self, "test1")
}
open class func test2() {
print(self, "test2")
}
}
class TestAA: TestA {
override class func test2() {
print(self, "test2", "override")
}
}
class TestBB: TestB {
override class func test2() {
print(self, "test2", "override")
}
}

View File

@ -0,0 +1,102 @@
//
// TestAlertVC.swift
// Example
//
// Created by xaoxuu on 2019/8/12.
// Copyright © 2019 Titan Studio. All rights reserved.
//
import UIKit
import ProHUD
class TestAlertVC: BaseListVC {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var titles: [String] {
return ["场景:正在同步(超时)", "场景:同步成功", "场景:同步失败和重试"]
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let row = indexPath.row
if row == 0 {
func f() {
let a = Alert.push(scene: .loading, title: "正在同步", message: "请稍等片刻") { (vm) in
vm.identifier = "loading"
}
a.animate(rotate: true)
a.didForceQuit { [weak self] in
let t = Toast.push(scene: .loading, title: "正在同步", message: "请稍等片刻点击展开为Alert") { (vm) in
vm.identifier = "loading"
}
t.animate(rotate: true)
t.didTapped { [weak t] in
t?.pop()
f()
}
self?.simulateSync()
}
simulateSync()
}
f()
} else if row == 1 {
Alert.push(scene: .loading, title: "正在同步", message: "请稍等片刻") { (vm) in
vm.identifier = "loading"
}.animate(rotate: true)
DispatchQueue.main.asyncAfter(deadline: .now()+2) {
if let a = Alert.get("loading").last {
a.update { (vm) in
vm.scene = .success
vm.title = "同步成功"
vm.message = nil
}
}
}
} else if row == 2 {
Alert.push() { (vm) in
vm.identifier = "loading"
}
func loading() {
if let a = Alert.get("loading").last {
a.update { (vm) in
vm.scene = .loading
vm.title = "正在同步"
vm.message = "请稍等片刻"
vm.remove(action: 0, 1)
}
a.animate(rotate: true)
DispatchQueue.main.asyncAfter(deadline: .now()+2) {
a.update { (vm) in
vm.scene = .error
vm.title = "同步失败"
vm.message = "请检查网络是否通畅"
vm.add(action: .default, title: "重试") {
loading()
}
vm.add(action: .cancel, title: "取消", handler: nil)
}
}
}
}
loading()
}
}
func simulateSync() {
DispatchQueue.main.asyncAfter(deadline: .now() + 15) {
if let t = Alert.get("loading").last {
t.update { (vm) in
vm.scene = .success
vm.title = "同步成功"
vm.message = "啊哈哈哈哈哈哈哈哈"
}
}
}
}
}

View File

@ -0,0 +1,100 @@
//
// TestGuardVC.swift
// Example
//
// Created by xaoxuu on 2019/8/12.
// Copyright © 2019 Titan Studio. All rights reserved.
//
import UIKit
import ProHUD
import Inspire
class TestGuardVC: BaseListVC {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var titles: [String] {
return ["场景:删除菜单", "场景:升级至专业版", "场景:隐私协议页面"]
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let row = indexPath.row
if row == 0 {
Guard.push(to: self.navigationController) { (vm) in
let vc = vm.vc
vm.add(action: .destructive, title: "删除") {
Alert.push(scene: .delete, title: "确认删除", message: "此操作不可撤销") { (vm) in
let vc = vm.vc
vm.add(action: .destructive, title: "删除") {
vc?.pop()
}
vm.add(action: .cancel, title: "取消", handler: nil)
}
vc?.pop()
}
vm.add(action: .cancel, title: "取消", handler: nil)
}
} else if row == 1 {
// id
if Guard.get("pro", from: self.navigationController).count == 0 {
Guard.push(to: self.navigationController) { (vm) in
let vc = vm.vc
vm.identifier = "pro"
vm.add(title: "升级至专业版")
vm.add(subTitle: "解锁功能")
vm.add(message: "功能1功能2...")
vm.add(subTitle: "价格")
vm.add(message: "只需一次性付费$2999即可永久享用。")
vm.add(action: .destructive, title: "购买") { [weak vc] in
Alert.push(scene: .confirm, title: "确认购买", message: "一旦购买拒不退款") { (vm) in
let vc = vm.vc
vm.add(action: .destructive, title: "购买") { [weak vc] in
vc?.update({ (vm) in
vm.scene = .success
vm.title = "购买成功"
vm.message = "感谢您的支持"
vm.remove(action: 1)
vm.update(action: 0, style: .default, title: "我知道了") {
vc?.pop()
}
})
}
vm.add(action: .cancel, title: "取消", handler: nil)
}
vc?.pop()
}
vm.add(action: .cancel, title: "取消", handler: nil)
}
}
} else if row == 2 {
let g = Guard.push(to: self.navigationController) { (vm) in
let vc = vm.vc
vc?.isFullScreen = true
let titleLabel = vm.add(title: "隐私协议")
titleLabel.snp.makeConstraints { (mk) in
mk.height.equalTo(44)
}
let tv = UITextView()
tv.backgroundColor = .white
vc?.textStack.addArrangedSubview(tv)
tv.text = "这里可以插入一个webView"
vm.add(message: "请认真阅读以上内容,当您阅读完毕并同意协议内容时点击接受按钮。")
vm.add(action: .default, title: "接受") { [weak vc] in
vc?.pop()
}
}
}
}
}

View File

@ -0,0 +1,97 @@
//
// TestToastVC.swift
// Example
//
// Created by xaoxuu on 2019/8/12.
// Copyright © 2019 Titan Studio. All rights reserved.
//
import UIKit
import ProHUD
class TestToastVC: BaseListVC {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var titles: [String] {
return ["场景:正在同步",
"场景:同步成功",
"场景:同步失败",
"场景:设备电量过低",
"传入指定图标",
"禁止手势移除",
"组合使用示例"]
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let row = indexPath.row
if row == 0 {
Toast.push(scene: .loading, title: "正在同步", message: "请稍等片刻") { (vm) in
vm.identifier = "loading"
}.animate(rotate: true)
simulateSync()
} else if row == 1 {
let t = Toast.push(scene: .success, title: "同步成功", message: "点击查看详情")
t.didTapped { [weak self, weak t] in
self?.presentEmptyVC(title: "详情")
t?.pop()
}
} else if row == 2 {
let t = Toast.push(scene: .error, title: "同步失败", message: "请稍后重试。点击查看详情") { (vm) in
vm.duration = 0
}
t.didTapped { [weak self, weak t] in
self?.presentEmptyVC(title: "这是错误详情")
t?.pop()
}
} else if row == 3 {
Toast.push(scene: .warning, title: "设备电量过低", message: "请及时对设备进行充电,以免影响使用。")
} else if row == 4 {
Toast.push(scene: .default, title: "传入指定图标测试", message: "这是消息内容") { (vm) in
vm.icon = UIImage(named: "icon_download")
}
} else if row == 5 {
Toast.push(scene: .default, title: "禁止手势移除", message: "这条消息无法通过向上滑动移出屏幕。5秒后自动消失每次拖拽都会刷新倒计时。") { (vm) in
vm.removable = false
vm.duration = 5
}
} else if row == 6 {
let t = Toast.push(scene: .default, title: "好友邀请", message: "你收到一条好友邀请,点击查看详情。", duration: 10)
t.didTapped { [weak t] in
t?.pop()
Alert.push(scene: .confirm, title: "好友邀请", message: "用户xxx想要添加你为好友是否同意") { (vm) in
let vc = vm.vc
vm.add(action: .default, title: "接受") {
vc?.pop()
Toast.push(scene: .success, title: "好友添加成功", message: "这是消息内容")
}
vm.add(action: .cancel, title: "拒绝") {
}
}
}
}
}
func simulateSync() {
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
if let t = Toast.get("loading").last {
t.update { (vm) in
vm.scene = .success
vm.title = "同步成功"
vm.message = "啊哈哈哈哈哈哈哈哈"
}
}
}
}
}

View File

@ -8,8 +8,10 @@
import UIKit
import ProHUD
import SnapKit
class ViewController: BaseListVC {
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
@ -20,14 +22,17 @@ class ViewController: UIViewController {
cfg.rootViewController = self
cfg.alert { (a) in
a.duration = 1
// a.durationForScene { (s) -> TimeInterval? in
// return 1
// }
a.forceQuitTimer = 3
// a.iconSize = .init(width: 20, height: 80)
// a.reloadData
// a.iconSize = .init(width: 20, height: 80)
a.iconForScene { (s) -> UIImage? in
return UIImage(named: "icon_download")
}
// a.iconForScene { (s) -> UIImage? in
// return UIImage(named: "icon_download")
// }
}
cfg.toast { (t) in
@ -39,15 +44,21 @@ class ViewController: UIViewController {
}
}
}
override var titles: [String] {
return ["Toast", "Alert", "Guard"]
}
@IBAction func test(_ sender: UIButton) {
// testAlert()
testToast()
// testUpdateAction()
// testGuard()
// fastGuard()
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
navigationController?.pushViewController(TestToastVC(), animated: true)
} else if indexPath.row == 1 {
navigationController?.pushViewController(TestAlertVC(), animated: true)
} else {
navigationController?.pushViewController(TestGuardVC(), animated: true)
}
}
func testAlert() {
@ -59,53 +70,6 @@ class ViewController: UIViewController {
vm.add(action: .default, title: "OK", handler: nil)
}
// a.update()
// Alert.push(scene: .loading, title: "Loading") { (a) in
// a.animate(rotate: true)
// DispatchQueue.main.asyncAfter(deadline: .now()+1) {
// a.update { (vm) in
// vm.message = ""
// }
// a.animate(rotate: true)
// }
// DispatchQueue.main.asyncAfter(deadline: .now()+2) {
// a.update { (vm) in
// vm.message = ""
// }
// a.animate(rotate: true)
// }
// DispatchQueue.main.asyncAfter(deadline: .now()+3) {
// a.update { (vm) in
// vm.scene = .success
// vm.add(action: .default, title: "OK") { [weak a] in
// a?.pop()
// }
// }
// }
// DispatchQueue.main.asyncAfter(deadline: .now()+4) {
// a.update { (vm) in
// vm.update(action: 0, style: .cancel, title: "Cancel", handler: nil)
// }
// }
// }
// Alert.push(scene: .delete, title: "", message: "") { (a) in
// a.identifier = ""
// DispatchQueue.main.asyncAfter(deadline: .now()+1) {
// a.update { (vm) in
// vm.add(action: .destructive, title: "") { [weak a] in
// a?.update({ (vm) in
// vm.message = " "
// vm.remove(action: 1)
// vm.update(action: 0, style: .destructive, title: "", handler: {
// a?.pop()
// })
// })
// }
// vm.add(action: .cancel, title: "", handler: nil)
// }
// }
//
// }
}
func testDelete() {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 493 KiB

View File

@ -11,7 +11,7 @@ import SnapKit
import Inspire
public extension ProHUD.Configuration {
class Alert {
struct Alert {
// MARK:
/// iPad
public var maxWidth = CGFloat(400)
@ -59,8 +59,10 @@ public extension ProHUD.Configuration {
privReloadData = callback
}
/// Loading
public var duration = TimeInterval(2)
/// viewmodeldurationnil
public func durationForScene(_ callback: @escaping (ProHUD.Alert.Scene) -> TimeInterval?) {
privDurationForScene = callback
}
/// 退
public var forceQuitTimer = TimeInterval(30)
@ -81,9 +83,15 @@ public extension ProHUD.Configuration {
// MARK: -
internal extension ProHUD.Configuration.Alert {
var reloadData: (ProHUD.Alert) -> Void {
return privReloadData
}
var durationForScene: (ProHUD.Alert.Scene) -> TimeInterval? {
return privDurationForScene
}
}
@ -233,11 +241,11 @@ fileprivate var privUpdateTextStack: (ProHUD.Alert) -> Void = {
fileprivate var privUpdateActionStack: (ProHUD.Alert) -> Void = {
return { (vc) in
let config = cfg.alert
if vc.buttonEvents.count > 0 {
if vc.actionStack.arrangedSubviews.count > 0 {
//
vc.contentStack.addArrangedSubview(vc.actionStack)
// iPad
if isPortrait == false && vc.buttonEvents.count < 4 {
if isPortrait == false && vc.actionStack.arrangedSubviews.count < 4 {
vc.actionStack.axis = .horizontal
vc.actionStack.alignment = .fill
vc.actionStack.distribution = .fillEqually
@ -332,14 +340,8 @@ fileprivate var privReloadData: (ProHUD.Alert) -> Void = {
}
}
//
if vc.vm.duration == nil {
if vc.vm.scene == .loading {
vc.vm.duration = 0
} else {
vc.vm.duration = config.duration
}
}
//
vc.vm.updateDuration()
// 退
vc.vm.forceQuitTimerBlock?.cancel()
@ -358,3 +360,15 @@ fileprivate var privReloadData: (ProHUD.Alert) -> Void = {
}
}()
fileprivate var privDurationForScene: (ProHUD.Alert.Scene) -> TimeInterval? = {
return { (scene) in
switch scene {
case .loading:
return nil
default:
return 2
}
}
}()

View File

@ -125,10 +125,12 @@ public extension Alert {
UIView.animateForAlertBuildOut(animations: {
window.backgroundColor = window.backgroundColor?.withAlphaComponent(0)
}) { (done) in
if Alert.alerts.count == 0 {
Alert.alertWindow = nil
}
}
}
}
///
/// - Parameter callback:
@ -178,13 +180,13 @@ public extension Alert {
/// - Parameter title:
/// - Parameter message:
/// - Parameter actions:
@discardableResult class func push(scene: Alert.Scene = .default, title: String? = nil, message: String? = nil, actions: ((inout ViewModel) -> Void)? = nil) -> Alert {
@discardableResult class func push(scene: Alert.Scene = .default, title: String? = nil, message: String? = nil, _ actions: ((inout ViewModel) -> Void)? = nil) -> Alert {
return Alert(scene: scene, title: title, message: message, actions: actions).push()
}
///
/// - Parameter identifier:
class func alerts(_ identifier: String?) -> [Alert] {
class func get(_ identifier: String?) -> [Alert] {
var aa = [Alert]()
for a in Alert.alerts {
if a.vm.identifier == identifier {
@ -203,7 +205,7 @@ public extension Alert {
///
/// - Parameter identifier:
class func pop(_ identifier: String?) {
for a in alerts(identifier) {
for a in get(identifier) {
a.pop()
}
}
@ -271,10 +273,16 @@ internal extension Alert {
for view in self.actionStack.arrangedSubviews {
if let btn = view as? UIButton {
btn.removeFromSuperview()
if let _ = buttonEvents[btn] {
buttonEvents.removeValue(forKey: btn)
}
}
}
} else if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton {
btn.removeFromSuperview()
if let _ = buttonEvents[btn] {
buttonEvents.removeValue(forKey: btn)
}
}
if self.actionStack.arrangedSubviews.count == 0 {
self.actionStack.removeFromSuperview()

View File

@ -65,15 +65,7 @@ public extension Alert {
/// 0
public var duration: TimeInterval? {
didSet {
durationBlock?.cancel()
if let t = duration, t > 0 {
durationBlock = DispatchWorkItem(block: { [weak self] in
self?.vc?.pop()
})
DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: durationBlock!)
} else {
durationBlock = nil
}
updateDuration()
}
}
@ -90,6 +82,18 @@ public extension Alert {
/// 退
internal var forceQuitCallback: (() -> Void)?
internal func updateDuration() {
durationBlock?.cancel()
if let t = duration ?? cfg.alert.durationForScene(scene), t > 0 {
durationBlock = DispatchWorkItem(block: { [weak self] in
self?.vc?.pop()
})
DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: durationBlock!)
} else {
durationBlock = nil
}
}
}
}

View File

@ -97,6 +97,9 @@ fileprivate var privReloadData: (ProHUD.Guard) -> Void = {
vc.contentView.layer.shadowOpacity = 0.12
}
vc.contentView.snp.makeConstraints { (mk) in
if isPortrait && vc.isFullScreen {
mk.top.equalToSuperview()
}
mk.centerX.equalToSuperview()
if UIDevice.current.userInterfaceIdiom == .phone {
if width < config.cardMaxWidth {
@ -111,7 +114,11 @@ fileprivate var privReloadData: (ProHUD.Guard) -> Void = {
}
// stack
vc.contentStack.snp.makeConstraints { (mk) in
if isPortrait && vc.isFullScreen {
mk.top.equalToSuperview().offset(Inspire.shared.screen.safeAreaInsets.top)
} else {
mk.top.equalToSuperview().offset(config.padding)
}
mk.centerX.equalToSuperview()
if width < config.cardMaxWidth {
let bottom = Inspire.shared.screen.safeAreaInsets.bottom

View File

@ -7,6 +7,7 @@
//
import SnapKit
import Inspire
public typealias Guard = ProHUD.Guard
@ -44,11 +45,14 @@ public extension ProHUD {
///
public var force = false
///
public var isFullScreen = false
///
private var displaying = false
///
public var backgroundColor: UIColor? = UIColor(white: 0, alpha: 0.5)
public var backgroundColor: UIColor? = UIColor(white: 0, alpha: 0.4)
public var vm = ViewModel()
@ -142,7 +146,9 @@ public extension Guard {
cfg.guard.reloadData(self)
}
func willAppear(_ callback: (() -> Void)?) {
willAppearCallback = callback
}
///
/// - Parameter callback:
func didDisappear(_ callback: (() -> Void)?) {
@ -159,13 +165,13 @@ public extension Guard {
/// - Parameter title:
/// - Parameter message:
/// - Parameter icon:
@discardableResult class func push(to viewController: UIViewController? = nil, actions: ((inout ViewModel) -> Void)? = nil) -> Guard {
@discardableResult class func push(to viewController: UIViewController? = nil, _ actions: ((inout ViewModel) -> Void)? = nil) -> Guard {
return Guard(actions: actions).push(to: viewController)
}
///
/// - Parameter identifier:
class func guards(_ identifier: String? = nil, from viewController: UIViewController? = nil) -> [Guard] {
class func get(_ identifier: String? = nil, from viewController: UIViewController? = nil) -> [Guard] {
var gg = [Guard]()
if let vc = viewController ?? cfg.rootViewController {
for child in vc.children {
@ -194,7 +200,7 @@ public extension Guard {
///
/// - Parameter identifier:
class func pop(from viewController: UIViewController?) {
for g in guards(from: viewController) {
for g in get(from: viewController) {
g.pop()
}
}
@ -304,10 +310,16 @@ internal extension Guard {
for view in self.actionStack.arrangedSubviews {
if let btn = view as? UIButton {
btn.removeFromSuperview()
if let _ = buttonEvents[btn] {
buttonEvents.removeValue(forKey: btn)
}
}
}
} else if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton {
btn.removeFromSuperview()
if let _ = buttonEvents[btn] {
buttonEvents.removeValue(forKey: btn)
}
}
cfg.guard.reloadStack(self)
UIView.animateForAlert {

View File

@ -13,6 +13,8 @@ public class HUDController: UIViewController {
///
internal var disappearCallback: (() -> Void)?
internal var willAppearCallback: (() -> Void)?
///
internal var buttonEvents = [UIButton:() -> Void]()
@ -36,6 +38,11 @@ public class HUDController: UIViewController {
// Do any additional setup after loading the view.
}
public override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
willAppearCallback?()
}
public override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
disappearCallback?()

View File

@ -46,8 +46,10 @@ public extension ProHUD.Configuration {
privReloadData = callback
}
/// Loading
public var duration = TimeInterval(3)
/// viewmodeldurationnil
public mutating func durationForScene(_ callback: @escaping (ProHUD.Toast.Scene) -> TimeInterval?) {
privDurationForScene = callback
}
}
}
@ -60,6 +62,10 @@ internal extension ProHUD.Configuration.Toast {
return privReloadData
}
var durationForScene: (ProHUD.Toast.Scene) -> TimeInterval? {
return privDurationForScene
}
}
// MARK: -
@ -79,6 +85,7 @@ fileprivate var privReloadData: (ProHUD.Toast) -> Void = {
}
//
vc.imageView.image = vc.vm.icon ?? privIconForScene(vc.vm.scene)
vc.imageView.layer.removeAllAnimations()
vc.titleLabel.textColor = cfg.primaryLabelColor
vc.titleLabel.text = vc.vm.title
vc.bodyLabel.textColor = cfg.secondaryLabelColor
@ -104,14 +111,10 @@ fileprivate var privReloadData: (ProHUD.Toast) -> Void = {
}
vc.view.layoutIfNeeded()
//
if vc.vm.duration == nil {
if vc.vm.scene == .loading {
vc.vm.duration = 0
} else {
vc.vm.duration = config.duration
}
}
//
vc.vm.updateDuration()
}
}()
@ -136,3 +139,17 @@ fileprivate var privIconForScene: (ProHUD.Toast.Scene) -> UIImage? = {
return ProHUD.image(named: imgStr)
}
}()
fileprivate var privDurationForScene: (ProHUD.Toast.Scene) -> TimeInterval? = {
return { (scene) in
switch scene {
case .loading:
return nil
case .error, .warning:
return 5
default:
return 3
}
}
}()

View File

@ -65,7 +65,7 @@ public extension ProHUD {
/// - Parameter title:
/// - Parameter message:
/// - Parameter icon:
public convenience init(scene: Scene = .default, title: String? = nil, message: String? = nil, icon: UIImage? = nil, actions: ((inout ViewModel) -> Void)? = nil) {
public convenience init(scene: Scene = .default, title: String? = nil, message: String? = nil, icon: UIImage? = nil, duration: TimeInterval? = nil, actions: ((inout ViewModel) -> Void)? = nil) {
self.init()
vm.vc = self
@ -73,6 +73,7 @@ public extension ProHUD {
vm.title = title
vm.message = message
vm.icon = icon
vm.duration = duration
actions?(&vm)
//
@ -180,6 +181,20 @@ public extension Toast {
return self
}
func animate(rotate: Bool) {
if rotate {
DispatchQueue.main.async {
let ani = CABasicAnimation(keyPath: "transform.rotation.z")
ani.toValue = Double.pi * 2.0
ani.duration = 3
ani.repeatCount = 10000
self.imageView.layer.add(ani, forKey: "rotationAnimation")
}
} else {
imageView.layer.removeAllAnimations()
}
}
}
@ -191,13 +206,13 @@ public extension Toast {
/// - Parameter title:
/// - Parameter message:
/// - Parameter actions:
@discardableResult class func push(scene: Toast.Scene = .default, title: String? = nil, message: String? = nil, actions: ((inout ViewModel) -> Void)? = nil) -> Toast {
return Toast(scene: scene, title: title, message: message, actions: actions).push()
@discardableResult class func push(scene: Toast.Scene = .default, title: String? = nil, message: String? = nil, duration: TimeInterval? = nil, _ actions: ((inout ViewModel) -> Void)? = nil) -> Toast {
return Toast(scene: scene, title: title, message: message, duration: duration, actions: actions).push()
}
/// toast
/// - Parameter identifier:
class func toasts(_ identifier: String?) -> [Toast] {
class func get(_ identifier: String?) -> [Toast] {
var tt = [Toast]()
for t in toasts {
if t.vm.identifier == identifier {
@ -234,7 +249,7 @@ public extension Toast {
///
/// - Parameter identifier:
class func pop(_ identifier: String?) {
for t in toasts(identifier) {
for t in get(identifier) {
t.pop()
}
}

View File

@ -59,15 +59,7 @@ public extension Toast {
///
public var duration: TimeInterval? {
didSet {
durationBlock?.cancel()
if let t = duration, t > 0 {
durationBlock = DispatchWorkItem(block: { [weak self] in
self?.vc?.pop()
})
DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: durationBlock!)
} else {
durationBlock = nil
}
updateDuration()
}
}
@ -85,6 +77,17 @@ public extension Toast {
///
internal var tapCallback: (() -> Void)?
internal func updateDuration() {
durationBlock?.cancel()
if let t = duration ?? cfg.toast.durationForScene(scene), t > 0 {
durationBlock = DispatchWorkItem(block: { [weak self] in
self?.vc?.pop()
})
DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: durationBlock!)
} else {
durationBlock = nil
}
}
}