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 -[![Build Status](http://img.shields.io/travis/SPStore/SPAlertController.svg?style=flat)](https://travis-ci.org/SPStore/SPAlertController) [![Pod Version](http://img.shields.io/cocoapods/v/SPAlertController.svg?style=flat)](http://cocoadocs.org/docsets/SPAlertController/) [![Pod Platform](http://img.shields.io/cocoapods/p/SPAlertController.svg?style=flat)](http://cocoadocs.org/docsets/SPAlertController/) ![Language](https://img.shields.io/badge/language-Object--C-ff69b4.svg) [![Pod License](http://img.shields.io/cocoapods/l/SPAlertController.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0.html) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](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 - -![image](https://github.com/SPStore/SPAlertController/blob/master/Images/3006981-6f3752d49e579460.jpg) ``` // 该属性是制造对话框的毛玻璃效果,3.0版本开始采用的是系统私有类_UIDimmingKnockoutBackdropView所实现 @@ -173,7 +179,7 @@ SPAlertControllerStyleAlert下的圆角半径 ![image](https://github.com/SPStore/SPAlertController/blob/master/Images/6AAAA07F90853F52CA6166D815F619A9.jpg) -## 自定义各大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; ``` ![image](https://github.com/SPStore/SPAlertController/blob/master/Images/3006981-9544748007937417.jpg) -## 关于自定义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-small.jpg)](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/1.jpg) +[![](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/2-small.jpg)](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/2.jpg) +[![](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/3-small.jpg)](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/3.jpg) +[![](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/4-small.jpg)](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/4.jpg) +[![](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/5-small.jpg)](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/5.jpg) +[![](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/6-small.jpg)](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/6.jpg) +[![](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/7-small.jpg)](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/7.jpg) +[![](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/8-small.jpg)](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/8.jpg) +[![](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/9-small.jpg)](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/9.jpg) +[![](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/10-small.jpg)](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/10.jpg) +[![](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/11-small.jpg)](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/11.jpg) +[![](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/12-small.jpg)](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/12.jpg) +[![](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/13-small.jpg)](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/13.jpg) +[![](https://raw.githubusercontent.com/wiki/SPStore/SPAlertController/Screetshots/14-small.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; } }