diff --git a/.DS_Store b/.DS_Store
index 71571e3..59e10a7 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/.build/arm64-apple-macosx/debug/SPAlertController.build/module.modulemap b/.build/arm64-apple-macosx/debug/SPAlertController.build/module.modulemap
new file mode 100644
index 0000000..ed109d6
--- /dev/null
+++ b/.build/arm64-apple-macosx/debug/SPAlertController.build/module.modulemap
@@ -0,0 +1,4 @@
+module SPAlertController {
+ umbrella header "/Users/shengping_le/SPAlertController/SPAlertController/SPAlertController.h"
+ export *
+}
diff --git a/.build/arm64-apple-macosx/debug/index/db/v13/saved/data.mdb b/.build/arm64-apple-macosx/debug/index/db/v13/saved/data.mdb
new file mode 100644
index 0000000..aa89ad8
Binary files /dev/null and b/.build/arm64-apple-macosx/debug/index/db/v13/saved/data.mdb differ
diff --git a/.build/arm64-apple-macosx/debug/index/db/v13/saved/lock.mdb b/.build/arm64-apple-macosx/debug/index/db/v13/saved/lock.mdb
new file mode 100644
index 0000000..6bbd36d
Binary files /dev/null and b/.build/arm64-apple-macosx/debug/index/db/v13/saved/lock.mdb differ
diff --git a/.build/workspace-state.json b/.build/workspace-state.json
new file mode 100644
index 0000000..71deae9
--- /dev/null
+++ b/.build/workspace-state.json
@@ -0,0 +1,11 @@
+{
+ "object" : {
+ "artifacts" : [
+
+ ],
+ "dependencies" : [
+
+ ]
+ },
+ "version" : 6
+}
\ No newline at end of file
diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/.swiftpm/xcode/xcuserdata/shengping_le.xcuserdatad/xcschemes/xcschememanagement.plist b/.swiftpm/xcode/xcuserdata/shengping_le.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..e08ca5d
--- /dev/null
+++ b/.swiftpm/xcode/xcuserdata/shengping_le.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,14 @@
+
+
+
+
+ SchemeUserState
+
+ SPAlertController.xcscheme_^#shared#^_
+
+ orderHint
+ 0
+
+
+
+
diff --git a/Example/.DS_Store b/Example/.DS_Store
old mode 100644
new mode 100755
index b58dc8a..60eadb4
Binary files a/Example/.DS_Store and b/Example/.DS_Store differ
diff --git a/Example/SPAlertController.xcodeproj/project.pbxproj b/Example/SPAlertController.xcodeproj/project.pbxproj
old mode 100644
new mode 100755
index 9dd0e0c..9ccc926
--- a/Example/SPAlertController.xcodeproj/project.pbxproj
+++ b/Example/SPAlertController.xcodeproj/project.pbxproj
@@ -7,8 +7,6 @@
objects = {
/* Begin PBXBuildFile section */
- 090BCB9221CEA18300057E1F /* PopView.m in Sources */ = {isa = PBXBuildFile; fileRef = 090BCB9121CEA18300057E1F /* PopView.m */; };
- 090BCB9921CEAE2200057E1F /* SPButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 090BCB9821CEAE2200057E1F /* SPButton.m */; };
09810FC621C4F90300E702E1 /* image8.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 09810FB821C4F90300E702E1 /* image8.jpg */; };
09810FC721C4F90300E702E1 /* image9.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 09810FB921C4F90300E702E1 /* image9.jpg */; };
09810FC821C4F90300E702E1 /* image7.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 09810FBA21C4F90300E702E1 /* image7.jpg */; };
@@ -27,26 +25,19 @@
522C267D21D0D5B2004EBDEB /* SendAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = 522C267C21D0D5B2004EBDEB /* SendAlertView.m */; };
522C267F21D0D5F0004EBDEB /* SendAlertView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 522C267E21D0D5F0004EBDEB /* SendAlertView.xib */; };
522C268621D0E40A004EBDEB /* send1.jpeg in Resources */ = {isa = PBXBuildFile; fileRef = 522C268121D0E409004EBDEB /* send1.jpeg */; };
- 522C268F21D0EB17004EBDEB /* send0.jpeg in Resources */ = {isa = PBXBuildFile; fileRef = 522C268E21D0EB16004EBDEB /* send0.jpeg */; };
+ 5270519B22EE9FF50016D0DB /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 52F6A5C521B60F86006AF8CC /* main.m */; };
+ 5270519D22EEAF410016D0DB /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 52F6A5B721B60F83006AF8CC /* AppDelegate.m */; };
+ 5270519E22EEBC660016D0DB /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 52F6A5C521B60F86006AF8CC /* main.m */; };
52CB4ACC21B616E400B6090B /* MyCenterView.m in Sources */ = {isa = PBXBuildFile; fileRef = 52CB4AB321B616E400B6090B /* MyCenterView.m */; };
- 52CB4ACD21B616E400B6090B /* ShoppingCartCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 52CB4AB521B616E400B6090B /* ShoppingCartCell.xib */; };
- 52CB4ACE21B616E400B6090B /* ShoppingCartView.m in Sources */ = {isa = PBXBuildFile; fileRef = 52CB4AB621B616E400B6090B /* ShoppingCartView.m */; };
- 52CB4ACF21B616E400B6090B /* ShoppingCartItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 52CB4AB721B616E400B6090B /* ShoppingCartItem.m */; };
- 52CB4AD021B616E400B6090B /* ShoppingCartCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 52CB4AB821B616E400B6090B /* ShoppingCartCell.m */; };
- 52CB4AD121B616E400B6090B /* CommodityListView.m in Sources */ = {isa = PBXBuildFile; fileRef = 52CB4ABD21B616E400B6090B /* CommodityListView.m */; };
- 52CB4AD221B616E400B6090B /* PickerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 52CB4AC021B616E400B6090B /* PickerView.m */; };
- 52CB4AD321B616E400B6090B /* PassWordView.m in Sources */ = {isa = PBXBuildFile; fileRef = 52CB4AC321B616E400B6090B /* PassWordView.m */; };
- 52CB4AD421B616E400B6090B /* MyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 52CB4AC421B616E400B6090B /* MyView.xib */; };
- 52CB4AD521B616E400B6090B /* MyView.m in Sources */ = {isa = PBXBuildFile; fileRef = 52CB4AC721B616E400B6090B /* MyView.m */; };
- 52F6A5B821B60F83006AF8CC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 52F6A5B721B60F83006AF8CC /* AppDelegate.m */; };
52F6A5BB21B60F83006AF8CC /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 52F6A5BA21B60F83006AF8CC /* ViewController.m */; };
52F6A5BE21B60F83006AF8CC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 52F6A5BC21B60F83006AF8CC /* Main.storyboard */; };
52F6A5C021B60F86006AF8CC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 52F6A5BF21B60F86006AF8CC /* Assets.xcassets */; };
52F6A5C321B60F86006AF8CC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 52F6A5C121B60F86006AF8CC /* LaunchScreen.storyboard */; };
- 52F6A5C621B60F86006AF8CC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 52F6A5C521B60F86006AF8CC /* main.m */; };
52F6A5D021B60F86006AF8CC /* SPAlertControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 52F6A5CF21B60F86006AF8CC /* SPAlertControllerTests.m */; };
52F6A5DB21B60F86006AF8CC /* SPAlertControllerUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 52F6A5DA21B60F86006AF8CC /* SPAlertControllerUITests.m */; };
- 52F6A5EB21B6101E006AF8CC /* SPAlertController.m in Sources */ = {isa = PBXBuildFile; fileRef = 52F6A5E921B6101D006AF8CC /* SPAlertController.m */; };
+ BB05FF082455887700950629 /* UIColor+DarkMode.m in Sources */ = {isa = PBXBuildFile; fileRef = BB05FF072455887700950629 /* UIColor+DarkMode.m */; };
+ BB54D6B02E70869400CC72BC /* SPAlertController.m in Sources */ = {isa = PBXBuildFile; fileRef = BB54D6AE2E70869400CC72BC /* SPAlertController.m */; };
+ BB5EA69D2457C75E005AE698 /* send0.jpeg in Resources */ = {isa = PBXBuildFile; fileRef = BB5EA69C2457C75E005AE698 /* send0.jpeg */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -67,10 +58,6 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
- 090BCB9021CEA18300057E1F /* PopView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PopView.h; sourceTree = ""; };
- 090BCB9121CEA18300057E1F /* PopView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PopView.m; sourceTree = ""; };
- 090BCB9721CEAE2200057E1F /* SPButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPButton.h; sourceTree = ""; };
- 090BCB9821CEAE2200057E1F /* SPButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPButton.m; sourceTree = ""; };
09810FB821C4F90300E702E1 /* image8.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = image8.jpg; sourceTree = ""; };
09810FB921C4F90300E702E1 /* image9.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = image9.jpg; sourceTree = ""; };
09810FBA21C4F90300E702E1 /* image7.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = image7.jpg; sourceTree = ""; };
@@ -93,25 +80,8 @@
522C267C21D0D5B2004EBDEB /* SendAlertView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SendAlertView.m; sourceTree = ""; };
522C267E21D0D5F0004EBDEB /* SendAlertView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SendAlertView.xib; sourceTree = ""; };
522C268121D0E409004EBDEB /* send1.jpeg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = send1.jpeg; sourceTree = ""; };
- 522C268E21D0EB16004EBDEB /* send0.jpeg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = send0.jpeg; sourceTree = ""; };
52CB4AB221B616E400B6090B /* MyCenterView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyCenterView.h; sourceTree = ""; };
52CB4AB321B616E400B6090B /* MyCenterView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MyCenterView.m; sourceTree = ""; };
- 52CB4AB521B616E400B6090B /* ShoppingCartCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ShoppingCartCell.xib; sourceTree = ""; };
- 52CB4AB621B616E400B6090B /* ShoppingCartView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShoppingCartView.m; sourceTree = ""; };
- 52CB4AB721B616E400B6090B /* ShoppingCartItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShoppingCartItem.m; sourceTree = ""; };
- 52CB4AB821B616E400B6090B /* ShoppingCartCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShoppingCartCell.m; sourceTree = ""; };
- 52CB4AB921B616E400B6090B /* ShoppingCartView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShoppingCartView.h; sourceTree = ""; };
- 52CB4ABA21B616E400B6090B /* ShoppingCartCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShoppingCartCell.h; sourceTree = ""; };
- 52CB4ABB21B616E400B6090B /* ShoppingCartItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShoppingCartItem.h; sourceTree = ""; };
- 52CB4ABD21B616E400B6090B /* CommodityListView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CommodityListView.m; sourceTree = ""; };
- 52CB4ABE21B616E400B6090B /* CommodityListView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommodityListView.h; sourceTree = ""; };
- 52CB4AC021B616E400B6090B /* PickerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PickerView.m; sourceTree = ""; };
- 52CB4AC121B616E400B6090B /* PickerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PickerView.h; sourceTree = ""; };
- 52CB4AC321B616E400B6090B /* PassWordView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PassWordView.m; sourceTree = ""; };
- 52CB4AC421B616E400B6090B /* MyView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MyView.xib; sourceTree = ""; };
- 52CB4AC521B616E400B6090B /* MyView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyView.h; sourceTree = ""; };
- 52CB4AC621B616E400B6090B /* PassWordView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PassWordView.h; sourceTree = ""; };
- 52CB4AC721B616E400B6090B /* MyView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MyView.m; sourceTree = ""; };
52F6A5B321B60F83006AF8CC /* SPAlertController.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SPAlertController.app; sourceTree = BUILT_PRODUCTS_DIR; };
52F6A5B621B60F83006AF8CC /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
52F6A5B721B60F83006AF8CC /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
@@ -128,8 +98,11 @@
52F6A5D621B60F86006AF8CC /* SPAlertControllerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SPAlertControllerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
52F6A5DA21B60F86006AF8CC /* SPAlertControllerUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SPAlertControllerUITests.m; sourceTree = ""; };
52F6A5DC21B60F86006AF8CC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
- 52F6A5E921B6101D006AF8CC /* SPAlertController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPAlertController.m; sourceTree = ""; };
- 52F6A5EA21B6101D006AF8CC /* SPAlertController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPAlertController.h; sourceTree = ""; };
+ BB05FF062455887700950629 /* UIColor+DarkMode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIColor+DarkMode.h"; sourceTree = ""; };
+ BB05FF072455887700950629 /* UIColor+DarkMode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIColor+DarkMode.m"; sourceTree = ""; };
+ BB54D6AD2E70869400CC72BC /* SPAlertController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SPAlertController.h; sourceTree = ""; };
+ BB54D6AE2E70869400CC72BC /* SPAlertController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SPAlertController.m; sourceTree = ""; };
+ BB5EA69C2457C75E005AE698 /* send0.jpeg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = send0.jpeg; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -157,17 +130,6 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
- 090BCB8F21CEA0E000057E1F /* CustomView7 */ = {
- isa = PBXGroup;
- children = (
- 090BCB9021CEA18300057E1F /* PopView.h */,
- 090BCB9121CEA18300057E1F /* PopView.m */,
- 090BCB9721CEAE2200057E1F /* SPButton.h */,
- 090BCB9821CEAE2200057E1F /* SPButton.m */,
- );
- path = CustomView7;
- sourceTree = "";
- };
09810FB721C4F90300E702E1 /* Images */ = {
isa = PBXGroup;
children = (
@@ -184,7 +146,7 @@
09810FB821C4F90300E702E1 /* image8.jpg */,
09810FB921C4F90300E702E1 /* image9.jpg */,
522C268121D0E409004EBDEB /* send1.jpeg */,
- 522C268E21D0EB16004EBDEB /* send0.jpeg */,
+ BB5EA69C2457C75E005AE698 /* send0.jpeg */,
);
path = Images;
sourceTree = "";
@@ -205,13 +167,8 @@
isa = PBXGroup;
children = (
522C267421D0CF91004EBDEB /* CustomView1 */,
- 52CB4AC221B616E400B6090B /* CustomView2 */,
- 52CB4AB421B616E400B6090B /* CustomView3 */,
- 52CB4ABC21B616E400B6090B /* CustomView4 */,
- 52CB4ABF21B616E400B6090B /* CustomView5 */,
52CB4AC821B616E400B6090B /* CustomView5 */,
52CB4AB121B616E400B6090B /* CustomView6 */,
- 090BCB8F21CEA0E000057E1F /* CustomView7 */,
);
path = CustomViews;
sourceTree = "";
@@ -225,50 +182,6 @@
path = CustomView6;
sourceTree = "";
};
- 52CB4AB421B616E400B6090B /* CustomView3 */ = {
- isa = PBXGroup;
- children = (
- 52CB4ABA21B616E400B6090B /* ShoppingCartCell.h */,
- 52CB4AB821B616E400B6090B /* ShoppingCartCell.m */,
- 52CB4AB521B616E400B6090B /* ShoppingCartCell.xib */,
- 52CB4ABB21B616E400B6090B /* ShoppingCartItem.h */,
- 52CB4AB721B616E400B6090B /* ShoppingCartItem.m */,
- 52CB4AB921B616E400B6090B /* ShoppingCartView.h */,
- 52CB4AB621B616E400B6090B /* ShoppingCartView.m */,
- );
- path = CustomView3;
- sourceTree = "";
- };
- 52CB4ABC21B616E400B6090B /* CustomView4 */ = {
- isa = PBXGroup;
- children = (
- 52CB4ABE21B616E400B6090B /* CommodityListView.h */,
- 52CB4ABD21B616E400B6090B /* CommodityListView.m */,
- );
- path = CustomView4;
- sourceTree = "";
- };
- 52CB4ABF21B616E400B6090B /* CustomView5 */ = {
- isa = PBXGroup;
- children = (
- 52CB4AC121B616E400B6090B /* PickerView.h */,
- 52CB4AC021B616E400B6090B /* PickerView.m */,
- );
- path = CustomView5;
- sourceTree = "";
- };
- 52CB4AC221B616E400B6090B /* CustomView2 */ = {
- isa = PBXGroup;
- children = (
- 52CB4AC521B616E400B6090B /* MyView.h */,
- 52CB4AC721B616E400B6090B /* MyView.m */,
- 52CB4AC421B616E400B6090B /* MyView.xib */,
- 52CB4AC621B616E400B6090B /* PassWordView.h */,
- 52CB4AC321B616E400B6090B /* PassWordView.m */,
- );
- path = CustomView2;
- sourceTree = "";
- };
52CB4AC821B616E400B6090B /* CustomView5 */ = {
isa = PBXGroup;
children = (
@@ -304,18 +217,19 @@
52F6A5B521B60F83006AF8CC /* SPAlertController */ = {
isa = PBXGroup;
children = (
- 52F6A5E821B6101D006AF8CC /* SPAlertController */,
+ BB54D6AF2E70869400CC72BC /* SPAlertController */,
52F6A5B621B60F83006AF8CC /* AppDelegate.h */,
52F6A5B721B60F83006AF8CC /* AppDelegate.m */,
52F6A5B921B60F83006AF8CC /* ViewController.h */,
52F6A5BA21B60F83006AF8CC /* ViewController.m */,
+ BB05FF062455887700950629 /* UIColor+DarkMode.h */,
+ BB05FF072455887700950629 /* UIColor+DarkMode.m */,
52CB4AB021B616E400B6090B /* CustomViews */,
52F6A5BC21B60F83006AF8CC /* Main.storyboard */,
52F6A5BF21B60F86006AF8CC /* Assets.xcassets */,
52F6A5C121B60F86006AF8CC /* LaunchScreen.storyboard */,
52F6A5C421B60F86006AF8CC /* Info.plist */,
09810FB721C4F90300E702E1 /* Images */,
- 52F6A5C521B60F86006AF8CC /* main.m */,
);
path = SPAlertController;
sourceTree = "";
@@ -323,6 +237,7 @@
52F6A5CE21B60F86006AF8CC /* SPAlertControllerTests */ = {
isa = PBXGroup;
children = (
+ 52F6A5C521B60F86006AF8CC /* main.m */,
52F6A5CF21B60F86006AF8CC /* SPAlertControllerTests.m */,
52F6A5D121B60F86006AF8CC /* Info.plist */,
);
@@ -338,14 +253,15 @@
path = SPAlertControllerUITests;
sourceTree = "";
};
- 52F6A5E821B6101D006AF8CC /* SPAlertController */ = {
+ BB54D6AF2E70869400CC72BC /* SPAlertController */ = {
isa = PBXGroup;
children = (
- 52F6A5EA21B6101D006AF8CC /* SPAlertController.h */,
- 52F6A5E921B6101D006AF8CC /* SPAlertController.m */,
+ BB54D6AD2E70869400CC72BC /* SPAlertController.h */,
+ BB54D6AE2E70869400CC72BC /* SPAlertController.m */,
);
- path = SPAlertController;
- sourceTree = "";
+ name = SPAlertController;
+ path = ../SPAlertController;
+ sourceTree = SOURCE_ROOT;
};
/* End PBXGroup section */
@@ -454,12 +370,12 @@
09810FCC21C4F90300E702E1 /* image5.jpg in Resources */,
52F6A5C321B60F86006AF8CC /* LaunchScreen.storyboard in Resources */,
522C267F21D0D5F0004EBDEB /* SendAlertView.xib in Resources */,
+ BB5EA69D2457C75E005AE698 /* send0.jpeg in Resources */,
522C268621D0E40A004EBDEB /* send1.jpeg in Resources */,
09810FCA21C4F90300E702E1 /* image6.jpg in Resources */,
09810FD121C4F90300E702E1 /* image2.jpg in Resources */,
09810FCF21C4F90300E702E1 /* 背景2.jpg in Resources */,
09810FC821C4F90300E702E1 /* image7.jpg in Resources */,
- 522C268F21D0EB17004EBDEB /* send0.jpeg in Resources */,
09810FD021C4F90300E702E1 /* image0.jpg in Resources */,
52F6A5C021B60F86006AF8CC /* Assets.xcassets in Resources */,
09810FD321C4F90300E702E1 /* image3.jpg in Resources */,
@@ -468,8 +384,6 @@
52F6A5BE21B60F83006AF8CC /* Main.storyboard in Resources */,
09810FCB21C4F90300E702E1 /* image4.jpg in Resources */,
09810FC721C4F90300E702E1 /* image9.jpg in Resources */,
- 52CB4AD421B616E400B6090B /* MyView.xib in Resources */,
- 52CB4ACD21B616E400B6090B /* ShoppingCartCell.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -494,24 +408,16 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 5270519E22EEBC660016D0DB /* main.m in Sources */,
+ BB54D6B02E70869400CC72BC /* SPAlertController.m in Sources */,
+ 5270519D22EEAF410016D0DB /* AppDelegate.m in Sources */,
522C267A21D0D0B7004EBDEB /* SPTextView.m in Sources */,
- 090BCB9221CEA18300057E1F /* PopView.m in Sources */,
- 52CB4ACF21B616E400B6090B /* ShoppingCartItem.m in Sources */,
52F6A5BB21B60F83006AF8CC /* ViewController.m in Sources */,
522C267D21D0D5B2004EBDEB /* SendAlertView.m in Sources */,
- 52CB4AD321B616E400B6090B /* PassWordView.m in Sources */,
- 090BCB9921CEAE2200057E1F /* SPButton.m in Sources */,
+ BB05FF082455887700950629 /* UIColor+DarkMode.m in Sources */,
52CB4ACC21B616E400B6090B /* MyCenterView.m in Sources */,
522C267321D0C422004EBDEB /* ScoreView.m in Sources */,
522C267021D0C31F004EBDEB /* HCSStarRatingView.m in Sources */,
- 52CB4ACE21B616E400B6090B /* ShoppingCartView.m in Sources */,
- 52F6A5EB21B6101E006AF8CC /* SPAlertController.m in Sources */,
- 52F6A5C621B60F86006AF8CC /* main.m in Sources */,
- 52CB4AD121B616E400B6090B /* CommodityListView.m in Sources */,
- 52CB4AD521B616E400B6090B /* MyView.m in Sources */,
- 52F6A5B821B60F83006AF8CC /* AppDelegate.m in Sources */,
- 52CB4AD021B616E400B6090B /* ShoppingCartCell.m in Sources */,
- 52CB4AD221B616E400B6090B /* PickerView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -520,6 +426,7 @@
buildActionMask = 2147483647;
files = (
52F6A5D021B60F86006AF8CC /* SPAlertControllerTests.m in Sources */,
+ 5270519B22EE9FF50016D0DB /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -683,12 +590,13 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
- DEVELOPMENT_TEAM = MP8K63J94Y;
+ DEVELOPMENT_TEAM = AYQTA2673R;
INFOPLIST_FILE = SPAlertController/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
+ MARKETING_VERSION = 4.0.0;
PRODUCT_BUNDLE_IDENTIFIER = com.idress.SPAlertController;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
@@ -700,12 +608,13 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
- DEVELOPMENT_TEAM = MP8K63J94Y;
+ DEVELOPMENT_TEAM = AYQTA2673R;
INFOPLIST_FILE = SPAlertController/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
+ MARKETING_VERSION = 4.0.0;
PRODUCT_BUNDLE_IDENTIFIER = com.idress.SPAlertController;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
diff --git a/Example/SPAlertController.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Example/SPAlertController.xcodeproj/project.xcworkspace/contents.xcworkspacedata
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Example/SPAlertController.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController.xcodeproj/project.xcworkspace/xcuserdata/leshengping.xcuserdatad/UserInterfaceState.xcuserstate b/Example/SPAlertController.xcodeproj/project.xcworkspace/xcuserdata/leshengping.xcuserdatad/UserInterfaceState.xcuserstate
old mode 100644
new mode 100755
index a44f987..45f65fc
Binary files a/Example/SPAlertController.xcodeproj/project.xcworkspace/xcuserdata/leshengping.xcuserdatad/UserInterfaceState.xcuserstate and b/Example/SPAlertController.xcodeproj/project.xcworkspace/xcuserdata/leshengping.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/Example/SPAlertController.xcodeproj/project.xcworkspace/xcuserdata/libo.xcuserdatad/UserInterfaceState.xcuserstate b/Example/SPAlertController.xcodeproj/project.xcworkspace/xcuserdata/libo.xcuserdatad/UserInterfaceState.xcuserstate
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController.xcodeproj/project.xcworkspace/xcuserdata/shengping_le.xcuserdatad/UserInterfaceState.xcuserstate b/Example/SPAlertController.xcodeproj/project.xcworkspace/xcuserdata/shengping_le.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..6f06eb4
Binary files /dev/null and b/Example/SPAlertController.xcodeproj/project.xcworkspace/xcuserdata/shengping_le.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/Example/SPAlertController.xcodeproj/xcuserdata/leshengping.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Example/SPAlertController.xcodeproj/xcuserdata/leshengping.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController.xcodeproj/xcuserdata/leshengping.xcuserdatad/xcschemes/xcschememanagement.plist b/Example/SPAlertController.xcodeproj/xcuserdata/leshengping.xcuserdatad/xcschemes/xcschememanagement.plist
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController.xcodeproj/xcuserdata/libo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Example/SPAlertController.xcodeproj/xcuserdata/libo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController.xcodeproj/xcuserdata/libo.xcuserdatad/xcschemes/xcschememanagement.plist b/Example/SPAlertController.xcodeproj/xcuserdata/libo.xcuserdatad/xcschemes/xcschememanagement.plist
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController.xcodeproj/xcuserdata/shengping_le.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Example/SPAlertController.xcodeproj/xcuserdata/shengping_le.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
new file mode 100644
index 0000000..8f6e687
--- /dev/null
+++ b/Example/SPAlertController.xcodeproj/xcuserdata/shengping_le.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -0,0 +1,6 @@
+
+
+
diff --git a/Example/SPAlertController.xcodeproj/xcuserdata/shengping_le.xcuserdatad/xcschemes/xcschememanagement.plist b/Example/SPAlertController.xcodeproj/xcuserdata/shengping_le.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..e08ca5d
--- /dev/null
+++ b/Example/SPAlertController.xcodeproj/xcuserdata/shengping_le.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,14 @@
+
+
+
+
+ SchemeUserState
+
+ SPAlertController.xcscheme_^#shared#^_
+
+ orderHint
+ 0
+
+
+
+
diff --git a/Example/SPAlertController/.DS_Store b/Example/SPAlertController/.DS_Store
old mode 100644
new mode 100755
index 2bfcf9e..7c038ff
Binary files a/Example/SPAlertController/.DS_Store and b/Example/SPAlertController/.DS_Store differ
diff --git a/Example/SPAlertController/AppDelegate.h b/Example/SPAlertController/AppDelegate.h
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/AppDelegate.m b/Example/SPAlertController/AppDelegate.m
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/AppIcon.appiconset/Contents.json b/Example/SPAlertController/Assets.xcassets/AppIcon.appiconset/Contents.json
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/Contents.json b/Example/SPAlertController/Assets.xcassets/Contents.json
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/publish_10.imageset/publish_10@2x.png b/Example/SPAlertController/Assets.xcassets/publish_10.imageset/publish_10@2x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/publish_10.imageset/publish_10@3x.png b/Example/SPAlertController/Assets.xcassets/publish_10.imageset/publish_10@3x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/publish_11.imageset/publish_11@2x.png b/Example/SPAlertController/Assets.xcassets/publish_11.imageset/publish_11@2x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/publish_11.imageset/publish_11@3x.png b/Example/SPAlertController/Assets.xcassets/publish_11.imageset/publish_11@3x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/publish_6.imageset/publish_6@2x.png b/Example/SPAlertController/Assets.xcassets/publish_6.imageset/publish_6@2x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/publish_6.imageset/publish_6@3x.png b/Example/SPAlertController/Assets.xcassets/publish_6.imageset/publish_6@3x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/publish_7.imageset/publish_7@2x.png b/Example/SPAlertController/Assets.xcassets/publish_7.imageset/publish_7@2x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/publish_7.imageset/publish_7@3x.png b/Example/SPAlertController/Assets.xcassets/publish_7.imageset/publish_7@3x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/publish_8.imageset/publish_8@2x.png b/Example/SPAlertController/Assets.xcassets/publish_8.imageset/publish_8@2x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/publish_8.imageset/publish_8@3x.png b/Example/SPAlertController/Assets.xcassets/publish_8.imageset/publish_8@3x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/publish_9.imageset/publish_9@2x.png b/Example/SPAlertController/Assets.xcassets/publish_9.imageset/publish_9@2x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/publish_9.imageset/publish_9@3x.png b/Example/SPAlertController/Assets.xcassets/publish_9.imageset/publish_9@3x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/success.imageset/Contents.json b/Example/SPAlertController/Assets.xcassets/success.imageset/Contents.json
old mode 100644
new mode 100755
diff --git "a/Example/SPAlertController/Assets.xcassets/success.imageset/\345\213\276.png" "b/Example/SPAlertController/Assets.xcassets/success.imageset/\345\213\276.png"
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/telephone.imageset/Contents.json b/Example/SPAlertController/Assets.xcassets/telephone.imageset/Contents.json
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/telephone.imageset/telephone@2x.png b/Example/SPAlertController/Assets.xcassets/telephone.imageset/telephone@2x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/telephone.imageset/telephone@3x.png b/Example/SPAlertController/Assets.xcassets/telephone.imageset/telephone@3x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/video.imageset/Contents.json b/Example/SPAlertController/Assets.xcassets/video.imageset/Contents.json
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/video.imageset/video@2x.png b/Example/SPAlertController/Assets.xcassets/video.imageset/video@2x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/video.imageset/video@3x.png b/Example/SPAlertController/Assets.xcassets/video.imageset/video@3x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/wechatLogo.imageset/Contents.json b/Example/SPAlertController/Assets.xcassets/wechatLogo.imageset/Contents.json
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/wechatLogo.imageset/wechatLogo@2x.png b/Example/SPAlertController/Assets.xcassets/wechatLogo.imageset/wechatLogo@2x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/wechatLogo.imageset/wechatLogo@3x.png b/Example/SPAlertController/Assets.xcassets/wechatLogo.imageset/wechatLogo@3x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/zhiwen.imageset/Contents.json b/Example/SPAlertController/Assets.xcassets/zhiwen.imageset/Contents.json
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/zhiwen.imageset/zhiwen@2x.png b/Example/SPAlertController/Assets.xcassets/zhiwen.imageset/zhiwen@2x.png
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Assets.xcassets/zhiwen.imageset/zhiwen@3x.png b/Example/SPAlertController/Assets.xcassets/zhiwen.imageset/zhiwen@3x.png
old mode 100644
new mode 100755
diff --git "a/Example/SPAlertController/Assets.xcassets/\345\207\217\345\217\267.imageset/Contents.json" "b/Example/SPAlertController/Assets.xcassets/\345\207\217\345\217\267.imageset/Contents.json"
old mode 100644
new mode 100755
diff --git "a/Example/SPAlertController/Assets.xcassets/\345\207\217\345\217\267.imageset/\345\207\217\345\217\267-1.png" "b/Example/SPAlertController/Assets.xcassets/\345\207\217\345\217\267.imageset/\345\207\217\345\217\267-1.png"
old mode 100644
new mode 100755
diff --git "a/Example/SPAlertController/Assets.xcassets/\345\207\217\345\217\267.imageset/\345\207\217\345\217\267-2.png" "b/Example/SPAlertController/Assets.xcassets/\345\207\217\345\217\267.imageset/\345\207\217\345\217\267-2.png"
old mode 100644
new mode 100755
diff --git "a/Example/SPAlertController/Assets.xcassets/\345\207\217\345\217\267.imageset/\345\207\217\345\217\267.png" "b/Example/SPAlertController/Assets.xcassets/\345\207\217\345\217\267.imageset/\345\207\217\345\217\267.png"
old mode 100644
new mode 100755
diff --git "a/Example/SPAlertController/Assets.xcassets/\345\212\240\345\217\267.imageset/Contents.json" "b/Example/SPAlertController/Assets.xcassets/\345\212\240\345\217\267.imageset/Contents.json"
old mode 100644
new mode 100755
diff --git "a/Example/SPAlertController/Assets.xcassets/\345\212\240\345\217\267.imageset/\345\212\240\345\217\267-1.png" "b/Example/SPAlertController/Assets.xcassets/\345\212\240\345\217\267.imageset/\345\212\240\345\217\267-1.png"
old mode 100644
new mode 100755
diff --git "a/Example/SPAlertController/Assets.xcassets/\345\212\240\345\217\267.imageset/\345\212\240\345\217\267-3.png" "b/Example/SPAlertController/Assets.xcassets/\345\212\240\345\217\267.imageset/\345\212\240\345\217\267-3.png"
old mode 100644
new mode 100755
diff --git "a/Example/SPAlertController/Assets.xcassets/\345\212\240\345\217\267.imageset/\345\212\240\345\217\267-4.png" "b/Example/SPAlertController/Assets.xcassets/\345\212\240\345\217\267.imageset/\345\212\240\345\217\267-4.png"
old mode 100644
new mode 100755
diff --git "a/Example/SPAlertController/Assets.xcassets/\345\217\226\346\266\210.imageset/Contents.json" "b/Example/SPAlertController/Assets.xcassets/\345\217\226\346\266\210.imageset/Contents.json"
old mode 100644
new mode 100755
diff --git "a/Example/SPAlertController/Assets.xcassets/\345\217\226\346\266\210.imageset/\345\217\211-1.png" "b/Example/SPAlertController/Assets.xcassets/\345\217\226\346\266\210.imageset/\345\217\211-1.png"
old mode 100644
new mode 100755
diff --git "a/Example/SPAlertController/Assets.xcassets/\345\217\226\346\266\210.imageset/\345\217\211-2.png" "b/Example/SPAlertController/Assets.xcassets/\345\217\226\346\266\210.imageset/\345\217\211-2.png"
old mode 100644
new mode 100755
diff --git "a/Example/SPAlertController/Assets.xcassets/\345\217\226\346\266\210.imageset/\345\217\211-3.png" "b/Example/SPAlertController/Assets.xcassets/\345\217\226\346\266\210.imageset/\345\217\211-3.png"
old mode 100644
new mode 100755
diff --git "a/Example/SPAlertController/Assets.xcassets/\350\213\271\346\236\234logo.imageset/Contents.json" "b/Example/SPAlertController/Assets.xcassets/\350\213\271\346\236\234logo.imageset/Contents.json"
old mode 100644
new mode 100755
diff --git "a/Example/SPAlertController/Assets.xcassets/\350\213\271\346\236\234logo.imageset/\350\213\271\346\236\234logo.png" "b/Example/SPAlertController/Assets.xcassets/\350\213\271\346\236\234logo.imageset/\350\213\271\346\236\234logo.png"
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Base.lproj/LaunchScreen.storyboard b/Example/SPAlertController/Base.lproj/LaunchScreen.storyboard
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Base.lproj/Main.storyboard b/Example/SPAlertController/Base.lproj/Main.storyboard
old mode 100644
new mode 100755
index 5cc94e2..b9205fd
--- a/Example/SPAlertController/Base.lproj/Main.storyboard
+++ b/Example/SPAlertController/Base.lproj/Main.storyboard
@@ -1,11 +1,11 @@
-
+
-
+
@@ -39,30 +39,9 @@
-
-
-
@@ -71,13 +50,30 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Example/SPAlertController/CustomViews/CustomView1/SendAlertView.h b/Example/SPAlertController/CustomViews/CustomView1/SendAlertView.h
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/CustomViews/CustomView1/SendAlertView.m b/Example/SPAlertController/CustomViews/CustomView1/SendAlertView.m
old mode 100644
new mode 100755
index b59d767..fdc41bf
--- a/Example/SPAlertController/CustomViews/CustomView1/SendAlertView.m
+++ b/Example/SPAlertController/CustomViews/CustomView1/SendAlertView.m
@@ -8,6 +8,8 @@
#import "SendAlertView.h"
#import "SPTextView.h"
+#import "UIColor+DarkMode.h"
+
@interface SendAlertView()
@property (weak, nonatomic) IBOutlet UIImageView *userIconView;
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
@@ -27,6 +29,7 @@ + (instancetype)shareSendAlertView {
- (void)awakeFromNib {
[super awakeFromNib];
+ self.backgroundColor = [UIColor colorPairsWithLightColor:[UIColor whiteColor] darkColor:[UIColor colorWithRed:44.0 / 255.0 green:44.0 / 255.0 blue:44.0 / 255.0 alpha:1.0]];
self.userIconView.layer.cornerRadius = 4.0;
self.userIconView.layer.masksToBounds = YES;
self.textView.delegate = self;
@@ -34,7 +37,7 @@ - (void)awakeFromNib {
self.textView.layer.borderColor = [[UIColor grayColor] colorWithAlphaComponent:0.3].CGColor;
self.textView.placeholder = @"给朋友留言";
self.textView.placeholderColor = [UIColor lightGrayColor];
-
+ self.textView.backgroundColor = [UIColor colorPairsWithLightColor:[UIColor colorWithRed:247.0 / 255.0 green:247.0 / 255.0 blue:247.0 / 255.0 alpha:1.0] darkColor:[UIColor colorWithRed:54.0 / 255.0 green:54.0 / 255.0 blue:54.0 / 255.0 alpha:1.0]];
_textH = ceil(self.textView.font.lineHeight) + self.textView.textContainerInset.top + self.textView.textContainerInset.bottom;
}
diff --git a/Example/SPAlertController/CustomViews/CustomView1/SendAlertView.xib b/Example/SPAlertController/CustomViews/CustomView1/SendAlertView.xib
old mode 100644
new mode 100755
index f960e04..f2a55ef
--- a/Example/SPAlertController/CustomViews/CustomView1/SendAlertView.xib
+++ b/Example/SPAlertController/CustomViews/CustomView1/SendAlertView.xib
@@ -1,11 +1,9 @@
-
-
-
-
+
+
-
+
@@ -90,7 +88,7 @@
-
+
diff --git a/Example/SPAlertController/CustomViews/CustomView17/ScoreView.h b/Example/SPAlertController/CustomViews/CustomView17/ScoreView.h
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/CustomViews/CustomView17/ScoreView.m b/Example/SPAlertController/CustomViews/CustomView17/ScoreView.m
old mode 100644
new mode 100755
index 5a9c943..859e4ef
--- a/Example/SPAlertController/CustomViews/CustomView17/ScoreView.m
+++ b/Example/SPAlertController/CustomViews/CustomView17/ScoreView.m
@@ -8,12 +8,13 @@
#import "ScoreView.h"
#import "HCSStarRatingView.h"
+#import "UIColor+DarkMode.h"
@interface ScoreView()
@property (nonatomic, weak) HCSStarRatingView *starRatingView;
-@property (nonatomic, weak) UIView *line;
-@property (nonatomic, weak) UIButton *finishButton;
+//@property (nonatomic, weak) UIView *line;
+//@property (nonatomic, weak) UIButton *finishButton;
@property (nonatomic, strong) NSMutableArray *subViewContraints;
@end
@@ -22,6 +23,8 @@ @implementation ScoreView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
+ self.backgroundColor = [UIColor alertBackgroundColor];
+
HCSStarRatingView *starRatingView = [[HCSStarRatingView alloc] init];
starRatingView.translatesAutoresizingMaskIntoConstraints = NO;
starRatingView.maximumValue = 5;
@@ -30,24 +33,10 @@ - (instancetype)initWithFrame:(CGRect)frame {
starRatingView.spacing = 20;
starRatingView.tintColor = [UIColor colorWithRed:0.0 green:0.48 blue:1.0 alpha:1.0];
starRatingView.allowsHalfStars = YES;
+ starRatingView.backgroundColor = [UIColor alertBackgroundColor];
[starRatingView addTarget:self action:@selector(starRatingViewDidChangeValue:) forControlEvents:UIControlEventValueChanged];
[self addSubview:starRatingView];
_starRatingView = starRatingView;
-
- UIView *line = [UIView new];
- line.translatesAutoresizingMaskIntoConstraints = NO;
- line.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:0.3];
- [self addSubview:line];
- _line = line;
-
- UIButton *finishButton = [UIButton buttonWithType:UIButtonTypeCustom];
- finishButton.translatesAutoresizingMaskIntoConstraints = NO;
- finishButton.backgroundColor = [UIColor whiteColor];
- [finishButton setTitle:@"完成" forState:UIControlStateNormal];
- [finishButton setTitleColor:[UIColor colorWithRed:0.0 green:0.48 blue:1.0 alpha:1.0] forState:UIControlStateNormal];
- [finishButton addTarget:self action:@selector(finishButtonAction) forControlEvents:UIControlEventTouchUpInside];
- [self addSubview:finishButton];
- _finishButton = finishButton;
}
return self;
}
@@ -67,8 +56,8 @@ - (void)updateConstraints {
CGFloat lineH = 1.0/[UIScreen mainScreen].scale;
HCSStarRatingView *starRatingView = self.starRatingView;
- UIView *line = self.line;
- UIButton *finishButton = self.finishButton;
+// UIView *line = self.line;
+// UIButton *finishButton = self.finishButton;
NSMutableArray *subViewContraints = [NSMutableArray array];
if (self.subViewContraints) {
@@ -78,18 +67,18 @@ - (void)updateConstraints {
[subViewContraints addObject:[NSLayoutConstraint constraintWithItem:starRatingView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:40]];
[subViewContraints addObject:[NSLayoutConstraint constraintWithItem:starRatingView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:-40]];
[subViewContraints addObject:[NSLayoutConstraint constraintWithItem:starRatingView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:0]];
- [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:starRatingView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:line attribute:NSLayoutAttributeTop multiplier:1.0f constant:0]];
+ [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:starRatingView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0]];
[subViewContraints addObject:[NSLayoutConstraint constraintWithItem:starRatingView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:50]];
- [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:line attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0]];
- [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:line attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:0]];
- [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:line attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:finishButton attribute:NSLayoutAttributeTop multiplier:1.0f constant:0]];
- [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:line attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:lineH]];
-
- [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:finishButton attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0]];
- [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:finishButton attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:0]];
- [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:finishButton attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0]];
- [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:finishButton attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:50]];
+// [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:line attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0]];
+// [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:line attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:0]];
+// [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:line attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:finishButton attribute:NSLayoutAttributeTop multiplier:1.0f constant:0]];
+// [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:line attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:lineH]];
+//
+// [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:finishButton attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0]];
+// [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:finishButton attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:0]];
+// [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:finishButton attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0]];
+// [subViewContraints addObject:[NSLayoutConstraint constraintWithItem:finishButton attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:50]];
[NSLayoutConstraint activateConstraints:subViewContraints];
self.subViewContraints = subViewContraints;
}
diff --git a/Example/SPAlertController/CustomViews/CustomView2/MyView.h b/Example/SPAlertController/CustomViews/CustomView2/MyView.h
deleted file mode 100644
index e620861..0000000
--- a/Example/SPAlertController/CustomViews/CustomView2/MyView.h
+++ /dev/null
@@ -1,19 +0,0 @@
-//
-// MyView.h
-// SPAlertController
-//
-// Created by 乐升平 on 17/10/21.
-// Copyright © 2017年 iDress. All rights reserved.
-//
-
-#import
-#import "PassWordView.h"
-
-@interface MyView : UIView
-
-+ (instancetype)shareMyView;
-
-@property (weak, nonatomic) IBOutlet PassWordView *passwordView;
-@property (weak, nonatomic) IBOutlet UIButton *cancelButton;
-
-@end
diff --git a/Example/SPAlertController/CustomViews/CustomView2/MyView.m b/Example/SPAlertController/CustomViews/CustomView2/MyView.m
deleted file mode 100644
index c1e328f..0000000
--- a/Example/SPAlertController/CustomViews/CustomView2/MyView.m
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-// MyView.m
-// SPAlertController
-//
-// Created by 乐升平 on 17/10/21.
-// Copyright © 2017年 iDress. All rights reserved.
-//
-
-#import "MyView.h"
-
-@interface MyView()
-
-@end
-
-@implementation MyView
-
-- (instancetype)initWithCoder:(NSCoder *)aDecoder {
- if (self = [super initWithCoder:aDecoder]) {
- }
- return self;
-}
-
-- (void)awakeFromNib {
- [super awakeFromNib];
-}
-
-
-+ (instancetype)shareMyView {
- return [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil] lastObject];
-}
-
-
-@end
diff --git a/Example/SPAlertController/CustomViews/CustomView2/MyView.xib b/Example/SPAlertController/CustomViews/CustomView2/MyView.xib
deleted file mode 100644
index 826332a..0000000
--- a/Example/SPAlertController/CustomViews/CustomView2/MyView.xib
+++ /dev/null
@@ -1,159 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Example/SPAlertController/CustomViews/CustomView2/PassWordView.h b/Example/SPAlertController/CustomViews/CustomView2/PassWordView.h
deleted file mode 100644
index f5a95e3..0000000
--- a/Example/SPAlertController/CustomViews/CustomView2/PassWordView.h
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-// WCLPassWordView.h
-// Youqun
-//
-// Created by 乐升平 on 16/6/1.
-// Copyright © 2016年 iDress. All rights reserved.
-//
-
-#import
-@class PassWordView;
-
-@protocol PassWordViewDelegate
-
-@optional
-/**
- * 监听输入的改变
- */
-- (void)passWordDidChange:(PassWordView *)passWord;
-
-/**
- * 监听输入的完成时
- */
-- (void)passWordCompleteInput:(PassWordView *)passWord;
-
-/**
- * 监听开始输入
- */
-- (void)passWordBeginInput:(PassWordView *)passWord;
-
-
-@end
-
-IB_DESIGNABLE
-
-@interface PassWordView : UIView
-
-@property (assign, nonatomic) IBInspectable NSUInteger passWordNum;//密码的位数
-@property (assign, nonatomic) IBInspectable CGFloat squareWidth;//正方形的大小
-@property (assign, nonatomic) IBInspectable CGFloat pointRadius;//黑点的半径
-@property (strong, nonatomic) IBInspectable UIColor *pointColor;//黑点的颜色
-@property (strong, nonatomic) IBInspectable UIColor *rectColor;//边框的颜色
-@property (weak, nonatomic) IBOutlet id delegate;
-@property (strong, nonatomic, readonly) NSMutableString *textStore;//保存密码的字符串
-
-@end
-
diff --git a/Example/SPAlertController/CustomViews/CustomView2/PassWordView.m b/Example/SPAlertController/CustomViews/CustomView2/PassWordView.m
deleted file mode 100644
index 53ce545..0000000
--- a/Example/SPAlertController/CustomViews/CustomView2/PassWordView.m
+++ /dev/null
@@ -1,152 +0,0 @@
-//
-// WCLPassWordView.m
-// Youqun
-//
-// Created by 乐升平 on 16/6/1.
-// Copyright © 2016年 iDress. All rights reserved.
-//
-
-#import "PassWordView.h"
-
-@interface PassWordView ()
-
-@property (strong, nonatomic) NSMutableString *textStore;// 保存密码的字符串
-
-@end
-
-@implementation PassWordView
-
-static NSString * const MONEYNUMBERS = @"0123456789";
-
-- (instancetype)initWithCoder:(NSCoder *)coder {
- self = [super initWithCoder:coder];
- if (self) {
- self.textStore = [NSMutableString string];
- self.squareWidth = 45;
- self.passWordNum = 6;
- self.pointRadius = 6;
- self.rectColor = [UIColor colorWithRed:51.0/255.0 green:51.0/255.0 blue:51.0/255.0 alpha:1.0];
- self.pointColor = [UIColor colorWithRed:223.0/255.0 green:223.0/255.0 blue:223.0/255.0 alpha:1.0];
- [self becomeFirstResponder];
- }
- return self;
-}
-
-/**
- * 设置正方形的边长
- */
-- (void)setSquareWidth:(CGFloat)squareWidth {
- _squareWidth = squareWidth;
- [self setNeedsDisplay];
-}
-
-/**
- * 设置键盘的类型
- */
-- (UIKeyboardType)keyboardType {
- return UIKeyboardTypeNumberPad;
-}
-
-/**
- * 设置密码的位数
- */
-- (void)setPassWordNum:(NSUInteger)passWordNum {
- _passWordNum = passWordNum;
- [self setNeedsDisplay];
-}
-
-- (BOOL)becomeFirstResponder {
- if ([self.delegate respondsToSelector:@selector(passWordBeginInput:)]) {
- [self.delegate passWordBeginInput:self];
- }
- return [super becomeFirstResponder];
-}
-
-/**
- * 是否能成为第一响应者
- */
-- (BOOL)canBecomeFirstResponder {
- return YES;
-}
-
-- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
- if (![self isFirstResponder]) {
- [self becomeFirstResponder];
- }
-}
-
-#pragma mark - UIKeyInput
-/**
- * 用于显示的文本对象是否有任何文本
- */
-- (BOOL)hasText {
- return self.textStore.length > 0;
-}
-
-/**
- * 插入文本
- */
-- (void)insertText:(NSString *)text {
- if (self.textStore.length < self.passWordNum) {
- //判断是否是数字
- NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:MONEYNUMBERS] invertedSet];
- NSString*filtered = [[text componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];
- BOOL basicTest = [text isEqualToString:filtered];
- if(basicTest) {
- [self.textStore appendString:text];
- if ([self.delegate respondsToSelector:@selector(passWordDidChange:)]) {
- [self.delegate passWordDidChange:self];
- }
- if (self.textStore.length == self.passWordNum) {
- if ([self.delegate respondsToSelector:@selector(passWordCompleteInput:)]) {
- [self.delegate passWordCompleteInput:self];
- }
- }
- [self setNeedsDisplay];
- }
- }
-}
-
-/**
- * 删除文本
- */
-- (void)deleteBackward {
- if (self.textStore.length > 0) {
- [self.textStore deleteCharactersInRange:NSMakeRange(self.textStore.length - 1, 1)];
- if ([self.delegate respondsToSelector:@selector(passWordDidChange:)]) {
- [self.delegate passWordDidChange:self];
- }
- }
- [self setNeedsDisplay];
-}
-
-// Only override drawRect: if you perform custom drawing.
-- (void)drawRect:(CGRect)rect {
- CGFloat height = rect.size.height;
- CGFloat width = rect.size.width;
- CGFloat x = (width - self.squareWidth*self.passWordNum)/2.0;
- CGFloat y = (height - self.squareWidth)/2.0;
- CGContextRef context = UIGraphicsGetCurrentContext();
- //画外框
- CGContextAddRect(context, CGRectMake( x, y, self.squareWidth*self.passWordNum, self.squareWidth));
- CGContextSetLineWidth(context, 1);
- CGContextSetStrokeColorWithColor(context, self.rectColor.CGColor);
- CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
- //画竖条
- for (int i = 1; i <= self.passWordNum; i++) {
- CGContextMoveToPoint(context, x+i*self.squareWidth, y);
- CGContextAddLineToPoint(context, x+i*self.squareWidth, y+self.squareWidth);
- CGContextClosePath(context);
- }
- CGContextDrawPath(context, kCGPathFillStroke);
- CGContextSetFillColorWithColor(context, self.pointColor.CGColor);
- //画黑点
- for (int i = 1; i <= self.textStore.length; i++) {
- CGContextAddArc(context, x+i*self.squareWidth - self.squareWidth/2.0, y+self.squareWidth/2, self.pointRadius, 0, M_PI*2, YES);
- CGContextDrawPath(context, kCGPathFill);
- }
-}
-
-
-@end
-
diff --git a/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartCell.h b/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartCell.h
deleted file mode 100644
index 2d0a8fb..0000000
--- a/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartCell.h
+++ /dev/null
@@ -1,16 +0,0 @@
-//
-// ShoppingCartCell.h
-// SPAlertController
-//
-// Created by 乐升平 on 17/10/21.
-// Copyright © 2017年 iDress. All rights reserved.
-//
-
-#import
-
-@class ShoppingCartItem;
-
-@interface ShoppingCartCell : UITableViewCell
-@property (nonatomic, strong) ShoppingCartItem *item;
-@end
-
diff --git a/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartCell.m b/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartCell.m
deleted file mode 100644
index 2492792..0000000
--- a/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartCell.m
+++ /dev/null
@@ -1,89 +0,0 @@
-//
-// ShoppingCartCell.m
-// SPAlertController
-//
-// Created by 乐升平 on 17/10/21.
-// Copyright © 2017年 iDress. All rights reserved.
-//
-
-#import "ShoppingCartCell.h"
-#import "ShoppingCartItem.h"
-
-@interface ShoppingCartCell()
-@property (weak, nonatomic) IBOutlet UILabel *foodNmaeLabel;
-@property (weak, nonatomic) IBOutlet UILabel *priceLabel;
-@property (weak, nonatomic) IBOutlet UILabel *countLabel;
-
-@end
-
-@implementation ShoppingCartCell
-
-- (void)awakeFromNib {
- [super awakeFromNib];
- // Initialization code
-
-}
-
-- (void)setItem:(ShoppingCartItem *)item {
- _item = item;
- self.foodNmaeLabel.text = item.foodName;
- self.priceLabel.text = [self finallyFoodPrice:item.price];
-}
-
-- (IBAction)reduce:(UIButton *)sender {
- NSInteger i = [self.countLabel.text integerValue];
- i--;
- if (i < 1) {
- i = 1;
- } else {
- self.item.price = self.item.price - self.item.price / (i+1);
- }
- self.countLabel.text = [NSString stringWithFormat:@"%zd",i];
- self.priceLabel.text = [self finallyFoodPrice:self.item.price];
-
-}
-
-- (IBAction)add:(UIButton *)sender {
- NSInteger i = [self.countLabel.text integerValue];
- i++;
- self.item.price = self.item.price + self.item.price / (i-1);
- self.countLabel.text = [NSString stringWithFormat:@"%zd",i];
- self.priceLabel.text = [self finallyFoodPrice:self.item.price];
-}
-
-- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
- [super setSelected:selected animated:animated];
-
- // Configure the view for the selected state
-}
-
-// 最终的价格
-- (NSString *)finallyFoodPrice:(float)price {
-
- // 新价格保留maxDecimalPlaces为位小数转成字符串
- NSString *priceString = [NSString stringWithFormat:@"%.5f",price];
- // 通过小数点进行分割,然后取小数部分
- NSArray *parts = [priceString componentsSeparatedByString:@"."];
- if (parts.count > 1) {
- // 取小数部分
- NSString *dot = parts[1];
-
- if ([dot hasSuffix:@"00000"]) {
- return [NSString stringWithFormat:@"¥%.0f",price];
- } else if ([dot hasSuffix:@"0000"]) {
- return [NSString stringWithFormat:@"¥%.1f",price];
- } else if ([dot hasSuffix:@"000"]) {
- return [NSString stringWithFormat:@"¥%.2f",price];
- } else if ([dot hasSuffix:@"00"]) {
- return [NSString stringWithFormat:@"¥%.3f",price];
- } else if ([dot hasSuffix:@"0"]) {
- return [NSString stringWithFormat:@"¥%.4f",price];
- } else {
- return priceString;
- }
- }
- return nil;
-}
-
-
-@end
diff --git a/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartCell.xib b/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartCell.xib
deleted file mode 100644
index 4710629..0000000
--- a/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartCell.xib
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartItem.h b/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartItem.h
deleted file mode 100644
index 427adb1..0000000
--- a/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartItem.h
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// ShoppingCartItem.h
-// SPAlertController
-//
-// Created by 乐升平 on 17/10/21.
-// Copyright © 2017年 iDress. All rights reserved.
-//
-
-#import
-
-@interface ShoppingCartItem : NSObject
-@property (nonatomic, copy) NSString *foodName;
-@property (nonatomic, assign) double price;
-@end
diff --git a/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartItem.m b/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartItem.m
deleted file mode 100644
index 035aad8..0000000
--- a/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartItem.m
+++ /dev/null
@@ -1,13 +0,0 @@
-//
-// ShoppingCartItem.m
-// SPAlertController
-//
-// Created by 乐升平 on 17/10/21.
-// Copyright © 2017年 iDress. All rights reserved.
-//
-
-#import "ShoppingCartItem.h"
-
-@implementation ShoppingCartItem
-
-@end
diff --git a/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartView.h b/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartView.h
deleted file mode 100644
index 7d4c528..0000000
--- a/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartView.h
+++ /dev/null
@@ -1,13 +0,0 @@
-//
-// ShoppingCartView.h
-// SPAlertController
-//
-// Created by 乐升平 on 17/10/21.
-// Copyright © 2017年 iDress. All rights reserved.
-//
-
-#import
-
-@interface ShoppingCartView : UIView
-
-@end
diff --git a/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartView.m b/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartView.m
deleted file mode 100644
index a21dc79..0000000
--- a/Example/SPAlertController/CustomViews/CustomView3/ShoppingCartView.m
+++ /dev/null
@@ -1,178 +0,0 @@
-//
-// ShoppingCartView.m
-// SPAlertController
-//
-// Created by 乐升平 on 17/10/21.
-// Copyright © 2017年 iDress. All rights reserved.
-//
-
-#import "ShoppingCartView.h"
-#import "ShoppingCartCell.h"
-#import "ShoppingCartItem.h"
-
-@interface ShoppingCartView()
-@property (nonatomic, strong) UITableView *tableView;
-@property (nonatomic, strong) NSMutableArray *dataSource;
-@property (nonatomic, strong) UILabel *topLabel;
-@end
-
-@implementation ShoppingCartView
-
-- (instancetype)initWithFrame:(CGRect)frame {
- if (self = [super initWithFrame:frame]) {
- [self initialize];
-
- }
- return self;
-}
-
-- (instancetype)initWithCoder:(NSCoder *)aDecoder {
- if (self = [super initWithCoder:aDecoder]) {
- [self initialize];
- }
- return self;
-}
-
-- (void)initialize {
-
- [self addSubview:self.topLabel];
- [self addSubview:self.tableView];
-
- NSArray *dataArr = [self getData];
-
- for (int i = 0; i < dataArr.count; i++) {
- ShoppingCartItem *item = [[ShoppingCartItem alloc] init];
- [item setValuesForKeysWithDictionary:dataArr[i]];
- [self.dataSource addObject:item];
- }
-}
-
-- (void)hideTopView {
-
-}
-
-- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
- return self.dataSource.count;
-}
-
-- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
-
- ShoppingCartCell *cell = [tableView dequeueReusableCellWithIdentifier:@"shoppingCartCell" forIndexPath:indexPath];
- cell.item = self.dataSource[indexPath.row];
- return cell;
-
-}
-
-- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
- return 50;
-}
-
-- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
- [tableView deselectRowAtIndexPath:indexPath animated:NO];
- NSLog(@"----点到了cell");
-}
-
-- (UITableView *)tableView {
- if (!_tableView) {
- _tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
- _tableView.dataSource = self;
- _tableView.delegate = self;
- _tableView.showsVerticalScrollIndicator = NO;
- [_tableView registerNib:[UINib nibWithNibName:NSStringFromClass([ShoppingCartCell class]) bundle:nil] forCellReuseIdentifier:@"shoppingCartCell"];
- }
- return _tableView;
-}
-
-- (UILabel *)topLabel {
- if (!_topLabel) {
- _topLabel = [[UILabel alloc] init];
- _topLabel.backgroundColor = [UIColor whiteColor];
- _topLabel.backgroundColor = [UIColor colorWithRed:244.0/255.0 green:244.0/255.0 blue:244.0/255.0 alpha:1];
- _topLabel.textAlignment = NSTextAlignmentCenter;
- _topLabel.text = @"购物车";
-
- }
- return _topLabel;
-}
-
-- (NSMutableArray *)dataSource {
-
- if (!_dataSource) {
- _dataSource = [NSMutableArray array];
- }
- return _dataSource;
-}
-
-- (void)layoutSubviews {
- [super layoutSubviews];
-
- CGFloat topLabelY = 0.;
- if (@available(iOS 11.0, *)) {
- topLabelY = self.safeAreaInsets.top;
- } else {
- topLabelY = 20;
- }
- self.topLabel.frame = CGRectMake(0, topLabelY, self.bounds.size.width, 44);
- CGFloat tableViewY = CGRectGetMaxY(self.topLabel.frame);
- self.tableView.frame = CGRectMake(0, tableViewY, self.frame.size.width, self.frame.size.height-tableViewY);
-
-}
-
-- (NSArray *)getData {
- NSArray *dataArr = @[@{
- @"foodName":@"鱼香肉丝",
- @"price":@(21.5),
- },
- @{
- @"foodName":@"辣椒炒肉",
- @"price":@(18),
- },
- @{
- @"foodName":@"梅干菜",
- @"price":@(20.1),
- },
- @{
- @"foodName":@"西红柿蛋汤",
- @"price":@(12.306),
- },
- @{
- @"foodName":@"红烧鲫鱼",
- @"price":@(35.8),
- },
- @{
- @"foodName":@"啤酒鸭",
- @"price":@(29),
- },
- @{
- @"foodName":@"宫爆鸡丁",
- @"price":@(28),
- },
- @{
- @"foodName":@"湖南一碗香",
- @"price":@(37.5),
- },
- @{
- @"foodName":@"鸡汤",
- @"price":@(16),
- },
- @{
- @"foodName":@"鸽子汤",
- @"price":@(18.5),
- },
- @{
- @"foodName":@"王老吉",
- @"price":@(8),
- },
- @{
- @"foodName":@"米饭",
- @"price":@(2),
- },
- ];
-
- return dataArr;
-}
-
-@end
-
-
-
diff --git a/Example/SPAlertController/CustomViews/CustomView4/CommodityListView.h b/Example/SPAlertController/CustomViews/CustomView4/CommodityListView.h
deleted file mode 100644
index 3d93d2c..0000000
--- a/Example/SPAlertController/CustomViews/CustomView4/CommodityListView.h
+++ /dev/null
@@ -1,13 +0,0 @@
-//
-// CommodityListView.h
-// SPAlertController
-//
-// Created by 乐升平 on 17/10/22.
-// Copyright © 2017年 iDress. All rights reserved.
-//
-
-#import
-
-@interface CommodityListView : UIView
-
-@end
diff --git a/Example/SPAlertController/CustomViews/CustomView4/CommodityListView.m b/Example/SPAlertController/CustomViews/CustomView4/CommodityListView.m
deleted file mode 100644
index c7a01d0..0000000
--- a/Example/SPAlertController/CustomViews/CustomView4/CommodityListView.m
+++ /dev/null
@@ -1,82 +0,0 @@
-//
-// CommodityListView.m
-// SPAlertController
-//
-// Created by 乐升平 on 17/10/22.
-// Copyright © 2017年 iDress. All rights reserved.
-//
-
-#import "CommodityListView.h"
-
-@interface CommodityListView()
-@property (nonatomic, weak) UIScrollView *scrollView;
-@property (nonatomic, strong) NSMutableArray *imageViews;
-@end
-
-@implementation CommodityListView
-
-- (instancetype)initWithFrame:(CGRect)frame {
- if (self = [super initWithFrame:frame]) {
- [self initialize];
- }
- return self;
-}
-
-- (instancetype)initWithCoder:(NSCoder *)aDecoder {
- if (self = [super initWithCoder:aDecoder]) {
- [self initialize];
- }
- return self;
-}
-
-- (void)initialize {
-
- NSArray *images = @[@"image0.jpg",@"image1.jpg",@"image2.jpg",@"image3.jpg",@"image4.jpg",@"image5.jpg",@"image6.jpg",@"image7.jpg",@"image8.jpg",@"image9.jpg"];
-
- UIScrollView *scrollView = [[UIScrollView alloc] init];
- scrollView.backgroundColor = [UIColor colorWithRed:244.0/255.0 green:244.0/255.0 blue:244.0/255.0 alpha:1];
- scrollView.showsVerticalScrollIndicator = NO;
- [self addSubview:scrollView];
- _scrollView = scrollView;
-
- for (int i = 0; i < images.count; i++) {
- UIImageView *imageView = [[UIImageView alloc] init];
- imageView.image = [UIImage imageNamed:images[i]];
- imageView.backgroundColor = [UIColor redColor];
- [scrollView addSubview:imageView];
- [self.imageViews addObject:imageView];
- }
-}
-
-- (NSMutableArray *)imageViews {
-
- if (!_imageViews) {
- _imageViews = [NSMutableArray array];
-
- }
- return _imageViews;
-}
-
-
-- (void)layoutSubviews {
- [super layoutSubviews];
- self.scrollView.frame = self.bounds;
-
- CGFloat imageViewW = self.bounds.size.width/2-20;
- CGFloat imageViewH = self.bounds.size.height;
- CGFloat imageViewY = 0;
- if (@available(iOS 11.0, *)) {
- imageViewY = self.safeAreaInsets.top;
- }
- UIImageView *lastImageView;
- for (int i = 0; i < self.imageViews.count; i++) {
- UIImageView *imageView = self.imageViews[i];
- imageView.frame = CGRectMake((imageViewW +10) * i, imageViewY, imageViewW, imageViewH);
- if (i == self.imageViews.count-1) {
- lastImageView = imageView;
- }
- }
- self.scrollView.contentSize = CGSizeMake(CGRectGetMaxX(lastImageView.frame), 0);
-}
-
-@end
diff --git a/Example/SPAlertController/CustomViews/CustomView5/PickerView.h b/Example/SPAlertController/CustomViews/CustomView5/PickerView.h
deleted file mode 100644
index 5e6c92e..0000000
--- a/Example/SPAlertController/CustomViews/CustomView5/PickerView.h
+++ /dev/null
@@ -1,16 +0,0 @@
-//
-// PickerView.h
-// SPAlertController
-//
-// Created by Libo on 2017/11/15.
-// Copyright © 2017年 iDress. All rights reserved.
-//
-
-#import
-
-@interface PickerView : UIView
-
-@property (nonatomic, copy) void(^cancelClickedBlock)();
-@property (nonatomic, copy) void(^doneClickedBlock)();
-
-@end
diff --git a/Example/SPAlertController/CustomViews/CustomView5/PickerView.m b/Example/SPAlertController/CustomViews/CustomView5/PickerView.m
deleted file mode 100644
index 1e8020e..0000000
--- a/Example/SPAlertController/CustomViews/CustomView5/PickerView.m
+++ /dev/null
@@ -1,119 +0,0 @@
-//
-// MyTitleView.m
-// SPAlertController
-//
-// Created by Libo on 2017/11/5.
-// Copyright © 2017年 iDress. All rights reserved.
-//
-
-#import "PickerView.h"
-
-@interface PickerView()
-
-@property (nonatomic, strong) UIPickerView *pickerView;
-@property (nonatomic, strong) UIToolbar *toolbar;
-
-@end
-
-@implementation PickerView
-
-- (instancetype)initWithFrame:(CGRect)frame {
- if (self = [super initWithFrame:frame]) {
- [self initialize];
- }
- return self;
-}
-
-- (instancetype)initWithCoder:(NSCoder *)aDecoder {
- if (self = [super initWithCoder:aDecoder]) {
- [self initialize];
- }
- return self;
-}
-
-- (void)initialize {
- [self addSubview:self.toolbar];
- [self addSubview:self.pickerView];
-}
-
-- (void)doneClick {
- if (self.doneClickedBlock) {
- self.doneClickedBlock();
- }
-}
-
-- (void)cancelClick {
- if (self.cancelClickedBlock) {
- self.cancelClickedBlock();
- }
-}
-
-- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
- return 1;
-}
-
-- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
- return 2;
-}
-
-- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
- return @[@"男",@"女"][row];
-}
-
-- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {
- UILabel *pickerLabel = (UILabel *)view;
- if (!pickerLabel) {
- pickerLabel = [[UILabel alloc] init];
- pickerLabel.adjustsFontSizeToFitWidth = YES;
- pickerLabel.textAlignment = NSTextAlignmentCenter;
- [pickerLabel setFont:[UIFont boldSystemFontOfSize:18]];
- }
- pickerLabel.text = [self pickerView:pickerView titleForRow:row forComponent:component];
- return pickerLabel;
-}
-
-- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component {
- return 50;
-}
-
-- (UIPickerView *)pickerView {
- if (!_pickerView) {
- _pickerView = [[UIPickerView alloc] init];
- _pickerView.delegate = self;
- _pickerView.dataSource = self;
- _pickerView.backgroundColor = [UIColor colorWithRed:239.0/255.0 green:239.0/255.0 blue:244.0/255.0 alpha:1];
- }
- return _pickerView;
-}
-
-- (UIToolbar *)toolbar {
-
- if (!_toolbar) {
- UIBarButtonItem *doneBBI = [[UIBarButtonItem alloc]
- initWithTitle:@"确定"
- style:UIBarButtonItemStyleDone
- target:self
- action:@selector(doneClick)];
-
- UIBarButtonItem *cancelBBI = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStylePlain target:self action:@selector(cancelClick)];
- UIBarButtonItem *flexibleBBI = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
- _toolbar = [[UIToolbar alloc] init];
- // 设置tollbar的背景色
- _toolbar.barTintColor = [UIColor whiteColor];
- NSArray *toolbarItems = [NSArray arrayWithObjects:cancelBBI, flexibleBBI, doneBBI, nil];
- [_toolbar setItems:toolbarItems];
- }
- return _toolbar;
-}
-
-- (void)layoutSubviews {
- [super layoutSubviews];
- self.toolbar.frame = CGRectMake(0, 0, self.bounds.size.width, 40);
- self.pickerView.frame = CGRectMake(0, CGRectGetMaxY(self.toolbar.frame), self.bounds.size.width, self.bounds.size.height-40);
-}
-
-@end
-
-
-
-
diff --git a/Example/SPAlertController/CustomViews/CustomView6/MyCenterView.h b/Example/SPAlertController/CustomViews/CustomView6/MyCenterView.h
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/CustomViews/CustomView6/MyCenterView.m b/Example/SPAlertController/CustomViews/CustomView6/MyCenterView.m
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/CustomViews/CustomView7/PopView.h b/Example/SPAlertController/CustomViews/CustomView7/PopView.h
deleted file mode 100644
index c8e923e..0000000
--- a/Example/SPAlertController/CustomViews/CustomView7/PopView.h
+++ /dev/null
@@ -1,28 +0,0 @@
-//
-// PopView.h
-// SPAlertController
-//
-// Created by Libo on 2018/12/23.
-// Copyright © 2018 乐升平. All rights reserved.
-//
-
-#import
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface PopView : UIView
-
-- (instancetype)initWithImages:(NSArray *)images
- titles:(NSArray *)titles
- clickedButtonBlock:(void(^)(NSInteger index))clickedButtonBlock
- cancelBlock:(void(^)(PopView *popView))cancelBlock;
-
-@property (nonatomic, copy) void(^tapBackgroundBlock)(PopView *popView);
-
-- (void)open;
-
-- (void)close;
-
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/Example/SPAlertController/CustomViews/CustomView7/PopView.m b/Example/SPAlertController/CustomViews/CustomView7/PopView.m
deleted file mode 100644
index 301226b..0000000
--- a/Example/SPAlertController/CustomViews/CustomView7/PopView.m
+++ /dev/null
@@ -1,231 +0,0 @@
-//
-// PopView.m
-// SPAlertController
-//
-// Created by Libo on 2018/12/23.
-// Copyright © 2018 乐升平. All rights reserved.
-//
-
-#import "PopView.h"
-#import "SPButton.h" // SPButton的github地址:https://github.com/SPStore/SPButton
-
-static NSInteger const kColumnCount = 4; // 每一页的列数
-static NSInteger const kRowCount = 2; // 每一页的行数
-static CGFloat const kColSpacing = 15; // 列间距
-static CGFloat const kRowSpacing = 20; // 行间距
-static NSTimeInterval kAnimationDuration = 0.7; // 动画总时长
-static NSTimeInterval kDelay = 0.0618; // 按钮接着上一个按钮的延时时间
-
-@interface PopView()
-@property (nonatomic, strong) UIScrollView *scrollView;
-@property (nonatomic, strong) UIPageControl *pageControl;
-@property (nonatomic, strong) UIButton *cancelButton;
-@property (nonatomic, strong) UIView *line;
-@property (nonatomic, copy) void (^clickedButtonBlock)(NSInteger);
-@property (nonatomic, copy) void (^cancelBlock)(PopView *popView);
-@end
-
-@implementation PopView
-{
- NSInteger buttonCount;
-}
-
-- (instancetype)initWithImages:(NSArray *)images
- titles:(NSArray *)titles
- clickedButtonBlock:(void (^)(NSInteger))clickedButtonBlock
- cancelBlock:(void (^)(PopView *popView))cancelBlock {
-
- _clickedButtonBlock = clickedButtonBlock;
- _cancelBlock = cancelBlock;
-
- UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction)];
- [self addGestureRecognizer:tap];
-
- CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
- CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height;
-
- if (self = [self initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight)]) {
- buttonCount = MIN(images.count, titles.count);
- for (int i = 0; i < buttonCount; i++) {
- SPButton *button = [[SPButton alloc] initWithImagePosition:SPButtonImagePositionTop];
- [button setImage:[UIImage imageNamed:images[i]] forState:UIControlStateNormal];
- [button setTitle:titles[i] forState:UIControlStateNormal];
- button.titleLabel.font = [UIFont systemFontOfSize:14];
- [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
- button.imageView.contentMode = UIViewContentModeScaleAspectFit;
- button.imageTitleSpace = 5;
- [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
- button.tag = i+100;
- [self.scrollView addSubview:button];
- }
- }
- return self;
-}
-
-- (instancetype)initWithFrame:(CGRect)frame {
- if (self = [super initWithFrame:frame]) {
-
- }
- return self;
-}
-
-- (void)open {
-
- for (int i = 0; i < buttonCount; i++) {
- SPButton *button = [self.scrollView viewWithTag:i+100];
- CGFloat buttonH = button.bounds.size.height;
- CGFloat totalH = (buttonH * kRowCount + kRowSpacing * (kRowCount - 1));
- CGFloat buttonEndY = button.frame.origin.y - totalH - buttonH;
- // delay参数计算出来的意思是:每一列比它的上一列延时kDelay秒
- [UIView animateWithDuration:kAnimationDuration
- delay:i % kColumnCount * kDelay
- usingSpringWithDamping:0.6
- initialSpringVelocity:0
- options:UIViewAnimationOptionCurveEaseIn animations:^{
- CGRect buttonFrame = button.frame;
- buttonFrame.origin.y = buttonEndY;
- button.frame = buttonFrame;
- } completion:^(BOOL finished) {
- }];
- }
-}
-
-- (void)close {
- for (int i = 0; i < buttonCount; i++) {
- SPButton *button = [self.scrollView viewWithTag:i+100];
- CGFloat buttonH = button.bounds.size.height;
- CGFloat totalH = (buttonH * kRowCount + kRowSpacing * (kRowCount - 1));
- CGFloat buttonBeginY = button.frame.origin.y + buttonH + totalH;
-
- // delay参数计算出来的意思是:第一行每个按钮都比第二行的每个按钮延时0.1秒,同时每列比它的下一列延时kDelay秒
- [UIView animateWithDuration:kAnimationDuration
- delay:(1-i/kColumnCount)/10.0 + (kDelay * kColumnCount - i % kColumnCount * kDelay - kDelay)
- usingSpringWithDamping:0.6
- initialSpringVelocity:0
- options:UIViewAnimationOptionCurveEaseOut animations:^{
- CGRect buttonFrame = button.frame;
- buttonFrame.origin.y = buttonBeginY;
- button.frame = buttonFrame;
- } completion:^(BOOL finished) {
- [self removeFromSuperview];
- }];
- }
-}
-
-- (void)buttonAction:(UIButton *)sender {
- if (self.clickedButtonBlock) {
- self.clickedButtonBlock(sender.tag-100);
- }
-}
-
-- (void)tapAction {
- if (self.tapBackgroundBlock) {
- self.tapBackgroundBlock(self);
- }
-}
-
-- (void)cancelButtonAction {
- if (self.cancelBlock) {
- self.cancelBlock(self);
- }
-}
-
-- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
- CGFloat offsetX = scrollView.contentOffset.x;
- self.pageControl.currentPage = (NSInteger)(offsetX / self.bounds.size.width + 0.5);
-}
-
-- (void)layoutSubviews {
- [super layoutSubviews];
-
- CGFloat bottom = 0;
- if (@available(iOS 11.0, *)) {
- bottom = self.safeAreaInsets.bottom;
- }
-
- CGFloat superWidth = self.frame.size.width;
- CGFloat superHeight = self.frame.size.height;
-
- CGFloat cancelButtonW = superWidth;
- CGFloat cancelButtonH = 40;
- CGFloat cancelButtonX = 0;
- CGFloat cancelButtonY = superHeight-cancelButtonH-bottom;
- self.cancelButton.frame = CGRectMake(cancelButtonX, cancelButtonY, cancelButtonW, cancelButtonH);
-
- CGFloat lineW = superWidth;
- CGFloat lineH = 1.0/[UIScreen mainScreen].scale;
- CGFloat lineX = 0;
- CGFloat lineY = superHeight-cancelButtonH-lineH-bottom;
- self.line.frame = CGRectMake(lineX, lineY, lineW, lineH);
-
- CGFloat scrollViewH = superHeight-cancelButtonH-lineH-bottom;
- self.scrollView.frame = CGRectMake(0, 0, superWidth, scrollViewH);
- self.pageControl.frame = CGRectMake(0, superHeight-cancelButtonH-lineH-bottom-30, superWidth, 30);
-
- // 先计算好每个按钮的动画前的frame,等执行动画的时候只要改变y值即可
- NSInteger buttonCountEveryPage = kColumnCount * kRowCount; // 每一页的按钮个数
- NSInteger pageCount = (buttonCount-1) / buttonCountEveryPage + 1; // 总页数
- self.pageControl.numberOfPages = pageCount;
-
- for (int i = 0; i < buttonCount; i++) {
- SPButton *button = [self.scrollView viewWithTag:i+100];
- NSInteger page = i / buttonCountEveryPage; // 第几页
- NSInteger row = (i - buttonCountEveryPage * page) / kColumnCount; // 第几页的第几行
- NSInteger col = i % kColumnCount; // 第几列
- CGFloat buttonW = (superWidth - kColSpacing * (kColumnCount + 1)) / kColumnCount;
- CGFloat buttonH = MIN(buttonW, button.currentImage.size.width)+30;
- CGFloat buttonX = kColSpacing + (buttonW + kColSpacing) * col + page * superWidth;
- CGFloat buttonBeginY = scrollViewH + (buttonH + kRowSpacing) * row;
- button.frame = CGRectMake(buttonX, buttonBeginY, buttonW, buttonH);
- }
- self.scrollView.contentSize = CGSizeMake(superWidth * pageCount, 0);
-}
-
-- (UIScrollView *)scrollView {
-
- if (!_scrollView) {
- _scrollView = [[UIScrollView alloc] init];
- _scrollView.showsVerticalScrollIndicator = NO;
- _scrollView.showsHorizontalScrollIndicator = NO;
- _scrollView.scrollsToTop = NO;
- _scrollView.bounces = NO;
- _scrollView.pagingEnabled = YES;
- _scrollView.delegate = self;
- [self addSubview:_scrollView];
- }
- return _scrollView;
-}
-
-- (UIPageControl *)pageControl {
- if (!_pageControl) {
- _pageControl = [[UIPageControl alloc] init];
- _pageControl.currentPageIndicatorTintColor = [UIColor orangeColor];
- _pageControl.pageIndicatorTintColor = [UIColor lightGrayColor];
- [self addSubview:_pageControl];
- }
- return _pageControl;
-}
-
-- (UIButton *)cancelButton {
-
- if (!_cancelButton) {
- _cancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
- _cancelButton.backgroundColor = [UIColor clearColor];
- [_cancelButton setImage:[UIImage imageNamed:@"取消"] forState:UIControlStateNormal];
- [_cancelButton addTarget:self action:@selector(cancelButtonAction) forControlEvents:UIControlEventTouchUpInside];
- [self addSubview:_cancelButton];
- }
- return _cancelButton;
-}
-
-- (UIView *)line {
-
- if (!_line) {
- _line = [[UIView alloc] init];
- _line.backgroundColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.3];
- [self addSubview:_line];
- }
- return _line;
-}
-
-@end
diff --git a/Example/SPAlertController/CustomViews/CustomView7/SPButton.h b/Example/SPAlertController/CustomViews/CustomView7/SPButton.h
deleted file mode 100755
index bb4b3c8..0000000
--- a/Example/SPAlertController/CustomViews/CustomView7/SPButton.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// SPButton.h
-// SPButton
-//
-// Created by 乐升平 on 2018/11/20.
-// Copyright © 2018 乐升平. All rights reserved.
-// github:https://github.com/SPStore/SPButton
-
-#import
-
-NS_ASSUME_NONNULL_BEGIN
-
-
-typedef NS_ENUM(NSInteger, SPButtonImagePosition) {
- SPButtonImagePositionLeft = 0, // 图片在文字左侧
- SPButtonImagePositionRight = 1, // 图片在文字右侧
- SPButtonImagePositionTop = 2, // 图片在文字上侧
- SPButtonImagePositionBottom = 3 // 图片在文字下侧
-};
-
-IB_DESIGNABLE
-@interface SPButton : UIButton
-
-- (instancetype)initWithImagePosition:(SPButtonImagePosition)imagePosition;
-
-#if TARGET_INTERFACE_BUILDER // storyBoard/xib中设置
-@property (nonatomic,assign) IBInspectable NSInteger imagePosition; // 图片位置
-@property (nonatomic, assign) IBInspectable CGFloat imageTitleSpace; // 图片和文字之间的间距
-#else // 纯代码设置
-@property (nonatomic) SPButtonImagePosition imagePosition; // 图片位置
-@property (nonatomic, assign) CGFloat imageTitleSpace; // 图片和文字之间的间距
-#endif
-
-
-@end
-
-
-NS_ASSUME_NONNULL_END
diff --git a/Example/SPAlertController/CustomViews/CustomView7/SPButton.m b/Example/SPAlertController/CustomViews/CustomView7/SPButton.m
deleted file mode 100755
index 457665b..0000000
--- a/Example/SPAlertController/CustomViews/CustomView7/SPButton.m
+++ /dev/null
@@ -1,598 +0,0 @@
-//
-// SPButton.m
-// SPButton
-//
-// Created by 乐升平 on 2018/11/20.
-// Copyright © 2018 乐升平. All rights reserved.
-//
-
-#import "SPButton.h"
-
-@implementation SPButton
-
-- (instancetype)initWithImagePosition:(SPButtonImagePosition)imagePosition {
- if (self = [super init]) {
- self.imagePosition = imagePosition;
- }
- return self;
-}
-
-#pragma mark - system methods
-
-- (instancetype)initWithFrame:(CGRect)frame {
- if (self = [super initWithFrame:frame]) {
- [self initialize];
- }
- return self;
-}
-
-- (instancetype)initWithCoder:(NSCoder *)aDecoder {
- if (self = [super initWithCoder:aDecoder]) {
- [self initialize];
- }
- return self;
-}
-
-- (void)initialize {
- _imagePosition = SPButtonImagePositionLeft;
- _imageTitleSpace = 0.0;
-}
-
-// 下面这2个方法,我所知道的:
-// 在第一次调用titleLabel和imageView的getter方法(懒加载)时,alloc init之前会调用一次(无论有无图片文字都会直接调),因此,在重写这2个方法时,在方法里面不要使用self.imageView和self.titleLabel,因为这2个控件是懒加载,如果在重写的这2个方法里是第一调用imageView和titleLabel的getter方法, 则会造成死循环
-// 在layoutsSubviews中如果文字或图片不为空时会调用, 测试方式:在重写的这两个方法里调用setNeedsLayout(layutSubviews),发现会造成死循环
-// 设置文字图片、改动文字和图片、设置对齐方式,设置内容区域等时会调用,其实设置这些属性,系统是调用了layoutSubviews从而间接的去调用imageRectForContentRect:和titleRectForContentRect:
-// ...
-- (CGRect)imageRectForContentRect:(CGRect)contentRect {
- // 先获取系统为我们计算好的rect,这样大小图片在左右时我们就不要自己去计算,我门要改变的,仅仅是origin
- CGRect imageRect = [super imageRectForContentRect:contentRect];
- CGRect titleRect = [super titleRectForContentRect:contentRect];
- if (!self.currentTitle) { // 如果没有文字,则图片占据整个button,空格算一个文字
- return imageRect;
- }
- switch (self.imagePosition) {
- case SPButtonImagePositionLeft: { // 图片在左
- imageRect = [self imageRectImageAtLeftForContentRect:contentRect imageRect:imageRect titleRect:titleRect];
- }
- break;
- case SPButtonImagePositionRight: {
- imageRect = [self imageRectImageAtRightForContentRect:contentRect imageRect:imageRect titleRect:titleRect];
- }
- break;
- case SPButtonImagePositionTop: {
- imageRect = [self imageRectImageAtTopForContentRect:contentRect imageRect:imageRect titleRect:titleRect];
- }
- break;
- case SPButtonImagePositionBottom: {
- imageRect = [self imageRectImageAtBottomForContentRect:contentRect imageRect:imageRect titleRect:titleRect];
- }
- break;
- }
- return imageRect;
-}
-
-- (CGRect)titleRectForContentRect:(CGRect)contentRect {
- CGRect titleRect = [super titleRectForContentRect:contentRect];
- CGRect imageRect = [super imageRectForContentRect:contentRect];
- if (!self.currentImage) { // 如果没有图片
- return titleRect;
- }
- switch (self.imagePosition) {
- case SPButtonImagePositionLeft: {
- titleRect = [self titleRectImageAtLeftForContentRect:contentRect titleRect:titleRect imageRect:imageRect];
- }
- break;
- case SPButtonImagePositionRight: {
- titleRect = [self titleRectImageAtRightForContentRect:contentRect titleRect:titleRect imageRect:imageRect];
- }
- break;
- case SPButtonImagePositionTop: {
- titleRect = [self titleRectImageAtTopForContentRect:contentRect titleRect:titleRect imageRect:imageRect];
- }
- break;
- case SPButtonImagePositionBottom: {
- titleRect = [self titleRectImageAtBottomForContentRect:contentRect titleRect:titleRect imageRect:imageRect];
- }
- break;
- }
- return titleRect;
-
-}
-
-- (void)sizeToFit {
- // 这个super很重要,它能保证下面使用的self.frame的值是系统计算好的结果
- [super sizeToFit];
-
- CGRect myFrame = self.frame;
- switch (self.imagePosition) {
- case SPButtonImagePositionLeft:
- case SPButtonImagePositionRight: // 图片在左右时,在系统计算好的基础上宽度再加间距
- myFrame.size.width = self.frame.size.width + _imageTitleSpace;
- break;
- case SPButtonImagePositionTop:
- case SPButtonImagePositionBottom: {// 图片在上下时,就不能再在系统计算的基础上增减值了,因为系统计算是基于图片在左文字在右时进行的,宽度依赖图片+文字之和,而图片在上下时,宽度应该依赖图片和文字较大的那个
- CGFloat imageFitWidth = self.contentEdgeInsets.left + self.currentImage.size.width + self.contentEdgeInsets.right;
- CGFloat titleFitWidth = self.contentEdgeInsets.left + [self calculateTitleSizeForSystemTitleSize:CGSizeMake(0, 0)].width + self.contentEdgeInsets.right;
- myFrame.size.width = MAX(imageFitWidth, titleFitWidth);
- myFrame.size.height = self.contentEdgeInsets.top + self.currentImage.size.height + [self calculateTitleSizeForSystemTitleSize:CGSizeMake(0, 0)].height + self.contentEdgeInsets.bottom + _imageTitleSpace;
- }
- break;
- default:
- break;
- }
-
- self.frame = myFrame;
-}
-
-#pragma - private
-
-// ----------------------------------------------------- left -----------------------------------------------------
-
-- (CGRect)imageRectImageAtLeftForContentRect:(CGRect)contentRect imageRect:(CGRect)imageRect titleRect:(CGRect)titleRect {
- CGPoint imageOrigin = imageRect.origin;
- CGSize imageSize = imageRect.size;
-
- //CGSize titleSize = titleRect.size;
-
- switch (self.contentHorizontalAlignment) {
- case UIControlContentHorizontalAlignmentCenter: // 中心对齐
- // imageView的x值向左偏移间距的一半,另一半由titleLabe分担,不用管会不会超出contentRect,我定的规则是允许超出,如果对此作出限制,那么必须要对图片或者文字宽高有所压缩,压缩只能由imageEdgeInsets决定,当图片的内容区域容不下时才产生宽度压缩
- imageOrigin.x = imageOrigin.x - _imageTitleSpace*0.5;
- break;
- case UIControlContentHorizontalAlignmentRight:
- case UIControlContentHorizontalAlignmentTrailing: // 右对齐
- imageOrigin.x = imageOrigin.x - _imageTitleSpace;
- break;
- case UIControlContentHorizontalAlignmentFill: // 填充整个按钮,水平填充模式有点怪异,填充的意思是将图片和文字整个水平填满,但是,事实上能够被填满,但是titleLabel的x值不会发生变化,即图片被拉伸,但是图片的右边会预留一个titleLabel的宽度,这个titleLabel的宽度由系统计算,我们不必关心计算过程。还有,填充模式下,设置图片的contentMode是不管用的,因为系统强制设置了图片的大小
- imageOrigin.x = imageOrigin.x - _imageTitleSpace*0.5;
- break;
- default: // 剩下的就是左对齐,左对齐image不用做任何改变
- break;
- }
- imageRect.size = imageSize;
- imageRect.origin = imageOrigin;
- return imageRect;
-}
-
-- (CGRect)titleRectImageAtLeftForContentRect:(CGRect)contentRect titleRect:(CGRect)titleRect imageRect:(CGRect)imageRect {
- CGPoint titleOrigin = titleRect.origin;
- CGSize titleSize = titleRect.size;
-
- //CGSize imageSize = imageRect.size;
-
- switch (self.contentHorizontalAlignment) {
- case UIControlContentHorizontalAlignmentCenter: { // 中心对齐
- titleOrigin.x = titleOrigin.x + _imageTitleSpace * 0.5;
- }
- break;
- case UIControlContentHorizontalAlignmentLeft:
- case UIControlContentHorizontalAlignmentLeading: { // 左对齐
- titleOrigin.x = titleOrigin.x + _imageTitleSpace;
- }
- break;
- case UIControlContentHorizontalAlignmentFill: // 填充整个按钮
- // 填充整个按钮,水平填充模式有点怪异,填充的意思是将图片和文字整个水平填满,但是,事实上能够被填满,但是titleLabel的x值不会发生变化,即图片被拉伸,但是图片的右边会预留一个titleLabel的宽度,这个titleLabel的宽度由系统计算,我们不必关心计算过程。还有,填充模式下,设置图片的contentMode是不管用的,因为系统强制设置了图片的大小
- // 宽度减去间距的一半,另一半由imageView分担,x值保持系统值
- titleOrigin.x = titleOrigin.x + _imageTitleSpace * 0.5;
- break;
- default: // 剩下的就是右对齐,右对齐titleLabel不用做任何改变
- break;
- }
-
- titleRect.size = titleSize;
- titleRect.origin = titleOrigin;
- return titleRect;
-}
-
-// ----------------------------------------------------- right -----------------------------------------------------
-
-- (CGRect)imageRectImageAtRightForContentRect:(CGRect)contentRect imageRect:(CGRect)imageRect titleRect:(CGRect)titleRect {
-
- CGFloat imageSafeWidth = contentRect.size.width - self.imageEdgeInsets.left - self.imageEdgeInsets.right;
- if (imageRect.size.width >= imageSafeWidth) {
- return imageRect;
- }
-
- CGPoint imageOrigin = imageRect.origin;
- CGSize imageSize = imageRect.size;
- CGSize titleSize = titleRect.size;
-
- // 这里水平中心对齐,跟图片在右边时的中心对齐时差别在于:图片在右边时中心对齐考虑了titleLabel+imageView这个整体,而这里只单独考虑imageView
- if (imageSize.width + titleSize.width > imageSafeWidth) {
- imageSize.width = imageSize.width - (imageSize.width + titleSize.width - imageSafeWidth);
- }
-
- CGFloat buttonWidth = contentRect.size.width + self.contentEdgeInsets.left + self.contentEdgeInsets.right;
- titleSize = [self calculateTitleSizeForSystemTitleSize:titleSize];
-
- switch (self.contentHorizontalAlignment) {
- case UIControlContentHorizontalAlignmentCenter: // 中心对齐
- // (contentRect.size.width - self.imageEdgeInsets.left - self.imageEdgeInsets.right - (imageSize.width + titleSize.width))/2.0+titleSize.width指的是imageView在其有效区域内联合titleLabel整体居中时的x值,有效区域指的是contentRect内缩imageEdgeInsets后的区域
- imageOrigin.x = (contentRect.size.width - self.imageEdgeInsets.left - self.imageEdgeInsets.right - (imageSize.width + titleSize.width))/2.0 + titleSize.width + self.contentEdgeInsets.left + self.imageEdgeInsets.left + _imageTitleSpace * 0.5;
- break;
- case UIControlContentHorizontalAlignmentLeft:
- case UIControlContentHorizontalAlignmentLeading: // 左对齐
- imageOrigin.x = self.contentEdgeInsets.left + self.imageEdgeInsets.left + titleSize.width + _imageTitleSpace;
- break;
- case UIControlContentHorizontalAlignmentRight:
- case UIControlContentHorizontalAlignmentTrailing: // 右对齐
- // 注意image的大小要使用系统计算的结果,这里不能使用self.currentImage.size.width,当imageEdgeInsets的left过大时可以进行测试
- imageOrigin.x = buttonWidth - imageSize.width - self.imageEdgeInsets.right - self.contentEdgeInsets.right;
- break;
- case UIControlContentHorizontalAlignmentFill: // 填充
- imageOrigin.x = buttonWidth - imageSize.width - self.imageEdgeInsets.right - self.contentEdgeInsets.right + _imageTitleSpace * 0.5;
- break;
- }
- imageRect.size = imageSize;
- imageRect.origin = imageOrigin;
- return imageRect;
-}
-
-- (CGRect)titleRectImageAtRightForContentRect:(CGRect)contentRect titleRect:(CGRect)titleRect imageRect:(CGRect)imageRect {
-
- CGPoint titleOrigin = titleRect.origin;
- CGSize titleSize = titleRect.size;
- CGSize imageSize = imageRect.size;
-
- CGFloat buttonWidth = contentRect.size.width + self.contentEdgeInsets.left + self.contentEdgeInsets.right;
-
- switch (self.contentHorizontalAlignment) {
- case UIControlContentHorizontalAlignmentCenter: // 中心对齐
- // (contentRect.size.width - self.titleEdgeInsets.left - self.titleEdgeInsets.right - (imageSize.width + titleSize.width))/2.0的意思是titleLabel在其有效区域内联合imageView整体居中时的x值,有效区域指的是contentRect内缩titleEdgeInsets后的区域
- titleOrigin.x = (contentRect.size.width - self.titleEdgeInsets.left - self.titleEdgeInsets.right - (imageSize.width + titleSize.width))/2.0 + self.contentEdgeInsets.left + self.titleEdgeInsets.left - _imageTitleSpace * 0.5;
- break;
- case UIControlContentHorizontalAlignmentLeft:
- case UIControlContentHorizontalAlignmentLeading: // 左对齐
- titleOrigin.x = self.contentEdgeInsets.left + self.titleEdgeInsets.left;
- break;
- case UIControlContentHorizontalAlignmentRight:
- case UIControlContentHorizontalAlignmentTrailing: // 右对齐
- // 这里必须使用self.currentImage的宽度。不能使用imageSize.width,因为图片可能会被压缩或者拉伸,例如当图片的imageEdgeInsets的right设置过大,图片的宽度就会被压缩,这时的图片宽度不是我们要的
- titleOrigin.x = buttonWidth - (titleSize.width + self.currentImage.size.width) - self.titleEdgeInsets.right - self.contentEdgeInsets.right - _imageTitleSpace;
- break;
- case UIControlContentHorizontalAlignmentFill:
- titleOrigin.x = buttonWidth - (titleSize.width + self.currentImage.size.width) - self.titleEdgeInsets.right - self.contentEdgeInsets.right - _imageTitleSpace * 0.5;
- break;
- }
- titleRect.size = titleSize;
- titleRect.origin = titleOrigin;
- return titleRect;
-}
-
-// ----------------------------------------------------- top -----------------------------------------------------
-
-- (CGRect)imageRectImageAtTopForContentRect:(CGRect)contentRect imageRect:(CGRect)imageRect titleRect:(CGRect)titleRect {
- CGPoint imageOrigin = imageRect.origin;
- CGSize imageSize = self.currentImage.size;
- CGSize titleSize = [self calculateTitleSizeForSystemTitleSize:titleRect.size];
-
- CGFloat imageSafeWidth = contentRect.size.width - self.imageEdgeInsets.left - self.imageEdgeInsets.right;
- CGFloat imageSafeHeight = contentRect.size.height - self.imageEdgeInsets.top - self.imageEdgeInsets.bottom;
-
- // 这里水平中心对齐,跟图片在右边时的中心对齐时差别在于:图片在右边时中心对齐考虑了titleLabel+imageView这个整体,而这里只单独考虑imageView
- if (imageSize.width > imageSafeWidth) {
- imageSize.width = imageSafeWidth;
- }
- if (imageSize.height > imageSafeHeight) {
- imageSize.height = imageSafeHeight;
- }
-
- CGFloat buttonWidth = contentRect.size.width + self.contentEdgeInsets.left + self.contentEdgeInsets.right;
- CGFloat buttonHeight = contentRect.size.height + self.contentEdgeInsets.top + self.contentEdgeInsets.bottom;
-
- // 水平方向
- switch (self.contentHorizontalAlignment) {
- case UIControlContentHorizontalAlignmentCenter: {// 中心对齐
- imageOrigin.x = (contentRect.size.width - self.imageEdgeInsets.left - self.imageEdgeInsets.right - imageSize.width) / 2.0 + self.contentEdgeInsets.left + self.imageEdgeInsets.left;
- }
- break;
- case UIControlContentHorizontalAlignmentLeft:
- case UIControlContentHorizontalAlignmentLeading: // 左对齐
- imageOrigin.x = self.contentEdgeInsets.left + self.imageEdgeInsets.left;
- break;
- case UIControlContentHorizontalAlignmentRight:
- case UIControlContentHorizontalAlignmentTrailing: // 右对齐
- imageOrigin.x = buttonWidth - imageSize.width - self.imageEdgeInsets.right - self.contentEdgeInsets.right;
- break;
- case UIControlContentHorizontalAlignmentFill: // 填充
- imageOrigin.x = self.contentEdgeInsets.left + self.imageEdgeInsets.left;
- imageSize.width = imageSafeWidth; // 宽度填满
- break;
- }
-
- // 给图片高度作最大限制,超出限制对高度进行压缩,这样还可以保证titeLabel不会超出其有效区域
- CGFloat imageTitleLimitMaxH = contentRect.size.height - self.imageEdgeInsets.top - self.imageEdgeInsets.bottom;
- if (imageSize.height < imageTitleLimitMaxH) {
- if (titleSize.height + imageSize.height > imageTitleLimitMaxH) {
- CGFloat beyondValue = titleSize.height + self.currentImage.size.height - imageTitleLimitMaxH;
- imageSize.height = imageSize.height - beyondValue;
- }
- }
-
- // 垂直方向
- switch (self.contentVerticalAlignment) {
- case UIControlContentVerticalAlignmentCenter: // 中心对齐
- // (imageSize.height + titleSize.height)这个整体高度很重要,这里相当于按照按钮原有规则进行对齐,即按钮的对齐方式不管是设置谁的insets,计算时都是以图片+文字这个整体作为考虑对象
- imageOrigin.y = (contentRect.size.height - self.imageEdgeInsets.top - self.imageEdgeInsets.bottom - (imageSize.height + titleSize.height)) / 2.0 + self.contentEdgeInsets.top + self.imageEdgeInsets.top - _imageTitleSpace * 0.5;
- break;
- case UIControlContentVerticalAlignmentTop: // 顶部对齐
- imageOrigin.y = self.contentEdgeInsets.top + self.imageEdgeInsets.top - _imageTitleSpace * 0.5;
- break;
- case UIControlContentVerticalAlignmentBottom: // 底部对齐
- imageOrigin.y = buttonHeight - (imageSize.height + titleSize.height) - self.contentEdgeInsets.bottom - self.imageEdgeInsets.bottom - _imageTitleSpace * 0.5;
- break;
- case UIControlContentVerticalAlignmentFill: // 填充
- imageOrigin.y = self.contentEdgeInsets.top + self.imageEdgeInsets.top - _imageTitleSpace * 0.5;
- imageSize.height = contentRect.size.height - self.imageEdgeInsets.top - self.imageEdgeInsets.bottom - [self calculateTitleSizeForSystemTitleSize:titleSize].height;
- break;
- }
- imageRect.size = imageSize;
- imageRect.origin = imageOrigin;
- return imageRect;
-}
-
-- (CGRect)titleRectImageAtTopForContentRect:(CGRect)contentRect titleRect:(CGRect)titleRect imageRect:(CGRect)imageRect {
- CGPoint titleOrigin = titleRect.origin;
- CGSize imageSize = self.currentImage.size;
- CGSize titleSize = [self calculateTitleSizeForSystemTitleSize:titleRect.size];
-
- CGFloat buttonWidth = contentRect.size.width + self.contentEdgeInsets.left + self.contentEdgeInsets.right;
- CGFloat buttonHeight = contentRect.size.height + self.contentEdgeInsets.top + self.contentEdgeInsets.bottom;
-
- // 这个if语句的含义是:计算图片由于设置了contentEdgeInsets而被压缩的高度,设置imageEdgeInsets被压缩的高度不计算在内。这样做的目的是,当设置了contentEdgeInsets时,图片可能会被压缩,此时titleLabel的y值依赖于图片压缩后的高度,当设置了imageEdgeInsets时,图片也可能被压缩,此时titleLabel的y值依赖于图片压缩前的高度,这样以来,设置imageEdgeInsets就不会对titleLabel的y值产生影响
- if (imageSize.height + titleSize.height > contentRect.size.height) {
- imageSize.height = self.currentImage.size.height - (self.currentImage.size.height + titleSize.height - contentRect.size.height);
- }
- // titleLabel的安全宽度,这里一定要改变宽度值,因为当外界设置了titleEdgeInsets值时,系统计算出来的所有值都是在”左图右文“的基础上进行的,这个基础上可能会导致titleLabel的宽度被压缩,所以我们在此自己重新计算
- CGFloat titleSafeWidth = contentRect.size.width - self.titleEdgeInsets.left - self.titleEdgeInsets.right;
- if (titleSize.width > titleSafeWidth) {
- titleSize.width = titleSafeWidth;
- }
-
- // 水平方向
- switch (self.contentHorizontalAlignment) {
- case UIControlContentHorizontalAlignmentCenter: {// 中心对齐
-
- titleOrigin.x = (titleSafeWidth - titleSize.width) / 2.0 + self.contentEdgeInsets.left + self.titleEdgeInsets.left;
- }
- break;
- case UIControlContentHorizontalAlignmentLeft:
- case UIControlContentHorizontalAlignmentLeading: // 左对齐
- titleOrigin.x = self.contentEdgeInsets.left + self.titleEdgeInsets.left;
- break;
- case UIControlContentHorizontalAlignmentRight:
- case UIControlContentHorizontalAlignmentTrailing: // 右对齐
- titleOrigin.x = buttonWidth - titleSize.width - self.titleEdgeInsets.right - self.contentEdgeInsets.right;
- break;
- case UIControlContentHorizontalAlignmentFill: // 填充
- titleOrigin.x = self.contentEdgeInsets.left + self.titleEdgeInsets.left;
- // titleLabel宽度上不填充,按系统一样,在有效区域内,自适应文字宽度
- break;
- }
-
- if (titleSize.height > contentRect.size.height - self.titleEdgeInsets.top - self.titleEdgeInsets.bottom) {
- titleSize.height = contentRect.size.height - self.titleEdgeInsets.top - self.titleEdgeInsets.bottom;
- }
-
- // 垂直方向
- switch (self.contentVerticalAlignment) {
- case UIControlContentVerticalAlignmentCenter: {// 中心对齐
- // (imageSize.height + titleSize.height)这个整体高度很重要,这里相当于按照按钮原有规则进行对齐,即按钮的对齐方式不管是设置谁的Insets,计算时都是以图片+文字这个整体作为考虑对象
- titleOrigin.y = (contentRect.size.height - self.titleEdgeInsets.top - self.titleEdgeInsets.bottom - (imageSize.height + titleSize.height)) / 2.0 + imageSize.height + self.contentEdgeInsets.top + self.titleEdgeInsets.top + _imageTitleSpace * 0.5;
- }
- break;
- case UIControlContentVerticalAlignmentTop: // 顶部对齐
- titleOrigin.y = self.contentEdgeInsets.top + self.titleEdgeInsets.top + imageSize.height + _imageTitleSpace * 0.5;
- break;
- case UIControlContentVerticalAlignmentBottom: // 底部对齐
- titleOrigin.y = buttonHeight - titleSize.height - self.contentEdgeInsets.bottom - self.titleEdgeInsets.bottom+ _imageTitleSpace * 0.5;
- break;
- case UIControlContentVerticalAlignmentFill: // 填充
- titleOrigin.y = buttonHeight - titleSize.height - self.contentEdgeInsets.bottom - self.titleEdgeInsets.bottom + _imageTitleSpace * 0.5;
- break;
- }
-
- titleRect.size = titleSize;
- titleRect.origin = titleOrigin;
- return titleRect;
-}
-
-// ----------------------------------------------------- bottom -----------------------------------------------------
-
-- (CGRect)imageRectImageAtBottomForContentRect:(CGRect)contentRect imageRect:(CGRect)imageRect titleRect:(CGRect)titleRect {
- CGPoint imageOrigin = imageRect.origin;
- CGSize imageSize = self.currentImage.size;
- CGSize titleSize = [self calculateTitleSizeForSystemTitleSize:titleRect.size];
-
- CGFloat imageSafeWidth = contentRect.size.width - self.imageEdgeInsets.left - self.imageEdgeInsets.right;
- CGFloat imageSafeHeight = contentRect.size.height - self.imageEdgeInsets.top - self.imageEdgeInsets.bottom;
-
- // 这里水平中心对齐,跟图片在右边时的中心对齐时差别在于:图片在右边时中心对齐考虑了titleLabel+imageView这个整体,而这里只单独考虑imageView
- if (imageSize.width > imageSafeWidth) {
- imageSize.width = imageSafeWidth;
- }
- if (imageSize.height > imageSafeHeight) {
- imageSize.height = imageSafeHeight;
- }
-
- CGFloat buttonWidth = contentRect.size.width + self.contentEdgeInsets.left + self.contentEdgeInsets.right;
- CGFloat buttonHeight = contentRect.size.height + self.contentEdgeInsets.top + self.contentEdgeInsets.bottom;
-
- // 水平方向
- switch (self.contentHorizontalAlignment) {
- case UIControlContentHorizontalAlignmentCenter: {// 中心对齐
- imageOrigin.x = (contentRect.size.width - self.imageEdgeInsets.left - self.imageEdgeInsets.right - imageSize.width) / 2.0 + self.contentEdgeInsets.left + self.imageEdgeInsets.left;
- }
- break;
- case UIControlContentHorizontalAlignmentLeft:
- case UIControlContentHorizontalAlignmentLeading: // 左对齐
- imageOrigin.x = self.contentEdgeInsets.left + self.imageEdgeInsets.left;
- break;
- case UIControlContentHorizontalAlignmentRight:
- case UIControlContentHorizontalAlignmentTrailing: // 右对齐
- imageOrigin.x = buttonWidth - imageSize.width - self.imageEdgeInsets.right - self.contentEdgeInsets.right;
- break;
- case UIControlContentHorizontalAlignmentFill: // 填充
- imageOrigin.x = self.contentEdgeInsets.left + self.imageEdgeInsets.left;
- imageSize.width = imageSafeWidth; // 宽度填满
- break;
- }
-
- // 给图片高度作最大限制,超出限制对高度进行压缩,这样还可以保证titeLabel不会超出其有效区域
- CGFloat imageTitleLimitMaxH = contentRect.size.height - self.imageEdgeInsets.top - self.imageEdgeInsets.bottom;
- if (imageSize.height < imageTitleLimitMaxH) {
- if (titleSize.height + imageSize.height > imageTitleLimitMaxH) {
- CGFloat beyondValue = titleSize.height + self.currentImage.size.height - imageTitleLimitMaxH;
- imageSize.height = imageSize.height - beyondValue;
- }
- }
- // 垂直方向
- switch (self.contentVerticalAlignment) {
- case UIControlContentVerticalAlignmentCenter: // 中心对齐
- // (self.currentImage.size.height + titleSize.height)这个整体高度很重要,这里相当于按照按钮原有规则进行对齐,即按钮的对齐方式不管是设置谁的insets,计算时都是以图片+文字这个整体作为考虑对象
- imageOrigin.y = (contentRect.size.height - self.imageEdgeInsets.top - self.imageEdgeInsets.bottom - (imageSize.height + titleSize.height)) / 2.0 + titleSize.height + self.contentEdgeInsets.top + self.imageEdgeInsets.top + _imageTitleSpace * 0.5;
- break;
- case UIControlContentVerticalAlignmentTop: // 顶部对齐
- imageOrigin.y = self.contentEdgeInsets.top + self.imageEdgeInsets.top + titleSize.height + _imageTitleSpace * 0.5;
- break;
- case UIControlContentVerticalAlignmentBottom: // 底部对齐
- imageOrigin.y = buttonHeight - imageSize.height - self.contentEdgeInsets.bottom - self.imageEdgeInsets.bottom + _imageTitleSpace * 0.5;
- break;
- case UIControlContentVerticalAlignmentFill: // 填充
- // 这里不能使用titleSize.height,因为垂直填充模式下,系统计算出的titleSize就是contentRect的高度,我们需要的是titleLabel拉伸前的高度
- imageSize.height = contentRect.size.height - self.imageEdgeInsets.top - self.imageEdgeInsets.bottom - [self calculateTitleSizeForSystemTitleSize:titleSize].height;
- imageOrigin.y = buttonHeight - imageSize.height - self.contentEdgeInsets.bottom - self.imageEdgeInsets.bottom + _imageTitleSpace * 0.5;
- break;
- }
-
- imageRect.size = imageSize;
- imageRect.origin = imageOrigin;
- return imageRect;
-}
-
-- (CGRect)titleRectImageAtBottomForContentRect:(CGRect)contentRect titleRect:(CGRect)titleRect imageRect:(CGRect)imageRect {
- CGPoint titleOrigin = titleRect.origin;
- CGSize imageSize = self.currentImage.size;
- CGSize titleSize = [self calculateTitleSizeForSystemTitleSize:titleRect.size];
-
- // 这个if语句的含义是:计算图片由于设置了contentEdgeInsets而被压缩的高度,设置imageEdgeInsets被压缩的高度不计算在内。这样做的目的是,当设置了contentEdgeInsets时,图片可能会被压缩,此时titleLabel的y值依赖于图片压缩后的高度,当设置了imageEdgeInsets时,图片也可能被压缩,此时titleLabel的y值依赖于图片压缩前的高度,这样一来,设置imageEdgeInsets就不会对titleLabel的y值产生影响
- if (self.currentImage.size.height + titleSize.height > contentRect.size.height) {
- imageSize.height = self.currentImage.size.height - (self.currentImage.size.height + titleSize.height - contentRect.size.height);
- }
-
- // titleLabel的安全宽度,因为当外界设置了titleEdgeInsets值时,系统计算出来的所有值都是在”左图右文“的基础上进行的,这个基础上可能会导致titleLabel的宽度被压缩,所以我们在此自己重新计算
- CGFloat titleSafeWidth = contentRect.size.width - self.titleEdgeInsets.left - self.titleEdgeInsets.right;
- if (titleSize.width > titleSafeWidth) {
- titleSize.width = titleSafeWidth;
- }
-
- CGFloat buttonWidth = contentRect.size.width + self.contentEdgeInsets.left + self.contentEdgeInsets.right;
- CGFloat buttonHeight = contentRect.size.height + self.contentEdgeInsets.top + self.contentEdgeInsets.bottom;
-
- // 水平方向
- switch (self.contentHorizontalAlignment) {
- case UIControlContentHorizontalAlignmentCenter: {// 中心对齐
- titleOrigin.x = (titleSafeWidth - titleSize.width) / 2.0 + self.contentEdgeInsets.left + self.titleEdgeInsets.left;
- }
- break;
- case UIControlContentHorizontalAlignmentLeft:
- case UIControlContentHorizontalAlignmentLeading: // 左对齐
- titleOrigin.x = self.contentEdgeInsets.left + self.titleEdgeInsets.left;
- break;
- case UIControlContentHorizontalAlignmentRight:
- case UIControlContentHorizontalAlignmentTrailing: // 右对齐
- titleOrigin.x = buttonWidth - titleSize.width - self.titleEdgeInsets.right - self.contentEdgeInsets.right;
- break;
- case UIControlContentHorizontalAlignmentFill: // 填充
- titleOrigin.x = self.contentEdgeInsets.left + self.titleEdgeInsets.left;
- // titleLabel宽度上不填充,按系统一样,在有效区域内,自适应文字宽度
- break;
- }
-
- if (titleSize.height > contentRect.size.height - self.titleEdgeInsets.top - self.titleEdgeInsets.bottom) {
- titleSize.height = contentRect.size.height - self.titleEdgeInsets.top - self.titleEdgeInsets.bottom;
- }
-
- // 垂直方向
- switch (self.contentVerticalAlignment) {
- case UIControlContentVerticalAlignmentCenter: // 中心对齐
- // (self.currentImage.size.height + titleSize.height)这个整体高度很重要,这里相当于按照按钮原有规则进行对齐,即按钮的对齐方式不管是设置谁的Insets,计算时都是以图片+文字这个整体作为考虑对象
- titleOrigin.y = (contentRect.size.height - self.titleEdgeInsets.top - self.titleEdgeInsets.bottom - (imageSize.height + titleSize.height)) / 2.0 + self.contentEdgeInsets.top + self.titleEdgeInsets.top - _imageTitleSpace * 0.5;
- break;
- case UIControlContentVerticalAlignmentTop: // 顶部对齐
- titleOrigin.y = self.contentEdgeInsets.top + self.titleEdgeInsets.top - _imageTitleSpace * 0.5;
- break;
- case UIControlContentVerticalAlignmentBottom: // 底部对齐
- titleOrigin.y = buttonHeight - (titleSize.height + imageSize.height) - self.contentEdgeInsets.bottom - self.titleEdgeInsets.bottom - _imageTitleSpace * 0.5;
- break;
- case UIControlContentVerticalAlignmentFill: // 填充
- titleOrigin.y = self.contentEdgeInsets.top + self.titleEdgeInsets.top - _imageTitleSpace * 0.5;
- break;
- }
-
- titleRect.size = titleSize;
- titleRect.origin = titleOrigin;
- return titleRect;
-}
-
-// 自己计算titleLabel的大小
-- (CGSize)calculateTitleSizeForSystemTitleSize:(CGSize)titleSize {
- CGSize myTitleSize = titleSize;
- // 获取按钮里的titleLabel,之所以遍历获取而不直接调用self.titleLabel,是因为假如这里是第一次调用self.titleLabel,则会跟titleRectForContentRect: 方法造成死循环,titleLabel的getter方法中,alloc init之前调用了titleRectForContentRect:
- UILabel *titleLabel = [self findTitleLabel];
- if (!titleLabel) { // 此时还没有创建titleLabel,先通过系统button的字体进行文字宽度计算
- CGFloat fontSize = [UIFont buttonFontSize]; // 按钮默认字体,18号
- // 说明外界使用了被废弃的font属性,被废弃但是依然生效
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- if (self.font.pointSize != [UIFont buttonFontSize]) {
- fontSize = self.font.pointSize;
- }
-#pragma clang diagnostic pop
- myTitleSize.height = ceil([self.currentTitle boundingRectWithSize:CGSizeMake(titleSize.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]} context:nil].size.height);
- // 根据文字计算宽度,取上整,补齐误差,保证跟titleLabel.intrinsicContentSize.width一致
- myTitleSize.width = ceil([self.currentTitle boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, titleSize.height) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]} context:nil].size.width);
- } else { // 说明此时titeLabel已经产生,直接取titleLabel的内容宽度
- myTitleSize.width = titleLabel.intrinsicContentSize.width;
- myTitleSize.height = titleLabel.intrinsicContentSize.height;
- }
- return myTitleSize;
-}
-
-// 遍历获取按钮里面的titleLabel
-- (UILabel *)findTitleLabel {
- for (UIView *subView in self.subviews) {
- if ([subView isKindOfClass:NSClassFromString(@"UIButtonLabel")]) {
- UILabel *titleLabel = (UILabel *)subView;
- return titleLabel;
- }
- }
- return nil;
-}
-
-
-
-#pragma mark - setter
-// 以下所有setter方法中都调用了layoutSubviews, 其实是为了间接的调用imageRectForContentRect:和titleRectForContentRect:,不能直接调用imageRectForContentRect:和titleRectForContentRect:,因为按钮的子控件布局最终都是通过调用layoutSubviews而确定,如果直接调用这两个方法,那么只能保证我们能够获取的CGRect是对的,但并不会作用在titleLabel和imageView上
-- (void)setImagePosition:(SPButtonImagePosition)imagePosition {
- _imagePosition = imagePosition;
- [self setNeedsLayout];
-}
-
-- (void)setImageTitleSpace:(CGFloat)imageTitleSpace {
- _imageTitleSpace = imageTitleSpace;
- [self setNeedsLayout];
-}
-
-- (void)setContentHorizontalAlignment:(UIControlContentHorizontalAlignment)contentHorizontalAlignment {
- [super setContentHorizontalAlignment:contentHorizontalAlignment];
- [self setNeedsLayout];
-}
-
-// 垂直方向的排列方式在设置之前如果调用了titleLabel或imageView的getter方法,则设置后不会生效,点击一下按钮之后就生效了,这应该属于按钮的一个小bug,我们只要重写它的setter方法重新布局一次就好
-- (void)setContentVerticalAlignment:(UIControlContentVerticalAlignment)contentVerticalAlignment {
- [super setContentVerticalAlignment:contentVerticalAlignment];
- [self setNeedsLayout];
-}
-
-@end
diff --git a/Example/SPAlertController/Images/image0.jpg b/Example/SPAlertController/Images/image0.jpg
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Images/image1.jpg b/Example/SPAlertController/Images/image1.jpg
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Images/image2.jpg b/Example/SPAlertController/Images/image2.jpg
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Images/image3.jpg b/Example/SPAlertController/Images/image3.jpg
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Images/image4.jpg b/Example/SPAlertController/Images/image4.jpg
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Images/image5.jpg b/Example/SPAlertController/Images/image5.jpg
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Images/image6.jpg b/Example/SPAlertController/Images/image6.jpg
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Images/image7.jpg b/Example/SPAlertController/Images/image7.jpg
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Images/image8.jpg b/Example/SPAlertController/Images/image8.jpg
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Images/image9.jpg b/Example/SPAlertController/Images/image9.jpg
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Images/send0.jpeg b/Example/SPAlertController/Images/send0.jpeg
index 709419d..72285c0 100644
Binary files a/Example/SPAlertController/Images/send0.jpeg and b/Example/SPAlertController/Images/send0.jpeg differ
diff --git a/Example/SPAlertController/Images/send1.jpeg b/Example/SPAlertController/Images/send1.jpeg
old mode 100644
new mode 100755
diff --git "a/Example/SPAlertController/Images/\350\203\214\346\231\2571.jpg" "b/Example/SPAlertController/Images/\350\203\214\346\231\2571.jpg"
old mode 100644
new mode 100755
diff --git "a/Example/SPAlertController/Images/\350\203\214\346\231\2572.jpg" "b/Example/SPAlertController/Images/\350\203\214\346\231\2572.jpg"
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/Info.plist b/Example/SPAlertController/Info.plist
old mode 100644
new mode 100755
index fcb4b34..1312a7e
--- a/Example/SPAlertController/Info.plist
+++ b/Example/SPAlertController/Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 3.0.1
+ $(MARKETING_VERSION)
CFBundleVersion
1
LSRequiresIPhoneOS
diff --git a/Example/SPAlertController/SPAlertController/SPAlertController.h b/Example/SPAlertController/SPAlertController/SPAlertController.h
deleted file mode 100644
index 6429d6d..0000000
--- a/Example/SPAlertController/SPAlertController/SPAlertController.h
+++ /dev/null
@@ -1,229 +0,0 @@
-//
-// SPAlertController.h
-// SPAlertController
-//
-// Created by 乐升平 on 18/10/12. https://github.com/SPStore/SPAlertController
-// Copyright © 2018年 iDress. All rights reserved.
-//
-
-#import
-
-NS_ASSUME_NONNULL_BEGIN
-
-typedef NS_ENUM(NSInteger, SPAlertControllerStyle) {
- SPAlertControllerStyleActionSheet = 0, // 从四周的某一侧弹出(顶/左/底/右),从哪边弹出,就往哪边对齐
- SPAlertControllerStyleAlert, // 从中间弹出
-};
-
-typedef NS_ENUM(NSInteger, SPAlertAnimationType) {
- SPAlertAnimationTypeDefault = 0, // 默认动画,如果是SPAlertControllerStyleActionSheet样式,默认动画等效于SPAlertAnimationTypeFromBottom,如果是SPAlertControllerStyleAlert样式,默认动画等效于SPAlertAnimationTypeShrink
- SPAlertAnimationTypeFromBottom, // 从底部弹出
- SPAlertAnimationTypeFromTop, // 从顶部弹出
- SPAlertAnimationTypeFromRight, // 从右边弹出
- SPAlertAnimationTypeFromLeft, // 从左边弹出
-
- SPAlertAnimationTypeShrink, // 收缩动画
- SPAlertAnimationTypeExpand, // 发散动画
- SPAlertAnimationTypeFade, // 渐变动画
-
- SPAlertAnimationTypeNone, // 无动画
- SPAlertAnimationTypeAlpha NS_ENUM_DEPRECATED_IOS(8_0, 8_0, "Use SPAlertAnimationTypeFad instead"), // 渐变动画
- SPAlertAnimationTypeRaiseUp NS_ENUM_DEPRECATED_IOS(8_0, 8_0, "Use SPAlertAnimationTypeFromBottom instead"), // 从底部弹出
- SPAlertAnimationTypeDropDown NS_ENUM_DEPRECATED_IOS(8_0, 8_0, "Use SPAlertAnimationTypeFromTop instead"), // 从顶部弹出
-};
-
-typedef NS_ENUM(NSInteger, SPAlertActionStyle) {
- SPAlertActionStyleDefault = 0, // 默认样式
- SPAlertActionStyleCancel, // 取消样式,字体加粗
- SPAlertActionStyleDestructive // 红色字体样式
-};
-
-typedef NS_ENUM(NSInteger, SPBackgroundViewAppearanceStyle) {
- SPBackgroundViewAppearanceStyleTranslucent = 0, // 无毛玻璃效果,黑色透明(默认是0.5透明)
- SPBackgroundViewAppearanceStyleBlurDark,
- SPBackgroundViewAppearanceStyleBlurExtraLight,
- SPBackgroundViewAppearanceStyleBlurLight,
-};
-
-// ===================================================== SPAlertAction =====================================================
-
-@interface SPAlertAction : NSObject
-/**
- * 创建一个action
- *
- * @param title 标题
- * @param style action样式
- * @param handler 点击后的bolok回调
- */
-+ (instancetype)actionWithTitle:(nullable NSString *)title style:(SPAlertActionStyle)style handler:(void (^ __nullable)(SPAlertAction *action))handler;
-
-/** action的标题 */
-@property(nullable, nonatomic, copy) NSString *title;
-/** action的富文本标题 */
-@property(nullable, nonatomic, copy) NSAttributedString *attributedTitle;
-/** action的图标,位于title的左边 */
-@property(nullable, nonatomic, copy) UIImage *image;
-/** title跟image之间的间距 */
-@property (nonatomic, assign) CGFloat imageTitleSpacing;
-/** 样式 */
-@property(nonatomic, readonly) SPAlertActionStyle style;
-/** 是否能点击,默认为YES */
-@property(nonatomic, getter=isEnabled) BOOL enabled;
-/** action的标题颜色,这个颜色只是普通文本的颜色,富文本颜色需要用NSForegroundColorAttributeName */
-@property(nonatomic, strong) UIColor *titleColor;
-/** action的标题字体,如果文字太长显示不全,会自动改变字体自适应按钮宽度,最多压缩文字为原来的0.5倍封顶 */
-@property(nonatomic, strong) UIFont *titleFont;
-/** action的标题的内边距,如果在不改变字体的情况下想增大action的高度,可以设置该属性的top和bottom值,默认UIEdgeInsetsMake(0, 15, 0, 15) */
-@property(nonatomic, assign) UIEdgeInsets titleEdgeInsets;
-
-@end
-
-// ===================================================== SPAlertController =====================================================
-
-@protocol SPAlertControllerDelegate;
-@interface SPAlertController : UIViewController
-
-+ (instancetype)alertControllerWithTitle:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle;
-+ (instancetype)alertControllerWithTitle:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType; // animationType传SPAlertAnimationTypeDefault则跟第一个类方法等效
-
-- (void)addAction:(SPAlertAction *)action;
-@property (nonatomic, readonly) NSArray *actions;
-
-/* 添加文本输入框
- * 一旦添加后就会回调一次(仅回调一次,因此可以在这个block块里面自由定制textFiled,如设置textField的属性,设置代理,添加addTarget,监听通知等);
- */
-- (void)addTextFieldWithConfigurationHandler:(void (^ __nullable)(UITextField *textField))configurationHandler;
-@property(nullable, nonatomic, readonly) NSArray *textFields;
-
-/** 主标题 */
-@property(nullable, nonatomic, copy) NSString *title;
-/** 副标题 */
-@property(nullable, nonatomic, copy) NSString *message;
-/** 主标题(富文本) */
-@property(nullable, nonatomic, copy) NSAttributedString *attributedTitle;
-/** 副标题(富文本) */
-@property(nullable, nonatomic, copy) NSAttributedString *attributedMessage;
-/** 头部图标,位置处于title之上,大小取决于图片本身大小 */
-@property(nullable,nonatomic, copy) UIImage *image;
-
-/** 主标题颜色 */
-@property(nonatomic, strong) UIColor *titleColor;
-/** 主标题字体,默认18,加粗 */
-@property(nonatomic, strong) UIFont *titleFont;
-/** 副标题颜色 */
-@property(nonatomic, strong) UIColor *messageColor;
-/** 副标题字体,默认16,未加粗 */
-@property(nonatomic, strong) UIFont *messageFont;
-/** 对齐方式(包括主标题和副标题) */
-@property(nonatomic, assign) NSTextAlignment textAlignment;
-/** 头部图标的限制大小,默认无穷大 */
-@property (nonatomic, assign) CGSize imageLimitSize;
-
-/*
- * action水平排列还是垂直排列
- * actionSheet样式下:默认为UILayoutConstraintAxisVertical(垂直排列), 如果设置为UILayoutConstraintAxisHorizontal(水平排列),则除去取消样式action之外的其余action将水平排列
- * alert样式下:当actions的个数大于2,或者某个action的title显示不全时为UILayoutConstraintAxisVertical(垂直排列),否则默认为UILayoutConstraintAxisHorizontal(水平排列),此样式下设置该属性可以修改所有action的排列方式
- * 不论哪种样式,只要外界设置了该属性,永远以外界设置的优先
- */
-@property(nonatomic) UILayoutConstraintAxis actionAxis;
-
-/* 距离屏幕边缘的最小间距
- * alert样式下该属性是指对话框四边与屏幕边缘之间的距离,此样式下默认值随设备变化,actionSheet样式下是指弹出边的对立边与屏幕之间的距离,比如如果从右边弹出,那么该属性指的就是对话框左边与屏幕之间的距离,此样式下默认值为70
- */
-@property(nonatomic, assign) CGFloat minDistanceToEdges;
-
-/** 圆角半径,只有alert样式有效*/
-@property(nonatomic, assign) CGFloat cornerRadiusForAlert;
-
-/** 对话框的偏移量,y值为正向下偏移,为负向上偏移;x值为正向右偏移,为负向左偏移,该属性只对SPAlertControllerStyleAlert样式有效,键盘的frame改变会自动偏移,如果外界手动设置偏移只会取手动设置的 */
-@property(nonatomic, assign) CGPoint offsetForAlert;
-/** 设置alert样式下的偏移量,动画为NO则跟属性offsetForAlert等效 */
-- (void)setOffsetForAlert:(CGPoint)offsetForAlert animated:(BOOL)animated;
-
-/** 是否需要对话框拥有毛玻璃,默认为YES----Dialog单词是对话框的意思 */
-@property(nonatomic, assign) BOOL needDialogBlur;
-
-/** 是否单击背景退出对话框,默认为YES */
-@property(nonatomic, assign) BOOL tapBackgroundViewDismiss;
-
-@property(nonatomic, weak) id delegate;
-
-@property(nonatomic, readonly) SPAlertControllerStyle preferredStyle;
-@property(nonatomic, readonly) SPAlertAnimationType animationType;
-
-/** 设置action与下一个action之间的间距, action仅限于非取消样式,必须在'-addAction:'之后设置,iOS11或iOS11以上才能使用 */
-- (void)setCustomSpacing:(CGFloat)spacing afterAction:(SPAlertAction *)action API_AVAILABLE(ios(11.0));
-- (CGFloat)customSpacingAfterAction:(SPAlertAction *)action API_AVAILABLE(ios(11.0));
-
-/** 设置蒙层的外观样式,可通过alpha调整透明度 */
-- (void)setBackgroundViewAppearanceStyle:(SPBackgroundViewAppearanceStyle)style alpha:(CGFloat)alpha;
-
-// 插入一个组件view,位置处于头部和action部分之间,要求头部和action部分同时存在
-- (void)insertComponentView:(nullable UIView *)componentView;
-
-
-// ---------------------------------------------- custom -----------------------------------------------------
-/**
- 创建控制器(自定义整个对话框)
-
- @param customAlertView 整个对话框的自定义view
- @param preferredStyle 对话框样式
- @param animationType 动画类型
- @return 控制器对象
- */
-+ (instancetype)alertControllerWithCustomAlertView:(nullable UIView *)customAlertView preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType;
-/**
- 创建控制器(自定义对话框的头部)
-
- @param customHeaderView 头部自定义view
- @param preferredStyle 对话框样式
- @param animationType 动画类型
- @return 控制器对象
- */
-+ (instancetype)alertControllerWithCustomHeaderView:(nullable UIView *)customHeaderView preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType;
-/**
- 创建控制器(自定义对话框的action部分)
-
- @param customActionSequenceView action部分的自定义view
- @param title 大标题
- @param message 副标题
- @param preferredStyle 对话框样式
- @param animationType 动画类型
- @return 控制器对象
- */
-+ (instancetype)alertControllerWithCustomActionSequenceView:(nullable UIView *)customActionSequenceView title:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType;
-
-/** 更新自定义view的size,自定义了哪个view,该size指的就是哪个view的size,比如屏幕旋转,自定义view的大小发生了改变,可通过该方法更新 */
-- (void)updateCustomViewSize:(CGSize)size;
-
-@property (nonatomic, assign) CGFloat maxTopMarginForActionSheet NS_DEPRECATED_IOS(8_0, 8_0,"Use minDistanceToEdgeForAlert instead"); // actionSheet样式下,最大的顶部间距,从底部、右边、左边弹出时默认为0,iPhoneX及以上机型默认44,从顶部弹出时无论哪种机型都默认为0;注意该属性中的top单词不是精确的指顶部,当从右边弹出时,top指的就是左,从左边弹出时,top指的就是右,从顶部弹出时,top指的就是底
-@property(nonatomic, assign) CGFloat maxMarginForAlert NS_DEPRECATED_IOS(8_0, 8_0,"Use minDistanceToEdgeForAlert instead");// alert样式下,四周的最小间距,默认为20,该属性起名有误,应该是最小,而不是最大,3.0版本属性名已改,叫minDistanceToEdgeForAlert
-@property(nonatomic, assign) NSInteger maxNumberOfActionHorizontalArrangementForAlert NS_DEPRECATED_IOS(8_0, 8_0,"Use actionAxis instead");// alert样式下,水平排列的最大个数,如果大于了这个数,则所有action将垂直排列,默认是2;在添加action之前设置性能会更佳,由于水平排列的action都是排布在footerView上,所以如果自定义了footerView,该属性将失去效用
-@property(nonatomic, assign) CGFloat offsetYForAlert NS_DEPRECATED_IOS(8_0, 8_0,"Use offset instead"); // 对话框垂直方向上的偏移
-+ (instancetype)alertControllerWithTitle:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType customView:(nullable UIView *)customView NS_DEPRECATED_IOS(8_0, 8_0,"Use +alertControllerWithCustomView:preferredStyle:animationType:");
-+ (instancetype)alertControllerWithPreferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType customHeaderView:(nullable UIView *)customHeaderView NS_DEPRECATED_IOS(8_0, 8_0,"Use +alertControllerWithCustomHeaderView:preferredStyle:animationType:");
-+ (instancetype)alertControllerWithTitle:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType customCenterView:(nullable UIView *)customCenterView NS_DEPRECATED_IOS(8_0, 8_0,"Use +alertControllerWithComponentView:title:message:(nullable NSString *)message preferredStyle:animationType:");
-+ (instancetype)alertControllerWithTitle:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType customFooterView:(nullable UIView *)customFooterView NS_DEPRECATED_IOS(8_0, 8_0,"Use +alertControllerWithCustomActionGroupView:title:message: preferredStyle:animationType:");
-@end
-
-@protocol SPAlertControllerDelegate
-@optional;
-- (void)willPresentAlertController:(SPAlertController *)alertController; // 将要present
-- (void)didPresentAlertController:(SPAlertController *)alertController; // 已经present
-- (void)willDismissAlertController:(SPAlertController *)alertController; // 将要dismiss
-- (void)didDismissAlertController:(SPAlertController *)alertController; // 已经dismiss
-
-- (void)sp_alertControllerWillShow:(SPAlertController *)alertController NS_DEPRECATED_IOS(8_0, 8_0,"Use -willPresentAlertController:");
-- (void)sp_alertControllerDidShow:(SPAlertController *)alertController NS_DEPRECATED_IOS(8_0, 8_0,"Use -DidPresentAlertController:");
-- (void)sp_alertControllerWillHide:(SPAlertController *)alertController NS_DEPRECATED_IOS(8_0, 8_0,"Use -willDismissAlertController:");
-- (void)sp_alertControllerDidHide:(SPAlertController *)alertController NS_DEPRECATED_IOS(8_0, 8_0,"Use -DidDismissAlertController:");
-@end
-
-@interface SPAlertPresentationController : UIPresentationController
-@end
-
-@interface SPAlertAnimation : NSObject
-+ (instancetype)animationIsPresenting:(BOOL)presenting;
-@end
-
-NS_ASSUME_NONNULL_END
diff --git a/Example/SPAlertController/SPAlertController/SPAlertController.m b/Example/SPAlertController/SPAlertController/SPAlertController.m
deleted file mode 100644
index effadd7..0000000
--- a/Example/SPAlertController/SPAlertController/SPAlertController.m
+++ /dev/null
@@ -1,2591 +0,0 @@
-//
-// SPAlertController.m
-// SPAlertController
-//
-// Created by 乐升平 on 18/10/12. https://github.com/SPStore/SPAlertController
-// Copyright © 2018年 iDress. All rights reserved.
-//
-
-#import "SPAlertController.h"
-
-#define SP_SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
-#define SP_SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
-#define SP_LINE_COLOR [[UIColor grayColor] colorWithAlphaComponent:0.3]
-#define SP_NORMAL_COLOR [[UIColor whiteColor] colorWithAlphaComponent:0.7]
-#define SP_SELECTED_COLOR [UIColor colorWithWhite:1 alpha:0.4]
-#define SP_LINE_WIDTH 1.0 / [UIScreen mainScreen].scale
-#define Is_iPhoneX MAX(SP_SCREEN_WIDTH, SP_SCREEN_HEIGHT) >= 812
-#define SP_STATUS_BAR_HEIGHT (Is_iPhoneX ? 44 : 20)
-#define SP_ACTION_TITLE_FONTSIZE 18
-#define SP_ACTION_HEIGHT 49.0
-
-#pragma mark ---------------------------- SPAlertAction begin --------------------------------
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-
-@interface SPAlertAction()
-
-@property (nonatomic, assign) SPAlertActionStyle style;
-@property (nonatomic, copy) void (^handler)(SPAlertAction *action);
-// 当在addAction之后设置action属性时,会回调这个block,设置相应控件的字体、颜色等
-// 如果没有这个block,那使用时,只有在addAction之前设置action的属性才有效
-@property (nonatomic, copy) void (^propertyChangedBlock)(SPAlertAction *action, BOOL needUpdateConstraints);
-@end
-
-@implementation SPAlertAction
-
-// 由于要对装载action的数组进行拷贝,所以SPAlertAction也需要支持拷贝
-- (id)copyWithZone:(NSZone *)zone {
- SPAlertAction *action = [[[self class] alloc] init];
- action.title = self.title;
- action.attributedTitle = self.attributedTitle;
- action.image = self.image;
- action.imageTitleSpacing = self.imageTitleSpacing;
- action.style = self.style;
- action.enabled = self.enabled;
- action.titleColor = self.titleColor;
- action.titleFont = self.titleFont;
- action.titleEdgeInsets = self.titleEdgeInsets;
- action.handler = self.handler;
- action.propertyChangedBlock = self.propertyChangedBlock;
- return action;
-}
-
-+ (instancetype)actionWithTitle:(nullable NSString *)title style:(SPAlertActionStyle)style handler:(void (^ __nullable)(SPAlertAction *action))handler {
- SPAlertAction *action = [[self alloc] initWithTitle:title style:(SPAlertActionStyle)style handler:handler];
- return action;
-}
-
-- (instancetype)initWithTitle:(nullable NSString *)title style:(SPAlertActionStyle)style handler:(void (^ __nullable)(SPAlertAction *action))handler {
- self = [self init];
- self.title = title;
- self.style = style;
- self.handler = handler;
- if (style == SPAlertActionStyleDestructive) {
- self.titleColor = [UIColor redColor];
- self.titleFont = [UIFont systemFontOfSize:SP_ACTION_TITLE_FONTSIZE];
- } else if (style == SPAlertActionStyleCancel) {
- self.titleColor = [UIColor blackColor];
- self.titleFont = [UIFont boldSystemFontOfSize:SP_ACTION_TITLE_FONTSIZE];
- } else {
- self.titleColor = [UIColor blackColor];
- self.titleFont = [UIFont systemFontOfSize:SP_ACTION_TITLE_FONTSIZE];
- }
- return self;
-}
-
-- (instancetype)init {
- if (self = [super init]) {
- [self initialize];
- }
- return self;
-}
-
-- (void)initialize {
- _enabled = YES; // 默认能点击
- _titleColor = [UIColor blackColor];
- _titleFont = [UIFont systemFontOfSize:SP_ACTION_TITLE_FONTSIZE];
- _titleEdgeInsets = UIEdgeInsetsMake(0, 15, 0, 15);
-}
-
-- (void)setTitle:(NSString *)title {
- _title = title;
- if (self.propertyChangedBlock) {
- self.propertyChangedBlock(self, YES);
- }
-}
-
-- (void)setAttributedTitle:(NSAttributedString *)attributedTitle {
- _attributedTitle = attributedTitle;
- if (self.propertyChangedBlock) {
- self.propertyChangedBlock(self, YES);
- }
-}
-
-- (void)setImage:(UIImage *)image {
- _image = image;
- if (self.propertyChangedBlock) {
- self.propertyChangedBlock(self, YES);
- }
-}
-
-- (void)setImageTitleSpacing:(CGFloat)imageTitleSpacing {
- _imageTitleSpacing = imageTitleSpacing;
- if (self.propertyChangedBlock) {
- self.propertyChangedBlock(self, YES);
- }
-}
-
-- (void)setTitleColor:(UIColor *)titleColor {
- _titleColor = titleColor;
- if (self.propertyChangedBlock) {
- self.propertyChangedBlock(self,NO); // 颜色改变不需要更新布局
- }
-}
-
-- (void)setTitleFont:(UIFont *)titleFont {
- _titleFont = titleFont;
- if (self.propertyChangedBlock) {
- self.propertyChangedBlock(self,YES); // 字体改变需要更新布局
- }
-}
-
-- (void)setEnabled:(BOOL)enabled {
- _enabled = enabled;
- if (self.propertyChangedBlock) {
- self.propertyChangedBlock(self,NO); // enabled改变不需要更新布局
- }
-}
-
-@end
-
-#pragma mark ---------------------------- SPAlertAction end ----------------------------
-
-#pragma mark ---------------------------- SPInterfaceActionItemSeparatorView begin --------------------------------
-
-@interface SPInterfaceActionItemSeparatorView : UIView
-@end
-@implementation SPInterfaceActionItemSeparatorView
-- (instancetype)init {
- if (self = [super init]) {
- self.backgroundColor = SP_LINE_COLOR;
- }
- return self;
-}
-
-- (void)layoutSubviews {
- [super layoutSubviews];
- self.backgroundColor = self.frame.size.height > SP_LINE_WIDTH ? [[UIColor grayColor] colorWithAlphaComponent:0.2] : SP_LINE_COLOR;
-}
-
-@end
-#pragma mark ---------------------------- SPAlertControllerActionView end --------------------------------
-
-#pragma mark ---------------------------- SPInterfaceHeaderScrollView begin ----------------------------
-
-@interface SPInterfaceHeaderScrollView : UIScrollView
-@property (nonatomic, weak) UIView *contentView;
-@property (nonatomic, weak) UILabel *titleLabel;
-@property (nonatomic, weak) UILabel *messageLabel;
-@property (nonatomic, weak) UIImageView *imageView;
-@property (nonatomic, assign) CGSize imageLimitSize;
-@property (nonatomic, weak) UIStackView *textFieldView;
-@property (nonatomic, strong) NSMutableArray *textFields;
-@property (nonatomic, assign) UIEdgeInsets contentEdgeInsets;
-@property (nonatomic, copy) void(^headerViewSfeAreaDidChangBlock)(void);
-@end
-
-@implementation SPInterfaceHeaderScrollView
-
-- (instancetype)initWithFrame:(CGRect)frame {
- if (self = [super initWithFrame:frame]) {
- self.showsHorizontalScrollIndicator = NO;
- if (@available(iOS 11.0, *)) {
- self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
- }
- self.contentEdgeInsets = UIEdgeInsetsMake(20, 15, 20, 15);
- }
- return self;
-}
-
-- (void)addTextField:(UITextField *)textField {
- [self.textFields addObject:textField];
- // 将textView添加到self.textFieldView中的布局队列中,UIStackView会根据设置的属性自动布局
- [self.textFieldView addArrangedSubview:textField];
- // 由于self.textFieldView是没有高度的,它的高度由子控件撑起,所以子控件必须要有高度
- [[NSLayoutConstraint constraintWithItem:textField attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:25.0f] setActive:YES];
- [self setNeedsUpdateConstraints];
-}
-
-- (NSMutableArray *)textFields {
- if (!_textFields) {
- _textFields = [[NSMutableArray alloc] init];
- }
- return _textFields;
-}
-
-- (void)safeAreaInsetsDidChange {
- [super safeAreaInsetsDidChange];
- CGFloat safeTop = self.safeAreaInsets.top < 20 ? 20 : self.safeAreaInsets.top+10;
- CGFloat safeLeft = self.safeAreaInsets.left < 15 ? 15 : self.safeAreaInsets.left;
- CGFloat safeBottom = self.safeAreaInsets.bottom < 20 ? 20 : self.safeAreaInsets.bottom+6;
- CGFloat safeRight = self.safeAreaInsets.right < 15 ? 15 : self.safeAreaInsets.right;
- _contentEdgeInsets = UIEdgeInsetsMake(safeTop, safeLeft, safeBottom, safeRight);
- // 这个block,主要是更新Label的最大预估宽度
- if (self.headerViewSfeAreaDidChangBlock) {
- self.headerViewSfeAreaDidChangBlock();
- }
- [self setNeedsUpdateConstraints];
-}
-
-- (void)updateConstraints {
- [super updateConstraints];
- UIView *contentView = self.contentView;
- // 对contentView布局
- // 先移除旧约束,再添加新约束
- [NSLayoutConstraint deactivateConstraints:self.constraints];
- [NSLayoutConstraint deactivateConstraints:contentView.constraints];
-
- [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[contentView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(contentView)]];
- [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[contentView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(contentView)]];
- [[NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0] setActive:YES];
- NSLayoutConstraint *equalHeightConstraint = [NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0];
- equalHeightConstraint.priority = 998.0f; // 优先级不能最高, 最顶层的父view有高度限制,如果子控件撑起后的高度大于限制高度,则scrollView滑动查看全部内容
- equalHeightConstraint.active = YES;
-
- UIImageView *imageView = _imageView;
- UIStackView *textFieldView = _textFieldView;
-
- CGFloat leftMargin = self.contentEdgeInsets.left;
- CGFloat rightMargin = self.contentEdgeInsets.right;
- CGFloat topMargin = self.contentEdgeInsets.top;
- CGFloat bottomMargin = self.contentEdgeInsets.bottom;
-
- // 对iconView布局
- if (imageView.image) {
- NSMutableArray *imageViewConstraints = [NSMutableArray array];
- [imageViewConstraints addObject:[NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:MIN(imageView.image.size.width, _imageLimitSize.width)]];
- [imageViewConstraints addObject:[NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:MIN(imageView.image.size.height, _imageLimitSize.height)]];
- [imageViewConstraints addObject:[NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:contentView attribute:NSLayoutAttributeCenterX multiplier:1.f constant:0]];
- [imageViewConstraints addObject:[NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:contentView attribute:NSLayoutAttributeTop multiplier:1.f constant:topMargin]];
- if (_titleLabel.text.length || _titleLabel.attributedText.length) {
- [imageViewConstraints addObject:[NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:_titleLabel attribute:NSLayoutAttributeTop multiplier:1.f constant:-17]];
- } else if (_messageLabel.text.length || _messageLabel.attributedText.length) {
- [imageViewConstraints addObject:[NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:_messageLabel attribute:NSLayoutAttributeTop multiplier:1.f constant:-17]];
- } else if (_textFields.count) {
- [imageViewConstraints addObject:[NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:textFieldView attribute:NSLayoutAttributeTop multiplier:1.f constant:-17]];
- } else {
- [imageViewConstraints addObject:[NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:contentView attribute:NSLayoutAttributeBottom multiplier:1.f constant:-bottomMargin]];
- }
- [NSLayoutConstraint activateConstraints:imageViewConstraints];
- }
-
- // 对titleLabel和messageLabel布局
- NSMutableArray *titleLabelConstraints = [NSMutableArray array];
- NSMutableArray *labels = [NSMutableArray array];
- if (_titleLabel.text.length || _titleLabel.attributedText.length) {
- [labels insertObject:_titleLabel atIndex:0];
- }
- if (_messageLabel.text.length || _messageLabel.attributedText.length) {
- [labels addObject:_messageLabel];
- }
- [labels enumerateObjectsUsingBlock:^(UILabel *label, NSUInteger idx, BOOL * _Nonnull stop) {
- // 左右间距
- [titleLabelConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|-(==leftMargin)-[label]-(==rightMargin)-|"] options:0 metrics:@{@"leftMargin":@(leftMargin),@"rightMargin":@(rightMargin)} views:NSDictionaryOfVariableBindings(label)]];
- // 第一个子控件顶部间距
- if (idx == 0) {
- if (!imageView.image) {
- [titleLabelConstraints addObject:[NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:contentView attribute:NSLayoutAttributeTop multiplier:1.f constant:topMargin]];
- }
- }
- // 最后一个子控件底部间距
- if (idx == labels.count - 1) {
- if (self.textFields.count) {
- [titleLabelConstraints addObject:[NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:textFieldView attribute:NSLayoutAttributeTop multiplier:1.f constant:-bottomMargin]];
- } else {
- [titleLabelConstraints addObject:[NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:contentView attribute:NSLayoutAttributeBottom multiplier:1.f constant:-bottomMargin]];
- }
- }
- // 子控件之间的垂直间距
- if (idx > 0) {
- [titleLabelConstraints addObject:[NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:labels[idx - 1] attribute:NSLayoutAttributeBottom multiplier:1.f constant:7.5]];
- }
- }];
- [NSLayoutConstraint activateConstraints:titleLabelConstraints];
-
- if (self.textFields.count) {
- NSMutableArray *textFieldViewConstraints = [NSMutableArray array];
- if (!labels.count && !imageView.image) { // 没有titleLabel、messageLabel和iconView,textFieldView的顶部相对contentView,否则不用写,因为前面写好了
- [textFieldViewConstraints addObject:[NSLayoutConstraint constraintWithItem:textFieldView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:contentView attribute:NSLayoutAttributeTop multiplier:1.f constant:topMargin]];
- }
- [textFieldViewConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"H:|-(==leftMargin)-[textFieldView]-(==rightMargin)-|"] options:0 metrics:@{@"leftMargin":@(leftMargin),@"rightMargin":@(rightMargin)} views:NSDictionaryOfVariableBindings(textFieldView)]];
- [textFieldViewConstraints addObject:[NSLayoutConstraint constraintWithItem:textFieldView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:contentView attribute:NSLayoutAttributeBottom multiplier:1.f constant:-bottomMargin]];
-
- [NSLayoutConstraint activateConstraints:textFieldViewConstraints];
- }
-
- // systemLayoutSizeFittingSize:方法获取子控件撑起contentView后的高度,如果子控件是UILabel,那么子label必须设置preferredMaxLayoutWidth,否则当label多行文本时计算不准确
- NSLayoutConstraint *contentViewHeightConstraint = [NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:[contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height];
- contentViewHeightConstraint.active = YES;
-}
-
-- (UIView *)contentView {
- if (!_contentView) {
- UIView *contentView = [[UIView alloc] init];
- contentView.translatesAutoresizingMaskIntoConstraints = NO;
- [self addSubview:contentView];
- _contentView = contentView;
- }
- return _contentView;
-}
-
-- (UILabel *)titleLabel {
- if (!_titleLabel) {
- UILabel *titleLabel = [[UILabel alloc] init];
- titleLabel.font = [UIFont boldSystemFontOfSize:18];
- titleLabel.textAlignment = NSTextAlignmentCenter;
- titleLabel.textColor = [UIColor blackColor];
- titleLabel.numberOfLines = 0;
- titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
- [self.contentView addSubview:titleLabel];
- _titleLabel = titleLabel;
- }
- return _titleLabel;
-}
-
-- (UILabel *)messageLabel {
- if (!_messageLabel) {
- UILabel *messageLabel = [[UILabel alloc] init];
- messageLabel.font = [UIFont systemFontOfSize:18];
- messageLabel.textAlignment = NSTextAlignmentCenter;
- messageLabel.textColor = [UIColor grayColor];
- messageLabel.numberOfLines = 0;
- messageLabel.translatesAutoresizingMaskIntoConstraints = NO;
- [self.contentView addSubview:messageLabel];
- _messageLabel = messageLabel;
- }
- return _messageLabel;
-}
-
-- (UIImageView *)imageView {
- if (!_imageView) {
- UIImageView *imageView = [[UIImageView alloc] init];
- imageView.translatesAutoresizingMaskIntoConstraints = NO;
- [self.contentView insertSubview:imageView atIndex:0];
- _imageView = imageView;
- }
- return _imageView;
-}
-
-- (UIStackView *)textFieldView {
- if (!_textFieldView) {
- UIStackView *textFieldView = [[UIStackView alloc] init];
- textFieldView.translatesAutoresizingMaskIntoConstraints = NO;
- textFieldView.distribution = UIStackViewDistributionFillEqually;
- textFieldView.axis = UILayoutConstraintAxisVertical;
- if (self.textFields.count) {
- [self.contentView addSubview:textFieldView];
- }
- _textFieldView = textFieldView;
- }
- return _textFieldView;
-}
-
-@end
-
-#pragma mark ---------------------------- SPInterfaceHeaderScrollView end ----------------------------
-
-#pragma mark ---------------------------- SPAlertControllerActionView begin --------------------------------
-
-@interface SPAlertControllerActionView : UIView {
- id _target;
- SEL _methodAction;
-}
-@property (nonatomic, strong) SPAlertAction *action;
-@property (nonatomic, weak) UIButton *actionButton;
-@property (nonatomic, strong) NSMutableArray *actionButtonConstraints;
-@property (nonatomic, assign) CGFloat afterSpacing;
-- (void)addTarget:(id)target action:(SEL)action;
-@end
-
-@implementation SPAlertControllerActionView
-
-- (instancetype)init {
- if (self = [super init]) {
- _afterSpacing = SP_LINE_WIDTH;
- }
- return self;
-}
-
-- (void)setAction:(SPAlertAction *)action {
- _action = action;
-
- self.actionButton.titleLabel.font = action.titleFont;
- if (action.enabled) {
- [self.actionButton setTitleColor:action.titleColor forState:UIControlStateNormal];
- } else {
- [self.actionButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
- }
-
- // 注意不能赋值给按钮的titleEdgeInsets,当只有文字时,按钮的titleEdgeInsets设置top和bottom值无效
- self.actionButton.contentEdgeInsets = action.titleEdgeInsets;
- self.actionButton.enabled = action.enabled;
- if (action.attributedTitle) {
- // 这里之所以要设置按钮颜色为黑色,是因为如果外界在addAction:之后设置按钮的富文本,那么富文本的颜色在没有采用NSForegroundColorAttributeName的情况下会自动读取按钮上普通文本的颜色,在addAction:之前设置会保持默认色(黑色),为了在addAction:前后设置富文本保持统一,这里先将按钮置为黑色,富文本就会是黑色
- [self.actionButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
-
- if ([action.attributedTitle.string containsString:@"\n"] || [action.attributedTitle.string containsString:@"\r"]) {
- self.actionButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
- }
- [self.actionButton setAttributedTitle:action.attributedTitle forState:UIControlStateNormal];
-
- // 设置完富文本之后,还原按钮普通文本的颜色,其实这行代码加不加都不影响,只是为了让按钮普通文本的颜色保持跟action.titleColor一致
- [self.actionButton setTitleColor:action.titleColor forState:UIControlStateNormal];
- } else {
- if ([action.title containsString:@"\n"] || [action.title containsString:@"\r"]) {
- self.actionButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
- }
- [self.actionButton setTitle:action.title forState:UIControlStateNormal];
- }
- [self.actionButton setImage:action.image forState:UIControlStateNormal];
- self.actionButton.titleEdgeInsets = UIEdgeInsetsMake(0, action.imageTitleSpacing, 0, -action.imageTitleSpacing);
- self.actionButton.imageEdgeInsets = UIEdgeInsetsMake(0, -action.imageTitleSpacing, 0, action.imageTitleSpacing);
-}
-
-- (void)addTarget:(id)target action:(SEL)methodAction {
- _target = target;
- _methodAction = methodAction;
-}
-
-- (void)touchUpInside:(UIButton *)sender {
- // 用函数指针实现_target调用_methodAction,相当于[_target performSelector:_methodAction withObject:self];但是后者会报警告
- SEL selector = _methodAction;
- IMP imp = [_target methodForSelector:selector];
- void (*func)(id, SEL,SPAlertControllerActionView *) = (void *)imp;
- func(_target, selector, self);
-}
-
-- (void)touchDown:(UIButton *)sender {
- sender.backgroundColor = SP_SELECTED_COLOR;
-}
-
-- (void)touchDragExit:(UIButton *)sender {
- sender.backgroundColor = SP_NORMAL_COLOR;
-}
-
-// 安全区域发生了改变,在这个方法里自动适配iPhoneX
-- (void)safeAreaInsetsDidChange {
- [super safeAreaInsetsDidChange];
- // safeAreaInsets+titleEdgeInsets
- self.actionButton.contentEdgeInsets = UIEdgeInsetsAddEdgeInsets(self.safeAreaInsets, _action.titleEdgeInsets);
- [self setNeedsUpdateConstraints];
-}
-
-UIEdgeInsets UIEdgeInsetsAddEdgeInsets(UIEdgeInsets i1,UIEdgeInsets i2) {
- if (i1.bottom > 21) {
- i1.bottom = 21; // 34的高度太大,这里转为21
- }
- return UIEdgeInsetsMake(i1.top+i2.top, i1.left+i2.left, i1.bottom+i2.bottom, i1.right+i2.right);
-}
-
-- (void)updateConstraints {
- [super updateConstraints];
-
- UIButton *actionButton = self.actionButton;
- if (self.actionButtonConstraints) {
- [NSLayoutConstraint deactivateConstraints:self.actionButtonConstraints];
- self.actionButtonConstraints = nil;
- }
- NSMutableArray *actionButtonConstraints = [NSMutableArray array];
- [actionButtonConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[actionButton]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(actionButton)]];
- [actionButtonConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[actionButton]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(actionButton)]];
- // 按钮必须确认高度,因为其父视图及父视图的父视图乃至根视图都没有设置高度,而且必须用NSLayoutRelationEqual,如果用NSLayoutRelationGreaterThanOrEqual,虽然也能撑起父视图,但是当某个按钮的高度有所变化以后,stackView会将其余按钮按的高度同比增减。
- // titleLabel的内容自适应的高度
- CGFloat labelH = actionButton.titleLabel.intrinsicContentSize.height;
- // 按钮的上下内边距之和
- CGFloat topBottom_insetsSum = actionButton.contentEdgeInsets.top+actionButton.contentEdgeInsets.bottom;
- // 文字的上下间距之和,等于SP_ACTION_HEIGHT-默认字体大小,这是为了保证文字上下有一个固定间距值,不至于使文字靠按钮太紧,,由于按钮内容默认垂直居中,所以最终的顶部或底部间距为topBottom_marginSum/2.0,这个间距,几乎等于18号字体时,最小高度为49时的上下间距
- CGFloat topBottom_marginSum = SP_ACTION_HEIGHT-[UIFont systemFontOfSize:SP_ACTION_TITLE_FONTSIZE].lineHeight;
- // 按钮高度
- CGFloat buttonH = labelH+topBottom_insetsSum+topBottom_marginSum;
- UIStackView *stackView = (UIStackView *)self.superview;
- NSLayoutRelation relation = NSLayoutRelationEqual;
- if ([stackView isKindOfClass:[UIStackView class]] && stackView.axis == UILayoutConstraintAxisHorizontal) {
- relation = NSLayoutRelationGreaterThanOrEqual;
- }
- // 如果字体保持默认18号,只有一行文字时最终结果约等于SP_ACTION_HEIGHT
- NSLayoutConstraint *buttonHonstraint = [NSLayoutConstraint constraintWithItem:actionButton attribute:NSLayoutAttributeHeight relatedBy:relation toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:buttonH];
- buttonHonstraint.priority = 999;
- [actionButtonConstraints addObject:buttonHonstraint];
- // 给一个最小高度,当按钮字体很小时,如果还按照上面的高度计算,高度会比较小
- NSLayoutConstraint *minHConstraint = [NSLayoutConstraint constraintWithItem:actionButton attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SP_ACTION_HEIGHT+topBottom_insetsSum];
- minHConstraint.priority = UILayoutPriorityRequired;
- [self addConstraints:actionButtonConstraints];
- self.actionButtonConstraints = actionButtonConstraints;
-}
-
-- (UIButton *)actionButton {
- if (!_actionButton) {
- UIButton *actionButton = [UIButton buttonWithType:UIButtonTypeCustom];
- actionButton.backgroundColor = SP_NORMAL_COLOR;
- actionButton.translatesAutoresizingMaskIntoConstraints = NO;
- actionButton.titleLabel.textAlignment = NSTextAlignmentCenter;
- actionButton.titleLabel.adjustsFontSizeToFitWidth = YES;
- actionButton.titleLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
- actionButton.titleLabel.minimumScaleFactor = 0.5;
- [actionButton addTarget:self action:@selector(touchUpInside:) forControlEvents:UIControlEventTouchUpInside]; // 手指按下然后在按钮有效事件范围内抬起
- [actionButton addTarget:self action:@selector(touchDown:) forControlEvents:UIControlEventTouchDown | UIControlEventTouchDragInside]; // 手指按下或者手指按下后往外拽再往内拽
- [actionButton addTarget:self action:@selector(touchDragExit:) forControlEvents:UIControlEventTouchDragExit | UIControlEventTouchUpOutside | UIControlEventTouchCancel]; // 手指被迫停止、手指按下后往外拽或者取消,取消的可能性:比如点击的那一刻突然来电话
- [self addSubview:actionButton];
- _actionButton = actionButton;
- }
- return _actionButton;
-}
-
-@end
-#pragma mark ---------------------------- SPAlertControllerActionView end --------------------------------
-
-#pragma mark ---------------------------- SPInterfaceActionSequenceView begin --------------------------------
-
-@interface SPInterfaceActionSequenceView : UIView
-@property (nonatomic, weak) UIScrollView *scrollView;
-@property (nonatomic, weak) UIView *contentView;
-@property (nonatomic, weak) UIView *cancelView;
-@property (nonatomic, weak) SPInterfaceActionItemSeparatorView *cancelActionLine;
-@property (nonatomic, weak) UIStackView *stackView;
-@property (nonatomic, strong) SPAlertAction *cancelAction;
-@property (nonatomic, strong) NSMutableArray *actionLineConstraints;
-@property (nonatomic, strong) NSMutableArray *actions;
-@property (nonatomic, assign) UIStackViewDistribution stackViewDistribution;
-@property (nonatomic, assign) UILayoutConstraintAxis axis;
-@property (nonatomic, copy) void (^buttonClickedInActionViewBlock)(NSInteger index);
-@end
-
-@implementation SPInterfaceActionSequenceView
-
-- (void)setAxis:(UILayoutConstraintAxis)axis {
- _axis = axis;
- self.stackView.axis = axis;
- [self setNeedsUpdateConstraints];
-}
-
-- (void)setStackViewDistribution:(UIStackViewDistribution)stackViewDistribution {
- _stackViewDistribution = stackViewDistribution;
- self.stackView.distribution = stackViewDistribution;
- [self setNeedsUpdateConstraints];
-}
-
-- (void)buttonClickedInActionView:(SPAlertControllerActionView *)actionView {
- NSInteger index = [self.actions indexOfObject:actionView.action];
- if (self.buttonClickedInActionViewBlock) {
- self.buttonClickedInActionViewBlock(index);
- }
-}
-
-- (void)setCustomSpacing:(CGFloat)spacing afterActionIndex:(NSInteger)index {
- UIStackView *stackView = self.stackView;
- SPAlertControllerActionView *actionView = stackView.arrangedSubviews[index];
- actionView.afterSpacing = spacing;
- if (@available(iOS 11.0, *)) {
- [self.stackView setCustomSpacing:spacing afterView:actionView];
- }
- [self updateLineConstraints];
-}
-
-- (CGFloat)customSpacingAfterActionIndex:(NSInteger)index {
- UIStackView *stackView = self.stackView;
- SPAlertControllerActionView *actionView = stackView.arrangedSubviews[index];
- if (@available(iOS 11.0, *)) {
- return [self.stackView customSpacingAfterView:actionView];
- } else {
- return 0.0;
- }
-}
-
-- (void)addAction:(SPAlertAction *)action {
- [self.actions addObject:action];
- UIStackView *stackView = self.stackView;
-
- SPAlertControllerActionView *currentActionView = [[SPAlertControllerActionView alloc] init];
- currentActionView.action = action;
- [currentActionView addTarget:self action:@selector(buttonClickedInActionView:)];
- [stackView addArrangedSubview:currentActionView];
-
- if (stackView.arrangedSubviews.count > 1) { // arrangedSubviews个数大于1,说明本次添加至少是第2次添加,此时要加一条分割线
- [self addLineForStackView:stackView];
- }
- [self setNeedsUpdateConstraints];
-}
-
-- (void)addCancelAction:(SPAlertAction *)action {
- // 如果已经存在取消样式的按钮,则直接崩溃
- NSAssert(!_cancelAction, @"SPAlertController can only have one action with a style of SPAlertActionStyleCancel");
- _cancelAction = action;
- [self.actions addObject:action];
- SPAlertControllerActionView *cancelActionView = [[SPAlertControllerActionView alloc] init];
- cancelActionView.translatesAutoresizingMaskIntoConstraints = NO;
- cancelActionView.action = action;
- [cancelActionView addTarget:self action:@selector(buttonClickedInActionView:)];
- [self.cancelView addSubview:cancelActionView];
- [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[cancelActionView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(cancelActionView)]];
- [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[cancelActionView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(cancelActionView)]];
-
- [self setNeedsUpdateConstraints];
-}
-
-// 为stackView添加分割线(细节)
-- (void)addLineForStackView:(UIStackView *)stackView {
- SPInterfaceActionItemSeparatorView *actionLine = [[SPInterfaceActionItemSeparatorView alloc] init];
- actionLine.translatesAutoresizingMaskIntoConstraints = NO;
- // 这里必须用addSubview:,不能用addArrangedSubview:,因为分割线不参与排列布局
- [stackView addSubview:actionLine];
-}
-
-// 从一个数组筛选出不在另一个数组中的数组
-- (NSArray *)filteredArrayFromArray:(NSArray *)array notInArray:(NSArray *)otherArray {
- NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT (SELF in %@)", otherArray];
- // 用谓词语句筛选出所有的分割线
- NSArray *subArray = [array filteredArrayUsingPredicate:predicate];
- return subArray;
-}
-
-// 更新分割线约束(细节)
-- (void)updateLineConstraints {
-
- UIStackView *stackView = self.stackView;
- NSArray *arrangedSubviews = stackView.arrangedSubviews;
- if (arrangedSubviews.count <= 1) return;
- // 用谓词语句筛选出所有的分割线
- NSArray *lines = [self filteredArrayFromArray:stackView.subviews notInArray:stackView.arrangedSubviews];
- if (arrangedSubviews.count < lines.count) return;
- NSMutableArray *actionLineConstraints = [NSMutableArray array];
- if (self.actionLineConstraints) {
- [NSLayoutConstraint deactivateConstraints:self.actionLineConstraints];
- self.actionLineConstraints = nil;
- }
- for (int i = 0; i < lines.count; i++) {
- SPInterfaceActionItemSeparatorView *actionLine = lines[i];
- SPAlertControllerActionView *actionView1 = arrangedSubviews[i];
- SPAlertControllerActionView *actionView2 = arrangedSubviews[i+1];
- if (self.axis == UILayoutConstraintAxisHorizontal) {
- [actionLineConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[actionLine]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(actionLine)]];
- [actionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:actionLine attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:actionView1 attribute:NSLayoutAttributeRight multiplier:1.0 constant:0]];
- [actionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:actionLine attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:actionView2 attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0]];
- [actionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:actionLine attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:actionView1.afterSpacing]];
- } else {
- [actionLineConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[actionLine]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(actionLine)]];
- [actionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:actionLine attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:actionView1 attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0]];
- [actionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:actionLine attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:actionView2 attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];
- [actionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:actionLine attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:actionView1.afterSpacing]];
- }
- }
- [NSLayoutConstraint activateConstraints:actionLineConstraints];
- self.actionLineConstraints = actionLineConstraints;
-}
-
-- (void)updateConstraints {
- [super updateConstraints];
- UIView *scrollView = self.scrollView;
- UIView *contentView = self.contentView;
- UIView *cancelView = self.cancelView;
- SPInterfaceActionItemSeparatorView *cancelActionLine = self.cancelActionLine;
-
- [NSLayoutConstraint deactivateConstraints:self.constraints];
- if (scrollView && scrollView.superview) {
- // 对scrollView布局
- NSMutableArray *scrollViewConstraints = [NSMutableArray array];
- [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[scrollView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(scrollView)]];
- [scrollViewConstraints addObject:[NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];
- if (cancelActionLine.superview) {
- [scrollViewConstraints addObject:[NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:cancelActionLine attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];
- } else {
- [scrollViewConstraints addObject:[NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0]];
- }
- [NSLayoutConstraint activateConstraints:scrollViewConstraints];
-
- [NSLayoutConstraint deactivateConstraints:scrollView.constraints];
- // 对contentView布局
- [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[contentView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(contentView)]];
- [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[contentView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(contentView)]];
- [[NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0] setActive:YES];
- NSLayoutConstraint *equalHeightConstraint = [NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0];
- // 计算scrolView的最小和最大高度,下面这个if语句是保证当actions的g总个数大于4时,scrollView的高度至少为4个半SP_ACTION_HEIGHT的高度,否则自适应内容
- CGFloat minHeight = 0.0;
- if (_axis == UILayoutConstraintAxisVertical) {
- if (self.cancelAction) {
- if (self.actions.count > 4) { // 如果有取消按钮且action总个数大于4,则除去取消按钮之外的其余部分的高度至少为3个半SP_ACTION_HEIGHT的高度,即加上取消按钮就是总高度至少为4个半SP_ACTION_HEIGHT的高度
- minHeight = SP_ACTION_HEIGHT * 3.5;
- equalHeightConstraint.priority = 997.0f; // 优先级为997,必须小于998.0,因为头部如果内容过多时高度也会有限制,头部的优先级为998.0.这里定的规则是,当头部和action部分同时过多时,头部的优先级更高,但是它不能高到以至于action部分小于最小高度
- } else { // 如果有取消按钮但action的个数大不于4,则该多高就显示多高
- equalHeightConstraint.priority = 1000.0f; // 由子控件撑起
- }
- } else {
- if (self.actions.count > 4) {
- minHeight = SP_ACTION_HEIGHT * 4.5;
- equalHeightConstraint.priority = 997.0f;
- } else {
- equalHeightConstraint.priority = 1000.0f;
- }
- }
- } else {
- minHeight = SP_ACTION_HEIGHT;
- }
- NSLayoutConstraint *minHeightConstraint = [NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:minHeight];
- minHeightConstraint.priority = 999.0;// 优先级不能大于对话框的最小顶部间距的优先级(999.0)
- minHeightConstraint.active = YES;
- equalHeightConstraint.active = YES;
-
- UIStackView *stackView = self.stackView;
- [NSLayoutConstraint deactivateConstraints:contentView.constraints];
- // 对stackView布局
- [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[stackView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(stackView)]];
- [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[stackView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(stackView)]];
-
- // 对stackView里面的分割线布局
- [self updateLineConstraints];
- }
-
- if (self.cancelActionLine.superview) { // cancelActionLine有superView则必有scrollView和cancelView
- NSMutableArray *cancelActionLineConstraints = [NSMutableArray array];
- [cancelActionLineConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[cancelActionLine]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(cancelActionLine)]];
- [cancelActionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:cancelActionLine attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:cancelView attribute:NSLayoutAttributeTop multiplier:1.0f constant:0]];
- [cancelActionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:cancelActionLine attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:6.0]];
- [NSLayoutConstraint activateConstraints:cancelActionLineConstraints];
- }
-
- // 对cancelView布局
- if (self.cancelAction) { // 有取消样式的按钮才对cancelView布局
- NSMutableArray *cancelViewConstraints = [NSMutableArray array];
- [cancelViewConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[cancelView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(cancelView)]];
- [cancelViewConstraints addObject:[NSLayoutConstraint constraintWithItem:cancelView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0]];
- if (!self.cancelActionLine.superview) {
- [cancelViewConstraints addObject:[NSLayoutConstraint constraintWithItem:cancelView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];
- }
- [NSLayoutConstraint activateConstraints:cancelViewConstraints];
- }
-}
-
-- (UIScrollView *)scrollView {
- if (!_scrollView) {
- UIScrollView *scrollView = [[UIScrollView alloc] init];
- scrollView.showsHorizontalScrollIndicator = NO;
- scrollView.translatesAutoresizingMaskIntoConstraints = NO;
- if (@available(iOS 11.0, *)) {
- scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
- }
- if ((self.cancelAction && self.actions.count > 1) || (!self.cancelAction && self.actions.count > 0)) {
- [self addSubview:scrollView];
- }
- _scrollView = scrollView;
- }
- return _scrollView;
-}
-
-- (UIView *)contentView {
- if (!_contentView) {
- UIView *contentView = [[UIView alloc] init];
- contentView.translatesAutoresizingMaskIntoConstraints = NO;
- [self.scrollView addSubview:contentView];
- _contentView = contentView;
- }
- return _contentView;
-}
-
-- (UIStackView *)stackView {
- if (!_stackView) {
- UIStackView *stackView = [[UIStackView alloc] init];
- stackView.translatesAutoresizingMaskIntoConstraints = NO;
- stackView.distribution = UIStackViewDistributionFillProportionally;
- stackView.spacing = SP_LINE_WIDTH; // 该间距腾出来的空间显示分割线
- stackView.axis = UILayoutConstraintAxisVertical;
- [self.contentView addSubview:stackView];
- _stackView = stackView;
- }
- return _stackView;
-}
-
-- (UIView *)cancelView {
- if (!_cancelView) {
- UIView *cancelView = [[UIView alloc] init];
- cancelView.translatesAutoresizingMaskIntoConstraints = NO;
- if (self.cancelAction) {
- [self addSubview:cancelView];
- }
- _cancelView = cancelView;
- }
- return _cancelView;
-}
-
-- (SPInterfaceActionItemSeparatorView *)cancelActionLine {
- if (!_cancelActionLine) {
- SPInterfaceActionItemSeparatorView *cancelActionLine = [[SPInterfaceActionItemSeparatorView alloc] init];
- cancelActionLine.translatesAutoresizingMaskIntoConstraints = NO;
- if (self.cancelView.superview && self.scrollView.superview) {
- [self addSubview:cancelActionLine];
- }
- _cancelActionLine = cancelActionLine;
- }
- return _cancelActionLine;
-}
-
-- (NSMutableArray *)actions {
- if (!_actions) {
- _actions = [[NSMutableArray alloc] init];
- }
- return _actions;
-}
-
-@end
-#pragma mark ---------------------------- SPInterfaceActionSequenceView end --------------------------------
-
-
-#pragma mark ---------------------------- SPAlertController begin --------------------------------
-
-@interface SPAlertController ()
-@property (nonatomic, strong) UIView *alertControllerView;
-@property (nonatomic, weak) UIView *containerView;
-@property (nonatomic, weak) UIView *alertView;
-@property (nonatomic, strong) UIView *customAlertView;
-@property (nonatomic, weak) SPInterfaceHeaderScrollView *headerView;
-@property (nonatomic, strong) UIView *customHeaderView;
-@property (nonatomic, weak) SPInterfaceActionSequenceView *actionSequenceView;
-@property (nonatomic, strong) UIView *customActionSequenceView;
-@property (nonatomic, strong) UIView *componentView;
-@property (nonatomic, assign) CGSize customViewSize;
-@property (nonatomic, weak) SPInterfaceActionItemSeparatorView *headerActionLine;
-@property (nonatomic, strong) NSMutableArray *headerActionLineConstraints;
-@property (nonatomic, weak) SPInterfaceActionItemSeparatorView *componentActionLine;
-@property (nonatomic, strong) NSMutableArray *componentViewConstraints;
-@property (nonatomic, strong) NSMutableArray *componentActionLineConstraints;
-@property (nonatomic, strong) UIView *dimmingKnockoutBackdropView;
-@property (nonatomic, strong) NSMutableArray *alertControllerViewConstraints;
-@property (nonatomic, strong) NSMutableArray *headerViewConstraints;
-@property (nonatomic, strong) NSMutableArray *actionSequenceViewConstraints;
-@property (nonatomic, assign) SPAlertControllerStyle preferredStyle;
-@property (nonatomic, assign) SPAlertAnimationType animationType;
-@property (nonatomic, assign) SPBackgroundViewAppearanceStyle backgroundViewAppearanceStyle;
-@property (nonatomic, assign) CGFloat backgroundViewAlpha;
-
-// action数组
-@property (nonatomic) NSArray *actions;
-// textFiled数组
-@property (nonatomic) NSArray *textFields;
-// 除去取消样式action的其余action数组
-@property (nonatomic) NSMutableArray *otherActions;
-@property (nonatomic, assign) BOOL isForceLayout; // 是否强制排列,外界设置了actionAxis属性认为是强制
-@property (nonatomic, assign) BOOL isForceOffset; // 是否强制偏移,外界设置了offsetForAlert属性认为是强制
-@end
-
-@implementation SPAlertController
-@synthesize title = _title;
-
-#pragma mark - public
-+ (instancetype)alertControllerWithTitle:(NSString *)title message:(NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle {
- SPAlertController *alertVc = [[SPAlertController alloc] initWithTitle:title message:message customAlertView:nil customHeaderView:nil customActionSequenceView:nil componentView:nil preferredStyle:preferredStyle animationType:SPAlertAnimationTypeDefault];
- return alertVc;
-}
-
-+ (instancetype)alertControllerWithTitle:(NSString *)title message:(NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType {
- SPAlertController *alertVc = [[SPAlertController alloc] initWithTitle:title message:message customAlertView:nil customHeaderView:nil customActionSequenceView:nil componentView:nil preferredStyle:preferredStyle animationType:animationType];
- return alertVc;
-}
-
-+ (instancetype)alertControllerWithCustomAlertView:(UIView *)customAlertView preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType {
- SPAlertController *alertVc = [[SPAlertController alloc] initWithTitle:nil message:nil customAlertView:customAlertView customHeaderView:nil customActionSequenceView:nil componentView:nil preferredStyle:preferredStyle animationType:animationType];
- return alertVc;
-}
-
-+ (instancetype)alertControllerWithCustomHeaderView:(UIView *)customHeaderView preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType {
- SPAlertController *alertVc = [[SPAlertController alloc] initWithTitle:nil message:nil customAlertView:nil customHeaderView:customHeaderView customActionSequenceView:nil componentView:nil preferredStyle:preferredStyle animationType:animationType];
- return alertVc;
-}
-
-+ (instancetype)alertControllerWithCustomActionSequenceView:(nullable UIView *)customActionSequenceView title:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType {
- SPAlertController *alertVc = [[SPAlertController alloc] initWithTitle:title message:message customAlertView:nil customHeaderView:nil customActionSequenceView:customActionSequenceView componentView:nil preferredStyle:preferredStyle animationType:animationType];
- return alertVc;
-}
-
-- (void)setOffsetForAlert:(CGPoint)offsetForAlert animated:(BOOL)animated {
- _offsetForAlert = offsetForAlert;
- _isForceOffset = YES;
- [self makeViewOffsetWithAnimated:animated];
-}
-
-- (void)insertComponentView:(UIView *)componentView {
- _componentView = componentView;
-}
-
-// 添加action
-- (void)addAction:(SPAlertAction *)action {
- NSMutableArray *actions = self.actions.mutableCopy;
- [actions addObject:action];
- self.actions = actions;
- if (self.preferredStyle == SPAlertControllerStyleAlert) { // alert样式不论是否为取消样式的按钮,都直接按顺序添加
- if (action.style != SPAlertActionStyleCancel) {
- [self.otherActions addObject:action];
- }
- [self.actionSequenceView addAction:action];
- } else { // actionSheet样式
- if (action.style == SPAlertActionStyleCancel) { // 如果是取消样式的按钮
- [self.actionSequenceView addCancelAction:action];
- } else {
- [self.otherActions addObject:action];
- [self.actionSequenceView addAction:action];
- }
- }
-
- if (!self.isForceLayout) { // 如果为NO,说明外界没有设置actionAxis,此时按照默认方式排列
- if (self.preferredStyle == SPAlertControllerStyleAlert) {
- if (self.actions.count > _maxNumberOfActionHorizontalArrangementForAlert) { // alert样式下,action的个数大于2时垂直排列,这里不等式右边写_maxNumberOfActionHorizontalArrangementForAlert是为了让被废弃的_maxNumberOfActionHorizontalArrangementForAlert依然生效
- _actionAxis = UILayoutConstraintAxisVertical; // 本框架任何一处都不允许调用actionAxis的setter方法,如果调用了则无法判断是外界调用还是内部调用
- [self updateActionAxis];
- } else { // action的个数小于等于2,action水平排列
- _actionAxis = UILayoutConstraintAxisHorizontal;
- [self updateActionAxis];
- }
- } else { // actionSheet样式下默认垂直排列
- _actionAxis = UILayoutConstraintAxisVertical;
- [self updateActionAxis];
-
- }
- } else {
- [self updateActionAxis];
- }
-
- // 这个block是保证外界在添加action之后再设置action属性时依然生效;当使用时在addAction之后再设置action的属性时,会回调这个block
- __weak typeof(self) weakSelf = self;
- action.propertyChangedBlock = ^(SPAlertAction *action, BOOL needUpdateConstraints) {
- __strong typeof(self) strongSelf = weakSelf;
- if (strongSelf.preferredStyle == SPAlertControllerStyleAlert) {
- // alert样式下:arrangedSubviews数组和actions是对应的
- NSInteger index = [strongSelf.actions indexOfObject:action];
- SPAlertControllerActionView *actionView = [strongSelf.actionSequenceView.stackView.arrangedSubviews objectAtIndex:index];
- if ([actionView isKindOfClass:[SPAlertControllerActionView class]]) {
- actionView.action = action;
- }
- if (strongSelf.presentationController.presentingViewController) {
- // 文字显示不全处理
- [strongSelf handleIncompleteTextDisplay];
- }
- } else {
- if (action.style == SPAlertActionStyleCancel) {
- // cancelView中只有唯一的一个actionView
- SPAlertControllerActionView *actionView = [strongSelf.actionSequenceView.cancelView.subviews lastObject];
- if ([actionView isKindOfClass:[SPAlertControllerActionView class]]) { // 这个判断可以不加,加判断是防止有一天改动框架不小心在cancelView中加了新的view产生安全隐患
- actionView.action = action;
- }
- } else {
- // actionSheet样式下:arrangedSubviews数组和otherActions是对应的
- NSInteger index = [strongSelf.otherActions indexOfObject:action];
- SPAlertControllerActionView *actionView = [strongSelf.actionSequenceView.stackView.arrangedSubviews objectAtIndex:index];
- if ([actionView isKindOfClass:[SPAlertControllerActionView class]]) {
- actionView.action = action;
- }
- }
- }
- if (strongSelf.presentationController.presentingViewController && needUpdateConstraints) { // 如果在present完成后的某个时刻再去设置action的属性,字体等改变需要更新布局
- [strongSelf.actionSequenceView setNeedsUpdateConstraints];
- }
- };
-}
-
-// 添加文本输入框
-- (void)addTextFieldWithConfigurationHandler:(void (^)(UITextField * _Nonnull))configurationHandler {
- NSString *errorDesc = [NSString stringWithFormat:@"SPAlertController does not allow '%@' to be called in the style of SPAlertControllerStyleActionSheet",NSStringFromSelector(_cmd)];
- NSAssert(self.preferredStyle == SPAlertControllerStyleAlert,errorDesc);
- UITextField *textField = [[UITextField alloc] init];
- textField.translatesAutoresizingMaskIntoConstraints = NO;
- textField.backgroundColor = [UIColor whiteColor];
- // 系统的UITextBorderStyleLine样式线条过于黑,所以自己设置
- textField.layer.borderWidth = SP_LINE_WIDTH;
- textField.layer.borderColor = [UIColor grayColor].CGColor;
- // 在左边设置一张view,充当光标左边的间距,否则光标紧贴textField不美观
- textField.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 0)];
- textField.leftView.userInteractionEnabled = NO;
- textField.leftViewMode = UITextFieldViewModeAlways;
- textField.font = [UIFont systemFontOfSize:14];
- // 去掉textField键盘上部的联想条
- textField.autocorrectionType = UITextAutocorrectionTypeNo;
- [textField addTarget:self action:@selector(textFieldDidEndOnExit:) forControlEvents:UIControlEventEditingDidEndOnExit];
- NSMutableArray *array = self.textFields.mutableCopy;
- [array addObject:textField];
- self.textFields = array;
- [self.headerView addTextField:textField];
- if (configurationHandler) {
- configurationHandler(textField);
- }
-}
-
-- (void)setCustomSpacing:(CGFloat)spacing afterAction:(SPAlertAction *)action {
- if (@available(iOS 11.0, *)) {
- if (action == nil) return;
- if (action.style == SPAlertActionStyleCancel) {
- NSLog(@"*** warning in -[SPAlertController setCustomSpacing:afterAction:]: 'the -action must not be a action with SPAlertActionStyleCancel style'");
- } else if (![self.otherActions containsObject:action]) {
- NSLog(@"*** warning in -[SPAlertController setCustomSpacing:afterAction:]: 'the -action must be contained in the -actions array, not a action with SPAlertActionStyleCancel style'");
- } else {
- NSInteger index = [self.otherActions indexOfObject:action];
- [self.actionSequenceView setCustomSpacing:spacing afterActionIndex:index];
- }
- } else {
- // 报异常
- [self doesNotRecognizeSelector:@selector(setCustomSpacing:afterAction:)];
- }
-}
-
-- (CGFloat)customSpacingAfterAction:(SPAlertAction *)action {
- if (@available(iOS 11.0, *)) {
- if ([self.otherActions containsObject:action]) {
- NSInteger index = [self.otherActions indexOfObject:action];
- return [self.actionSequenceView customSpacingAfterActionIndex:index];
- }
- } else {
- // 报异常
- [self doesNotRecognizeSelector:@selector(setCustomSpacing:afterAction:)];
- }
- return 0.0;
-}
-
-- (void)setBackgroundViewAppearanceStyle:(SPBackgroundViewAppearanceStyle)style alpha:(CGFloat)alpha {
- _backgroundViewAppearanceStyle = style;
- _backgroundViewAlpha = alpha;
-}
-
-- (void)updateCustomViewSize:(CGSize)size {
- _customViewSize = size;
- [self layoutAlertControllerView];
- [self layoutChildViews];
-}
-
-#pragma mark - Private
-- (instancetype)initWithTitle:(nullable NSString *)title message:(nullable NSString *)message customAlertView:(UIView *)customAlertView customHeaderView:(UIView *)customHeaderView customActionSequenceView:(UIView *)customActionSequenceView componentView:(UIView *)componentView preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType {
- self = [self init];
- _title = title;
- _message = message;
- _preferredStyle = preferredStyle;
- // 如果是默认动画,preferredStyle为alert时动画默认为alpha,preferredStyle为actionShee时动画默认为fromBottom
- if (animationType == SPAlertAnimationTypeDefault) {
- if (preferredStyle == SPAlertControllerStyleAlert) {
- animationType = SPAlertAnimationTypeShrink;
- } else {
- animationType = SPAlertAnimationTypeFromBottom;
- }
- }
- _animationType = animationType;
- if (preferredStyle == SPAlertControllerStyleAlert) {
- _maxMarginForAlert = (MIN(SP_SCREEN_WIDTH, SP_SCREEN_HEIGHT) - 275) / 2.0;
- _minDistanceToEdges = (MIN(SP_SCREEN_WIDTH, SP_SCREEN_HEIGHT) - 275) / 2.0;
- } else {
- _minDistanceToEdges = 70;
- _maxTopMarginForActionSheet = 70;
- }
- if (preferredStyle == SPAlertControllerStyleAlert) {
- _actionAxis = UILayoutConstraintAxisHorizontal;
- } else {
- _actionAxis = UILayoutConstraintAxisVertical;
- }
- _customAlertView = customAlertView;
- _customHeaderView = customHeaderView;
- _customActionSequenceView = customActionSequenceView;
- _componentView = componentView; // componentView参数是为了支持老版本的自定义footerView
- return self;
-}
-
-- (instancetype)init {
- if (self = [super init]) {
- [self initialize];
- }
- return self;
-}
-
-- (void)initialize {
- // 视图控制器定义它呈现视图控制器的过渡风格(默认为NO)
- self.providesPresentationContextTransitionStyle = YES;
- self.definesPresentationContext = YES;
- self.modalPresentationStyle = UIModalPresentationCustom;
- self.transitioningDelegate = self;
-
- _titleFont = [UIFont boldSystemFontOfSize:18];
- _titleColor = [UIColor blackColor];
- _messageFont = [UIFont systemFontOfSize:16];
- _messageColor = [UIColor grayColor];
- _textAlignment = NSTextAlignmentCenter;
- _imageLimitSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
- _backgroundViewAlpha = 0.5;
- _cornerRadiusForAlert = 6.0;
- _tapBackgroundViewDismiss = YES;
- _needDialogBlur = YES;
- _maxNumberOfActionHorizontalArrangementForAlert = 2;
-}
-
-- (void)layoutAlertControllerView {
- if (!self.alertControllerView.superview) return;
- if (self.alertControllerViewConstraints) {
- [NSLayoutConstraint deactivateConstraints:self.alertControllerViewConstraints];
- self.alertControllerViewConstraints = nil;
- }
- if (self.preferredStyle == SPAlertControllerStyleAlert) { // alert样式
- [self layoutAlertControllerViewForAlertStyle];
- } else { // actionSheet样式
- [self layoutAlertControllerViewForActionSheetStyle];
- }
-}
-
-- (void)layoutAlertControllerViewForAlertStyle {
- UIView *alertControllerView = self.alertControllerView;
- NSMutableArray *alertControllerViewConstraints = [NSMutableArray array];
- CGFloat topValue = _minDistanceToEdges;
- CGFloat bottomValue = _minDistanceToEdges;
- CGFloat maxWidth = MIN(SP_SCREEN_WIDTH, SP_SCREEN_HEIGHT)-_minDistanceToEdges * 2;
- CGFloat maxHeight = SP_SCREEN_HEIGHT-topValue-bottomValue;
- if (!self.customAlertView) {
- // 当屏幕旋转的时候,为了保持alert样式下的宽高不变,因此取MIN(SP_SCREEN_WIDTH, SP_SCREEN_HEIGHT)
- [alertControllerViewConstraints addObject:[NSLayoutConstraint constraintWithItem:alertControllerView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:maxWidth]];
- } else {
- [alertControllerViewConstraints addObject:[NSLayoutConstraint constraintWithItem:alertControllerView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:maxWidth]];
- if (_customViewSize.width) { // 如果宽度没有值,则会假定customAlertView水平方向能由子控件撑起
- // 限制最大宽度,且能保证内部约束不报警告
- CGFloat customWidth = MIN(_customViewSize.width, maxWidth);
- [alertControllerViewConstraints addObject:[NSLayoutConstraint constraintWithItem:alertControllerView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:customWidth]];
- }
- if (_customViewSize.height) { // 如果高度没有值,则会假定customAlertView垂直方向能由子控件撑起
- CGFloat customHeight = MIN(_customViewSize.height, maxHeight);
- [alertControllerViewConstraints addObject:[NSLayoutConstraint constraintWithItem:alertControllerView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:customHeight]];
- }
- }
- NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:alertControllerView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:alertControllerView.superview attribute:NSLayoutAttributeTop multiplier:1.0f constant:topValue];
- topConstraint.priority = 999.0;// 这里优先级为999.0是为了小于垂直中心的优先级,如果含有文本输入框,键盘弹出后,特别是旋转到横屏后,对话框的空间比较小,这个时候优先偏移垂直中心,顶部优先级按理说应该会被忽略,但是由于子控件含有scrollView,所以该优先级仍然会被激活,子控件显示不全scrollView可以滑动。如果外界自定义了整个对话框,且自定义的view上含有文本输入框,子控件不含有scrollView,顶部间距会被忽略
- [alertControllerViewConstraints addObject:topConstraint];
- NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:alertControllerView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationLessThanOrEqual toItem:alertControllerView.superview attribute:NSLayoutAttributeBottom multiplier:1.0f constant:-bottomValue];
- bottomConstraint.priority = 999.0; // 优先级跟顶部同理
- [alertControllerViewConstraints addObject:bottomConstraint];
- [alertControllerViewConstraints addObject:[NSLayoutConstraint constraintWithItem:alertControllerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:alertControllerView.superview attribute:NSLayoutAttributeCenterX multiplier:1.0 constant: _offsetForAlert.x]];
- NSLayoutConstraint *alertControllerViewConstraintCenterY = [NSLayoutConstraint constraintWithItem:alertControllerView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:alertControllerView.superview attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:(self.isBeingPresented && !self.isBeingDismissed) ? 0 : _offsetForAlert.y];
- [alertControllerViewConstraints addObject:alertControllerViewConstraintCenterY];
- [NSLayoutConstraint activateConstraints:alertControllerViewConstraints];
- self.alertControllerViewConstraints = alertControllerViewConstraints;
-}
-
-- (void)layoutAlertControllerViewForActionSheetStyle {
- switch (self.animationType) {
- case SPAlertAnimationTypeFromBottom:
- case SPAlertAnimationTypeRaiseUp:
- default:
- [self layoutAlertControllerViewForAnimationTypeWithHV:@"H"
- equalAttribute:NSLayoutAttributeBottom
- notEqualAttribute:NSLayoutAttributeTop
- lessOrGreaterRelation:NSLayoutRelationGreaterThanOrEqual];
- break;
- case SPAlertAnimationTypeFromTop:
- case SPAlertAnimationTypeDropDown:
- [self layoutAlertControllerViewForAnimationTypeWithHV:@"H"
- equalAttribute:NSLayoutAttributeTop
- notEqualAttribute:NSLayoutAttributeBottom
- lessOrGreaterRelation:NSLayoutRelationLessThanOrEqual];
- break;
- case SPAlertAnimationTypeFromLeft:
- [self layoutAlertControllerViewForAnimationTypeWithHV:@"V"
- equalAttribute:NSLayoutAttributeLeft
- notEqualAttribute:NSLayoutAttributeRight
- lessOrGreaterRelation:NSLayoutRelationLessThanOrEqual];
- break;
- case SPAlertAnimationTypeFromRight:
- [self layoutAlertControllerViewForAnimationTypeWithHV:@"V"
- equalAttribute:NSLayoutAttributeLeft
- notEqualAttribute:NSLayoutAttributeRight
- lessOrGreaterRelation:NSLayoutRelationLessThanOrEqual];
- break;
- }
-}
-
-- (void)layoutAlertControllerViewForAnimationTypeWithHV:(NSString *)hv
- equalAttribute:(NSLayoutAttribute)equalAttribute
- notEqualAttribute:(NSLayoutAttribute)notEqualAttribute
- lessOrGreaterRelation:(NSLayoutRelation)relation {
- UIView *alertControllerView = self.alertControllerView;
- NSMutableArray *alertControllerViewConstraints = [NSMutableArray array];
- if (!self.customAlertView) {
- [alertControllerViewConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"%@:|-0-[alertControllerView]-0-|",hv] options:0 metrics:nil views:NSDictionaryOfVariableBindings(alertControllerView)]];
- } else {
- NSLayoutAttribute centerXorY = [hv isEqualToString:@"H"] ? NSLayoutAttributeCenterX : NSLayoutAttributeCenterY;
- [alertControllerViewConstraints addObject:[NSLayoutConstraint constraintWithItem:alertControllerView attribute:centerXorY relatedBy:NSLayoutRelationEqual toItem:alertControllerView.superview attribute:centerXorY multiplier:1.0 constant:0]];
- if (_customViewSize.width) { // 如果宽度没有值,则会假定customAlertViewh水平方向能由子控件撑起
- CGFloat alertControllerViewWidth = 0.0;
- if ([hv isEqualToString:@"H"]) {
- alertControllerViewWidth = MIN(_customViewSize.width, SP_SCREEN_WIDTH);
- } else {
- alertControllerViewWidth = MIN(_customViewSize.width, SP_SCREEN_WIDTH-_minDistanceToEdges);
- }
- [alertControllerViewConstraints addObject:[NSLayoutConstraint constraintWithItem:alertControllerView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:alertControllerViewWidth]];
- }
- if (_customViewSize.height) { // 如果高度没有值,则会假定customAlertViewh垂直方向能由子控件撑起
- CGFloat alertControllerViewHeight = 0.0;
- if ([hv isEqualToString:@"H"]) {
- alertControllerViewHeight = MIN(_customViewSize.height, SP_SCREEN_HEIGHT-_minDistanceToEdges);
- } else {
- alertControllerViewHeight = MIN(_customViewSize.height, SP_SCREEN_HEIGHT);
- }
- [alertControllerViewConstraints addObject:[NSLayoutConstraint constraintWithItem:alertControllerView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:alertControllerViewHeight]];
- }
- }
- [alertControllerViewConstraints addObject:[NSLayoutConstraint constraintWithItem:alertControllerView attribute:equalAttribute relatedBy:NSLayoutRelationEqual toItem:alertControllerView.superview attribute:equalAttribute multiplier:1.0 constant:0]];
- NSLayoutConstraint *someSideConstraint = [NSLayoutConstraint constraintWithItem:alertControllerView attribute:notEqualAttribute relatedBy:relation toItem:alertControllerView.superview attribute:notEqualAttribute multiplier:1.0 constant:_minDistanceToEdges];
- someSideConstraint.priority = 999.0;
- [alertControllerViewConstraints addObject:someSideConstraint];
- [NSLayoutConstraint activateConstraints:alertControllerViewConstraints];
- self.alertControllerViewConstraints = alertControllerViewConstraints;
-}
-
-- (void)layoutChildViews {
- // 对头部布局
- [self layoutHeaderView];
-
- // 对头部和action部分之间的分割线布局
- [self layoutHeaderActionLine];
-
- // 对组件view布局
- [self layoutComponentView];
-
- // 对组件view与action部分之间的分割线布局
- [self layoutComponentActionLine];
-
- // 对action部分布局
- [self layoutActionSequenceView];
-}
-
-// 对头部布局,高度由子控件撑起
-- (void)layoutHeaderView {
- UIView *headerView = self.customHeaderView ? self.customHeaderView : self.headerView;
- if (!headerView.superview) return;
- UIView *alertView = self.alertView;
- NSMutableArray *headerViewConstraints = [NSMutableArray array];
- if (self.headerViewConstraints) {
- [NSLayoutConstraint deactivateConstraints:self.headerViewConstraints];
- self.headerViewConstraints = nil;
- }
- if (!self.customHeaderView) {
- [headerViewConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[headerView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(headerView)]];
- } else {
- if (_customViewSize.width) {
- CGFloat maxWidth = [self maxWidth];
- CGFloat headerViewWidth = MIN(maxWidth, _customViewSize.width);
- [headerViewConstraints addObject:[NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:headerViewWidth]];
- }
- if (_customViewSize.height) {
- NSLayoutConstraint *customHeightConstraint = [NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:_customViewSize.height];
- customHeightConstraint.priority = UILayoutPriorityDefaultHigh;
- [headerViewConstraints addObject:customHeightConstraint];
- }
- [headerViewConstraints addObject:[NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:alertView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];
- }
- [headerViewConstraints addObject:[NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:alertView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];
- if (!self.headerActionLine.superview) {
- [headerViewConstraints addObject:[NSLayoutConstraint constraintWithItem:headerView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:alertView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0]];
- }
- [NSLayoutConstraint activateConstraints:headerViewConstraints];
- self.headerViewConstraints = headerViewConstraints;
-}
-
-// 对头部和action部分之间的分割线布局
-- (void)layoutHeaderActionLine {
- if (!self.headerActionLine.superview) return;
- UIView *headerActionLine = self.headerActionLine;
- UIView *headerView = self.customHeaderView ? self.customHeaderView : self.headerView;
- UIView *actionSequenceView = self.customActionSequenceView ? self.customActionSequenceView : self.actionSequenceView;
- NSMutableArray *headerActionLineConstraints = [NSMutableArray array];
- if (self.headerActionLineConstraints) {
- [NSLayoutConstraint deactivateConstraints:self.headerActionLineConstraints];
- self.headerActionLineConstraints = nil;
- }
- [headerActionLineConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[headerActionLine]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(headerActionLine)]];
- [headerActionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:headerActionLine attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:headerView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0]];
- if (!self.componentView.superview) {
- [headerActionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:headerActionLine attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:actionSequenceView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];
- }
- [headerActionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:headerActionLine attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SP_LINE_WIDTH]];
-
- [NSLayoutConstraint activateConstraints:headerActionLineConstraints];
- self.headerActionLineConstraints = headerActionLineConstraints;
-}
-
-// 对组件view布局
-- (void)layoutComponentView {
- if (!self.componentView.superview) return;
- UIView *componentView = self.componentView;
- UIView *headerActionLine = self.headerActionLine;
- UIView *componentActionLine = self.componentActionLine;
- NSMutableArray *componentViewConstraints = [NSMutableArray array];
- if (self.componentViewConstraints) {
- [NSLayoutConstraint deactivateConstraints:self.componentViewConstraints];
- self.componentViewConstraints = nil;
- }
- [componentViewConstraints addObject:[NSLayoutConstraint constraintWithItem:componentView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:headerActionLine attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0]];
- [componentViewConstraints addObject:[NSLayoutConstraint constraintWithItem:componentView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:componentActionLine attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];
- [componentViewConstraints addObject:[NSLayoutConstraint constraintWithItem:componentView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.alertView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];
- if (_customViewSize.height) {
- NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:componentView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:_customViewSize.height];
- heightConstraint.priority = UILayoutPriorityDefaultHigh; // 750
- [componentViewConstraints addObject:heightConstraint];
- }
- if (_customViewSize.width) {
- CGFloat maxWidth = [self maxWidth];
- CGFloat componentViewWidth = MIN(maxWidth, _customViewSize.width);
- [componentViewConstraints addObject:[NSLayoutConstraint constraintWithItem:componentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:componentViewWidth]];
- }
- [NSLayoutConstraint activateConstraints:componentViewConstraints];
- self.componentViewConstraints = componentViewConstraints;
-}
-
-// 对组件view和action部分之间的分割线布局
-- (void)layoutComponentActionLine {
- if (!self.componentActionLine.superview) return;
- UIView *componentActionLine = self.componentActionLine;
- NSMutableArray *componentActionLineConstraints = [NSMutableArray array];
- if (self.componentActionLineConstraints) {
- [NSLayoutConstraint deactivateConstraints:self.componentActionLineConstraints];
- self.componentActionLineConstraints = nil;
- }
- [componentActionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:componentActionLine attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.actionSequenceView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];
- [componentActionLineConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[componentActionLine]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(componentActionLine)]];
- [componentActionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:componentActionLine attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SP_LINE_WIDTH]];
- [NSLayoutConstraint activateConstraints:componentActionLineConstraints];
- self.componentActionLineConstraints = componentActionLineConstraints;
-}
-
-// 对action部分布局,高度由子控件撑起
-- (void)layoutActionSequenceView {
- UIView *actionSequenceView = self.customActionSequenceView ? self.customActionSequenceView : self.actionSequenceView;
- if (!actionSequenceView.superview) return;
- UIView *alertView = self.alertView;
- UIView *headerActionLine = self.headerActionLine;
-
- NSMutableArray *actionSequenceViewConstraints = [NSMutableArray array];
- if (self.actionSequenceViewConstraints) {
- [NSLayoutConstraint deactivateConstraints:self.actionSequenceViewConstraints];
- self.actionSequenceViewConstraints = nil;
- }
- if (!self.customActionSequenceView) {
- [actionSequenceViewConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[actionSequenceView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(actionSequenceView)]];
- } else {
-
- if (_customViewSize.width) {
- CGFloat maxWidth = [self maxWidth];
- if (_customViewSize.width > maxWidth) _customViewSize.width = maxWidth;
- [actionSequenceViewConstraints addObject:[NSLayoutConstraint constraintWithItem:actionSequenceView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:_customViewSize.width]];
- }
- if (_customViewSize.height) {
- NSLayoutConstraint *customHeightConstraint = [NSLayoutConstraint constraintWithItem:actionSequenceView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:_customViewSize.height];
- customHeightConstraint.priority = UILayoutPriorityDefaultHigh;
- [actionSequenceViewConstraints addObject:customHeightConstraint];
- }
- [actionSequenceViewConstraints addObject:[NSLayoutConstraint constraintWithItem:actionSequenceView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:alertView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];
- }
- if (!headerActionLine) {
- [actionSequenceViewConstraints addObject:[NSLayoutConstraint constraintWithItem:actionSequenceView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:alertView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];
- }
- [actionSequenceViewConstraints addObject:[NSLayoutConstraint constraintWithItem:actionSequenceView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:alertView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0]];
-
- [NSLayoutConstraint activateConstraints:actionSequenceViewConstraints];
- self.actionSequenceViewConstraints = actionSequenceViewConstraints;
-}
-
-- (CGFloat)maxWidth {
- if (self.preferredStyle == SPAlertControllerStyleAlert) {
- return MIN(SP_SCREEN_WIDTH, SP_SCREEN_HEIGHT)-_minDistanceToEdges * 2;
- } else {
- return SP_SCREEN_WIDTH;
- }
-}
-
-// 文字显示不全处理
-- (void)handleIncompleteTextDisplay {
- // alert样式下水平排列时如果文字显示不全则垂直排列
- if (!self.isForceLayout) { // 外界没有设置排列方式
- if (self.preferredStyle == SPAlertControllerStyleAlert) {
- for (SPAlertAction *action in self.actions) {
- // 预估按钮宽度
- CGFloat preButtonWidth = (MIN(SP_SCREEN_WIDTH, SP_SCREEN_HEIGHT) - _minDistanceToEdges * 2 - SP_LINE_WIDTH * (self.actions.count - 1)) / self.actions.count - action.titleEdgeInsets.left - action.titleEdgeInsets.right;
- // 如果action的标题文字总宽度,大于按钮的contentRect的宽度,则说明水平排列会导致文字显示不全,此时垂直排列
- if (action.attributedTitle) {
- if (ceil([action.attributedTitle boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, SP_ACTION_HEIGHT) options:NSStringDrawingUsesLineFragmentOrigin context:nil].size.width) > preButtonWidth) {
- _actionAxis = UILayoutConstraintAxisVertical;
- [self updateActionAxis];
- [self.actionSequenceView setNeedsUpdateConstraints];
- break; // 一定要break,只要有一个按钮文字过长就垂直排列
- }
- } else {
- if (ceil([action.title boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, SP_ACTION_HEIGHT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:action.titleFont} context:nil].size.width) > preButtonWidth) {
- _actionAxis = UILayoutConstraintAxisVertical;
- [self updateActionAxis];
- [self.actionSequenceView setNeedsUpdateConstraints];
- break;
- }
- }
- }
- }
- }
-}
-
-// 专门处理第三方IQKeyboardManager,非自定义view时禁用IQKeyboardManager移动textView/textField效果,自定义view时取消禁用
-- (void)handleIQKeyboardManager {
- SEL selector = NSSelectorFromString(@"sharedManager");
- IMP imp = [NSClassFromString(@"IQKeyboardManager") methodForSelector:selector];
- if (imp != NULL) {
- NSObject *(*func)(id, SEL) = (void *)imp;
- NSObject *mgr = func(NSClassFromString(@"IQKeyboardManager"), selector);
- if ([mgr isKindOfClass:NSClassFromString(@"IQKeyboardManager")]) {
- @try {
- NSMutableSet *disabledDistanceHandlingClasses = [mgr valueForKey:@"_disabledDistanceHandlingClasses"];
- NSMutableSet *disabledToolbarClasses = [mgr valueForKey:@"_disabledToolbarClasses"];
- if (![disabledDistanceHandlingClasses containsObject:NSClassFromString(@"SPAlertController")]) {
- [disabledDistanceHandlingClasses addObject:NSClassFromString(@"SPAlertController")];
- [disabledToolbarClasses addObject:NSClassFromString(@"SPAlertController")];
- }
- } @catch (NSException *exception) {
- NSLog(@"exception = %@",exception);
- } @finally {
-
- }
- }
- }
-}
-
-- (void)configureHeaderView {
- if (self.image) {
- self.headerView.imageLimitSize = _imageLimitSize;
- self.headerView.imageView.image = _image;
- [self.headerView setNeedsUpdateConstraints];
- }
- if(self.attributedTitle.length) {
- self.headerView.titleLabel.attributedText = self.attributedTitle;
- [self setupPreferredMaxLayoutWidthForLabel:self.headerView.titleLabel];
- } else if(self.title.length) {
- self.headerView.titleLabel.text = _title;
- self.headerView.titleLabel.font = _titleFont;
- self.headerView.titleLabel.textColor = _titleColor;
- self.headerView.titleLabel.textAlignment = _textAlignment;
- [self setupPreferredMaxLayoutWidthForLabel:self.headerView.titleLabel];
- }
- if (self.attributedMessage.length) {
- self.headerView.messageLabel.attributedText = self.attributedMessage;
- [self setupPreferredMaxLayoutWidthForLabel:self.headerView.messageLabel];
- } else if (self.message.length) {
- self.headerView.messageLabel.text = _message;
- self.headerView.messageLabel.font = _messageFont;
- self.headerView.messageLabel.textColor = _messageColor;
- self.headerView.messageLabel.textAlignment = _textAlignment;
- [self setupPreferredMaxLayoutWidthForLabel:self.headerView.messageLabel];
- }
-}
-
-- (void)setupPreferredMaxLayoutWidthForLabel:(UILabel *)textLabel {
- if (self.preferredStyle == SPAlertControllerStyleAlert) {
- textLabel.preferredMaxLayoutWidth = MIN(SP_SCREEN_WIDTH, SP_SCREEN_HEIGHT) - self.minDistanceToEdges * 2 - self.headerView.contentEdgeInsets.left - self.headerView.contentEdgeInsets.right;
- } else {
- textLabel.preferredMaxLayoutWidth = SP_SCREEN_WIDTH - self.headerView.contentEdgeInsets.left - self.headerView.contentEdgeInsets.right;
- }
-}
-
-// 这个方法是实现点击回车切换到下一个textField,如果没有下一个,会自动退出键盘. 不能在代理方法里实现,因为如果设置了代理,外界就不能成为textFiled的代理了,通知也监听不到回车
-- (void)textFieldDidEndOnExit:(UITextField *)textField {
- NSInteger index = [self.textFields indexOfObject:textField];
- if (self.textFields.count > index+1) {
- UITextField *nextTextField = [self.textFields objectAtIndex:index+1];
- [textField resignFirstResponder];
- [nextTextField becomeFirstResponder];
- }
-}
-
-// 更新action的排列方式
-- (void)updateActionAxis {
- self.actionSequenceView.axis = _actionAxis;
- if (_actionAxis == UILayoutConstraintAxisVertical) {
- self.actionSequenceView.stackViewDistribution = UIStackViewDistributionFillProportionally;// 布局方式为子控件自适应内容高度
- } else {
- self.actionSequenceView.stackViewDistribution = UIStackViewDistributionFillEqually; // 布局方式为子控件等宽
- }
-}
-
-// 该方法是保证被废弃的maxNumberOfActionHorizontalArrangementForAlert属性的有效性
-- (void)setupActionAxis {
- if (self.preferredStyle == SPAlertControllerStyleAlert) {
- if (self.actions.count > self.maxNumberOfActionHorizontalArrangementForAlert) {
- _actionAxis = UILayoutConstraintAxisVertical;
- [self updateActionAxis];
- } else {
- _actionAxis = UILayoutConstraintAxisHorizontal;
- [self updateActionAxis];
- }
- }
-}
-
-- (void)makeViewOffsetWithAnimated:(BOOL)animated {
- if (!self.beingPresented && !self.beingDismissed) {
- [self layoutAlertControllerView];
- if (animated) {
- [UIView animateWithDuration:0.25 animations:^{
- [self.view.superview layoutIfNeeded];
- }];
- }
- }
-}
-
-// 获取自定义view的大小
-- (CGSize)sizeForCustomView:(UIView *)customView {
- [customView layoutIfNeeded];
- CGSize settingSize = customView.frame.size;
- CGSize fittingSize = [customView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
- return CGSizeMake(MAX(settingSize.width, fittingSize.width), MAX(settingSize.height, fittingSize.height));
-}
-
-#pragma mark - system methods
-
-- (void)loadView {
- // 重新创建self.view,这样可以采用自己的一套布局,轻松改变控制器view的大小
- self.view = self.alertControllerView;
-}
-
-- (void)viewDidLoad {
- [super viewDidLoad];
-
- [self configureHeaderView];
-
- self.needDialogBlur = _needDialogBlur;
-
- self.automaticallyAdjustsScrollViewInsets = NO;
-
-}
-
-- (void)viewWillAppear:(BOOL)animated {
- [super viewWillAppear:animated];
-
- [self handleIQKeyboardManager];
-
- if (!_isForceOffset && !_customAlertView && !_customHeaderView && !_customActionSequenceView && !_componentView) {
- // 监听键盘改变frame,键盘frame改变需要移动对话框
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardFrameWillChange:) name:UIKeyboardWillChangeFrameNotification object:nil];
- }
- if (self.textFields.count) {
- UITextField *firstTextfield = [self.textFields firstObject];
- if (!firstTextfield.isFirstResponder) {
- [firstTextfield becomeFirstResponder];
- }
- }
-}
-
-- (void)viewWillLayoutSubviews {
- [super viewWillLayoutSubviews];
- // 屏幕旋转后宽高发生了交换,头部的label最大宽度需要重新计算
- [self setupPreferredMaxLayoutWidthForLabel:self.headerView.titleLabel];
- [self setupPreferredMaxLayoutWidthForLabel:self.headerView.messageLabel];
- // 对自己创建的alertControllerView布局,在这个方法里,self.view才有父视图,有父视图才能改变其约束
- [self layoutAlertControllerView];
- [self layoutChildViews];
-}
-
-- (void)viewDidLayoutSubviews {
- [super viewDidLayoutSubviews];
- [self handleIncompleteTextDisplay];
-}
-
-- (void)viewDidAppear:(BOOL)animated {
- [super viewDidAppear:animated];
-
-}
-
-- (void)viewWillDisappear:(BOOL)animated {
- [super viewWillDisappear:animated];
-}
-
-- (void)viewDidDisappear:(BOOL)animated {
- [super viewDidDisappear:animated];
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
-}
-
-#pragma mark - 键盘通知
-
-- (void)keyboardFrameWillChange:(NSNotification *)notification {
- if (!_isForceOffset) {
- CGRect keyboardEndFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
- CGFloat keyboardEndY = keyboardEndFrame.origin.y;
- CGFloat diff = fabs((SP_SCREEN_HEIGHT-keyboardEndY)*0.5);
- _offsetForAlert.y = -diff;
- [self makeViewOffsetWithAnimated:YES];
- }
-}
-
-#pragma mark - setterx
-
-- (void)setTitle:(NSString *)title {
- _title = title;
- if (self.isViewLoaded) { // 如果条件为真,说明外界在对title赋值之前就已经使用了self.view,先走了viewDidLoad方法,如果先走的viewDidLoad,需要在title的setter方法中重新设置数据,以下setter方法中的条件同理
- self.headerView.titleLabel.text = title;
- // 文字发生变化后再更新布局,这里更新布局也不是那么重要,因为headerView中的布局方法只有当SPAlertController被present后才会走一次,而那时候,一般title,titleFont、message、messageFont等都是最新值,这里防止的是:在SPAlertController被present后的某个时刻再去设置title,titleFont等,我们要更新布局
- if (self.presentationController.presentingViewController) { // 这个if条件的意思是当SPAlertController被present后的某个时刻设置了title,如果在present之前设置的就不用更新,系统会主动更新
- [self.headerView setNeedsUpdateConstraints];
- }
- }
-}
-
-- (void)setTitleFont:(UIFont *)titleFont {
- _titleFont = titleFont;
- if (self.isViewLoaded) {
- self.headerView.titleLabel.font = titleFont;
- if (self.presentationController.presentingViewController) {
- [self.headerView setNeedsUpdateConstraints];
- }
- }
-}
-
-- (void)setTitleColor:(UIColor *)titleColor {
- _titleColor = titleColor;
- if (self.isViewLoaded) {
- self.headerView.titleLabel.textColor = titleColor;
- }
-}
-
-- (void)setMessage:(NSString *)message {
- _message = message;
- if (self.isViewLoaded) {
- self.headerView.messageLabel.text = message;
- if (self.presentationController.presentingViewController) {
- [self.headerView setNeedsUpdateConstraints];
- }
- }
-}
-
-- (void)setMessageFont:(UIFont *)messageFont {
- _messageFont = messageFont;
- if (self.isViewLoaded) {
- self.headerView.messageLabel.font = messageFont;
- if (self.presentationController.presentingViewController) {
- [self.headerView setNeedsUpdateConstraints];
- }
- }
-}
-
-- (void)setMessageColor:(UIColor *)messageColor {
- _messageColor = messageColor;
- if (self.isViewLoaded) {
- self.headerView.messageLabel.textColor = messageColor;
- }
-}
-
-- (void)setTextAlignment:(NSTextAlignment)textAlignment {
- _textAlignment = textAlignment;
- self.headerView.titleLabel.textAlignment = _textAlignment;
- self.headerView.messageLabel.textAlignment = _textAlignment;
-}
-
-- (void)setIcon:(UIImage *)image {
- _image = image;
- if (self.isViewLoaded) {
- self.headerView.imageView.image = _image;
- if (self.presentationController.presentingViewController) {
- [self.headerView setNeedsUpdateConstraints];
- }
- }
-}
-
-- (void)setIconLimitSize:(CGSize)imageLimitSize {
- _imageLimitSize = imageLimitSize;
- if (self.isViewLoaded) {
- self.headerView.imageLimitSize = _imageLimitSize;
- if (self.presentationController.presentingViewController) {
- [self.headerView setNeedsUpdateConstraints];
- }
- }
-}
-
-- (void)setAttributedTitle:(NSAttributedString *)attributedTitle {
- _attributedTitle = attributedTitle;
- if (self.isViewLoaded) {
- self.headerView.titleLabel.attributedText = _attributedTitle;
- if (self.presentationController.presentingViewController) {
- [self.headerView setNeedsUpdateConstraints];
- }
- }
-}
-
-- (void)setAttributedMessage:(NSAttributedString *)attributedMessage {
- _attributedMessage = attributedMessage;
- if (self.isViewLoaded) {
- self.headerView.messageLabel.attributedText = _attributedMessage;
- if (self.presentationController.presentingViewController) {
- [self.headerView setNeedsUpdateConstraints];
- }
- }
-}
-
-// 该属性3.0版本开始被废弃
-- (void)setMaxMarginForAlert:(CGFloat)maxMarginForAlert {
- _maxMarginForAlert = maxMarginForAlert;
- self.minDistanceToEdges = _maxMarginForAlert;
-}
-
-// 该属性3.0版本开始被废弃
-- (void)setMaxTopMarginForActionSheet:(CGFloat)maxTopMarginForActionSheet {
- _maxTopMarginForActionSheet = maxTopMarginForActionSheet;
- self.minDistanceToEdges = _maxTopMarginForActionSheet;
-}
-
-- (void)setMinDistanceToEdges:(CGFloat)minDistanceToEdges {
- _minDistanceToEdges = minDistanceToEdges;
- if (self.isViewLoaded) {
- [self setupPreferredMaxLayoutWidthForLabel:self.headerView.titleLabel];
- [self setupPreferredMaxLayoutWidthForLabel:self.headerView.messageLabel];
- if (self.presentationController.presentingViewController) {
- [self layoutAlertControllerView];
- [self.headerView setNeedsUpdateConstraints];
- [self.actionSequenceView setNeedsUpdateConstraints];
- }
- }
-}
-
-- (void)setCornerRadiusForAlert:(CGFloat)cornerRadiusForAlert {
- _cornerRadiusForAlert = cornerRadiusForAlert;
- if (self.preferredStyle == SPAlertControllerStyleAlert) {
- self.containerView.layer.cornerRadius = _cornerRadiusForAlert;
- self.containerView.layer.masksToBounds = YES;
- }
-}
-
-// 此属性3.0版本开始被废弃
-- (void)setMaxNumberOfActionHorizontalArrangementForAlert:(NSInteger)maxNumberOfActionHorizontalArrangementForAlert {
- _maxNumberOfActionHorizontalArrangementForAlert = maxNumberOfActionHorizontalArrangementForAlert;
- // 被废弃的maxNumberOfActionHorizontalArrangementForAlert属性需要的方法
- [self setupActionAxis];
-}
-
-- (void)setActionAxis:(UILayoutConstraintAxis)actionAxis {
- _actionAxis = actionAxis;
- // 调用该setter方法则认为是强制布局,该setter方法只有外界能调,这样才能判断外界有没有调用actionAxis的setter方法,从而是否按照外界的指定布局方式进行布局
- _isForceLayout = YES;
-
- [self updateActionAxis];
-}
-
-- (void)setOffsetForAlert:(CGPoint)offsetForAlert {
- _offsetForAlert = offsetForAlert;
- _isForceOffset = YES;
- [self makeViewOffsetWithAnimated:NO];
-}
-
-// 被废弃
-- (void)setOffsetYForAlert:(CGFloat)offsetYForAlert {
- _offsetYForAlert = offsetYForAlert;
- _offsetForAlert.y = _offsetYForAlert;
- _isForceOffset = YES;
-}
-
-- (void)setNeedDialogBlur:(BOOL)needDialogBlur {
- _needDialogBlur = needDialogBlur;
- if (_needDialogBlur) {
- self.containerView.backgroundColor = [UIColor clearColor];
- self.dimmingKnockoutBackdropView = [NSClassFromString(@"_UIDimmingKnockoutBackdropView") alloc];
- if (self.dimmingKnockoutBackdropView) {
- // 下面4行相当于self.dimmingKnockoutBackdropView = [self.dimmingKnockoutBackdropView performSelector:NSSelectorFromString(@"initWithStyle:") withObject:@(UIBlurEffectStyleLight)];
- SEL selector = NSSelectorFromString(@"initWithStyle:");
- IMP imp = [self.dimmingKnockoutBackdropView methodForSelector:selector];
- UIView *(*func)(id, SEL,UIBlurEffectStyle) = (void *)imp;
- self.dimmingKnockoutBackdropView = func(self.dimmingKnockoutBackdropView, selector, UIBlurEffectStyleLight);
- self.dimmingKnockoutBackdropView.frame = self.containerView.bounds;
- self.dimmingKnockoutBackdropView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- [self.containerView insertSubview:self.dimmingKnockoutBackdropView atIndex:0];
- } else { // 这个else是防止假如_UIDimmingKnockoutBackdropView这个类不存在了的时候,做一个备案,不过apple应该不会废弃某个类
- UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight];
- self.dimmingKnockoutBackdropView = [[UIVisualEffectView alloc] initWithEffect:blur];
- self.dimmingKnockoutBackdropView.frame = self.containerView.bounds;
- self.dimmingKnockoutBackdropView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
- [self.containerView insertSubview:self.dimmingKnockoutBackdropView atIndex:0];
- }
- } else {
- [self.dimmingKnockoutBackdropView removeFromSuperview];
- self.dimmingKnockoutBackdropView = nil;
- if (_customAlertView) {
- self.containerView.backgroundColor = [UIColor clearColor];
- } else {
- self.containerView.backgroundColor = [UIColor whiteColor];
- }
- }
-}
-
-#pragma mark - lazy load
-
-- (UIView *)alertControllerView {
- if (!_alertControllerView) {
- UIView *alertControllerView = [[UIView alloc] init];
- alertControllerView.translatesAutoresizingMaskIntoConstraints = NO;
- _alertControllerView = alertControllerView;
- }
- return _alertControllerView;
-}
-
-- (UIView *)containerView {
- if (!_containerView) {
- UIView *containerView = [[UIView alloc] init];
- containerView.frame = self.alertControllerView.bounds;
- containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- if (_preferredStyle == SPAlertControllerStyleAlert) {
- containerView.layer.cornerRadius = _cornerRadiusForAlert;
- containerView.layer.masksToBounds = YES;
- }
- [self.alertControllerView addSubview:containerView];
- _containerView = containerView;
- }
- return _containerView;
-}
-
-- (UIView *)alertView {
- if (!_alertView) {
- UIView *alertView = [[UIView alloc] init];
- alertView.frame = self.alertControllerView.bounds;
- alertView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- if (!self.customAlertView) {
- [self.containerView addSubview:alertView];
- }
- _alertView = alertView;
- }
- return _alertView;
-}
-
-- (UIView *)customAlertView {
- // customAlertView有值但是没有父view
- if (_customAlertView && !_customAlertView.superview) {
- if (CGSizeEqualToSize(_customViewSize, CGSizeZero)) {
- // 获取_customAlertView的大小
- _customViewSize = [self sizeForCustomView:_customAlertView];
- }
- // 必须在在下面2行代码之前获取_customViewSize
- _customAlertView.frame = self.alertControllerView.bounds;
- _customAlertView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- [self.containerView addSubview:_customAlertView];
- }
- return _customAlertView;
-}
-
-- (SPInterfaceHeaderScrollView *)headerView {
- if (!_headerView) {
- SPInterfaceHeaderScrollView *headerView = [[SPInterfaceHeaderScrollView alloc] init];
- headerView.backgroundColor = SP_NORMAL_COLOR;
- headerView.translatesAutoresizingMaskIntoConstraints = NO;
- __weak typeof(self) weakSelf = self;
- headerView.headerViewSfeAreaDidChangBlock = ^{
- [weakSelf setupPreferredMaxLayoutWidthForLabel:weakSelf.headerView.titleLabel];
- [weakSelf setupPreferredMaxLayoutWidthForLabel:weakSelf.headerView.messageLabel];
- };
- if (!self.customHeaderView) {
- if ((self.title.length || self.attributedTitle.length || self.message.length || self.attributedMessage.length || self.textFields.count || self.image)) {
- [self.alertView addSubview:headerView];
- }
- }
- _headerView = headerView;
- }
- return _headerView;
-}
-
-- (UIView *)customHeaderView {
- // _customHeaderView有值但是没有父view
- if (_customHeaderView && !_customHeaderView.superview) {
- // 获取_customHeaderView的大小
- if (CGSizeEqualToSize(_customViewSize, CGSizeZero)) {
- // 获取_customHeaderView的大小
- _customViewSize = [self sizeForCustomView:_customHeaderView];
- }
- _customHeaderView.translatesAutoresizingMaskIntoConstraints = NO;
- [self.alertView addSubview:_customHeaderView];
- }
- return _customHeaderView;
-}
-
-- (SPInterfaceActionSequenceView *)actionSequenceView {
- if (!_actionSequenceView) {
- SPInterfaceActionSequenceView *actionSequenceView = [[SPInterfaceActionSequenceView alloc] init];
- actionSequenceView.translatesAutoresizingMaskIntoConstraints = NO;
- __weak typeof(self) weakSelf = self;
- actionSequenceView.buttonClickedInActionViewBlock = ^(NSInteger index) {
- [weakSelf dismissViewControllerAnimated:YES completion:nil];
- SPAlertAction *action = weakSelf.actions[index];
- action.handler(action);
- };
- if (self.actions.count && !self.customActionSequenceView) {
- [self.alertView addSubview:actionSequenceView];
- }
- _actionSequenceView = actionSequenceView;
- }
- return _actionSequenceView;
-}
-
-- (UIView *)customActionSequenceView {
- // _customActionSequenceView有值但是没有父view
- if (_customActionSequenceView && !_customActionSequenceView.superview) {
- // 获取_customHeaderView的大小
- if (CGSizeEqualToSize(_customViewSize, CGSizeZero)) {
- // 获取_customActionSequenceView的大小
- _customViewSize = [self sizeForCustomView:_customActionSequenceView];
- }
- _customActionSequenceView.translatesAutoresizingMaskIntoConstraints = NO;
- [self.alertView addSubview:_customActionSequenceView];
- }
- return _customActionSequenceView;
-}
-
-- (SPInterfaceActionItemSeparatorView *)headerActionLine {
- if (!_headerActionLine) {
- SPInterfaceActionItemSeparatorView *headerActionLine = [[SPInterfaceActionItemSeparatorView alloc] init];
- headerActionLine.translatesAutoresizingMaskIntoConstraints = NO;
- if ((self.headerView.superview || self.customHeaderView.superview) && (self.actionSequenceView.superview || self.customActionSequenceView.superview)) {
- [self.alertView addSubview:headerActionLine];
- }
- _headerActionLine = headerActionLine;
- }
- return _headerActionLine;
-}
-
-- (UIView *)componentView {
- if (_componentView && !_componentView.superview) {
- NSAssert(self.headerActionLine.superview, @"Due to the -componentView is added between the -head and the -action section, the -head and -action must exist together");
- // 获取_componentView的大小
- if (CGSizeEqualToSize(_customViewSize, CGSizeZero)) {
- // 获取_componentView的大小
- _customViewSize = [self sizeForCustomView:_componentView];
- }
- _componentView.translatesAutoresizingMaskIntoConstraints = NO;
- [self.alertView addSubview:_componentView];
- }
- return _componentView;
-}
-
-- (SPInterfaceActionItemSeparatorView *)componentActionLine {
- if (!_componentActionLine) {
- SPInterfaceActionItemSeparatorView *componentActionLine = [[SPInterfaceActionItemSeparatorView alloc] init];
- componentActionLine.translatesAutoresizingMaskIntoConstraints = NO;
- // 必须组件view和action部分同时存在
- if (self.componentView.superview && (self.actionSequenceView.superview || self.customActionSequenceView.superview)) {
- [self.alertView addSubview:componentActionLine];
- }
- _componentActionLine = componentActionLine;
- }
- return _componentActionLine;
-}
-
-- (NSArray *)actions {
- if (!_actions) {
- _actions = [NSArray array];
- }
- return _actions;
-}
-
-- (NSArray *)textFields {
- if (!_textFields) {
- _textFields = [NSArray array];
- }
- return _textFields;
-}
-
-- (NSMutableArray *)otherActions {
- if (!_otherActions) {
- _otherActions = [[NSMutableArray alloc] init];
- }
- return _otherActions;
-}
-
-#pragma mark - UIViewControllerTransitioningDelegate
-- (nullable id )animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
- return [SPAlertAnimation animationIsPresenting:YES];
-}
-
-- (nullable id )animationControllerForDismissedController:(UIViewController *)dismissed {
- [self.view endEditing:YES];
- return [SPAlertAnimation animationIsPresenting:NO];
-}
-
-- (nullable UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(nullable UIViewController *)presenting sourceViewController:(UIViewController *)source NS_AVAILABLE_IOS(8_0) {
- return [[SPAlertPresentationController alloc] initWithPresentedViewController:presented presentingViewController:presenting];
-}
-
-#pragma mark - 被废弃的方法
-
-+ (instancetype)alertControllerWithTitle:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType customView:(UIView *)customView {
- SPAlertController *alertVc = [[SPAlertController alloc] initWithTitle:nil message:nil customAlertView:customView customHeaderView:nil customActionSequenceView:nil componentView:nil preferredStyle:preferredStyle animationType:animationType];
- return alertVc;
-}
-+ (instancetype)alertControllerWithPreferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType customHeaderView:(nullable UIView *)customHeaderView {
- SPAlertController *alertVc = [[SPAlertController alloc] initWithTitle:nil message:nil customAlertView:nil customHeaderView:customHeaderView customActionSequenceView:nil componentView:nil preferredStyle:preferredStyle animationType:animationType];
- return alertVc;
-}
-+ (instancetype)alertControllerWithTitle:(NSString *)title message:(NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType customCenterView:(UIView *)customCenterView {
- SPAlertController *alertVc = [[SPAlertController alloc] initWithTitle:title message:message customAlertView:nil customHeaderView:nil customActionSequenceView:nil componentView:customCenterView preferredStyle:preferredStyle animationType:animationType];
- return alertVc;
-}
-+ (instancetype)alertControllerWithTitle:(NSString *)title message:(NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType customFooterView:(UIView *)customFooterView {
- SPAlertController *alertVc = [[SPAlertController alloc] initWithTitle:title message:message customAlertView:nil customHeaderView:nil customActionSequenceView:customFooterView componentView:nil preferredStyle:preferredStyle animationType:animationType];
- return alertVc;
-}
-
-@end
-
-#pragma mark ---------------------------- SPAlertController end --------------------------------
-
-@interface SPOverlayView: UIView
-@property (nonatomic, strong) UIView *presentedView;
-@property (nonatomic, strong) UIVisualEffectView *effectView;
-@end
-
-@implementation SPOverlayView
-
-- (instancetype)initWithFrame:(CGRect)frame {
- if (self = [super initWithFrame:frame]) {
-
- }
- return self;
-}
-- (void)setAppearanceStyle:(SPBackgroundViewAppearanceStyle)appearanceStyle alpha:(CGFloat)alpha {
- switch (appearanceStyle) {
- case SPBackgroundViewAppearanceStyleTranslucent: {
- [self.effectView removeFromSuperview];
- self.effectView = nil;
- if (alpha < 0) {
- alpha = 0.5;
- }
- self.backgroundColor = [UIColor colorWithWhite:0 alpha:alpha];
- self.alpha = 0;
- }
- break;
- case SPBackgroundViewAppearanceStyleBlurExtraLight: {
- UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight];
- [self createVisualEffectViewWithBlur:blur alpha:alpha];
- }
- break;
- case SPBackgroundViewAppearanceStyleBlurLight: {
- UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
- [self createVisualEffectViewWithBlur:blur alpha:alpha];
- }
- break;
- case SPBackgroundViewAppearanceStyleBlurDark: {
- UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
- [self createVisualEffectViewWithBlur:blur alpha:alpha];
- }
- break;
- }
-}
-
-- (void)createVisualEffectViewWithBlur:(UIBlurEffect *)blur alpha:(CGFloat)alpha {
- self.backgroundColor = [UIColor clearColor];
- UIVisualEffectView *effectView = [[UIVisualEffectView alloc] initWithEffect:blur];
- effectView.frame = self.bounds;
- effectView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
- effectView.userInteractionEnabled = NO;
- effectView.alpha = alpha;
- [self addSubview:effectView];
- _effectView = effectView;
-}
-
-@end
-
-#pragma mark ---------------------------- SPAlertPresentationController begin --------------------------------
-
-@interface SPAlertPresentationController()
-@property (nonatomic, strong) SPOverlayView *overlayView;
-@end
-
-@implementation SPAlertPresentationController
-
-- (instancetype)initWithPresentedViewController:(UIViewController *)presentedViewController presentingViewController:(UIViewController *)presentingViewController {
- if (self = [super initWithPresentedViewController:presentedViewController presentingViewController:presentingViewController]) {
- }
- return self;
-}
-
-- (void)containerViewWillLayoutSubviews {
- [super containerViewWillLayoutSubviews];
- self.overlayView.frame = self.containerView.bounds;
-}
-
-- (void)containerViewDidLayoutSubviews {
- [super containerViewDidLayoutSubviews];
-
-}
-
-- (void)presentationTransitionWillBegin {
- [super presentationTransitionWillBegin];
-
- SPAlertController *alertController = (SPAlertController *)self.presentedViewController;
-
- [self.overlayView setAppearanceStyle:alertController.backgroundViewAppearanceStyle alpha:alertController.backgroundViewAlpha];
-
- // 遮罩的alpha值从0~1变化,UIViewControllerTransitionCoordinator协是一个过渡协调器,当执行模态过渡或push过渡时,可以对视图中的其他部分做动画
- id coordinator = [self.presentedViewController transitionCoordinator];
- if (coordinator) {
- [coordinator animateAlongsideTransition:^(id context) {
- self.overlayView.alpha = 1.0;
- } completion:nil];
- } else {
- self.overlayView.alpha = 1.0;
- }
- if ([alertController.delegate respondsToSelector:@selector(willPresentAlertController:)]) {
- [alertController.delegate willPresentAlertController:alertController];
- } else if ([alertController.delegate respondsToSelector:@selector(sp_alertControllerWillShow:)]) { // 支持老版本
- [alertController.delegate sp_alertControllerWillShow:alertController];
- }
-}
-
-- (void)presentationTransitionDidEnd:(BOOL)completed {
- [super presentationTransitionDidEnd:completed];
-
- SPAlertController *alertController = (SPAlertController *)self.presentedViewController;
- if ([alertController.delegate respondsToSelector:@selector(didPresentAlertController:)]) {
- [alertController.delegate didPresentAlertController:alertController];
- } else if ([alertController.delegate respondsToSelector:@selector(sp_alertControllerDidShow:)]) { // 支持老版本
- [alertController.delegate sp_alertControllerDidShow:alertController];
- }
-}
-
-- (void)dismissalTransitionWillBegin {
- [super dismissalTransitionWillBegin];
- // 遮罩的alpha值从1~0变化,UIViewControllerTransitionCoordinator协议执行动画可以保证和转场动画同步
- id coordinator = [self.presentedViewController transitionCoordinator];
- if (coordinator) {
- [coordinator animateAlongsideTransition:^(id context) {
- self.overlayView.alpha = 0.0;
- } completion:nil];
- } else {
- self.overlayView.alpha = 0.0;
- }
- SPAlertController *alertController = (SPAlertController *)self.presentedViewController;
- if ([alertController.delegate respondsToSelector:@selector(willDismissAlertController:)]) {
- [alertController.delegate willDismissAlertController:alertController];
- } else if ([alertController.delegate respondsToSelector:@selector(sp_alertControllerWillHide:)]) { // 支持老版本
- [alertController.delegate sp_alertControllerWillHide:alertController];
- }
-}
-
-- (void)dismissalTransitionDidEnd:(BOOL)completed {
- [super dismissalTransitionDidEnd:completed];
- if (completed) {
- [_overlayView removeFromSuperview];
- _overlayView = nil;
- }
- SPAlertController *alertController = (SPAlertController *)self.presentedViewController;
- if ([alertController.delegate respondsToSelector:@selector(didDismissAlertController:)]) {
- [alertController.delegate didDismissAlertController:alertController];
- } else if ([alertController.delegate respondsToSelector:@selector(sp_alertControllerDidHide:)]) { // 支持老版本
- [alertController.delegate sp_alertControllerDidHide:alertController];
- }
-}
-
-- (CGRect)frameOfPresentedViewInContainerView{
- return self.presentedView.frame;
-}
-
-- (void)tapOverlayView {
- SPAlertController *alertController = (SPAlertController *)self.presentedViewController;
- [alertController dismissViewControllerAnimated:YES completion:^{}];
-}
-
-- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
-}
-
-- (SPOverlayView *)overlayView {
- if (!_overlayView) {
- _overlayView = [[SPOverlayView alloc] init];
- _overlayView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapOverlayView)];
- [_overlayView addGestureRecognizer:tap];
- [self.containerView addSubview:_overlayView];
- }
- return _overlayView;
-}
-
-@end
-
-#pragma mark ---------------------------- SPAlertPresentationController end --------------------------------
-
-
-#pragma mark ---------------------------- SPAlertAnimation begin --------------------------------
-
-@interface SPAlertAnimation()
-@property (nonatomic, assign) BOOL presenting;
-@end
-
-@implementation SPAlertAnimation
-
-+ (instancetype)animationIsPresenting:(BOOL)isPresenting {
- return [[self alloc] initWithPresenting:isPresenting];
-}
-
-- (instancetype)initWithPresenting:(BOOL)isPresenting {
- if (self = [super init]) {
- self.presenting = isPresenting;
- }
- return self;
-}
-
-#pragma mark - UIViewControllerAnimatedTransitioning
-- (NSTimeInterval)transitionDuration:(nullable id )transitionContext {
- return 0.25f;
-}
-
-- (void)animateTransition:(id )transitionContext {
- if (self.presenting) {
- [self presentAnimationTransition:transitionContext];
- } else {
- [self dismissAnimationTransition:transitionContext];
- }
-}
-
-- (void)presentAnimationTransition:(id)transitionContext {
- SPAlertController *alertController = (SPAlertController *)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
-
- switch (alertController.animationType) {
- case SPAlertAnimationTypeRaiseUp:
- case SPAlertAnimationTypeFromBottom:
- [self raiseUpWhenPresentForController:alertController transition:transitionContext];
- break;
- case SPAlertAnimationTypeFromRight:
- [self fromRightWhenPresentForController:alertController transition:transitionContext];
- break;
- case SPAlertAnimationTypeDropDown:
- case SPAlertAnimationTypeFromTop:
- [self dropDownWhenPresentForController:alertController transition:transitionContext];
- break;
- case SPAlertAnimationTypeFromLeft:
- [self fromLeftWhenPresentForController:alertController transition:transitionContext];
- break;
- case SPAlertAnimationTypeAlpha:
- case SPAlertAnimationTypeFade:
- [self alphaWhenPresentForController:alertController transition:transitionContext];
- break;
- case SPAlertAnimationTypeExpand:
- [self expandWhenPresentForController:alertController transition:transitionContext];
- break;
- case SPAlertAnimationTypeShrink:
- [self shrinkWhenPresentForController:alertController transition:transitionContext];
- break;
- case SPAlertAnimationTypeNone:
- [self noneWhenPresentForController:alertController transition:transitionContext];
- break;
- default:
- break;
- }
-}
-
-- (void)dismissAnimationTransition:(id)transitionContext {
- SPAlertController *alertController = (SPAlertController *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
- if ([alertController isKindOfClass:[SPAlertController class]]) {
- switch (alertController.animationType) {
- case SPAlertAnimationTypeRaiseUp:
- case SPAlertAnimationTypeFromBottom:
- [self dismissCorrespondingRaiseUpForController:alertController transition:transitionContext];
- break;
- case SPAlertAnimationTypeFromRight:
- [self dismissCorrespondingFromRightForController:alertController transition:transitionContext];
- break;
- case SPAlertAnimationTypeFromLeft:
- [self dismissCorrespondingFromLeftForController:alertController transition:transitionContext];
- break;
- case SPAlertAnimationTypeDropDown:
- case SPAlertAnimationTypeFromTop:
- [self dismissCorrespondingDropDownForController:alertController transition:transitionContext];
- break;
- case SPAlertAnimationTypeAlpha:
- case SPAlertAnimationTypeFade:
- [self dismissCorrespondingAlphaForController:alertController transition:transitionContext];
- break;
- case SPAlertAnimationTypeExpand:
- [self dismissCorrespondingExpandForController:alertController transition:transitionContext];
- break;
- case SPAlertAnimationTypeShrink:
- [self dismissCorrespondingShrinkForController:alertController transition:transitionContext];
- break;
- case SPAlertAnimationTypeNone:
- [self dismissCorrespondingNoneForController:alertController transition:transitionContext];
- break;
- default:
- break;
- }
- }
-}
-
-// 从底部弹出的present动画
-- (void)raiseUpWhenPresentForController:(SPAlertController *)alertController transition:(id)transitionContext {
- UIView *containerView = [transitionContext containerView];
- // 将alertController的view添加到containerView上
- [containerView addSubview:alertController.view];
- // 标记需要刷新布局
- [containerView setNeedsLayout];
- // 在有标记刷新布局的情况下立即布局,这行代码很重要,第一:立即布局会立即调用SPAlertController的viewWillLayoutSubviews的方法,第二:立即布局后可以获取到alertController.view的frame
- [containerView layoutIfNeeded];
-
- // 这3行代码不能放在[containerView layoutIfNeeded]之前,如果放在之前,[containerView layoutIfNeeded]强制布局后会将以下设置的frame覆盖
- CGRect controlViewFrame = alertController.view.frame;
- controlViewFrame.origin.y = SP_SCREEN_HEIGHT;
- alertController.view.frame = controlViewFrame;
-
- [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
- CGRect controlViewFrame = alertController.view.frame;
- if (alertController.preferredStyle == SPAlertControllerStyleActionSheet) {
- controlViewFrame.origin.y = SP_SCREEN_HEIGHT-controlViewFrame.size.height;
- } else {
- controlViewFrame.origin.y = (SP_SCREEN_HEIGHT-controlViewFrame.size.height) / 2.0;
- [self offSetCenter:alertController];
- }
- alertController.view.frame = controlViewFrame;
- } completion:^(BOOL finished) {
- [transitionContext completeTransition:finished];
- [alertController layoutAlertControllerView];
- }];
-}
-
-// 从底部弹出对应的dismiss动画
-- (void)dismissCorrespondingRaiseUpForController:(SPAlertController *)alertController transition:(id)transitionContext {
-
- [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
- CGRect controlViewFrame = alertController.view.frame;
- controlViewFrame.origin.y = SP_SCREEN_HEIGHT;
- alertController.view.frame = controlViewFrame;
- } completion:^(BOOL finished) {
- [transitionContext completeTransition:finished];
- }];
-}
-
-// 从右边弹出的present动画
-- (void)fromRightWhenPresentForController:(SPAlertController *)alertController transition:(id)transitionContext {
-
- UIView *containerView = [transitionContext containerView];
- // 将alertController的view添加到containerView上
- [containerView addSubview:alertController.view];
- // 标记需要刷新布局
- [containerView setNeedsLayout];
- // 在有标记刷新布局的情况下立即布局,这行代码很重要,第一:立即布局会立即调用SPAlertController的viewWillLayoutSubviews的方法,第二:立即布局后可以获取到alertController.view的frame
- [containerView layoutIfNeeded];
-
- // 这3行代码不能放在[containerView layoutIfNeeded]之前,如果放在之前,[containerView layoutIfNeeded]强制布局后会将以下设置的frame覆盖
- CGRect controlViewFrame = alertController.view.frame;
- controlViewFrame.origin.x = SP_SCREEN_WIDTH;
- alertController.view.frame = controlViewFrame;
-
- if (alertController.preferredStyle == SPAlertControllerStyleAlert) {
- [self offSetCenter:alertController];
- }
- [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
- CGRect controlViewFrame = alertController.view.frame;
- if (alertController.preferredStyle == SPAlertControllerStyleActionSheet) {
- controlViewFrame.origin.x = SP_SCREEN_WIDTH-controlViewFrame.size.width;
- } else {
- controlViewFrame.origin.x = (SP_SCREEN_WIDTH-controlViewFrame.size.width) / 2.0;
- }
- alertController.view.frame = controlViewFrame;
- } completion:^(BOOL finished) {
- [transitionContext completeTransition:finished];
- [alertController layoutAlertControllerView];
- }];
-}
-
-// 从右边弹出对应的dismiss动画
-- (void)dismissCorrespondingFromRightForController:(SPAlertController *)alertController transition:(id)transitionContext {
-
- [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
- CGRect controlViewFrame = alertController.view.frame;
- controlViewFrame.origin.x = SP_SCREEN_WIDTH;
- alertController.view.frame = controlViewFrame;
- } completion:^(BOOL finished) {
- [transitionContext completeTransition:finished];
- }];
-}
-
-// 从左边弹出的present动画
-- (void)fromLeftWhenPresentForController:(SPAlertController *)alertController transition:(id)transitionContext {
-
- UIView *containerView = [transitionContext containerView];
- // 将alertController的view添加到containerView上
- [containerView addSubview:alertController.view];
- // 标记需要刷新布局
- [containerView setNeedsLayout];
- // 在有标记刷新布局的情况下立即布局,这行代码很重要,第一:立即布局会立即调用SPAlertController的viewWillLayoutSubviews的方法,第二:立即布局后可以获取到alertController.view的frame
- [containerView layoutIfNeeded];
-
- // 这3行代码不能放在[containerView layoutIfNeeded]之前,如果放在之前,[containerView layoutIfNeeded]强制布局后会将以下设置的frame覆盖
- CGRect controlViewFrame = alertController.view.frame;
- controlViewFrame.origin.x = -controlViewFrame.size.width;
- alertController.view.frame = controlViewFrame;
-
- if (alertController.preferredStyle == SPAlertControllerStyleAlert) {
- [self offSetCenter:alertController];
- }
- [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
- CGRect controlViewFrame = alertController.view.frame;
- if (alertController.preferredStyle == SPAlertControllerStyleActionSheet) {
- controlViewFrame.origin.x = 0;
- } else {
- controlViewFrame.origin.x = (SP_SCREEN_WIDTH-controlViewFrame.size.width) / 2.0;
- }
- alertController.view.frame = controlViewFrame;
- } completion:^(BOOL finished) {
- [transitionContext completeTransition:finished];
- [alertController layoutAlertControllerView];
- }];
-}
-
-// 从左边弹出对应的dismiss动画
-- (void)dismissCorrespondingFromLeftForController:(SPAlertController *)alertController transition:(id)transitionContext {
-
- [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
- CGRect controlViewFrame = alertController.view.frame;
- controlViewFrame.origin.x = -controlViewFrame.size.width;
- alertController.view.frame = controlViewFrame;
- } completion:^(BOOL finished) {
- [transitionContext completeTransition:finished];
- }];
-}
-
-// 从顶部弹出的present动画
-- (void)dropDownWhenPresentForController:(SPAlertController *)alertController transition:(id)transitionContext {
-
- UIView *containerView = [transitionContext containerView];
- // 将alertController的view添加到containerView上
- [containerView addSubview:alertController.view];
- // 标记需要刷新布局
- [containerView setNeedsLayout];
- // 在有标记刷新布局的情况下立即布局,这行代码很重要,第一:立即布局会立即调用SPAlertController的viewWillLayoutSubviews的方法,第二:立即布局后可以获取到alertController.view的frame
- [containerView layoutIfNeeded];
-
- // 这3行代码不能放在[containerView layoutIfNeeded]之前,如果放在之前,[containerView layoutIfNeeded]强制布局后会将以下设置的frame覆盖
- CGRect controlViewFrame = alertController.view.frame;
- controlViewFrame.origin.y = -controlViewFrame.size.height;
- alertController.view.frame = controlViewFrame;
-
- [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
- CGRect controlViewFrame = alertController.view.frame;
- if (alertController.preferredStyle == SPAlertControllerStyleActionSheet) {
- controlViewFrame.origin.y = 0;
- } else {
- controlViewFrame.origin.y = (SP_SCREEN_HEIGHT-controlViewFrame.size.height) / 2.0;
- [self offSetCenter:alertController];
- }
- alertController.view.frame = controlViewFrame;
- } completion:^(BOOL finished) {
- [transitionContext completeTransition:finished];
- [alertController layoutAlertControllerView];
- }];
-}
-
-// 从顶部弹出对应的dismiss动画
-- (void)dismissCorrespondingDropDownForController:(SPAlertController *)alertController transition:(id)transitionContext {
-
- [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
- CGRect controlViewFrame = alertController.view.frame;
- controlViewFrame.origin.y = -controlViewFrame.size.height;
- alertController.view.frame = controlViewFrame;
- } completion:^(BOOL finished) {
- [transitionContext completeTransition:finished];
- }];
-}
-
-// alpha值从0到1变化的present动画
-- (void)alphaWhenPresentForController:(SPAlertController *)alertController transition:(id)transitionContext {
-
- UIView *containerView = [transitionContext containerView];
- [containerView addSubview:alertController.view];
-
- // 标记需要刷新布局
- [containerView setNeedsLayout];
- // 在有标记刷新布局的情况下立即布局,这行代码很重要,第一:立即布局会立即调用SPAlertController的viewWillLayoutSubviews的方法,第二:立即布局后可以获取到alertController.view的frame,不仅如此,走了viewWillLayoutSubviews键盘就会弹出,此后可以获取到alertController.offset
- [containerView layoutIfNeeded];
-
- alertController.view.alpha = 0;
-
- [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
- [self offSetCenter:alertController];
- alertController.view.alpha = 1;
- } completion:^(BOOL finished) {
- [transitionContext completeTransition:finished];
- [alertController layoutAlertControllerView];
- }];
-}
-
-// alpha值从0到1变化对应的的dismiss动画
-- (void)dismissCorrespondingAlphaForController:(SPAlertController *)alertController transition:(id)transitionContext {
-
- [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
- alertController.view.alpha = 0;
- } completion:^(BOOL finished) {
- [transitionContext completeTransition:finished];
- }];
-}
-
-// 发散的prensent动画
-- (void)expandWhenPresentForController:(SPAlertController *)alertController transition:(id)transitionContext {
-
- UIView *containerView = [transitionContext containerView];
- [containerView addSubview:alertController.view];
-
- // 标记需要刷新布局
- [containerView setNeedsLayout];
- // 在有标记刷新布局的情况下立即布局,这行代码很重要,第一:立即布局会立即调用SPAlertController的viewWillLayoutSubviews的方法,第二:立即布局后可以获取到alertController.view的frame,不仅如此,走了viewWillLayoutSubviews键盘就会弹出,此后可以获取到alertController.offset
- [containerView layoutIfNeeded];
-
- alertController.view.transform = CGAffineTransformMakeScale(0.9, 0.9);
- alertController.view.alpha = 0.0;
-
- [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
- [self offSetCenter:alertController];
- alertController.view.transform = CGAffineTransformIdentity;
- alertController.view.alpha = 1.0;
- } completion:^(BOOL finished) {
- [transitionContext completeTransition:finished];
- [alertController layoutAlertControllerView];
- }];
-}
-
-// 发散对应的dismiss动画
-- (void)dismissCorrespondingExpandForController:(SPAlertController *)alertController transition:(id)transitionContext {
- [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
- alertController.view.transform = CGAffineTransformIdentity;
- alertController.view.alpha = 0.0;
- } completion:^(BOOL finished) {
- [transitionContext completeTransition:finished];
- }];
-}
-
-// 收缩的present动画
-- (void)shrinkWhenPresentForController:(SPAlertController *)alertController transition:(id)transitionContext {
-
- UIView *containerView = [transitionContext containerView];
- [containerView addSubview:alertController.view];
-
- // 标记需要刷新布局
- [containerView setNeedsLayout];
- // 在有标记刷新布局的情况下立即布局,这行代码很重要,第一:立即布局会立即调用SPAlertController的viewWillLayoutSubviews的方法,第二:立即布局后可以获取到alertController.view的frame,不仅如此,走了viewWillLayoutSubviews键盘就会弹出,此后可以获取到alertController.offset
- [containerView layoutIfNeeded];
-
- alertController.view.transform = CGAffineTransformMakeScale(1.1, 1.1);
- alertController.view.alpha = 0;
-
- [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
- [self offSetCenter:alertController];
- alertController.view.transform = CGAffineTransformIdentity;
- alertController.view.alpha = 1.0;
- } completion:^(BOOL finished) {
- [transitionContext completeTransition:finished];
- [alertController layoutAlertControllerView];
- }];
-}
-
-// 收缩对应的的dismiss动画
-- (void)dismissCorrespondingShrinkForController:(SPAlertController *)alertController transition:(id)transitionContext {
- // 与发散对应的dismiss动画相同
- [self dismissCorrespondingExpandForController:alertController transition:transitionContext];
-}
-
-// 无动画
-- (void)noneWhenPresentForController:(SPAlertController *)alertController transition:(id)transitionContext {
-
- UIView *containerView = [transitionContext containerView];
- [containerView addSubview:alertController.view];
- [transitionContext completeTransition:transitionContext.animated];
-}
-
-- (void)dismissCorrespondingNoneForController:(SPAlertController *)alertController transition:(id)transitionContext {
- [transitionContext completeTransition:transitionContext.animated];
-}
-
-- (void)offSetCenter:(SPAlertController *)alertController {
- if (!CGPointEqualToPoint(alertController.offsetForAlert, CGPointZero)) {
- CGPoint controlViewCenter = alertController.view.center;
- controlViewCenter.x = SP_SCREEN_WIDTH / 2.0 + alertController.offsetForAlert.x;
- controlViewCenter.y = SP_SCREEN_HEIGHT / 2.0 + alertController.offsetForAlert.y;
- alertController.view.center = controlViewCenter;
- }
-}
-
-@end
-#pragma clang diagnostic pop
-
-#pragma mark ---------------------------- SPAlertAnimation end --------------------------------
-
diff --git a/Example/SPAlertController/UIColor+DarkMode.h b/Example/SPAlertController/UIColor+DarkMode.h
new file mode 100644
index 0000000..e4a4cc3
--- /dev/null
+++ b/Example/SPAlertController/UIColor+DarkMode.h
@@ -0,0 +1,24 @@
+//
+// UIColor+DarkMode.h
+// SPAlertController
+//
+// Created by 乐升平 on 2020/4/26.
+// Copyright © 2020 乐升平. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface UIColor (DarkMode)
+
++ (UIColor *)alertBackgroundColor;
+
+/// 创建颜色对
+/// @param lightColor iOS13以下的系统显示的颜色或未开启深色模式下显示的颜色
+/// @param darkColor 深色模式下显示的颜色
++ (UIColor *) colorPairsWithLightColor:(UIColor *) lightColor darkColor:(UIColor *) darkColor;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Example/SPAlertController/UIColor+DarkMode.m b/Example/SPAlertController/UIColor+DarkMode.m
new file mode 100644
index 0000000..cb2f078
--- /dev/null
+++ b/Example/SPAlertController/UIColor+DarkMode.m
@@ -0,0 +1,32 @@
+//
+// UIColor+DarkMode.m
+// SPAlertController
+//
+// Created by 乐升平 on 2020/4/26.
+// Copyright © 2020 乐升平. All rights reserved.
+//
+
+#import "UIColor+DarkMode.h"
+
+@implementation UIColor (DarkMode)
+
++ (UIColor *)alertBackgroundColor {
+ return [self colorPairsWithLightColor:[[UIColor whiteColor] colorWithAlphaComponent:0.7]
+ darkColor:[UIColor colorWithRed:44.0 / 255.0 green:44.0 / 255.0 blue:44.0 / 255.0 alpha:1.0]];
+}
+
++ (UIColor *)colorPairsWithLightColor:(UIColor *)lightColor darkColor:(UIColor *)darkColor {
+ if (@available(iOS 13.0, *)) {
+ return [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
+ if(traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
+ return darkColor;
+ } else {
+ return lightColor;
+ }
+ }];
+ } else {
+ return lightColor;
+ }
+}
+
+@end
diff --git a/Example/SPAlertController/ViewController.h b/Example/SPAlertController/ViewController.h
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/ViewController.m b/Example/SPAlertController/ViewController.m
old mode 100644
new mode 100755
index e24c433..957f5ff
--- a/Example/SPAlertController/ViewController.m
+++ b/Example/SPAlertController/ViewController.m
@@ -8,27 +8,23 @@
#import "ViewController.h"
#import "SPAlertController.h"
-#import "MyView.h"
-#import "ShoppingCartView.h"
-#import "CommodityListView.h"
#import "SendAlertView.h"
#import "MyCenterView.h"
-#import "PopView.h"
#import "ScoreView.h"
-#import "PickerView.h"
+#import "UIColor+DarkMode.h"
#define ScreenWidth [UIScreen mainScreen].bounds.size.width
#define ScreenHeight [UIScreen mainScreen].bounds.size.height
-#define StatusHeight ([UIScreen mainScreen].bounds.size.height >= 812 ? 44 : 20)
+#define NaviHeight ([UIScreen mainScreen].bounds.size.height >= 812 ? 88 : 64)
// RGB颜色
#define SPColorRGBA(r, g, b, a) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:(a)]
-#define SYSTEM_COLOR [UIColor colorWithRed:0.0 green:0.48 blue:1.0 alpha:1.0]
+#define SYSTEM_BLUE_COLOR [UIColor colorWithRed:0.0 green:0.48 blue:1.0 alpha:1.0]
// 随机色
#define SPRandomColor ZCColorRGBA(arc4random_uniform(256), arc4random_uniform(256), arc4random_uniform(256),1)
-@interface ViewController ()
+@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic, strong) NSArray *titles;
@property (nonatomic, strong) NSArray *dataSource;
@@ -36,6 +32,7 @@ @interface ViewController () =iOS11才支持)"
- ],
- @[@"alert样式 默认动画(收缩动画)",@"alert样式 发散动画",@"alert样式 渐变动画",@"alert样式 垂直排列2个按钮",@"alert样式 水平排列2个以上的按钮",@"alert样式 设置头部图标",@"alert样式 含有文本输入框"
- ],
- @[@"富文本(action设置富文本)",@"富文本(头部设置富文本)"
- ],
- @[@"自定义头部(xib)",@"自定义整个对话框(alert样式)",@"自定义整个对话框(actionSheet样式(底))",@"自定义整个对话框(actionSheet样式(右))",@"自定义整个对话框(actionSheet样式(左))",@"自定义整个对话框(actionSheet样式(顶))",@"自定义整个对话框(pickerView)",@"自定义action部分",@"插入一个组件",@"自定义整个对话框(全屏)"
- ],
- @[@"当按钮过多时,以scrollView滑动",@"当文字和按钮同时过多时,二者都可滑动",@"含有文本输入框,且文字过多",@"action上的文字过长(垂直)",@"action上的文字过长(水平)"
- ],
- @[@"去除对话框的毛玻璃",@"透明黑色背景样式(背景无毛玻璃,默认)",@"背景毛玻璃Dark样式",@"背景毛玻璃ExtraLight样式",@"背景毛玻璃Light样式"
- ]
+ @[@"actionSheet样式 默认动画(从底部弹出,有取消按钮)",@"actionSheet样式 默认动画(从底部弹出,无取消按钮)",@"actionSheet样式 从顶部弹出(无标题)",@"actionSheet样式 从顶部弹出(有标题)",@"actionSheet样式 水平排列(有取消样式按钮)",@"actionSheet样式 水平排列(无取消样式按钮)",@"actionSheet样式 action含图标",@"actionSheet样式 模拟多分区样式(>=iOS11才支持)", @"点击action不dismiss"],
+ @[@"alert样式 默认动画(收缩动画)",@"alert样式 发散动画",@"alert样式 渐变动画",@"alert样式 垂直排列2个按钮",@"alert样式 水平排列2个以上的按钮",@"alert样式 设置头部图标",@"alert样式 含有文本输入框"],
+ @[@"富文本(action设置富文本)",@"富文本(头部设置富文本)"],
+ @[@"自定义头部(xib)",@"插入一个组件1",@"插入一个组件2"],
+ @[@"当按钮过多时,以scrollView滑动",@"当文字和按钮同时过多时,二者都可滑动",@"含有文本输入框,且文字过多",@"action上的文字过长(垂直)",@"action上的文字过长(水平)"],
+ @[@"背景毛玻璃Dark样式",@"背景毛玻璃ExtraLight样式",@"背景毛玻璃Light样式"]
];
}
+- (void)setupNavi {
+ self.navigationItem.title = @"演示Demo";
+ UIButton *changeBgButton = [UIButton buttonWithType:UIButtonTypeCustom];
+ changeBgButton.backgroundColor = [UIColor colorWithRed:200.0/255.0 green:200.0/255.0 blue:200.0/255.0 alpha:1.0];
+ [changeBgButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
+ [changeBgButton setTitle:@"切换背景" forState:UIControlStateNormal];
+ changeBgButton.titleLabel.font = [UIFont systemFontOfSize:12];
+ changeBgButton.frame = CGRectMake(0, 0, 70, 25);
+ changeBgButton.layer.cornerRadius = 5;
+ changeBgButton.layer.masksToBounds = YES;
+ [changeBgButton addTarget:self action:@selector(changeBackgroundImage:) forControlEvents:UIControlEventTouchUpInside];
+ self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:changeBgButton];
+
+ UIButton *blurButton = [UIButton buttonWithType:UIButtonTypeCustom];
+ blurButton.backgroundColor = [UIColor colorWithRed:200.0/255.0 green:200.0/255.0 blue:200.0/255.0 alpha:1.0];
+ [blurButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
+ [blurButton setTitle:@"打开毛玻璃" forState:UIControlStateNormal];
+ [blurButton setTitle:@"关闭毛玻璃" forState:UIControlStateSelected];
+ blurButton.titleLabel.font = [UIFont systemFontOfSize:12];
+ blurButton.frame = CGRectMake(0, 0, 70, 25);
+ blurButton.layer.cornerRadius = 5;
+ blurButton.layer.masksToBounds = YES;
+ [blurButton addTarget:self action:@selector(lookBlurAction:) forControlEvents:UIControlEventTouchUpInside];
+ self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:blurButton];
+
+}
+
+- (void)changeBackgroundImage:(UIButton *)sender {
+ if (!sender.selected) {
+ NSInteger c = 1+(arc4random() % 2);
+ self.tableView.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:@"背景%li.jpg",(long)c]]];
+ sender.backgroundColor = [UIColor orangeColor];
+ } else {
+ self.tableView.backgroundView = nil;
+ sender.backgroundColor = [UIColor colorWithRed:200.0/255.0 green:200.0/255.0 blue:200.0/255.0 alpha:1.0];
+ }
+ _haveBg = !sender.selected;
+ sender.selected = !sender.selected;
+ [self.tableView reloadData];
+}
+
+- (void)lookBlurAction:(UIButton *)sender {
+ _lookBlur = !sender.selected;
+ if (!sender.selected) {
+ sender.backgroundColor = [UIColor orangeColor];
+ if (!_haveBg) {
+ SPAlertController *alertVc = [SPAlertController alertControllerWithTitle:@"提示" message:@"切换背景看毛玻璃效果更明显哦!" preferredStyle:SPAlertControllerStyleAlert];
+ SPAlertAction *action = [SPAlertAction actionWithTitle:@"知道了" style:SPAlertActionStyleDefault handler:^(SPAlertAction * _Nonnull action) {
+
+ }];
+ [alertVc addAction:action];
+ [self presentViewController:alertVc animated:YES completion:nil];
+ }
+ } else {
+ sender.backgroundColor = [UIColor colorWithRed:200.0/255.0 green:200.0/255.0 blue:200.0/255.0 alpha:1.0];
+ }
+ sender.selected = !sender.selected;
+}
+
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.dataSource.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
- NSInteger index = [[dic valueForKey:[NSString stringWithFormat:@"%ld",section]] integerValue];
+ NSInteger index = [[dic valueForKey:[NSString stringWithFormat:@"%ld",(long)section]] integerValue];
if (index == 1) {
return 0;
} else {
@@ -1035,10 +972,11 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
cell.textLabel.font = [UIFont systemFontOfSize:15];
cell.textLabel.adjustsFontSizeToFitWidth = YES;
cell.textLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
- if (_lookBlur) {
+ if (_haveBg) {
cell.backgroundColor = [UIColor clearColor];
+ cell.textLabel.textColor = [UIColor blackColor];
} else {
- cell.backgroundColor = [UIColor whiteColor];
+ cell.textLabel.textColor = [UIColor colorPairsWithLightColor:[UIColor blackColor] darkColor:[UIColor whiteColor]];
}
cell.textLabel.text = self.dataSource[indexPath.section][indexPath.row];
return cell;
@@ -1054,7 +992,7 @@ - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger
UILabel *titleLabel = [[UILabel alloc] init];
titleLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
titleLabel.textAlignment = NSTextAlignmentCenter;
- titleLabel.font = [UIFont boldSystemFontOfSize:18];
+ titleLabel.font = [UIFont boldSystemFontOfSize:16];
titleLabel.userInteractionEnabled = YES;
titleLabel.tag = 200;
[header.contentView addSubview:titleLabel];
@@ -1065,6 +1003,14 @@ - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger
UILabel *titleLabel = [header viewWithTag:200];
titleLabel.text = self.titles[section];
header.tag = 100 + section;
+ if (_haveBg)
+ {
+ titleLabel.textColor = [UIColor blackColor];
+ }
+ else
+ {
+ titleLabel.textColor = [UIColor colorPairsWithLightColor:[UIColor blackColor] darkColor:[UIColor whiteColor]];
+ }
return header;
}
@@ -1072,15 +1018,15 @@ - (void)tapAction:(UITapGestureRecognizer *)tap {
UITableViewHeaderFooterView *header = (UITableViewHeaderFooterView *)tap.view;
NSInteger section = header.tag - 100;
- NSString *key = [NSString stringWithFormat:@"%ld",section];
+ NSString *key = [NSString stringWithFormat:@"%ld",(long)section];
if ([dic[key] integerValue] == 0) {
[dic setValue:@(1) forKey:key];
} else {
[dic setValue:@(0) forKey:key];
}
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
- if (self.tableView.contentOffset.y < -StatusHeight) {
- [self.tableView setContentOffset:CGPointMake(0, -StatusHeight) animated:YES];
+ if (self.tableView.contentOffset.y < -NaviHeight) {
+ [self.tableView setContentOffset:CGPointMake(0, -NaviHeight) animated:YES];
}
}
@@ -1117,6 +1063,9 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
case 7:
[self actionSheetTest8];
break;
+ case 8:
+ [self actionSheetTest9];
+ break;
}
} else if (indexPath.section == 1) { // alert样式区
switch (indexPath.row) {
@@ -1162,27 +1111,6 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
case 2:
[self customTest3];
break;
- case 3:
- [self customTest4];
- break;
- case 4:
- [self customTest5];
- break;
- case 5:
- [self customTest6];
- break;
- case 6:
- [self customTest7];
- break;
- case 7:
- [self customTest8];
- break;
- case 8:
- [self customTest9];
- break;
- case 9:
- [self customTest10];
- break;
}
} else if (indexPath.section == 4) { // 特殊情况区
switch (indexPath.row) {
@@ -1205,19 +1133,13 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
} else {
switch (indexPath.row) { // 毛玻璃区
case 0:
- [self dialogRemoveBlurTest1];
+ [self backgroundAppearanceStyleTest:UIBlurEffectStyleDark];
break;
case 1:
- [self backgroundAppearanceStyleTest2:SPBackgroundViewAppearanceStyleTranslucent];
+ [self backgroundAppearanceStyleTest:UIBlurEffectStyleExtraLight];
break;
case 2:
- [self backgroundAppearanceStyleTest2:SPBackgroundViewAppearanceStyleBlurDark];
- break;
- case 3:
- [self backgroundAppearanceStyleTest2:SPBackgroundViewAppearanceStyleBlurExtraLight];
- break;
- case 4:
- [self backgroundAppearanceStyleTest2:SPBackgroundViewAppearanceStyleBlurLight];
+ [self backgroundAppearanceStyleTest:UIBlurEffectStyleLight];
break;
}
}
diff --git a/Example/SPAlertControllerTests/Info.plist b/Example/SPAlertControllerTests/Info.plist
old mode 100644
new mode 100755
diff --git a/Example/SPAlertControllerTests/SPAlertControllerTests.m b/Example/SPAlertControllerTests/SPAlertControllerTests.m
old mode 100644
new mode 100755
diff --git a/Example/SPAlertController/main.m b/Example/SPAlertControllerTests/main.m
old mode 100644
new mode 100755
similarity index 100%
rename from Example/SPAlertController/main.m
rename to Example/SPAlertControllerTests/main.m
diff --git a/Example/SPAlertControllerUITests/Info.plist b/Example/SPAlertControllerUITests/Info.plist
old mode 100644
new mode 100755
diff --git a/Example/SPAlertControllerUITests/SPAlertControllerUITests.m b/Example/SPAlertControllerUITests/SPAlertControllerUITests.m
old mode 100644
new mode 100755
diff --git a/Images/.DS_Store b/Images/.DS_Store
old mode 100644
new mode 100755
diff --git a/Images/3006981-0b23494c3ba2a6fc.jpg b/Images/3006981-0b23494c3ba2a6fc.jpg
old mode 100644
new mode 100755
diff --git a/Images/3006981-3cd4a2b6ff4da206.jpg b/Images/3006981-3cd4a2b6ff4da206.jpg
old mode 100644
new mode 100755
diff --git a/Images/3006981-41170beb443f32f0.jpg b/Images/3006981-41170beb443f32f0.jpg
old mode 100644
new mode 100755
diff --git a/Images/3006981-6f3752d49e579460.jpg b/Images/3006981-6f3752d49e579460.jpg
old mode 100644
new mode 100755
diff --git a/Images/3006981-9544748007937417.jpg b/Images/3006981-9544748007937417.jpg
old mode 100644
new mode 100755
diff --git a/Images/3006981-9ed0416190e155dc.jpg b/Images/3006981-9ed0416190e155dc.jpg
old mode 100644
new mode 100755
diff --git a/Images/3006981-a12eae25bc1061d6.jpg b/Images/3006981-a12eae25bc1061d6.jpg
old mode 100644
new mode 100755
diff --git a/Images/3006981-b35b79b657815756.jpg b/Images/3006981-b35b79b657815756.jpg
old mode 100644
new mode 100755
diff --git a/Images/3CB7E93FDA241F253BFE156D0B4AA7E2.jpg b/Images/3CB7E93FDA241F253BFE156D0B4AA7E2.jpg
old mode 100644
new mode 100755
diff --git a/Images/6AAAA07F90853F52CA6166D815F619A9.jpg b/Images/6AAAA07F90853F52CA6166D815F619A9.jpg
old mode 100644
new mode 100755
diff --git a/Images/F4FB539593B4CC499E65735E4F1E8227.jpg b/Images/F4FB539593B4CC499E65735E4F1E8227.jpg
old mode 100644
new mode 100755
diff --git a/LICENSE b/LICENSE
new file mode 100755
index 0000000..a1c0f2e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright © 2018-2019 leshengping (lesp163@163.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/Package.swift b/Package.swift
new file mode 100644
index 0000000..c45f504
--- /dev/null
+++ b/Package.swift
@@ -0,0 +1,23 @@
+// swift-tools-version:5.3
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+
+let package = Package(
+ name: "SPAlertController",
+ platforms: [
+ .iOS(.v9)
+ ],
+ products: [
+ .library(
+ name: "SPAlertController",
+ targets: ["SPAlertController"]),
+ ],
+ dependencies: [],
+ targets: [
+ .target(
+ name: "SPAlertController",
+ path: "SPAlertController",
+ publicHeadersPath: ".")
+ ]
+)
diff --git a/README.md b/README.md
old mode 100644
new mode 100755
index e6e3ea4..e1abc26
--- a/README.md
+++ b/README.md
@@ -1,42 +1,51 @@
-
-# 3.0版本有极大的优化,由于采用了iOS9之后推出的UIStackView,因此3.0版本只支持iOS9及其以上系统
# SPAlertController
-[](https://travis-ci.org/SPStore/SPAlertController)
[](http://cocoadocs.org/docsets/SPAlertController/)
[](http://cocoadocs.org/docsets/SPAlertController/)

[](https://www.apache.org/licenses/LICENSE-2.0.html)
[](https://github.com/SPStore/SPAlertController)
# 目录
-* [CocoaPods](#CocoaPods)
+* [安装](#安装)
+ * [CocoaPods](#CocoaPods)
+ * [Swift Package Manager](#Swift-Package-Manager)
* [使用示例](#使用示例)
* [API及属性详解](#API及属性详解)
-* [自定义各大View](#自定义各大View)
+* [自定义View](#自定义View)
+* [深色模式预览](#深色模式预览)
* [历史版本](#历史版本)
## 功能特点
-- [x] 采用VFL布局,3.0版本开始核心控件为UIStackView,风格与微信几乎零误差
-- [x] 3.0版本开始对话框头部新增图片设置
-- [x] 3.0版本开始action支持图片设置
+- [x] 采用VFL布局,3.0版本开始,核心控件为UIStackView,风格与微信几乎零误差
+- [x] 3.0版本开始,对话框头部新增图片设置
+- [x] 3.0版本开始,action支持图片设置
- [x] 3.0版本开始,iOS11及其以上系统可单独设置指定action后的间距
-- [x] 3.0版本开始支持富文本
+- [x] 3.0版本开始,支持富文本
- [x] action的排列可灵活设置垂直排列和水平排列
- [x] 每个action的高度自适应
- [x] 支持旋转(横竖屏)
-- [x] 可以自定义各种UIView
+- [x] 支持自定义头部视图
+- [x] 支持头部和action之间插入自定义视图
- [x] 支持对话框毛玻璃和背景蒙层毛玻璃
- [x] 全面适配iPhoneX,iPhoneXR,iPhoneXS,iPhoneXS MAX
-## CocoaPods
-##### 版本3.0.1
+- [x] 全面适配深色模式
+
+## 安装
+
+### CocoaPods
```
platform:ios,'9.0'
target 'MyApp' do
- pod 'SPAlertController', '~> 3.0.1'
+ pod 'SPAlertController', '~> 4.1.0'
end
-
-3.0.1版本使背景蒙层动画更加的柔和
```
+### Swift Package Manager
+Swift Package Manager是Apple官方提供的依赖管理工具,在Xcode中集成。
+
+- Xcode 11+,打开你的项目,选择:File > Swift Packages > Add Package Dependency
+- 输入仓库地址:https://github.com/SPStore/SPAlertController
+- 选择版本规则:Up to Next Major(4.1.0)
+
## 使用示例
```
SPAlertController *alert = [SPAlertController alertControllerWithTitle:@"我是主标题" message:@"我是副标题" preferredStyle:SPAlertControllerStyleActionSheet];
@@ -112,9 +121,6 @@ SPAlertAction *action3 = [SPAlertAction actionWithTitle:@"Cancel" style:SPAlertA
@property(nonatomic, assign) CGFloat minDistanceToEdges;
```
-* 图中红色画线都是指minDistanceToEdges
-
-
```
// 该属性是制造对话框的毛玻璃效果,3.0版本开始采用的是系统私有类_UIDimmingKnockoutBackdropView所实现
@@ -173,7 +179,7 @@ SPAlertControllerStyleAlert下的圆角半径

-## 自定义各大View
+## 自定义View
* 自定义对话框的头部
```
+ (instancetype)alertControllerWithCustomHeaderView:(nullable UIView *)customHeaderView preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType;
@@ -192,90 +198,42 @@ SPAlertControllerStyleAlert下的圆角半径
+ (instancetype)alertControllerWithCustomActionSequenceView:(nullable UIView *)customActionSequenceView title:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType;
```

-## 关于自定义view的大小
-* 非自动布局,在传入自定义view之前,应该为自定义的view设置好frame,也可以在传入自定义view之后,调用API```- (void)updateCustomViewSize:(CGSize)size```设置其大小;
-* 自动布局,如果宽度和高度都能由子控件撑起来,那么你不需要设置frame,否则,宽度和高度只要有其中一个无法由子控件撑起,那么就必须设置其值,比如高度能被子控件撑起来,而宽度不能,那么你就必须手动设置一个宽度,高度可以不用设置或者设置为0都可。如果是xib或者storyboard,若自定义的view无法由子控件撑起来,SPAlertController会读取xib/storyboard中的默认frame,如果不合适,那么你应该修改xib/storyboard中的默认frame或者用纯代码重新设置frame。如果自定义view的宽度能够被子控件撑起,但同时又手动设置了自定义view的宽度,那么SPAlertController会取自动撑起的宽度和手动设置的宽度中较大的那个,高度同理。有一种情况要值得注意:如果子控件类似按钮这种不设置大小就自动会产生大小的子控件,同时该按钮设置了左右间距,那么它就能将自定义的view的宽度撑起,但是这种撑起来的宽度可能并非你想要的,因为按钮宽度是由内容自动产生,不是你设置的,这时你应该手动设置按钮的宽度,以便自定义的view的宽度被撑起的恰到好处,或者手动设置自定义view的宽度,这个手动设置的宽度,应该要比没有手动设置宽度的按钮将自定义view撑起来的宽度要大。
-* 当自定义的view的大小在对话框显示期间发生了变化,你应该调用```- (void)updateCustomViewSize:(CGSize)size```通知SPAlertController更新其大小
+## 深色模式预览
+[](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/1.jpg)
+[](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/2.jpg)
+[](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/3.jpg)
+[](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/4.jpg)
+[](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/5.jpg)
+[](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/6.jpg)
+[](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/7.jpg)
+[](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/8.jpg)
+[](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/9.jpg)
+[](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/10.jpg)
+[](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/11.jpg)
+[](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/12.jpg)
+[](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/13.jpg)
+[](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/14.jpg)
## 历史版本
-##### 版本3.0
-```
-platform:ios,'9.0'
-target 'MyApp' do
- pod 'SPAlertController', '~> 3.0'
-end
-
-3.0版本进行了全方位的大重构
-```
-##### 版本2.5.2(老版本的终结版)
-```
-platform:ios,'8.0'
-target 'MyApp' do
- pod 'SPAlertController', '~> 2.5.2'
-end
-
-按钮处于最底部时长按touchDown事件的延时现象采用新方式解决,另外修复了内存泄露问题
-```
-##### 版本2.5.1
-```
-platform:ios,'8.0'
-target 'MyApp' do
- pod 'SPAlertController', '~> 2.5.1'
-end
-
-此版本修改了action的选中效果,以及解决iOS11之后,按钮处于最底部时长按touchDown事件的延时现象
-```
-##### 版本2.5.0
-```
-platform:ios,'8.0'
-target 'MyApp' do
- pod 'SPAlertController', '~> 2.5.0'
-end
-
-此版本在2.2.1版本的基础上主要改动有:
-1、毛玻璃思路另辟蹊径,毛玻璃效果不会受到背景遮罩的影响,同时背景遮罩不再被镂空
-2、增加动画枚举,可以从左右弹出
-3、自定义view时的背景色改为透明色
-4、增加actionHeight属性,修复maxNumberOfActionHorizontalArrangementForAlert属性
-5、去除了中间tableView的最后一条分割线
-6、修改了分割线的颜色,更加接近微信原生
-7、修复centerView上有textView/textField,旋转屏幕后不可见问题
-8、优化代码
+| 版本 | 更新日期 | 支持最低系统版本 |更新内容 |
+| :------------:| :------------:| :------------:|------------|
+|v4.1.0|2025.09.09|iOS9.0|1、修复title和message同时为空的情况下,在部分机型上无法弹出的问题
2、action事件回调改为dimiss动画完成之后
3、action新增allowsAutoDismiss和backgroundColor属性
4、修复深色模式下模糊效果失效问题
5、支持SPM|
+|v4.0.0|2020.04.27|iOS9.0|适配深色模式|
+|v3.1.0|2019.08.08|iOS9.0|1、actionSheet样式加了单边圆角效果
2、毛玻璃默认为NO
3、当不需要毛玻璃效果时,actionButton的选中背景色修改(灰度0.1),属于bug修复
4、“取消action”上的分割线背景色修改(灰度由0.3变为0.2),高度由6增加为8
5、每个actionButton的最小高度由49变为55|
+|v3.0.4|2019.06.03|iOS9.0|修复了tapBackgroundViewDismiss属性无效问题|
+|v3.0.3|2019.05.30|iOS9.0|修复了action点击的回调为nil时闪退问题|
+|v3.0.2|2019.05.09|iOS9.0|修复了内存泄漏问题|
+|v3.0.1|2019.01.03|iOS9.0|背景蒙层动画更加的柔和|
+|v3.0.0|2018.12.29|iOS9.0|全方位的大重构|
+|v2.5.2|2018.12.03|iOS8.0|1、按钮处于最底部时长按touchDown事件的延时现象采用新方式解决
2、修复了内存泄露问题|
+|v2.5.1|2018.11.07|iOS8.0|1、修改了action的选中效果
2、解决iOS11之后,按钮处于最底部时长按touchDown事件的延时现象|
+|v2.5.0|2018.11.07|iOS8.0|1、毛玻璃思路另辟蹊径,毛玻璃效果不会受到背景遮罩的影响,同时背景遮罩不再被镂空
2、增加动画枚举,可以从左右弹出
3、自定义view时的背景色改为透明色
4、增加actionHeight属性,修复maxNumberOfActionHorizontalArrangementForAlert属性
5、去除了中间tableView的最后一条分割线
6、修改了分割线的颜色,更加接近微信原生
7、修复centerView上有textView/textField,旋转屏幕后不可见问题
8、优化代码|
+|v2.1.1|2018.11.01|iOS8.0||
+|v2.1.0|2018.10.18|iOS8.0||
+|v2.0.0|2017.11.19|iOS8.0||
+|v1.7.0|2017.11.06|iOS8.0||
+|v1.5.0|2017.11.06|iOS8.0||
+|v1.0.1|2017.10.24|iOS8.0||
+|v1.0.0|2017.10.24|iOS8.0|||
-```
-##### 版本2.1.1
-```
-platform:ios,'8.0'
-target 'MyApp' do
- pod 'SPAlertController', '~> 2.1.1'
-end
-```
-##### 版本2.1.0
-```
-platform:ios,'8.0'
-target 'MyApp' do
- pod 'SPAlertController', '~> 2.1.0'
-end
-```
-##### 版本2.0
-```
-platform:ios,'8.0'
-target 'MyApp' do
- pod 'SPAlertController', '~> 2.0'
-end
-```
-##### 版本1.7.0
-```
-platform:ios,'8.0'
-target 'MyApp' do
- pod 'SPAlertController', '~> 1.7.0'
-end
-```
-##### 版本1.0.1
-```
-platform:ios,'8.0'
-target 'MyApp' do
- pod 'SPAlertController', '~> 1.0.1'
-end
-```
[回到顶部](#目录)
diff --git a/SPAlertController.podspec b/SPAlertController.podspec
old mode 100644
new mode 100755
index 749c249..0069af1
--- a/SPAlertController.podspec
+++ b/SPAlertController.podspec
@@ -16,8 +16,8 @@ Pod::Spec.new do |s|
#
s.name = "SPAlertController"
- s.version = "3.0.1"
- s.summary = "提醒对话框."
+ s.version = "4.1.0"
+ s.summary = "iOS 弹窗,提醒对话框,支持多种样式和自定义,适配深色模式"
# This description is used to generate tags and improve search results.
# * Think: What does it do? Why did you write it? What is the focus?
@@ -25,8 +25,8 @@ Pod::Spec.new do |s|
# * Write the description between the DESC delimiters below.
# * Finally, don't worry about the indent, CocoaPods strips it!
s.description = <<-DESC
- 这是一个提醒对话框
- DESC
+ 说明:4.1.0版本改进了键盘弹出时的动画处理,修复了键盘与弹窗动画冲突的问题,优化了UI组件内存管理,改进了深色模式的颜色适配,增加了Swift Package Manager支持
+ DESC
s.homepage = "https://github.com/SPStore/SPAlertController"
# s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif"
@@ -65,10 +65,10 @@ Pod::Spec.new do |s|
#
s.platform = :ios
- s.platform = :ios, "8.0"
+ s.platform = :ios, "9.0"
# When using multiple platforms
- s.ios.deployment_target = "8.0"
+ s.ios.deployment_target = "9.0"
# s.osx.deployment_target = "10.7"
# s.watchos.deployment_target = "2.0"
# s.tvos.deployment_target = "9.0"
@@ -80,7 +80,7 @@ Pod::Spec.new do |s|
# Supports git, hg, bzr, svn and HTTP.
#
- s.source = { :git => "https://github.com/SPStore/SPAlertController.git", :tag => s.version }
+ s.source = { :git => "https://github.com/SPStore/SPAlertController.git", :tag => "#{s.version}" }
# ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
@@ -130,9 +130,8 @@ Pod::Spec.new do |s|
# where they will only apply to your library. If you depend on other Podspecs
# you can include multiple dependencies to ensure it works.
- # s.requires_arc = true
+ s.requires_arc = true
# s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
# s.dependency "JSONKit", "~> 1.4"
-
end
diff --git a/SPAlertController/SPAlertController.h b/SPAlertController/SPAlertController.h
old mode 100644
new mode 100755
index 6429d6d..132969a
--- a/SPAlertController/SPAlertController.h
+++ b/SPAlertController/SPAlertController.h
@@ -3,7 +3,7 @@
// SPAlertController
//
// Created by 乐升平 on 18/10/12. https://github.com/SPStore/SPAlertController
-// Copyright © 2018年 iDress. All rights reserved.
+// Copyright © 2018-2019 leshengping (lesp163@163.com). All rights reserved.
//
#import
@@ -11,25 +11,25 @@
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, SPAlertControllerStyle) {
- SPAlertControllerStyleActionSheet = 0, // 从四周的某一侧弹出(顶/左/底/右),从哪边弹出,就往哪边对齐
+ SPAlertControllerStyleActionSheet = 0, // 从底部弹出
SPAlertControllerStyleAlert, // 从中间弹出
};
typedef NS_ENUM(NSInteger, SPAlertAnimationType) {
- SPAlertAnimationTypeDefault = 0, // 默认动画,如果是SPAlertControllerStyleActionSheet样式,默认动画等效于SPAlertAnimationTypeFromBottom,如果是SPAlertControllerStyleAlert样式,默认动画等效于SPAlertAnimationTypeShrink
+ // 如果是SPAlertControllerStyleActionSheet样式,默认动画等效于SPAlertAnimationTypeFromBottom
+ // 如果是SPAlertControllerStyleAlert样式,默认动画等效于SPAlertAnimationTypeShrink
+ SPAlertAnimationTypeDefault = 0,
+ // 方向动画
SPAlertAnimationTypeFromBottom, // 从底部弹出
SPAlertAnimationTypeFromTop, // 从顶部弹出
- SPAlertAnimationTypeFromRight, // 从右边弹出
- SPAlertAnimationTypeFromLeft, // 从左边弹出
-
+ // 效果动画
SPAlertAnimationTypeShrink, // 收缩动画
SPAlertAnimationTypeExpand, // 发散动画
SPAlertAnimationTypeFade, // 渐变动画
-
SPAlertAnimationTypeNone, // 无动画
- SPAlertAnimationTypeAlpha NS_ENUM_DEPRECATED_IOS(8_0, 8_0, "Use SPAlertAnimationTypeFad instead"), // 渐变动画
- SPAlertAnimationTypeRaiseUp NS_ENUM_DEPRECATED_IOS(8_0, 8_0, "Use SPAlertAnimationTypeFromBottom instead"), // 从底部弹出
- SPAlertAnimationTypeDropDown NS_ENUM_DEPRECATED_IOS(8_0, 8_0, "Use SPAlertAnimationTypeFromTop instead"), // 从顶部弹出
+
+ SPAlertAnimationTypeFromRight NS_ENUM_DEPRECATED_IOS(8_0, 26_0, "This enum value will be deprecated in a future version"), // 从右边弹出
+ SPAlertAnimationTypeFromLeft NS_ENUM_DEPRECATED_IOS(8_0, 26_0, "This enum value will be deprecated in a future version"), // 从左边弹出
};
typedef NS_ENUM(NSInteger, SPAlertActionStyle) {
@@ -38,112 +38,163 @@ typedef NS_ENUM(NSInteger, SPAlertActionStyle) {
SPAlertActionStyleDestructive // 红色字体样式
};
-typedef NS_ENUM(NSInteger, SPBackgroundViewAppearanceStyle) {
- SPBackgroundViewAppearanceStyleTranslucent = 0, // 无毛玻璃效果,黑色透明(默认是0.5透明)
- SPBackgroundViewAppearanceStyleBlurDark,
- SPBackgroundViewAppearanceStyleBlurExtraLight,
- SPBackgroundViewAppearanceStyleBlurLight,
-};
-
-// ===================================================== SPAlertAction =====================================================
+// =====================================================
+// SPAlertAction
+// =====================================================
@interface SPAlertAction : NSObject
-/**
- * 创建一个action
- *
- * @param title 标题
- * @param style action样式
- * @param handler 点击后的bolok回调
- */
+
+ (instancetype)actionWithTitle:(nullable NSString *)title style:(SPAlertActionStyle)style handler:(void (^ __nullable)(SPAlertAction *action))handler;
/** action的标题 */
@property(nullable, nonatomic, copy) NSString *title;
+
/** action的富文本标题 */
@property(nullable, nonatomic, copy) NSAttributedString *attributedTitle;
+
/** action的图标,位于title的左边 */
@property(nullable, nonatomic, copy) UIImage *image;
+
/** title跟image之间的间距 */
@property (nonatomic, assign) CGFloat imageTitleSpacing;
-/** 样式 */
-@property(nonatomic, readonly) SPAlertActionStyle style;
+
+/** 渲染颜色,当外部的图片使用了UIImageRenderingModeAlwaysTemplate时,使用该属性可改变图片的颜色 */
+@property (nonatomic, strong) UIColor *tintColor;
+
/** 是否能点击,默认为YES */
@property(nonatomic, getter=isEnabled) BOOL enabled;
+
/** action的标题颜色,这个颜色只是普通文本的颜色,富文本颜色需要用NSForegroundColorAttributeName */
@property(nonatomic, strong) UIColor *titleColor;
+
+/** action的背景颜色 */
+@property(nonatomic, strong) UIColor *backgroundColor;
+
/** action的标题字体,如果文字太长显示不全,会自动改变字体自适应按钮宽度,最多压缩文字为原来的0.5倍封顶 */
@property(nonatomic, strong) UIFont *titleFont;
-/** action的标题的内边距,如果在不改变字体的情况下想增大action的高度,可以设置该属性的top和bottom值,默认UIEdgeInsetsMake(0, 15, 0, 15) */
+
+/** action的标题的内边距,如果在不改变字体的情况下想增大action的高度,可以设置该属性的top和bottom值,默认UIEdgeInsetsMake(0, 15, 0, 15) */
@property(nonatomic, assign) UIEdgeInsets titleEdgeInsets;
+/** 样式 */
+@property(nonatomic, readonly) SPAlertActionStyle style;
+
+/** 点击后是否自动dismiss对话框,默认为YES */
+@property(nonatomic, assign) BOOL allowsAutoDismiss;
+
@end
-// ===================================================== SPAlertController =====================================================
+// =====================================================
+// SPAlertController
+// =====================================================
@protocol SPAlertControllerDelegate;
+
@interface SPAlertController : UIViewController
+ (instancetype)alertControllerWithTitle:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle;
-+ (instancetype)alertControllerWithTitle:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType; // animationType传SPAlertAnimationTypeDefault则跟第一个类方法等效
+
++ (instancetype)alertControllerWithTitle:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType;
+
++ (instancetype)alertControllerWithCustomHeaderView:(nonnull UIView *)customHeaderView preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType;
- (void)addAction:(SPAlertAction *)action;
@property (nonatomic, readonly) NSArray *actions;
-/* 添加文本输入框
- * 一旦添加后就会回调一次(仅回调一次,因此可以在这个block块里面自由定制textFiled,如设置textField的属性,设置代理,添加addTarget,监听通知等);
+/**
+ * 添加文本输入框
+ * 一旦添加后就会回调一次(仅回调一次,因此可以在这个block块里面自由定制textFiled,如设置textField的属性,设置代理,添加addTarget,监听通知等)
*/
- (void)addTextFieldWithConfigurationHandler:(void (^ __nullable)(UITextField *textField))configurationHandler;
@property(nullable, nonatomic, readonly) NSArray *textFields;
/** 主标题 */
@property(nullable, nonatomic, copy) NSString *title;
+
/** 副标题 */
@property(nullable, nonatomic, copy) NSString *message;
+
/** 主标题(富文本) */
@property(nullable, nonatomic, copy) NSAttributedString *attributedTitle;
+
/** 副标题(富文本) */
@property(nullable, nonatomic, copy) NSAttributedString *attributedMessage;
-/** 头部图标,位置处于title之上,大小取决于图片本身大小 */
+
+/** 头部图标,位置处于title之上,大小取决于图片本身大小 */
@property(nullable,nonatomic, copy) UIImage *image;
/** 主标题颜色 */
@property(nonatomic, strong) UIColor *titleColor;
-/** 主标题字体,默认18,加粗 */
+
+/** 主标题字体,默认18,加粗 */
@property(nonatomic, strong) UIFont *titleFont;
+
/** 副标题颜色 */
@property(nonatomic, strong) UIColor *messageColor;
-/** 副标题字体,默认16,未加粗 */
+
+/** 副标题字体,默认16,未加粗 */
@property(nonatomic, strong) UIFont *messageFont;
+
/** 对齐方式(包括主标题和副标题) */
@property(nonatomic, assign) NSTextAlignment textAlignment;
-/** 头部图标的限制大小,默认无穷大 */
+
+/** 头部图标的限制大小,默认无穷大 */
@property (nonatomic, assign) CGSize imageLimitSize;
-/*
+/** 图片的tintColor,当外部的图片使用了UIImageRenderingModeAlwaysTemplate时,该属性可起到作用 */
+@property (nonatomic, strong) UIColor *imageTintColor;
+
+/**
* action水平排列还是垂直排列
- * actionSheet样式下:默认为UILayoutConstraintAxisVertical(垂直排列), 如果设置为UILayoutConstraintAxisHorizontal(水平排列),则除去取消样式action之外的其余action将水平排列
- * alert样式下:当actions的个数大于2,或者某个action的title显示不全时为UILayoutConstraintAxisVertical(垂直排列),否则默认为UILayoutConstraintAxisHorizontal(水平排列),此样式下设置该属性可以修改所有action的排列方式
- * 不论哪种样式,只要外界设置了该属性,永远以外界设置的优先
+ *
+ * actionSheet样式下:
+ * 默认为UILayoutConstraintAxisVertical(垂直排列)
+ * 如果设置为UILayoutConstraintAxisHorizontal(水平排列),则除去取消样式action之外的其余action将水平排列
+ *
+ * alert样式下:
+ * 当actions的个数大于2,或者某个action的title显示不全时为UILayoutConstraintAxisVertical(垂直排列)
+ * 否则默认为UILayoutConstraintAxisHorizontal(水平排列),此样式下设置该属性可以修改所有action的排列方式
*/
@property(nonatomic) UILayoutConstraintAxis actionAxis;
-/* 距离屏幕边缘的最小间距
- * alert样式下该属性是指对话框四边与屏幕边缘之间的距离,此样式下默认值随设备变化,actionSheet样式下是指弹出边的对立边与屏幕之间的距离,比如如果从右边弹出,那么该属性指的就是对话框左边与屏幕之间的距离,此样式下默认值为70
+/**
+ * 距离屏幕边缘的最小间距
+ *
+ * alert样式下:
+ * 该属性是指对话框四边与屏幕边缘之间的距离,此样式下默认值随设备变化
+ *
+ * actionSheet样式下:
+ * 是指弹出边的对立边与屏幕之间的距离
+ * 比如如果从右边弹出,那么该属性指的就是对话框左边与屏幕之间的距离,此样式下默认值为70
*/
@property(nonatomic, assign) CGFloat minDistanceToEdges;
-/** 圆角半径,只有alert样式有效*/
-@property(nonatomic, assign) CGFloat cornerRadiusForAlert;
-
-/** 对话框的偏移量,y值为正向下偏移,为负向上偏移;x值为正向右偏移,为负向左偏移,该属性只对SPAlertControllerStyleAlert样式有效,键盘的frame改变会自动偏移,如果外界手动设置偏移只会取手动设置的 */
+/**
+ * 圆角半径
+ * SPAlertControllerStyleAlert样式下默认6.0f
+ * SPAlertControllerStyleActionSheet样式下默认13.0f
+ * 去除半径设置为0即可
+ */
+@property(nonatomic, assign) CGFloat cornerRadius;
+
+/**
+ * 对话框的偏移量
+ * y值为正向下偏移,为负向上偏移
+ * x值为正向右偏移,为负向左偏移
+ * 该属性只对SPAlertControllerStyleAlert样式有效
+ * 键盘的frame改变会自动偏移,如果手动设置偏移只会取手动设置的
+ */
@property(nonatomic, assign) CGPoint offsetForAlert;
/** 设置alert样式下的偏移量,动画为NO则跟属性offsetForAlert等效 */
- (void)setOffsetForAlert:(CGPoint)offsetForAlert animated:(BOOL)animated;
-/** 是否需要对话框拥有毛玻璃,默认为YES----Dialog单词是对话框的意思 */
+/** 使用键盘动画参数调整视图位置 */
+- (void)makeViewOffsetWithDuration:(NSTimeInterval)duration curve:(UIViewAnimationCurve)curve;
+
+/** 是否需要对话框拥有毛玻璃,默认为YES */
@property(nonatomic, assign) BOOL needDialogBlur;
-/** 是否单击背景退出对话框,默认为YES */
+/** 是否单击背景退出对话框,默认为YES */
@property(nonatomic, assign) BOOL tapBackgroundViewDismiss;
@property(nonatomic, weak) id delegate;
@@ -156,67 +207,62 @@ typedef NS_ENUM(NSInteger, SPBackgroundViewAppearanceStyle) {
- (CGFloat)customSpacingAfterAction:(SPAlertAction *)action API_AVAILABLE(ios(11.0));
/** 设置蒙层的外观样式,可通过alpha调整透明度 */
-- (void)setBackgroundViewAppearanceStyle:(SPBackgroundViewAppearanceStyle)style alpha:(CGFloat)alpha;
+- (void)setBackgroundViewAppearanceStyle:(UIBlurEffectStyle)style alpha:(CGFloat)alpha;
// 插入一个组件view,位置处于头部和action部分之间,要求头部和action部分同时存在
-- (void)insertComponentView:(nullable UIView *)componentView;
+- (void)insertComponentView:(nonnull UIView *)componentView;
-// ---------------------------------------------- custom -----------------------------------------------------
+// ----------------------------------------------
+// 自定义视图
+// ----------------------------------------------
/**
- 创建控制器(自定义整个对话框)
-
- @param customAlertView 整个对话框的自定义view
- @param preferredStyle 对话框样式
- @param animationType 动画类型
- @return 控制器对象
+ * 创建控制器(自定义整个对话框)
+ *
+ * @param customAlertView 整个对话框的自定义view
+ * @param preferredStyle 对话框样式
+ * @param animationType 动画类型
+ * @return 控制器对象
+ * @warning 此方法将在未来版本中移除
*/
-+ (instancetype)alertControllerWithCustomAlertView:(nullable UIView *)customAlertView preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType;
++ (instancetype)alertControllerWithCustomAlertView:(nonnull UIView *)customAlertView preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType NS_DEPRECATED_IOS(8_0, 26_0, "This API will be deprecated in a future version");
+
/**
- 创建控制器(自定义对话框的头部)
-
- @param customHeaderView 头部自定义view
- @param preferredStyle 对话框样式
- @param animationType 动画类型
- @return 控制器对象
+ * 创建控制器(自定义对话框的action部分)
+ *
+ * @param customActionSequenceView action部分的自定义view
+ * @param title 大标题
+ * @param message 副标题
+ * @param preferredStyle 对话框样式
+ * @param animationType 动画类型
+ * @return 控制器对象
+ * @warning 此方法将在未来版本中移除
*/
-+ (instancetype)alertControllerWithCustomHeaderView:(nullable UIView *)customHeaderView preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType;
-/**
- 创建控制器(自定义对话框的action部分)
-
- @param customActionSequenceView action部分的自定义view
- @param title 大标题
- @param message 副标题
- @param preferredStyle 对话框样式
- @param animationType 动画类型
- @return 控制器对象
++ (instancetype)alertControllerWithCustomActionSequenceView:(nonnull UIView *)customActionSequenceView title:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType NS_DEPRECATED_IOS(8_0, 26_0, "This API will be deprecated in a future version");
+
+/**
+ * 更新自定义view的size
+ * 比如屏幕旋转,自定义view的大小发生了改变,可通过该方法更新size
+ * @warning 此方法将在未来版本中移除
*/
-+ (instancetype)alertControllerWithCustomActionSequenceView:(nullable UIView *)customActionSequenceView title:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType;
-
-/** 更新自定义view的size,自定义了哪个view,该size指的就是哪个view的size,比如屏幕旋转,自定义view的大小发生了改变,可通过该方法更新 */
-- (void)updateCustomViewSize:(CGSize)size;
-
-@property (nonatomic, assign) CGFloat maxTopMarginForActionSheet NS_DEPRECATED_IOS(8_0, 8_0,"Use minDistanceToEdgeForAlert instead"); // actionSheet样式下,最大的顶部间距,从底部、右边、左边弹出时默认为0,iPhoneX及以上机型默认44,从顶部弹出时无论哪种机型都默认为0;注意该属性中的top单词不是精确的指顶部,当从右边弹出时,top指的就是左,从左边弹出时,top指的就是右,从顶部弹出时,top指的就是底
-@property(nonatomic, assign) CGFloat maxMarginForAlert NS_DEPRECATED_IOS(8_0, 8_0,"Use minDistanceToEdgeForAlert instead");// alert样式下,四周的最小间距,默认为20,该属性起名有误,应该是最小,而不是最大,3.0版本属性名已改,叫minDistanceToEdgeForAlert
-@property(nonatomic, assign) NSInteger maxNumberOfActionHorizontalArrangementForAlert NS_DEPRECATED_IOS(8_0, 8_0,"Use actionAxis instead");// alert样式下,水平排列的最大个数,如果大于了这个数,则所有action将垂直排列,默认是2;在添加action之前设置性能会更佳,由于水平排列的action都是排布在footerView上,所以如果自定义了footerView,该属性将失去效用
-@property(nonatomic, assign) CGFloat offsetYForAlert NS_DEPRECATED_IOS(8_0, 8_0,"Use offset instead"); // 对话框垂直方向上的偏移
-+ (instancetype)alertControllerWithTitle:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType customView:(nullable UIView *)customView NS_DEPRECATED_IOS(8_0, 8_0,"Use +alertControllerWithCustomView:preferredStyle:animationType:");
-+ (instancetype)alertControllerWithPreferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType customHeaderView:(nullable UIView *)customHeaderView NS_DEPRECATED_IOS(8_0, 8_0,"Use +alertControllerWithCustomHeaderView:preferredStyle:animationType:");
-+ (instancetype)alertControllerWithTitle:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType customCenterView:(nullable UIView *)customCenterView NS_DEPRECATED_IOS(8_0, 8_0,"Use +alertControllerWithComponentView:title:message:(nullable NSString *)message preferredStyle:animationType:");
-+ (instancetype)alertControllerWithTitle:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType customFooterView:(nullable UIView *)customFooterView NS_DEPRECATED_IOS(8_0, 8_0,"Use +alertControllerWithCustomActionGroupView:title:message: preferredStyle:animationType:");
+- (void)updateCustomViewSize:(CGSize)size NS_DEPRECATED_IOS(8_0, 26_0, "This API will be deprecated in a future version");
+
@end
@protocol SPAlertControllerDelegate
@optional;
-- (void)willPresentAlertController:(SPAlertController *)alertController; // 将要present
-- (void)didPresentAlertController:(SPAlertController *)alertController; // 已经present
-- (void)willDismissAlertController:(SPAlertController *)alertController; // 将要dismiss
-- (void)didDismissAlertController:(SPAlertController *)alertController; // 已经dismiss
-
-- (void)sp_alertControllerWillShow:(SPAlertController *)alertController NS_DEPRECATED_IOS(8_0, 8_0,"Use -willPresentAlertController:");
-- (void)sp_alertControllerDidShow:(SPAlertController *)alertController NS_DEPRECATED_IOS(8_0, 8_0,"Use -DidPresentAlertController:");
-- (void)sp_alertControllerWillHide:(SPAlertController *)alertController NS_DEPRECATED_IOS(8_0, 8_0,"Use -willDismissAlertController:");
-- (void)sp_alertControllerDidHide:(SPAlertController *)alertController NS_DEPRECATED_IOS(8_0, 8_0,"Use -DidDismissAlertController:");
+/** 将要present */
+- (void)willPresentAlertController:(SPAlertController *)alertController;
+
+/** 已经present */
+- (void)didPresentAlertController:(SPAlertController *)alertController;
+
+/** 将要dismiss */
+- (void)willDismissAlertController:(SPAlertController *)alertController;
+
+/** 已经dismiss */
+- (void)didDismissAlertController:(SPAlertController *)alertController;
+
@end
@interface SPAlertPresentationController : UIPresentationController
diff --git a/SPAlertController/SPAlertController.m b/SPAlertController/SPAlertController.m
old mode 100644
new mode 100755
index effadd7..8bf256b
--- a/SPAlertController/SPAlertController.m
+++ b/SPAlertController/SPAlertController.m
@@ -3,21 +3,121 @@
// SPAlertController
//
// Created by 乐升平 on 18/10/12. https://github.com/SPStore/SPAlertController
-// Copyright © 2018年 iDress. All rights reserved.
+// Copyright © 2018-2019 leshengping (lesp163@163.com). All rights reserved.
//
#import "SPAlertController.h"
-#define SP_SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
-#define SP_SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
-#define SP_LINE_COLOR [[UIColor grayColor] colorWithAlphaComponent:0.3]
-#define SP_NORMAL_COLOR [[UIColor whiteColor] colorWithAlphaComponent:0.7]
-#define SP_SELECTED_COLOR [UIColor colorWithWhite:1 alpha:0.4]
-#define SP_LINE_WIDTH 1.0 / [UIScreen mainScreen].scale
-#define Is_iPhoneX MAX(SP_SCREEN_WIDTH, SP_SCREEN_HEIGHT) >= 812
-#define SP_STATUS_BAR_HEIGHT (Is_iPhoneX ? 44 : 20)
-#define SP_ACTION_TITLE_FONTSIZE 18
-#define SP_ACTION_HEIGHT 49.0
+#define SPALERT_SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
+#define SPALERT_SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
+
+#define SPALERT_LINE_WIDTH 1.0 / [UIScreen mainScreen].scale
+
+#define SPALERT_IS_IPHONEX MAX(SPALERT_SCREEN_WIDTH, SPALERT_SCREEN_HEIGHT) >= 812
+#define SPALERT_STATUS_BAR_HEIGHT (SPALERT_IS_IPHONEX ? 44 : 20)
+#define SPALERT_ACTION_TITLE_FONTSIZE 18
+#define SPALERT_ACTION_HEIGHT 55.0
+
+@interface _SPColorStyle : NSObject
+
++ (UIColor *)normalColor;
++ (UIColor *)highlightedColor;
++ (UIColor *)lineColor;
++ (UIColor *)line2Color;
++ (UIColor *)lightLineColor;
++ (UIColor *)darkLineColor;
++ (UIColor *)lightWhite_DarkBlackColor;
++ (UIColor *)lightBlack_DarkWhiteColor;
++ (UIColor *)textViewBackgroundColor;
++ (UIColor *)alertRedColor;
++ (UIColor *)grayColor;
+
++ (UIColor *)colorPairsWithDynamicLightColor:(UIColor *)lightColor darkColor:(UIColor *)darkColor;
++ (UIColor *)colorPairsWithStaticLightColor:(UIColor *)lightColor darkColor:(UIColor *)darkColor;
+@end
+
+@implementation _SPColorStyle
+
++ (UIColor *)normalColor {
+ return [self colorPairsWithDynamicLightColor:[[UIColor whiteColor] colorWithAlphaComponent:0.7]
+ darkColor:[UIColor colorWithRed:70.0 / 255.0 green:70.0 / 255.0 blue:70.0 / 255.0 alpha:0.7]];
+}
+
++ (UIColor *)highlightedColor {
+ return [self colorPairsWithDynamicLightColor:[[UIColor grayColor] colorWithAlphaComponent:0.2]
+ darkColor:[UIColor colorWithRed:80.0 / 255.0 green:80.0 / 255.0 blue:80.0 / 255.0 alpha:0.7]];
+}
+
++ (UIColor *)lineColor {
+ return [self colorPairsWithDynamicLightColor:[self lightLineColor]
+ darkColor:[self darkLineColor]];
+}
+
++ (UIColor *)line2Color {
+ return [self colorPairsWithDynamicLightColor:[[UIColor grayColor] colorWithAlphaComponent:0.1]
+ darkColor:[[UIColor grayColor] colorWithAlphaComponent:0.25]];
+}
+
++ (UIColor *)lightWhite_DarkBlackColor {
+ return [self colorPairsWithDynamicLightColor:[UIColor whiteColor]
+ darkColor:[UIColor blackColor]];
+}
+
++ (UIColor *)lightBlack_DarkWhiteColor {
+ return [self colorPairsWithDynamicLightColor:[UIColor blackColor]
+ darkColor:[UIColor whiteColor]];
+}
+
++ (UIColor *)lightLineColor {
+ return [[UIColor grayColor] colorWithAlphaComponent:0.3];
+}
+
++ (UIColor *)darkLineColor {
+ return [[UIColor whiteColor] colorWithAlphaComponent:0.3];
+}
+
++ (UIColor *)textViewBackgroundColor {
+ return [self colorPairsWithDynamicLightColor:[UIColor colorWithRed:247.0 / 255.0 green:247.0 / 255.0 blue:247.0 / 255.0 alpha:1.0]
+ darkColor:[UIColor colorWithRed:54.0 / 255.0 green:54.0 / 255.0 blue:54.0 / 255.0 alpha:1.0]];
+}
+
++ (UIColor *)alertRedColor {
+ return [UIColor systemRedColor];
+}
+
++ (UIColor *)grayColor {
+ return [UIColor grayColor];
+}
+
++ (UIColor *)colorPairsWithDynamicLightColor:(UIColor *)lightColor darkColor:(UIColor *)darkColor {
+ if (@available(iOS 13.0, *)) {
+ return [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
+ if(traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
+ return darkColor;
+ } else {
+ return lightColor;
+ }
+ }];
+ } else {
+ return lightColor;
+ }
+}
+
++ (UIColor *)colorPairsWithStaticLightColor:(UIColor *)lightColor darkColor:(UIColor *)darkColor {
+ if (@available(iOS 13.0, *)) {
+ UIUserInterfaceStyle mode = UITraitCollection.currentTraitCollection.userInterfaceStyle;
+ if (mode == UIUserInterfaceStyleDark) {
+ return darkColor;
+ } else if (mode == UIUserInterfaceStyleLight) {
+ return lightColor;
+ } else {
+ return lightColor;
+ }
+ }
+ return lightColor;
+}
+
+@end
#pragma mark ---------------------------- SPAlertAction begin --------------------------------
@@ -37,6 +137,7 @@ @implementation SPAlertAction
// 由于要对装载action的数组进行拷贝,所以SPAlertAction也需要支持拷贝
- (id)copyWithZone:(NSZone *)zone {
+
SPAlertAction *action = [[[self class] alloc] init];
action.title = self.title;
action.attributedTitle = self.attributedTitle;
@@ -49,6 +150,8 @@ - (id)copyWithZone:(NSZone *)zone {
action.titleEdgeInsets = self.titleEdgeInsets;
action.handler = self.handler;
action.propertyChangedBlock = self.propertyChangedBlock;
+ action.allowsAutoDismiss = self.allowsAutoDismiss;
+ action.backgroundColor = self.backgroundColor;
return action;
}
@@ -63,14 +166,14 @@ - (instancetype)initWithTitle:(nullable NSString *)title style:(SPAlertActionSty
self.style = style;
self.handler = handler;
if (style == SPAlertActionStyleDestructive) {
- self.titleColor = [UIColor redColor];
- self.titleFont = [UIFont systemFontOfSize:SP_ACTION_TITLE_FONTSIZE];
+ self.titleColor = [_SPColorStyle alertRedColor];
+ self.titleFont = [UIFont systemFontOfSize:SPALERT_ACTION_TITLE_FONTSIZE];
} else if (style == SPAlertActionStyleCancel) {
- self.titleColor = [UIColor blackColor];
- self.titleFont = [UIFont boldSystemFontOfSize:SP_ACTION_TITLE_FONTSIZE];
+ self.titleColor = [_SPColorStyle lightBlack_DarkWhiteColor];
+ self.titleFont = [UIFont boldSystemFontOfSize:SPALERT_ACTION_TITLE_FONTSIZE];
} else {
- self.titleColor = [UIColor blackColor];
- self.titleFont = [UIFont systemFontOfSize:SP_ACTION_TITLE_FONTSIZE];
+ self.titleColor = [_SPColorStyle lightBlack_DarkWhiteColor];
+ self.titleFont = [UIFont systemFontOfSize:SPALERT_ACTION_TITLE_FONTSIZE];
}
return self;
}
@@ -84,9 +187,11 @@ - (instancetype)init {
- (void)initialize {
_enabled = YES; // 默认能点击
- _titleColor = [UIColor blackColor];
- _titleFont = [UIFont systemFontOfSize:SP_ACTION_TITLE_FONTSIZE];
+ _allowsAutoDismiss = YES; // 默认点击后自动dismiss
+ _titleColor = [_SPColorStyle lightBlack_DarkWhiteColor];
+ _titleFont = [UIFont systemFontOfSize:SPALERT_ACTION_TITLE_FONTSIZE];
_titleEdgeInsets = UIEdgeInsetsMake(0, 15, 0, 15);
+ _backgroundColor = [_SPColorStyle normalColor];
}
- (void)setTitle:(NSString *)title {
@@ -124,6 +229,13 @@ - (void)setTitleColor:(UIColor *)titleColor {
}
}
+- (void)setBackgroundColor:(UIColor *)backgroundColor {
+ _backgroundColor = backgroundColor;
+ if (self.propertyChangedBlock) {
+ self.propertyChangedBlock(self,NO); // 背景色改变不需要更新布局
+ }
+}
+
- (void)setTitleFont:(UIFont *)titleFont {
_titleFont = titleFont;
if (self.propertyChangedBlock) {
@@ -149,14 +261,14 @@ @interface SPInterfaceActionItemSeparatorView : UIView
@implementation SPInterfaceActionItemSeparatorView
- (instancetype)init {
if (self = [super init]) {
- self.backgroundColor = SP_LINE_COLOR;
+ self.backgroundColor = [_SPColorStyle lineColor];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
- self.backgroundColor = self.frame.size.height > SP_LINE_WIDTH ? [[UIColor grayColor] colorWithAlphaComponent:0.2] : SP_LINE_COLOR;
+ self.backgroundColor = MIN(self.frame.size.width, self.frame.size.height) > SPALERT_LINE_WIDTH ? [_SPColorStyle line2Color] : [_SPColorStyle lineColor];
}
@end
@@ -165,12 +277,12 @@ - (void)layoutSubviews {
#pragma mark ---------------------------- SPInterfaceHeaderScrollView begin ----------------------------
@interface SPInterfaceHeaderScrollView : UIScrollView
-@property (nonatomic, weak) UIView *contentView;
-@property (nonatomic, weak) UILabel *titleLabel;
-@property (nonatomic, weak) UILabel *messageLabel;
-@property (nonatomic, weak) UIImageView *imageView;
+@property (nonatomic, strong) UIView *contentView;
+@property (nonatomic, strong) UILabel *titleLabel;
+@property (nonatomic, strong) UILabel *messageLabel;
+@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, assign) CGSize imageLimitSize;
-@property (nonatomic, weak) UIStackView *textFieldView;
+@property (nonatomic, strong) UIStackView *textFieldView;
@property (nonatomic, strong) NSMutableArray *textFields;
@property (nonatomic, assign) UIEdgeInsets contentEdgeInsets;
@property (nonatomic, copy) void(^headerViewSfeAreaDidChangBlock)(void);
@@ -194,10 +306,21 @@ - (void)addTextField:(UITextField *)textField {
// 将textView添加到self.textFieldView中的布局队列中,UIStackView会根据设置的属性自动布局
[self.textFieldView addArrangedSubview:textField];
// 由于self.textFieldView是没有高度的,它的高度由子控件撑起,所以子控件必须要有高度
- [[NSLayoutConstraint constraintWithItem:textField attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:25.0f] setActive:YES];
+ [[NSLayoutConstraint constraintWithItem:textField attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:30.0f] setActive:YES];
[self setNeedsUpdateConstraints];
}
+- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
+ [super traitCollectionDidChange:previousTraitCollection];
+ if (@available(iOS 13.0, *)) {
+ // 设置CGColor,不要传previousTraitCollection,previousTraitCollection指的是上一次的模式
+ UIColor *resolvedColor = [[_SPColorStyle lineColor] resolvedColorWithTraitCollection:self.traitCollection];
+ for (UITextField *textField in self.textFields) {
+ textField.layer.borderColor = resolvedColor.CGColor;
+ }
+ }
+}
+
- (NSMutableArray *)textFields {
if (!_textFields) {
_textFields = [[NSMutableArray alloc] init];
@@ -210,7 +333,7 @@ - (void)safeAreaInsetsDidChange {
CGFloat safeTop = self.safeAreaInsets.top < 20 ? 20 : self.safeAreaInsets.top+10;
CGFloat safeLeft = self.safeAreaInsets.left < 15 ? 15 : self.safeAreaInsets.left;
CGFloat safeBottom = self.safeAreaInsets.bottom < 20 ? 20 : self.safeAreaInsets.bottom+6;
- CGFloat safeRight = self.safeAreaInsets.right < 15 ? 15 : self.safeAreaInsets.right;
+ CGFloat safeRight = self.safeAreaInsets.right < 15 ? 15 : self.safeAreaInsets.right;
_contentEdgeInsets = UIEdgeInsetsMake(safeTop, safeLeft, safeBottom, safeRight);
// 这个block,主要是更新Label的最大预估宽度
if (self.headerViewSfeAreaDidChangBlock) {
@@ -325,7 +448,7 @@ - (UILabel *)titleLabel {
UILabel *titleLabel = [[UILabel alloc] init];
titleLabel.font = [UIFont boldSystemFontOfSize:18];
titleLabel.textAlignment = NSTextAlignmentCenter;
- titleLabel.textColor = [UIColor blackColor];
+ titleLabel.textColor = [_SPColorStyle lightBlack_DarkWhiteColor];
titleLabel.numberOfLines = 0;
titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:titleLabel];
@@ -339,7 +462,7 @@ - (UILabel *)messageLabel {
UILabel *messageLabel = [[UILabel alloc] init];
messageLabel.font = [UIFont systemFontOfSize:18];
messageLabel.textAlignment = NSTextAlignmentCenter;
- messageLabel.textColor = [UIColor grayColor];
+ messageLabel.textColor = [_SPColorStyle grayColor];
messageLabel.numberOfLines = 0;
messageLabel.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:messageLabel];
@@ -360,14 +483,14 @@ - (UIImageView *)imageView {
- (UIStackView *)textFieldView {
if (!_textFieldView) {
- UIStackView *textFieldView = [[UIStackView alloc] init];
- textFieldView.translatesAutoresizingMaskIntoConstraints = NO;
- textFieldView.distribution = UIStackViewDistributionFillEqually;
- textFieldView.axis = UILayoutConstraintAxisVertical;
if (self.textFields.count) {
+ UIStackView *textFieldView = [[UIStackView alloc] init];
+ textFieldView.translatesAutoresizingMaskIntoConstraints = NO;
+ textFieldView.distribution = UIStackViewDistributionFillEqually;
+ textFieldView.axis = UILayoutConstraintAxisVertical;
[self.contentView addSubview:textFieldView];
+ _textFieldView = textFieldView;
}
- _textFieldView = textFieldView;
}
return _textFieldView;
}
@@ -378,12 +501,11 @@ - (UIStackView *)textFieldView {
#pragma mark ---------------------------- SPAlertControllerActionView begin --------------------------------
-@interface SPAlertControllerActionView : UIView {
- id _target;
- SEL _methodAction;
-}
+@interface SPAlertControllerActionView : UIView
+@property (nonatomic, weak) id target;
+@property (nonatomic, assign) SEL methodAction;
@property (nonatomic, strong) SPAlertAction *action;
-@property (nonatomic, weak) UIButton *actionButton;
+@property (nonatomic, strong) UIButton *actionButton;
@property (nonatomic, strong) NSMutableArray *actionButtonConstraints;
@property (nonatomic, assign) CGFloat afterSpacing;
- (void)addTarget:(id)target action:(SEL)action;
@@ -393,7 +515,7 @@ @implementation SPAlertControllerActionView
- (instancetype)init {
if (self = [super init]) {
- _afterSpacing = SP_LINE_WIDTH;
+ _afterSpacing = SPALERT_LINE_WIDTH;
}
return self;
}
@@ -405,15 +527,21 @@ - (void)setAction:(SPAlertAction *)action {
if (action.enabled) {
[self.actionButton setTitleColor:action.titleColor forState:UIControlStateNormal];
} else {
- [self.actionButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
+ [self.actionButton setTitleColor:[action.titleColor colorWithAlphaComponent:0.4] forState:UIControlStateNormal];
+ }
+
+ // 设置背景色
+ if (action.backgroundColor) {
+ self.actionButton.backgroundColor = action.backgroundColor;
}
// 注意不能赋值给按钮的titleEdgeInsets,当只有文字时,按钮的titleEdgeInsets设置top和bottom值无效
self.actionButton.contentEdgeInsets = action.titleEdgeInsets;
self.actionButton.enabled = action.enabled;
+ self.actionButton.tintColor = action.tintColor;
if (action.attributedTitle) {
// 这里之所以要设置按钮颜色为黑色,是因为如果外界在addAction:之后设置按钮的富文本,那么富文本的颜色在没有采用NSForegroundColorAttributeName的情况下会自动读取按钮上普通文本的颜色,在addAction:之前设置会保持默认色(黑色),为了在addAction:前后设置富文本保持统一,这里先将按钮置为黑色,富文本就会是黑色
- [self.actionButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
+ [self.actionButton setTitleColor:[_SPColorStyle lightBlack_DarkWhiteColor] forState:UIControlStateNormal];
if ([action.attributedTitle.string containsString:@"\n"] || [action.attributedTitle.string containsString:@"\r"]) {
self.actionButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
@@ -444,14 +572,31 @@ - (void)touchUpInside:(UIButton *)sender {
IMP imp = [_target methodForSelector:selector];
void (*func)(id, SEL,SPAlertControllerActionView *) = (void *)imp;
func(_target, selector, self);
+
+ // 加动画才能看到高亮颜色
+ [UIView animateWithDuration:0.2 animations:^{
+ sender.backgroundColor = self.action.backgroundColor;
+ }];
}
- (void)touchDown:(UIButton *)sender {
- sender.backgroundColor = SP_SELECTED_COLOR;
+ sender.backgroundColor = [_SPColorStyle highlightedColor];
}
- (void)touchDragExit:(UIButton *)sender {
- sender.backgroundColor = SP_NORMAL_COLOR;
+ sender.backgroundColor = [_SPColorStyle normalColor];
+}
+
+- (SPAlertController *)findAlertController {
+ UIResponder *next = [self nextResponder];
+ do {
+ if ([next isKindOfClass:[SPAlertController class]]) {
+ return (SPAlertController *)next;
+ } else {
+ next = [next nextResponder];
+ }
+ } while (next != nil);
+ return nil;
}
// 安全区域发生了改变,在这个方法里自动适配iPhoneX
@@ -463,9 +608,6 @@ - (void)safeAreaInsetsDidChange {
}
UIEdgeInsets UIEdgeInsetsAddEdgeInsets(UIEdgeInsets i1,UIEdgeInsets i2) {
- if (i1.bottom > 21) {
- i1.bottom = 21; // 34的高度太大,这里转为21
- }
return UIEdgeInsetsMake(i1.top+i2.top, i1.left+i2.left, i1.bottom+i2.bottom, i1.right+i2.right);
}
@@ -485,8 +627,8 @@ - (void)updateConstraints {
CGFloat labelH = actionButton.titleLabel.intrinsicContentSize.height;
// 按钮的上下内边距之和
CGFloat topBottom_insetsSum = actionButton.contentEdgeInsets.top+actionButton.contentEdgeInsets.bottom;
- // 文字的上下间距之和,等于SP_ACTION_HEIGHT-默认字体大小,这是为了保证文字上下有一个固定间距值,不至于使文字靠按钮太紧,,由于按钮内容默认垂直居中,所以最终的顶部或底部间距为topBottom_marginSum/2.0,这个间距,几乎等于18号字体时,最小高度为49时的上下间距
- CGFloat topBottom_marginSum = SP_ACTION_HEIGHT-[UIFont systemFontOfSize:SP_ACTION_TITLE_FONTSIZE].lineHeight;
+ // 文字的上下间距之和,等于SPALERT_ACTION_HEIGHT-默认字体大小,这是为了保证文字上下有一个固定间距值,不至于使文字靠按钮太紧,,由于按钮内容默认垂直居中,所以最终的顶部或底部间距为topBottom_marginSum/2.0,这个间距,几乎等于18号字体时,最小高度为49时的上下间距
+ CGFloat topBottom_marginSum = SPALERT_ACTION_HEIGHT-[UIFont systemFontOfSize:SPALERT_ACTION_TITLE_FONTSIZE].lineHeight;
// 按钮高度
CGFloat buttonH = labelH+topBottom_insetsSum+topBottom_marginSum;
UIStackView *stackView = (UIStackView *)self.superview;
@@ -494,12 +636,12 @@ - (void)updateConstraints {
if ([stackView isKindOfClass:[UIStackView class]] && stackView.axis == UILayoutConstraintAxisHorizontal) {
relation = NSLayoutRelationGreaterThanOrEqual;
}
- // 如果字体保持默认18号,只有一行文字时最终结果约等于SP_ACTION_HEIGHT
+ // 如果字体保持默认18号,只有一行文字时最终结果约等于SPALERT_ACTION_HEIGHT
NSLayoutConstraint *buttonHonstraint = [NSLayoutConstraint constraintWithItem:actionButton attribute:NSLayoutAttributeHeight relatedBy:relation toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:buttonH];
buttonHonstraint.priority = 999;
[actionButtonConstraints addObject:buttonHonstraint];
// 给一个最小高度,当按钮字体很小时,如果还按照上面的高度计算,高度会比较小
- NSLayoutConstraint *minHConstraint = [NSLayoutConstraint constraintWithItem:actionButton attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SP_ACTION_HEIGHT+topBottom_insetsSum];
+ NSLayoutConstraint *minHConstraint = [NSLayoutConstraint constraintWithItem:actionButton attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SPALERT_ACTION_HEIGHT+topBottom_insetsSum];
minHConstraint.priority = UILayoutPriorityRequired;
[self addConstraints:actionButtonConstraints];
self.actionButtonConstraints = actionButtonConstraints;
@@ -508,7 +650,7 @@ - (void)updateConstraints {
- (UIButton *)actionButton {
if (!_actionButton) {
UIButton *actionButton = [UIButton buttonWithType:UIButtonTypeCustom];
- actionButton.backgroundColor = SP_NORMAL_COLOR;
+ actionButton.backgroundColor = [_SPColorStyle normalColor];
actionButton.translatesAutoresizingMaskIntoConstraints = NO;
actionButton.titleLabel.textAlignment = NSTextAlignmentCenter;
actionButton.titleLabel.adjustsFontSizeToFitWidth = YES;
@@ -529,11 +671,11 @@ - (UIButton *)actionButton {
#pragma mark ---------------------------- SPInterfaceActionSequenceView begin --------------------------------
@interface SPInterfaceActionSequenceView : UIView
-@property (nonatomic, weak) UIScrollView *scrollView;
-@property (nonatomic, weak) UIView *contentView;
-@property (nonatomic, weak) UIView *cancelView;
-@property (nonatomic, weak) SPInterfaceActionItemSeparatorView *cancelActionLine;
-@property (nonatomic, weak) UIStackView *stackView;
+@property (nonatomic, strong) UIScrollView *scrollView;
+@property (nonatomic, strong) UIView *contentView;
+@property (nonatomic, strong) UIView *cancelView;
+@property (nonatomic, strong) SPInterfaceActionItemSeparatorView *cancelActionLine;
+@property (nonatomic, strong) UIStackView *stackView;
@property (nonatomic, strong) SPAlertAction *cancelAction;
@property (nonatomic, strong) NSMutableArray *actionLineConstraints;
@property (nonatomic, strong) NSMutableArray *actions;
@@ -546,6 +688,7 @@ @implementation SPInterfaceActionSequenceView
- (void)setAxis:(UILayoutConstraintAxis)axis {
_axis = axis;
+ self.scrollView.scrollEnabled = axis == UILayoutConstraintAxisVertical;
self.stackView.axis = axis;
[self setNeedsUpdateConstraints];
}
@@ -636,7 +779,7 @@ - (void)updateLineConstraints {
UIStackView *stackView = self.stackView;
NSArray *arrangedSubviews = stackView.arrangedSubviews;
if (arrangedSubviews.count <= 1) return;
- // 用谓词语句筛选出所有的分割线
+ // 用谓词语句筛选出所有的分割线
NSArray *lines = [self filteredArrayFromArray:stackView.subviews notInArray:stackView.arrangedSubviews];
if (arrangedSubviews.count < lines.count) return;
NSMutableArray *actionLineConstraints = [NSMutableArray array];
@@ -690,26 +833,26 @@ - (void)updateConstraints {
[NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[contentView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(contentView)]];
[[NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0] setActive:YES];
NSLayoutConstraint *equalHeightConstraint = [NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0];
- // 计算scrolView的最小和最大高度,下面这个if语句是保证当actions的g总个数大于4时,scrollView的高度至少为4个半SP_ACTION_HEIGHT的高度,否则自适应内容
+ // 计算scrolView的最小和最大高度,下面这个if语句是保证当actions的g总个数大于4时,scrollView的高度至少为4个半SPALERT_ACTION_HEIGHT的高度,否则自适应内容
CGFloat minHeight = 0.0;
if (_axis == UILayoutConstraintAxisVertical) {
if (self.cancelAction) {
- if (self.actions.count > 4) { // 如果有取消按钮且action总个数大于4,则除去取消按钮之外的其余部分的高度至少为3个半SP_ACTION_HEIGHT的高度,即加上取消按钮就是总高度至少为4个半SP_ACTION_HEIGHT的高度
- minHeight = SP_ACTION_HEIGHT * 3.5;
+ if (self.actions.count > 4) { // 如果有取消按钮且action总个数大于4,则除去取消按钮之外的其余部分的高度至少为3个半SPALERT_ACTION_HEIGHT的高度,即加上取消按钮就是总高度至少为4个半SPALERT_ACTION_HEIGHT的高度
+ minHeight = SPALERT_ACTION_HEIGHT * 3.5;
equalHeightConstraint.priority = 997.0f; // 优先级为997,必须小于998.0,因为头部如果内容过多时高度也会有限制,头部的优先级为998.0.这里定的规则是,当头部和action部分同时过多时,头部的优先级更高,但是它不能高到以至于action部分小于最小高度
} else { // 如果有取消按钮但action的个数大不于4,则该多高就显示多高
equalHeightConstraint.priority = 1000.0f; // 由子控件撑起
}
} else {
if (self.actions.count > 4) {
- minHeight = SP_ACTION_HEIGHT * 4.5;
+ minHeight = SPALERT_ACTION_HEIGHT * 4.5;
equalHeightConstraint.priority = 997.0f;
} else {
equalHeightConstraint.priority = 1000.0f;
}
}
} else {
- minHeight = SP_ACTION_HEIGHT;
+ minHeight = SPALERT_ACTION_HEIGHT;
}
NSLayoutConstraint *minHeightConstraint = [NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:minHeight];
minHeightConstraint.priority = 999.0;// 优先级不能大于对话框的最小顶部间距的优先级(999.0)
@@ -730,7 +873,7 @@ - (void)updateConstraints {
NSMutableArray *cancelActionLineConstraints = [NSMutableArray array];
[cancelActionLineConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[cancelActionLine]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(cancelActionLine)]];
[cancelActionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:cancelActionLine attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:cancelView attribute:NSLayoutAttributeTop multiplier:1.0f constant:0]];
- [cancelActionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:cancelActionLine attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:6.0]];
+ [cancelActionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:cancelActionLine attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:8.0]];
[NSLayoutConstraint activateConstraints:cancelActionLineConstraints];
}
@@ -748,16 +891,17 @@ - (void)updateConstraints {
- (UIScrollView *)scrollView {
if (!_scrollView) {
- UIScrollView *scrollView = [[UIScrollView alloc] init];
- scrollView.showsHorizontalScrollIndicator = NO;
- scrollView.translatesAutoresizingMaskIntoConstraints = NO;
- if (@available(iOS 11.0, *)) {
- scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
- }
if ((self.cancelAction && self.actions.count > 1) || (!self.cancelAction && self.actions.count > 0)) {
+ UIScrollView *scrollView = [[UIScrollView alloc] init];
+ scrollView.showsHorizontalScrollIndicator = NO;
+ scrollView.alwaysBounceVertical = NO;
+ scrollView.translatesAutoresizingMaskIntoConstraints = NO;
+ if (@available(iOS 11.0, *)) {
+ scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
+ }
[self addSubview:scrollView];
+ _scrollView = scrollView;
}
- _scrollView = scrollView;
}
return _scrollView;
}
@@ -777,7 +921,7 @@ - (UIStackView *)stackView {
UIStackView *stackView = [[UIStackView alloc] init];
stackView.translatesAutoresizingMaskIntoConstraints = NO;
stackView.distribution = UIStackViewDistributionFillProportionally;
- stackView.spacing = SP_LINE_WIDTH; // 该间距腾出来的空间显示分割线
+ stackView.spacing = SPALERT_LINE_WIDTH; // 该间距腾出来的空间显示分割线
stackView.axis = UILayoutConstraintAxisVertical;
[self.contentView addSubview:stackView];
_stackView = stackView;
@@ -787,24 +931,24 @@ - (UIStackView *)stackView {
- (UIView *)cancelView {
if (!_cancelView) {
- UIView *cancelView = [[UIView alloc] init];
- cancelView.translatesAutoresizingMaskIntoConstraints = NO;
if (self.cancelAction) {
+ UIView *cancelView = [[UIView alloc] init];
+ cancelView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:cancelView];
+ _cancelView = cancelView;
}
- _cancelView = cancelView;
}
return _cancelView;
}
- (SPInterfaceActionItemSeparatorView *)cancelActionLine {
if (!_cancelActionLine) {
- SPInterfaceActionItemSeparatorView *cancelActionLine = [[SPInterfaceActionItemSeparatorView alloc] init];
- cancelActionLine.translatesAutoresizingMaskIntoConstraints = NO;
if (self.cancelView.superview && self.scrollView.superview) {
+ SPInterfaceActionItemSeparatorView *cancelActionLine = [[SPInterfaceActionItemSeparatorView alloc] init];
+ cancelActionLine.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:cancelActionLine];
+ _cancelActionLine = cancelActionLine;
}
- _cancelActionLine = cancelActionLine;
}
return _cancelActionLine;
}
@@ -824,18 +968,18 @@ - (NSMutableArray *)actions {
@interface SPAlertController ()
@property (nonatomic, strong) UIView *alertControllerView;
-@property (nonatomic, weak) UIView *containerView;
-@property (nonatomic, weak) UIView *alertView;
+@property (nonatomic, strong) UIView *containerView;
+@property (nonatomic, strong) UIView *alertView;
@property (nonatomic, strong) UIView *customAlertView;
-@property (nonatomic, weak) SPInterfaceHeaderScrollView *headerView;
+@property (nonatomic, strong) SPInterfaceHeaderScrollView *headerView;
@property (nonatomic, strong) UIView *customHeaderView;
-@property (nonatomic, weak) SPInterfaceActionSequenceView *actionSequenceView;
+@property (nonatomic, strong) SPInterfaceActionSequenceView *actionSequenceView;
@property (nonatomic, strong) UIView *customActionSequenceView;
@property (nonatomic, strong) UIView *componentView;
@property (nonatomic, assign) CGSize customViewSize;
-@property (nonatomic, weak) SPInterfaceActionItemSeparatorView *headerActionLine;
+@property (nonatomic, strong) SPInterfaceActionItemSeparatorView *headerActionLine;
@property (nonatomic, strong) NSMutableArray *headerActionLineConstraints;
-@property (nonatomic, weak) SPInterfaceActionItemSeparatorView *componentActionLine;
+@property (nonatomic, strong) SPInterfaceActionItemSeparatorView *componentActionLine;
@property (nonatomic, strong) NSMutableArray *componentViewConstraints;
@property (nonatomic, strong) NSMutableArray *componentActionLineConstraints;
@property (nonatomic, strong) UIView *dimmingKnockoutBackdropView;
@@ -844,7 +988,7 @@ @interface SPAlertController ()
@property (nonatomic, strong) NSMutableArray *actionSequenceViewConstraints;
@property (nonatomic, assign) SPAlertControllerStyle preferredStyle;
@property (nonatomic, assign) SPAlertAnimationType animationType;
-@property (nonatomic, assign) SPBackgroundViewAppearanceStyle backgroundViewAppearanceStyle;
+@property (nonatomic, assign) UIBlurEffectStyle backgroundViewAppearanceStyle;
@property (nonatomic, assign) CGFloat backgroundViewAlpha;
// action数组
@@ -855,6 +999,8 @@ @interface SPAlertController ()
@property (nonatomic) NSMutableArray *otherActions;
@property (nonatomic, assign) BOOL isForceLayout; // 是否强制排列,外界设置了actionAxis属性认为是强制
@property (nonatomic, assign) BOOL isForceOffset; // 是否强制偏移,外界设置了offsetForAlert属性认为是强制
+@property (nonatomic, assign) BOOL isSyncingKeyboardAnimation;
+
@end
@implementation SPAlertController
@@ -881,7 +1027,7 @@ + (instancetype)alertControllerWithCustomHeaderView:(UIView *)customHeaderView p
return alertVc;
}
-+ (instancetype)alertControllerWithCustomActionSequenceView:(nullable UIView *)customActionSequenceView title:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType {
++ (instancetype)alertControllerWithCustomActionSequenceView:(UIView *)customActionSequenceView title:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(SPAlertControllerStyle)preferredStyle animationType:(SPAlertAnimationType)animationType {
SPAlertController *alertVc = [[SPAlertController alloc] initWithTitle:title message:message customAlertView:nil customHeaderView:nil customActionSequenceView:customActionSequenceView componentView:nil preferredStyle:preferredStyle animationType:animationType];
return alertVc;
}
@@ -917,13 +1063,8 @@ - (void)addAction:(SPAlertAction *)action {
if (!self.isForceLayout) { // 如果为NO,说明外界没有设置actionAxis,此时按照默认方式排列
if (self.preferredStyle == SPAlertControllerStyleAlert) {
- if (self.actions.count > _maxNumberOfActionHorizontalArrangementForAlert) { // alert样式下,action的个数大于2时垂直排列,这里不等式右边写_maxNumberOfActionHorizontalArrangementForAlert是为了让被废弃的_maxNumberOfActionHorizontalArrangementForAlert依然生效
- _actionAxis = UILayoutConstraintAxisVertical; // 本框架任何一处都不允许调用actionAxis的setter方法,如果调用了则无法判断是外界调用还是内部调用
- [self updateActionAxis];
- } else { // action的个数小于等于2,action水平排列
- _actionAxis = UILayoutConstraintAxisHorizontal;
- [self updateActionAxis];
- }
+ _actionAxis = UILayoutConstraintAxisHorizontal;
+ [self updateActionAxis];
} else { // actionSheet样式下默认垂直排列
_actionAxis = UILayoutConstraintAxisVertical;
[self updateActionAxis];
@@ -972,14 +1113,14 @@ - (void)addAction:(SPAlertAction *)action {
// 添加文本输入框
- (void)addTextFieldWithConfigurationHandler:(void (^)(UITextField * _Nonnull))configurationHandler {
- NSString *errorDesc = [NSString stringWithFormat:@"SPAlertController does not allow '%@' to be called in the style of SPAlertControllerStyleActionSheet",NSStringFromSelector(_cmd)];
- NSAssert(self.preferredStyle == SPAlertControllerStyleAlert,errorDesc);
+ NSAssert(self.preferredStyle == SPAlertControllerStyleAlert,@"SPAlertController does not allow 'addTextFieldWithConfigurationHandler:' to be called in the style of SPAlertControllerStyleActionSheet");
UITextField *textField = [[UITextField alloc] init];
textField.translatesAutoresizingMaskIntoConstraints = NO;
- textField.backgroundColor = [UIColor whiteColor];
+ textField.backgroundColor = [_SPColorStyle textViewBackgroundColor];
// 系统的UITextBorderStyleLine样式线条过于黑,所以自己设置
- textField.layer.borderWidth = SP_LINE_WIDTH;
- textField.layer.borderColor = [UIColor grayColor].CGColor;
+ textField.layer.borderWidth = SPALERT_LINE_WIDTH;
+ // 这里设置的颜色是静态的,动态设置CGColor,还需要监听深浅模式的切换
+ textField.layer.borderColor = [_SPColorStyle colorPairsWithStaticLightColor:[_SPColorStyle lineColor] darkColor:[_SPColorStyle darkLineColor]].CGColor;
// 在左边设置一张view,充当光标左边的间距,否则光标紧贴textField不美观
textField.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 0)];
textField.leftView.userInteractionEnabled = NO;
@@ -1027,7 +1168,7 @@ - (CGFloat)customSpacingAfterAction:(SPAlertAction *)action {
return 0.0;
}
-- (void)setBackgroundViewAppearanceStyle:(SPBackgroundViewAppearanceStyle)style alpha:(CGFloat)alpha {
+- (void)setBackgroundViewAppearanceStyle:(UIBlurEffectStyle)style alpha:(CGFloat)alpha {
_backgroundViewAppearanceStyle = style;
_backgroundViewAlpha = alpha;
}
@@ -1054,12 +1195,11 @@ - (instancetype)initWithTitle:(nullable NSString *)title message:(nullable NSStr
}
_animationType = animationType;
if (preferredStyle == SPAlertControllerStyleAlert) {
- _maxMarginForAlert = (MIN(SP_SCREEN_WIDTH, SP_SCREEN_HEIGHT) - 275) / 2.0;
- _minDistanceToEdges = (MIN(SP_SCREEN_WIDTH, SP_SCREEN_HEIGHT) - 275) / 2.0;
+ _minDistanceToEdges = (MIN(SPALERT_SCREEN_WIDTH, SPALERT_SCREEN_HEIGHT) - 275) / 2.0;
} else {
_minDistanceToEdges = 70;
- _maxTopMarginForActionSheet = 70;
}
+ _cornerRadius = 13.0;
if (preferredStyle == SPAlertControllerStyleAlert) {
_actionAxis = UILayoutConstraintAxisHorizontal;
} else {
@@ -1087,16 +1227,15 @@ - (void)initialize {
self.transitioningDelegate = self;
_titleFont = [UIFont boldSystemFontOfSize:18];
- _titleColor = [UIColor blackColor];
+ _titleColor = [_SPColorStyle lightBlack_DarkWhiteColor];
_messageFont = [UIFont systemFontOfSize:16];
- _messageColor = [UIColor grayColor];
+ _messageColor = [_SPColorStyle grayColor];
_textAlignment = NSTextAlignmentCenter;
_imageLimitSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
+ _backgroundViewAppearanceStyle = -1;
_backgroundViewAlpha = 0.5;
- _cornerRadiusForAlert = 6.0;
_tapBackgroundViewDismiss = YES;
- _needDialogBlur = YES;
- _maxNumberOfActionHorizontalArrangementForAlert = 2;
+ _needDialogBlur = NO;
}
- (void)layoutAlertControllerView {
@@ -1117,10 +1256,10 @@ - (void)layoutAlertControllerViewForAlertStyle {
NSMutableArray *alertControllerViewConstraints = [NSMutableArray array];
CGFloat topValue = _minDistanceToEdges;
CGFloat bottomValue = _minDistanceToEdges;
- CGFloat maxWidth = MIN(SP_SCREEN_WIDTH, SP_SCREEN_HEIGHT)-_minDistanceToEdges * 2;
- CGFloat maxHeight = SP_SCREEN_HEIGHT-topValue-bottomValue;
+ CGFloat maxWidth = MIN(SPALERT_SCREEN_WIDTH, SPALERT_SCREEN_HEIGHT)-_minDistanceToEdges * 2;
+ CGFloat maxHeight = SPALERT_SCREEN_HEIGHT-topValue-bottomValue;
if (!self.customAlertView) {
- // 当屏幕旋转的时候,为了保持alert样式下的宽高不变,因此取MIN(SP_SCREEN_WIDTH, SP_SCREEN_HEIGHT)
+ // 当屏幕旋转的时候,为了保持alert样式下的宽高不变,因此取MIN(SPALERT_SCREEN_WIDTH, SPALERT_SCREEN_HEIGHT)
[alertControllerViewConstraints addObject:[NSLayoutConstraint constraintWithItem:alertControllerView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:maxWidth]];
} else {
[alertControllerViewConstraints addObject:[NSLayoutConstraint constraintWithItem:alertControllerView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:maxWidth]];
@@ -1150,7 +1289,6 @@ - (void)layoutAlertControllerViewForAlertStyle {
- (void)layoutAlertControllerViewForActionSheetStyle {
switch (self.animationType) {
case SPAlertAnimationTypeFromBottom:
- case SPAlertAnimationTypeRaiseUp:
default:
[self layoutAlertControllerViewForAnimationTypeWithHV:@"H"
equalAttribute:NSLayoutAttributeBottom
@@ -1158,7 +1296,6 @@ - (void)layoutAlertControllerViewForActionSheetStyle {
lessOrGreaterRelation:NSLayoutRelationGreaterThanOrEqual];
break;
case SPAlertAnimationTypeFromTop:
- case SPAlertAnimationTypeDropDown:
[self layoutAlertControllerViewForAnimationTypeWithHV:@"H"
equalAttribute:NSLayoutAttributeTop
notEqualAttribute:NSLayoutAttributeBottom
@@ -1172,8 +1309,8 @@ - (void)layoutAlertControllerViewForActionSheetStyle {
break;
case SPAlertAnimationTypeFromRight:
[self layoutAlertControllerViewForAnimationTypeWithHV:@"V"
- equalAttribute:NSLayoutAttributeLeft
- notEqualAttribute:NSLayoutAttributeRight
+ equalAttribute:NSLayoutAttributeRight
+ notEqualAttribute:NSLayoutAttributeLeft
lessOrGreaterRelation:NSLayoutRelationLessThanOrEqual];
break;
}
@@ -1193,18 +1330,18 @@ - (void)layoutAlertControllerViewForAnimationTypeWithHV:(NSString *)hv
if (_customViewSize.width) { // 如果宽度没有值,则会假定customAlertViewh水平方向能由子控件撑起
CGFloat alertControllerViewWidth = 0.0;
if ([hv isEqualToString:@"H"]) {
- alertControllerViewWidth = MIN(_customViewSize.width, SP_SCREEN_WIDTH);
+ alertControllerViewWidth = MIN(_customViewSize.width, SPALERT_SCREEN_WIDTH);
} else {
- alertControllerViewWidth = MIN(_customViewSize.width, SP_SCREEN_WIDTH-_minDistanceToEdges);
+ alertControllerViewWidth = MIN(_customViewSize.width, SPALERT_SCREEN_WIDTH-_minDistanceToEdges);
}
[alertControllerViewConstraints addObject:[NSLayoutConstraint constraintWithItem:alertControllerView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:alertControllerViewWidth]];
}
if (_customViewSize.height) { // 如果高度没有值,则会假定customAlertViewh垂直方向能由子控件撑起
CGFloat alertControllerViewHeight = 0.0;
if ([hv isEqualToString:@"H"]) {
- alertControllerViewHeight = MIN(_customViewSize.height, SP_SCREEN_HEIGHT-_minDistanceToEdges);
+ alertControllerViewHeight = MIN(_customViewSize.height, SPALERT_SCREEN_HEIGHT-_minDistanceToEdges);
} else {
- alertControllerViewHeight = MIN(_customViewSize.height, SP_SCREEN_HEIGHT);
+ alertControllerViewHeight = MIN(_customViewSize.height, SPALERT_SCREEN_HEIGHT);
}
[alertControllerViewConstraints addObject:[NSLayoutConstraint constraintWithItem:alertControllerView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:alertControllerViewHeight]];
}
@@ -1283,7 +1420,7 @@ - (void)layoutHeaderActionLine {
if (!self.componentView.superview) {
[headerActionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:headerActionLine attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:actionSequenceView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];
}
- [headerActionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:headerActionLine attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SP_LINE_WIDTH]];
+ [headerActionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:headerActionLine attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SPALERT_LINE_WIDTH]];
[NSLayoutConstraint activateConstraints:headerActionLineConstraints];
self.headerActionLineConstraints = headerActionLineConstraints;
@@ -1328,7 +1465,7 @@ - (void)layoutComponentActionLine {
}
[componentActionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:componentActionLine attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.actionSequenceView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];
[componentActionLineConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[componentActionLine]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(componentActionLine)]];
- [componentActionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:componentActionLine attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SP_LINE_WIDTH]];
+ [componentActionLineConstraints addObject:[NSLayoutConstraint constraintWithItem:componentActionLine attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:SPALERT_LINE_WIDTH]];
[NSLayoutConstraint activateConstraints:componentActionLineConstraints];
self.componentActionLineConstraints = componentActionLineConstraints;
}
@@ -1372,9 +1509,9 @@ - (void)layoutActionSequenceView {
- (CGFloat)maxWidth {
if (self.preferredStyle == SPAlertControllerStyleAlert) {
- return MIN(SP_SCREEN_WIDTH, SP_SCREEN_HEIGHT)-_minDistanceToEdges * 2;
+ return MIN(SPALERT_SCREEN_WIDTH, SPALERT_SCREEN_HEIGHT)-_minDistanceToEdges * 2;
} else {
- return SP_SCREEN_WIDTH;
+ return SPALERT_SCREEN_WIDTH;
}
}
@@ -1385,17 +1522,17 @@ - (void)handleIncompleteTextDisplay {
if (self.preferredStyle == SPAlertControllerStyleAlert) {
for (SPAlertAction *action in self.actions) {
// 预估按钮宽度
- CGFloat preButtonWidth = (MIN(SP_SCREEN_WIDTH, SP_SCREEN_HEIGHT) - _minDistanceToEdges * 2 - SP_LINE_WIDTH * (self.actions.count - 1)) / self.actions.count - action.titleEdgeInsets.left - action.titleEdgeInsets.right;
+ CGFloat preButtonWidth = (MIN(SPALERT_SCREEN_WIDTH, SPALERT_SCREEN_HEIGHT) - _minDistanceToEdges * 2 - SPALERT_LINE_WIDTH * (self.actions.count - 1)) / self.actions.count - action.titleEdgeInsets.left - action.titleEdgeInsets.right;
// 如果action的标题文字总宽度,大于按钮的contentRect的宽度,则说明水平排列会导致文字显示不全,此时垂直排列
if (action.attributedTitle) {
- if (ceil([action.attributedTitle boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, SP_ACTION_HEIGHT) options:NSStringDrawingUsesLineFragmentOrigin context:nil].size.width) > preButtonWidth) {
+ if (ceil([action.attributedTitle boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, SPALERT_ACTION_HEIGHT) options:NSStringDrawingUsesLineFragmentOrigin context:nil].size.width) > preButtonWidth) {
_actionAxis = UILayoutConstraintAxisVertical;
[self updateActionAxis];
[self.actionSequenceView setNeedsUpdateConstraints];
break; // 一定要break,只要有一个按钮文字过长就垂直排列
}
} else {
- if (ceil([action.title boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, SP_ACTION_HEIGHT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:action.titleFont} context:nil].size.width) > preButtonWidth) {
+ if (ceil([action.title boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, SPALERT_ACTION_HEIGHT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:action.titleFont} context:nil].size.width) > preButtonWidth) {
_actionAxis = UILayoutConstraintAxisVertical;
[self updateActionAxis];
[self.actionSequenceView setNeedsUpdateConstraints];
@@ -1407,34 +1544,11 @@ - (void)handleIncompleteTextDisplay {
}
}
-// 专门处理第三方IQKeyboardManager,非自定义view时禁用IQKeyboardManager移动textView/textField效果,自定义view时取消禁用
-- (void)handleIQKeyboardManager {
- SEL selector = NSSelectorFromString(@"sharedManager");
- IMP imp = [NSClassFromString(@"IQKeyboardManager") methodForSelector:selector];
- if (imp != NULL) {
- NSObject *(*func)(id, SEL) = (void *)imp;
- NSObject *mgr = func(NSClassFromString(@"IQKeyboardManager"), selector);
- if ([mgr isKindOfClass:NSClassFromString(@"IQKeyboardManager")]) {
- @try {
- NSMutableSet *disabledDistanceHandlingClasses = [mgr valueForKey:@"_disabledDistanceHandlingClasses"];
- NSMutableSet *disabledToolbarClasses = [mgr valueForKey:@"_disabledToolbarClasses"];
- if (![disabledDistanceHandlingClasses containsObject:NSClassFromString(@"SPAlertController")]) {
- [disabledDistanceHandlingClasses addObject:NSClassFromString(@"SPAlertController")];
- [disabledToolbarClasses addObject:NSClassFromString(@"SPAlertController")];
- }
- } @catch (NSException *exception) {
- NSLog(@"exception = %@",exception);
- } @finally {
-
- }
- }
- }
-}
-
- (void)configureHeaderView {
if (self.image) {
self.headerView.imageLimitSize = _imageLimitSize;
self.headerView.imageView.image = _image;
+ self.headerView.imageView.tintColor = _imageTintColor;
[self.headerView setNeedsUpdateConstraints];
}
if(self.attributedTitle.length) {
@@ -1461,17 +1575,17 @@ - (void)configureHeaderView {
- (void)setupPreferredMaxLayoutWidthForLabel:(UILabel *)textLabel {
if (self.preferredStyle == SPAlertControllerStyleAlert) {
- textLabel.preferredMaxLayoutWidth = MIN(SP_SCREEN_WIDTH, SP_SCREEN_HEIGHT) - self.minDistanceToEdges * 2 - self.headerView.contentEdgeInsets.left - self.headerView.contentEdgeInsets.right;
+ textLabel.preferredMaxLayoutWidth = MIN(SPALERT_SCREEN_WIDTH, SPALERT_SCREEN_HEIGHT) - self.minDistanceToEdges * 2 - self.headerView.contentEdgeInsets.left - self.headerView.contentEdgeInsets.right;
} else {
- textLabel.preferredMaxLayoutWidth = SP_SCREEN_WIDTH - self.headerView.contentEdgeInsets.left - self.headerView.contentEdgeInsets.right;
+ textLabel.preferredMaxLayoutWidth = SPALERT_SCREEN_WIDTH - self.headerView.contentEdgeInsets.left - self.headerView.contentEdgeInsets.right;
}
}
// 这个方法是实现点击回车切换到下一个textField,如果没有下一个,会自动退出键盘. 不能在代理方法里实现,因为如果设置了代理,外界就不能成为textFiled的代理了,通知也监听不到回车
- (void)textFieldDidEndOnExit:(UITextField *)textField {
NSInteger index = [self.textFields indexOfObject:textField];
- if (self.textFields.count > index+1) {
- UITextField *nextTextField = [self.textFields objectAtIndex:index+1];
+ if (self.textFields.count > index + 1) {
+ UITextField *nextTextField = [self.textFields objectAtIndex:index + 1];
[textField resignFirstResponder];
[nextTextField becomeFirstResponder];
}
@@ -1487,28 +1601,28 @@ - (void)updateActionAxis {
}
}
-// 该方法是保证被废弃的maxNumberOfActionHorizontalArrangementForAlert属性的有效性
-- (void)setupActionAxis {
- if (self.preferredStyle == SPAlertControllerStyleAlert) {
- if (self.actions.count > self.maxNumberOfActionHorizontalArrangementForAlert) {
- _actionAxis = UILayoutConstraintAxisVertical;
- [self updateActionAxis];
- } else {
- _actionAxis = UILayoutConstraintAxisHorizontal;
- [self updateActionAxis];
- }
+- (void)makeViewOffsetWithAnimated:(BOOL)animated {
+ [self layoutAlertControllerView];
+ if (animated) {
+ [UIView animateWithDuration:0.25 animations:^{
+ [self.view.superview layoutIfNeeded];
+ }];
}
}
-- (void)makeViewOffsetWithAnimated:(BOOL)animated {
- if (!self.beingPresented && !self.beingDismissed) {
- [self layoutAlertControllerView];
- if (animated) {
- [UIView animateWithDuration:0.25 animations:^{
- [self.view.superview layoutIfNeeded];
- }];
- }
- }
+- (void)makeViewOffsetWithDuration:(NSTimeInterval)duration curve:(UIViewAnimationCurve)curve {
+ [self layoutAlertControllerView];
+ if (self.isBeingPresented || self.isBeingDismissed) {
+ return;
+ }
+ [UIView animateWithDuration:duration
+ delay:0
+ options:(curve << 16) | UIViewAnimationOptionBeginFromCurrentState
+ animations:^{
+ [self.view.superview layoutIfNeeded];
+ } completion:^(BOOL finished) {
+ self.isSyncingKeyboardAnimation = NO;
+ }];
}
// 获取自定义view的大小
@@ -1539,9 +1653,7 @@ - (void)viewDidLoad {
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
-
- [self handleIQKeyboardManager];
-
+
if (!_isForceOffset && !_customAlertView && !_customHeaderView && !_customActionSequenceView && !_componentView) {
// 监听键盘改变frame,键盘frame改变需要移动对话框
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardFrameWillChange:) name:UIKeyboardWillChangeFrameNotification object:nil];
@@ -1549,6 +1661,7 @@ - (void)viewWillAppear:(BOOL)animated {
if (self.textFields.count) {
UITextField *firstTextfield = [self.textFields firstObject];
if (!firstTextfield.isFirstResponder) {
+ self.isSyncingKeyboardAnimation = YES;
[firstTextfield becomeFirstResponder];
}
}
@@ -1562,6 +1675,12 @@ - (void)viewWillLayoutSubviews {
// 对自己创建的alertControllerView布局,在这个方法里,self.view才有父视图,有父视图才能改变其约束
[self layoutAlertControllerView];
[self layoutChildViews];
+
+ if (self.preferredStyle == SPAlertControllerStyleActionSheet) {
+ [self setCornerRadius:_cornerRadius];
+ }
+
+ NSLog(@"kkkkkkkkkk ----2");
}
- (void)viewDidLayoutSubviews {
@@ -1569,13 +1688,13 @@ - (void)viewDidLayoutSubviews {
[self handleIncompleteTextDisplay];
}
-- (void)viewDidAppear:(BOOL)animated {
- [super viewDidAppear:animated];
-
-}
-
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
+
+ // 移除键盘通知
+ if (!_isForceOffset && !_customAlertView && !_customHeaderView && !_customActionSequenceView && !_componentView) {
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillChangeFrameNotification object:nil];
+ }
}
- (void)viewDidDisappear:(BOOL)animated {
@@ -1589,12 +1708,17 @@ - (void)dealloc {
#pragma mark - 键盘通知
- (void)keyboardFrameWillChange:(NSNotification *)notification {
- if (!_isForceOffset) {
+ if (!_isForceOffset && (_offsetForAlert.y == 0.0 || _textFields.lastObject.isFirstResponder)) {
CGRect keyboardEndFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat keyboardEndY = keyboardEndFrame.origin.y;
- CGFloat diff = fabs((SP_SCREEN_HEIGHT-keyboardEndY)*0.5);
+ CGFloat diff = fabs((SPALERT_SCREEN_HEIGHT - keyboardEndY) * 0.5);
_offsetForAlert.y = -diff;
- [self makeViewOffsetWithAnimated:YES];
+
+ // 使用键盘动画参数
+ NSTimeInterval duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
+ UIViewAnimationCurve curve = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
+
+ [self makeViewOffsetWithDuration:duration curve:curve];
}
}
@@ -1681,6 +1805,13 @@ - (void)setIconLimitSize:(CGSize)imageLimitSize {
}
}
+- (void)setImageTintColor:(UIColor *)imageTintColor {
+ _imageTintColor = imageTintColor;
+ if (self.isViewLoaded) {
+ self.headerView.imageView.tintColor = imageTintColor;
+ }
+}
+
- (void)setAttributedTitle:(NSAttributedString *)attributedTitle {
_attributedTitle = attributedTitle;
if (self.isViewLoaded) {
@@ -1701,18 +1832,6 @@ - (void)setAttributedMessage:(NSAttributedString *)attributedMessage {
}
}
-// 该属性3.0版本开始被废弃
-- (void)setMaxMarginForAlert:(CGFloat)maxMarginForAlert {
- _maxMarginForAlert = maxMarginForAlert;
- self.minDistanceToEdges = _maxMarginForAlert;
-}
-
-// 该属性3.0版本开始被废弃
-- (void)setMaxTopMarginForActionSheet:(CGFloat)maxTopMarginForActionSheet {
- _maxTopMarginForActionSheet = maxTopMarginForActionSheet;
- self.minDistanceToEdges = _maxTopMarginForActionSheet;
-}
-
- (void)setMinDistanceToEdges:(CGFloat)minDistanceToEdges {
_minDistanceToEdges = minDistanceToEdges;
if (self.isViewLoaded) {
@@ -1726,21 +1845,39 @@ - (void)setMinDistanceToEdges:(CGFloat)minDistanceToEdges {
}
}
-- (void)setCornerRadiusForAlert:(CGFloat)cornerRadiusForAlert {
- _cornerRadiusForAlert = cornerRadiusForAlert;
+- (void)setCornerRadius:(CGFloat)cornerRadius {
+ _cornerRadius = cornerRadius;
if (self.preferredStyle == SPAlertControllerStyleAlert) {
- self.containerView.layer.cornerRadius = _cornerRadiusForAlert;
+ self.containerView.layer.cornerRadius = _cornerRadius;
self.containerView.layer.masksToBounds = YES;
+ } else {
+ if (_cornerRadius > 0.0) {
+ UIRectCorner corner = UIRectCornerTopLeft | UIRectCornerTopRight;
+ switch (_animationType) {
+ case SPAlertAnimationTypeFromBottom:
+ corner = UIRectCornerTopLeft | UIRectCornerTopRight;
+ break;
+ case SPAlertAnimationTypeFromTop:
+ corner = UIRectCornerBottomLeft | UIRectCornerBottomRight;
+ break;
+ case SPAlertAnimationTypeFromLeft:
+ corner = UIRectCornerTopRight | UIRectCornerBottomRight;
+ break;
+ case SPAlertAnimationTypeFromRight:
+ corner = UIRectCornerTopLeft | UIRectCornerBottomLeft;
+ break;
+ default:
+ break;
+ }
+ CAShapeLayer *maskLayer = (CAShapeLayer *)_containerView.layer.mask;
+ maskLayer.path = [UIBezierPath bezierPathWithRoundedRect:_containerView.bounds byRoundingCorners:corner cornerRadii:CGSizeMake(_cornerRadius, _cornerRadius)].CGPath;
+ maskLayer.frame = _containerView.bounds;
+ } else {
+ _containerView.layer.mask = nil;
+ }
}
}
-// 此属性3.0版本开始被废弃
-- (void)setMaxNumberOfActionHorizontalArrangementForAlert:(NSInteger)maxNumberOfActionHorizontalArrangementForAlert {
- _maxNumberOfActionHorizontalArrangementForAlert = maxNumberOfActionHorizontalArrangementForAlert;
- // 被废弃的maxNumberOfActionHorizontalArrangementForAlert属性需要的方法
- [self setupActionAxis];
-}
-
- (void)setActionAxis:(UILayoutConstraintAxis)actionAxis {
_actionAxis = actionAxis;
// 调用该setter方法则认为是强制布局,该setter方法只有外界能调,这样才能判断外界有没有调用actionAxis的setter方法,从而是否按照外界的指定布局方式进行布局
@@ -1755,30 +1892,18 @@ - (void)setOffsetForAlert:(CGPoint)offsetForAlert {
[self makeViewOffsetWithAnimated:NO];
}
-// 被废弃
-- (void)setOffsetYForAlert:(CGFloat)offsetYForAlert {
- _offsetYForAlert = offsetYForAlert;
- _offsetForAlert.y = _offsetYForAlert;
- _isForceOffset = YES;
-}
-
- (void)setNeedDialogBlur:(BOOL)needDialogBlur {
_needDialogBlur = needDialogBlur;
if (_needDialogBlur) {
self.containerView.backgroundColor = [UIColor clearColor];
- self.dimmingKnockoutBackdropView = [NSClassFromString(@"_UIDimmingKnockoutBackdropView") alloc];
- if (self.dimmingKnockoutBackdropView) {
- // 下面4行相当于self.dimmingKnockoutBackdropView = [self.dimmingKnockoutBackdropView performSelector:NSSelectorFromString(@"initWithStyle:") withObject:@(UIBlurEffectStyleLight)];
- SEL selector = NSSelectorFromString(@"initWithStyle:");
- IMP imp = [self.dimmingKnockoutBackdropView methodForSelector:selector];
- UIView *(*func)(id, SEL,UIBlurEffectStyle) = (void *)imp;
- self.dimmingKnockoutBackdropView = func(self.dimmingKnockoutBackdropView, selector, UIBlurEffectStyleLight);
- self.dimmingKnockoutBackdropView.frame = self.containerView.bounds;
- self.dimmingKnockoutBackdropView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- [self.containerView insertSubview:self.dimmingKnockoutBackdropView atIndex:0];
- } else { // 这个else是防止假如_UIDimmingKnockoutBackdropView这个类不存在了的时候,做一个备案,不过apple应该不会废弃某个类
- UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight];
- self.dimmingKnockoutBackdropView = [[UIVisualEffectView alloc] initWithEffect:blur];
+ if (!self.dimmingKnockoutBackdropView) {
+ if (@available(iOS 13.0, *)) {
+ UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleSystemMaterial];
+ self.dimmingKnockoutBackdropView = [[UIVisualEffectView alloc] initWithEffect:blur];
+ } else {
+ UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
+ self.dimmingKnockoutBackdropView = [[UIVisualEffectView alloc] initWithEffect:blur];
+ }
self.dimmingKnockoutBackdropView.frame = self.containerView.bounds;
self.dimmingKnockoutBackdropView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.containerView insertSubview:self.dimmingKnockoutBackdropView atIndex:0];
@@ -1789,7 +1914,7 @@ - (void)setNeedDialogBlur:(BOOL)needDialogBlur {
if (_customAlertView) {
self.containerView.backgroundColor = [UIColor clearColor];
} else {
- self.containerView.backgroundColor = [UIColor whiteColor];
+ self.containerView.backgroundColor = [_SPColorStyle lightWhite_DarkBlackColor];
}
}
}
@@ -1811,10 +1936,16 @@ - (UIView *)containerView {
containerView.frame = self.alertControllerView.bounds;
containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
if (_preferredStyle == SPAlertControllerStyleAlert) {
- containerView.layer.cornerRadius = _cornerRadiusForAlert;
+ containerView.layer.cornerRadius = _cornerRadius;
containerView.layer.masksToBounds = YES;
+ } else {
+ if (_cornerRadius > 0.0) {
+ CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
+ containerView.layer.mask = maskLayer;
+ }
}
[self.alertControllerView addSubview:containerView];
+
_containerView = containerView;
}
return _containerView;
@@ -1822,13 +1953,13 @@ - (UIView *)containerView {
- (UIView *)alertView {
if (!_alertView) {
- UIView *alertView = [[UIView alloc] init];
- alertView.frame = self.alertControllerView.bounds;
- alertView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
if (!self.customAlertView) {
+ UIView *alertView = [[UIView alloc] init];
+ alertView.frame = self.alertControllerView.bounds;
+ alertView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.containerView addSubview:alertView];
+ _alertView = alertView;
}
- _alertView = alertView;
}
return _alertView;
}
@@ -1850,20 +1981,20 @@ - (UIView *)customAlertView {
- (SPInterfaceHeaderScrollView *)headerView {
if (!_headerView) {
- SPInterfaceHeaderScrollView *headerView = [[SPInterfaceHeaderScrollView alloc] init];
- headerView.backgroundColor = SP_NORMAL_COLOR;
- headerView.translatesAutoresizingMaskIntoConstraints = NO;
- __weak typeof(self) weakSelf = self;
- headerView.headerViewSfeAreaDidChangBlock = ^{
- [weakSelf setupPreferredMaxLayoutWidthForLabel:weakSelf.headerView.titleLabel];
- [weakSelf setupPreferredMaxLayoutWidthForLabel:weakSelf.headerView.messageLabel];
- };
if (!self.customHeaderView) {
if ((self.title.length || self.attributedTitle.length || self.message.length || self.attributedMessage.length || self.textFields.count || self.image)) {
+ SPInterfaceHeaderScrollView *headerView = [[SPInterfaceHeaderScrollView alloc] init];
+ headerView.backgroundColor = [_SPColorStyle normalColor];
+ headerView.translatesAutoresizingMaskIntoConstraints = NO;
+ __weak typeof(self) weakSelf = self;
+ headerView.headerViewSfeAreaDidChangBlock = ^{
+ [weakSelf setupPreferredMaxLayoutWidthForLabel:weakSelf.headerView.titleLabel];
+ [weakSelf setupPreferredMaxLayoutWidthForLabel:weakSelf.headerView.messageLabel];
+ };
[self.alertView addSubview:headerView];
+ _headerView = headerView;
}
}
- _headerView = headerView;
}
return _headerView;
}
@@ -1884,18 +2015,27 @@ - (UIView *)customHeaderView {
- (SPInterfaceActionSequenceView *)actionSequenceView {
if (!_actionSequenceView) {
- SPInterfaceActionSequenceView *actionSequenceView = [[SPInterfaceActionSequenceView alloc] init];
- actionSequenceView.translatesAutoresizingMaskIntoConstraints = NO;
- __weak typeof(self) weakSelf = self;
- actionSequenceView.buttonClickedInActionViewBlock = ^(NSInteger index) {
- [weakSelf dismissViewControllerAnimated:YES completion:nil];
- SPAlertAction *action = weakSelf.actions[index];
- action.handler(action);
- };
if (self.actions.count && !self.customActionSequenceView) {
+ SPInterfaceActionSequenceView *actionSequenceView = [[SPInterfaceActionSequenceView alloc] init];
+ actionSequenceView.translatesAutoresizingMaskIntoConstraints = NO;
+ __weak typeof(self) weakSelf = self;
+ actionSequenceView.buttonClickedInActionViewBlock = ^(NSInteger index) {
+ SPAlertAction *action = weakSelf.actions[index];
+ if (action.allowsAutoDismiss) {
+ [weakSelf dismissViewControllerAnimated:YES completion:^{
+ if (action.handler) {
+ action.handler(action);
+ }
+ }];
+ } else {
+ if (action.handler) {
+ action.handler(action);
+ }
+ }
+ };
[self.alertView addSubview:actionSequenceView];
+ _actionSequenceView = actionSequenceView;
}
- _actionSequenceView = actionSequenceView;
}
return _actionSequenceView;
}
@@ -1916,12 +2056,12 @@ - (UIView *)customActionSequenceView {
- (SPInterfaceActionItemSeparatorView *)headerActionLine {
if (!_headerActionLine) {
- SPInterfaceActionItemSeparatorView *headerActionLine = [[SPInterfaceActionItemSeparatorView alloc] init];
- headerActionLine.translatesAutoresizingMaskIntoConstraints = NO;
if ((self.headerView.superview || self.customHeaderView.superview) && (self.actionSequenceView.superview || self.customActionSequenceView.superview)) {
+ SPInterfaceActionItemSeparatorView *headerActionLine = [[SPInterfaceActionItemSeparatorView alloc] init];
+ headerActionLine.translatesAutoresizingMaskIntoConstraints = NO;
[self.alertView addSubview:headerActionLine];
+ _headerActionLine = headerActionLine;
}
- _headerActionLine = headerActionLine;
}
return _headerActionLine;
}
@@ -1942,13 +2082,13 @@ - (UIView *)componentView {
- (SPInterfaceActionItemSeparatorView *)componentActionLine {
if (!_componentActionLine) {
- SPInterfaceActionItemSeparatorView *componentActionLine = [[SPInterfaceActionItemSeparatorView alloc] init];
- componentActionLine.translatesAutoresizingMaskIntoConstraints = NO;
// 必须组件view和action部分同时存在
if (self.componentView.superview && (self.actionSequenceView.superview || self.customActionSequenceView.superview)) {
+ SPInterfaceActionItemSeparatorView *componentActionLine = [[SPInterfaceActionItemSeparatorView alloc] init];
+ componentActionLine.translatesAutoresizingMaskIntoConstraints = NO;
[self.alertView addSubview:componentActionLine];
+ _componentActionLine = componentActionLine;
}
- _componentActionLine = componentActionLine;
}
return _componentActionLine;
}
@@ -2012,7 +2152,6 @@ + (instancetype)alertControllerWithTitle:(NSString *)title message:(NSString *)m
#pragma mark ---------------------------- SPAlertController end --------------------------------
@interface SPOverlayView: UIView
-@property (nonatomic, strong) UIView *presentedView;
@property (nonatomic, strong) UIVisualEffectView *effectView;
@end
@@ -2024,9 +2163,9 @@ - (instancetype)initWithFrame:(CGRect)frame {
}
return self;
}
-- (void)setAppearanceStyle:(SPBackgroundViewAppearanceStyle)appearanceStyle alpha:(CGFloat)alpha {
+- (void)setAppearanceStyle:(UIBlurEffectStyle)appearanceStyle alpha:(CGFloat)alpha {
switch (appearanceStyle) {
- case SPBackgroundViewAppearanceStyleTranslucent: {
+ case -1: {
[self.effectView removeFromSuperview];
self.effectView = nil;
if (alpha < 0) {
@@ -2036,21 +2175,10 @@ - (void)setAppearanceStyle:(SPBackgroundViewAppearanceStyle)appearanceStyle alph
self.alpha = 0;
}
break;
- case SPBackgroundViewAppearanceStyleBlurExtraLight: {
- UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight];
- [self createVisualEffectViewWithBlur:blur alpha:alpha];
- }
- break;
- case SPBackgroundViewAppearanceStyleBlurLight: {
- UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
- [self createVisualEffectViewWithBlur:blur alpha:alpha];
- }
- break;
- case SPBackgroundViewAppearanceStyleBlurDark: {
- UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
+ default:{
+ UIBlurEffect *blur = [UIBlurEffect effectWithStyle:appearanceStyle];
[self createVisualEffectViewWithBlur:blur alpha:alpha];
}
- break;
}
}
@@ -2097,7 +2225,7 @@ - (void)presentationTransitionWillBegin {
SPAlertController *alertController = (SPAlertController *)self.presentedViewController;
[self.overlayView setAppearanceStyle:alertController.backgroundViewAppearanceStyle alpha:alertController.backgroundViewAlpha];
-
+
// 遮罩的alpha值从0~1变化,UIViewControllerTransitionCoordinator协是一个过渡协调器,当执行模态过渡或push过渡时,可以对视图中的其他部分做动画
id coordinator = [self.presentedViewController transitionCoordinator];
if (coordinator) {
@@ -2109,8 +2237,6 @@ - (void)presentationTransitionWillBegin {
}
if ([alertController.delegate respondsToSelector:@selector(willPresentAlertController:)]) {
[alertController.delegate willPresentAlertController:alertController];
- } else if ([alertController.delegate respondsToSelector:@selector(sp_alertControllerWillShow:)]) { // 支持老版本
- [alertController.delegate sp_alertControllerWillShow:alertController];
}
}
@@ -2120,8 +2246,6 @@ - (void)presentationTransitionDidEnd:(BOOL)completed {
SPAlertController *alertController = (SPAlertController *)self.presentedViewController;
if ([alertController.delegate respondsToSelector:@selector(didPresentAlertController:)]) {
[alertController.delegate didPresentAlertController:alertController];
- } else if ([alertController.delegate respondsToSelector:@selector(sp_alertControllerDidShow:)]) { // 支持老版本
- [alertController.delegate sp_alertControllerDidShow:alertController];
}
}
@@ -2139,8 +2263,6 @@ - (void)dismissalTransitionWillBegin {
SPAlertController *alertController = (SPAlertController *)self.presentedViewController;
if ([alertController.delegate respondsToSelector:@selector(willDismissAlertController:)]) {
[alertController.delegate willDismissAlertController:alertController];
- } else if ([alertController.delegate respondsToSelector:@selector(sp_alertControllerWillHide:)]) { // 支持老版本
- [alertController.delegate sp_alertControllerWillHide:alertController];
}
}
@@ -2153,8 +2275,6 @@ - (void)dismissalTransitionDidEnd:(BOOL)completed {
SPAlertController *alertController = (SPAlertController *)self.presentedViewController;
if ([alertController.delegate respondsToSelector:@selector(didDismissAlertController:)]) {
[alertController.delegate didDismissAlertController:alertController];
- } else if ([alertController.delegate respondsToSelector:@selector(sp_alertControllerDidHide:)]) { // 支持老版本
- [alertController.delegate sp_alertControllerDidHide:alertController];
}
}
@@ -2164,7 +2284,9 @@ - (CGRect)frameOfPresentedViewInContainerView{
- (void)tapOverlayView {
SPAlertController *alertController = (SPAlertController *)self.presentedViewController;
- [alertController dismissViewControllerAnimated:YES completion:^{}];
+ if (alertController.tapBackgroundViewDismiss) {
+ [alertController dismissViewControllerAnimated:YES completion:^{}];
+ }
}
- (void)dealloc {
@@ -2223,21 +2345,18 @@ - (void)presentAnimationTransition:(id)tra
SPAlertController *alertController = (SPAlertController *)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
switch (alertController.animationType) {
- case SPAlertAnimationTypeRaiseUp:
case SPAlertAnimationTypeFromBottom:
[self raiseUpWhenPresentForController:alertController transition:transitionContext];
break;
case SPAlertAnimationTypeFromRight:
[self fromRightWhenPresentForController:alertController transition:transitionContext];
break;
- case SPAlertAnimationTypeDropDown:
case SPAlertAnimationTypeFromTop:
[self dropDownWhenPresentForController:alertController transition:transitionContext];
break;
case SPAlertAnimationTypeFromLeft:
[self fromLeftWhenPresentForController:alertController transition:transitionContext];
break;
- case SPAlertAnimationTypeAlpha:
case SPAlertAnimationTypeFade:
[self alphaWhenPresentForController:alertController transition:transitionContext];
break;
@@ -2259,7 +2378,6 @@ - (void)dismissAnimationTransition:(id)tra
SPAlertController *alertController = (SPAlertController *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
if ([alertController isKindOfClass:[SPAlertController class]]) {
switch (alertController.animationType) {
- case SPAlertAnimationTypeRaiseUp:
case SPAlertAnimationTypeFromBottom:
[self dismissCorrespondingRaiseUpForController:alertController transition:transitionContext];
break;
@@ -2269,11 +2387,9 @@ - (void)dismissAnimationTransition:(id)tra
case SPAlertAnimationTypeFromLeft:
[self dismissCorrespondingFromLeftForController:alertController transition:transitionContext];
break;
- case SPAlertAnimationTypeDropDown:
case SPAlertAnimationTypeFromTop:
[self dismissCorrespondingDropDownForController:alertController transition:transitionContext];
break;
- case SPAlertAnimationTypeAlpha:
case SPAlertAnimationTypeFade:
[self dismissCorrespondingAlphaForController:alertController transition:transitionContext];
break;
@@ -2304,15 +2420,15 @@ - (void)raiseUpWhenPresentForController:(SPAlertController *)alertController tra
// 这3行代码不能放在[containerView layoutIfNeeded]之前,如果放在之前,[containerView layoutIfNeeded]强制布局后会将以下设置的frame覆盖
CGRect controlViewFrame = alertController.view.frame;
- controlViewFrame.origin.y = SP_SCREEN_HEIGHT;
+ controlViewFrame.origin.y = SPALERT_SCREEN_HEIGHT;
alertController.view.frame = controlViewFrame;
- [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
+ [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
CGRect controlViewFrame = alertController.view.frame;
if (alertController.preferredStyle == SPAlertControllerStyleActionSheet) {
- controlViewFrame.origin.y = SP_SCREEN_HEIGHT-controlViewFrame.size.height;
+ controlViewFrame.origin.y = SPALERT_SCREEN_HEIGHT-controlViewFrame.size.height;
} else {
- controlViewFrame.origin.y = (SP_SCREEN_HEIGHT-controlViewFrame.size.height) / 2.0;
+ controlViewFrame.origin.y = (SPALERT_SCREEN_HEIGHT-controlViewFrame.size.height) / 2.0;
[self offSetCenter:alertController];
}
alertController.view.frame = controlViewFrame;
@@ -2327,7 +2443,7 @@ - (void)dismissCorrespondingRaiseUpForController:(SPAlertController *)alertContr
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
CGRect controlViewFrame = alertController.view.frame;
- controlViewFrame.origin.y = SP_SCREEN_HEIGHT;
+ controlViewFrame.origin.y = SPALERT_SCREEN_HEIGHT;
alertController.view.frame = controlViewFrame;
} completion:^(BOOL finished) {
[transitionContext completeTransition:finished];
@@ -2347,18 +2463,18 @@ - (void)fromRightWhenPresentForController:(SPAlertController *)alertController t
// 这3行代码不能放在[containerView layoutIfNeeded]之前,如果放在之前,[containerView layoutIfNeeded]强制布局后会将以下设置的frame覆盖
CGRect controlViewFrame = alertController.view.frame;
- controlViewFrame.origin.x = SP_SCREEN_WIDTH;
+ controlViewFrame.origin.x = SPALERT_SCREEN_WIDTH;
alertController.view.frame = controlViewFrame;
if (alertController.preferredStyle == SPAlertControllerStyleAlert) {
[self offSetCenter:alertController];
}
- [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
+ [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
CGRect controlViewFrame = alertController.view.frame;
if (alertController.preferredStyle == SPAlertControllerStyleActionSheet) {
- controlViewFrame.origin.x = SP_SCREEN_WIDTH-controlViewFrame.size.width;
+ controlViewFrame.origin.x = SPALERT_SCREEN_WIDTH-controlViewFrame.size.width;
} else {
- controlViewFrame.origin.x = (SP_SCREEN_WIDTH-controlViewFrame.size.width) / 2.0;
+ controlViewFrame.origin.x = (SPALERT_SCREEN_WIDTH-controlViewFrame.size.width) / 2.0;
}
alertController.view.frame = controlViewFrame;
} completion:^(BOOL finished) {
@@ -2372,7 +2488,7 @@ - (void)dismissCorrespondingFromRightForController:(SPAlertController *)alertCon
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
CGRect controlViewFrame = alertController.view.frame;
- controlViewFrame.origin.x = SP_SCREEN_WIDTH;
+ controlViewFrame.origin.x = SPALERT_SCREEN_WIDTH;
alertController.view.frame = controlViewFrame;
} completion:^(BOOL finished) {
[transitionContext completeTransition:finished];
@@ -2398,12 +2514,12 @@ - (void)fromLeftWhenPresentForController:(SPAlertController *)alertController tr
if (alertController.preferredStyle == SPAlertControllerStyleAlert) {
[self offSetCenter:alertController];
}
- [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
+ [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
CGRect controlViewFrame = alertController.view.frame;
if (alertController.preferredStyle == SPAlertControllerStyleActionSheet) {
controlViewFrame.origin.x = 0;
} else {
- controlViewFrame.origin.x = (SP_SCREEN_WIDTH-controlViewFrame.size.width) / 2.0;
+ controlViewFrame.origin.x = (SPALERT_SCREEN_WIDTH-controlViewFrame.size.width) / 2.0;
}
alertController.view.frame = controlViewFrame;
} completion:^(BOOL finished) {
@@ -2440,12 +2556,12 @@ - (void)dropDownWhenPresentForController:(SPAlertController *)alertController tr
controlViewFrame.origin.y = -controlViewFrame.size.height;
alertController.view.frame = controlViewFrame;
- [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^{
+ [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
CGRect controlViewFrame = alertController.view.frame;
if (alertController.preferredStyle == SPAlertControllerStyleActionSheet) {
controlViewFrame.origin.y = 0;
} else {
- controlViewFrame.origin.y = (SP_SCREEN_HEIGHT-controlViewFrame.size.height) / 2.0;
+ controlViewFrame.origin.y = (SPALERT_SCREEN_HEIGHT-controlViewFrame.size.height) / 2.0;
[self offSetCenter:alertController];
}
alertController.view.frame = controlViewFrame;
@@ -2473,20 +2589,24 @@ - (void)alphaWhenPresentForController:(SPAlertController *)alertController trans
UIView *containerView = [transitionContext containerView];
[containerView addSubview:alertController.view];
- // 标记需要刷新布局
- [containerView setNeedsLayout];
- // 在有标记刷新布局的情况下立即布局,这行代码很重要,第一:立即布局会立即调用SPAlertController的viewWillLayoutSubviews的方法,第二:立即布局后可以获取到alertController.view的frame,不仅如此,走了viewWillLayoutSubviews键盘就会弹出,此后可以获取到alertController.offset
- [containerView layoutIfNeeded];
-
- alertController.view.alpha = 0;
-
- [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
- [self offSetCenter:alertController];
- alertController.view.alpha = 1;
- } completion:^(BOOL finished) {
- [transitionContext completeTransition:finished];
- [alertController layoutAlertControllerView];
- }];
+ if (!alertController.isSyncingKeyboardAnimation) {
+ // 标记需要刷新布局
+ [containerView setNeedsLayout];
+ // 在有标记刷新布局的情况下立即布局,这行代码很重要,第一:立即布局会立即调用SPAlertController的viewWillLayoutSubviews的方法,第二:立即布局后可以获取到alertController.view的frame,不仅如此,走了viewWillLayoutSubviews键盘就会弹出,此后可以获取到alertController.offset
+ [containerView layoutIfNeeded];
+
+ alertController.view.alpha = 0;
+
+ [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
+ [self offSetCenter:alertController];
+ alertController.view.alpha = 1;
+ } completion:^(BOOL finished) {
+ [transitionContext completeTransition:finished];
+ [alertController layoutAlertControllerView];
+ }];
+ } else {
+ [transitionContext completeTransition:YES];
+ }
}
// alpha值从0到1变化对应的的dismiss动画
@@ -2505,22 +2625,26 @@ - (void)expandWhenPresentForController:(SPAlertController *)alertController tran
UIView *containerView = [transitionContext containerView];
[containerView addSubview:alertController.view];
- // 标记需要刷新布局
- [containerView setNeedsLayout];
- // 在有标记刷新布局的情况下立即布局,这行代码很重要,第一:立即布局会立即调用SPAlertController的viewWillLayoutSubviews的方法,第二:立即布局后可以获取到alertController.view的frame,不仅如此,走了viewWillLayoutSubviews键盘就会弹出,此后可以获取到alertController.offset
- [containerView layoutIfNeeded];
-
- alertController.view.transform = CGAffineTransformMakeScale(0.9, 0.9);
- alertController.view.alpha = 0.0;
+ if (!alertController.isSyncingKeyboardAnimation) {
+ // 标记需要刷新布局
+ [containerView setNeedsLayout];
+ // 在有标记刷新布局的情况下立即布局,这行代码很重要,第一:立即布局会立即调用SPAlertController的viewWillLayoutSubviews的方法,第二:立即布局后可以获取到alertController.view的frame,不仅如此,走了viewWillLayoutSubviews键盘就会弹出,此后可以获取到alertController.offset
+ [containerView layoutIfNeeded];
+
+ alertController.view.transform = CGAffineTransformMakeScale(0.9, 0.9);
+ alertController.view.alpha = 0.0;
- [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
- [self offSetCenter:alertController];
- alertController.view.transform = CGAffineTransformIdentity;
- alertController.view.alpha = 1.0;
- } completion:^(BOOL finished) {
- [transitionContext completeTransition:finished];
- [alertController layoutAlertControllerView];
- }];
+ [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
+ [self offSetCenter:alertController];
+ alertController.view.transform = CGAffineTransformIdentity;
+ alertController.view.alpha = 1.0;
+ } completion:^(BOOL finished) {
+ [transitionContext completeTransition:finished];
+ [alertController layoutAlertControllerView];
+ }];
+ } else {
+ [transitionContext completeTransition:YES];
+ }
}
// 发散对应的dismiss动画
@@ -2538,23 +2662,24 @@ - (void)shrinkWhenPresentForController:(SPAlertController *)alertController tran
UIView *containerView = [transitionContext containerView];
[containerView addSubview:alertController.view];
-
- // 标记需要刷新布局
- [containerView setNeedsLayout];
- // 在有标记刷新布局的情况下立即布局,这行代码很重要,第一:立即布局会立即调用SPAlertController的viewWillLayoutSubviews的方法,第二:立即布局后可以获取到alertController.view的frame,不仅如此,走了viewWillLayoutSubviews键盘就会弹出,此后可以获取到alertController.offset
- [containerView layoutIfNeeded];
-
- alertController.view.transform = CGAffineTransformMakeScale(1.1, 1.1);
- alertController.view.alpha = 0;
-
- [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
- [self offSetCenter:alertController];
- alertController.view.transform = CGAffineTransformIdentity;
- alertController.view.alpha = 1.0;
- } completion:^(BOOL finished) {
- [transitionContext completeTransition:finished];
- [alertController layoutAlertControllerView];
- }];
+
+ if (!alertController.isSyncingKeyboardAnimation) {
+ // 标记需要刷新布局
+ [containerView setNeedsLayout];
+ // 在有标记刷新布局的情况下立即布局,这行代码很重要,第一:立即布局会立即调用SPAlertController的viewWillLayoutSubviews的方法,第二:立即布局后可以获取到alertController.view的frame,不仅如此,走了viewWillLayoutSubviews键盘就会弹出,此后可以获取到alertController.offset
+ [containerView layoutIfNeeded];
+
+ alertController.view.transform = CGAffineTransformMakeScale(1.1, 1.1);
+ [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
+ [self offSetCenter:alertController];
+ alertController.view.transform = CGAffineTransformIdentity;
+ } completion:^(BOOL finished) {
+ [transitionContext completeTransition:finished];
+ [alertController layoutAlertControllerView];
+ }];
+ } else {
+ [transitionContext completeTransition:YES];
+ }
}
// 收缩对应的的dismiss动画
@@ -2578,8 +2703,8 @@ - (void)dismissCorrespondingNoneForController:(SPAlertController *)alertControll
- (void)offSetCenter:(SPAlertController *)alertController {
if (!CGPointEqualToPoint(alertController.offsetForAlert, CGPointZero)) {
CGPoint controlViewCenter = alertController.view.center;
- controlViewCenter.x = SP_SCREEN_WIDTH / 2.0 + alertController.offsetForAlert.x;
- controlViewCenter.y = SP_SCREEN_HEIGHT / 2.0 + alertController.offsetForAlert.y;
+ controlViewCenter.x = SPALERT_SCREEN_WIDTH / 2.0 + alertController.offsetForAlert.x;
+ controlViewCenter.y = SPALERT_SCREEN_HEIGHT / 2.0 + alertController.offsetForAlert.y;
alertController.view.center = controlViewCenter;
}
}