diff --git a/DZNEmptyDataSet/Applications copy-Info.plist b/DZNEmptyDataSet/Applications copy-Info.plist
new file mode 100644
index 00000000..7b0138cd
--- /dev/null
+++ b/DZNEmptyDataSet/Applications copy-Info.plist
@@ -0,0 +1,45 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ UIAppFonts
+
+ IdealSans-Book-Pro.otf
+ Lato-Regular.ttf
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Storyboard
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UIViewControllerBasedStatusBarAppearance
+
+
+
diff --git a/DZNEmptyDataSet/DZNEmptyDataSet.xcodeproj/project.pbxproj b/DZNEmptyDataSet/DZNEmptyDataSet.xcodeproj/project.pbxproj
index c7e201b9..ead038fb 100644
--- a/DZNEmptyDataSet/DZNEmptyDataSet.xcodeproj/project.pbxproj
+++ b/DZNEmptyDataSet/DZNEmptyDataSet.xcodeproj/project.pbxproj
@@ -8,6 +8,17 @@
/* Begin PBXBuildFile section */
3AC13C2C04A330F6731CD271 /* Pods_DZNEmptyDataSetTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C5DC4B343BE997FFAA0048 /* Pods_DZNEmptyDataSetTests.framework */; };
+ 7DA71C25286E0CBE00C69885 /* UIScrollView+DZNEmptyExt.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DA71C23286E0CBE00C69885 /* UIScrollView+DZNEmptyExt.m */; };
+ 7DA71C26286E0CBE00C69885 /* UIScrollView+DZNEmptyExt.h in Headers */ = {isa = PBXBuildFile; fileRef = 7DA71C24286E0CBE00C69885 /* UIScrollView+DZNEmptyExt.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 7DA71C8B286EF48200C69885 /* DZNEmptyDataSet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F58A3E321E66AEE90086E0EF /* DZNEmptyDataSet.framework */; };
+ 7DA71CAF286EF68900C69885 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7DA71CA3286EF68900C69885 /* InfoPlist.strings */; };
+ 7DA71CB0286EF68900C69885 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7DA71CA5286EF68900C69885 /* LaunchScreen.storyboard */; };
+ 7DA71CB1286EF68900C69885 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DA71CA7286EF68900C69885 /* main.m */; };
+ 7DA71CB2286EF68900C69885 /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7DA71CA9286EF68900C69885 /* Storyboard.storyboard */; };
+ 7DA71CB4286EF68900C69885 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DA71CAD286EF68900C69885 /* AppDelegate.m */; };
+ 7DA71CB5286EF68900C69885 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DA71CAE286EF68900C69885 /* MainViewController.m */; };
+ 7DA71CFA286EFBF600C69885 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F58A3E7F1E66B62F0086E0EF /* Assets.xcassets */; };
+ 7DA71D00286F010700C69885 /* UIColor+Hexadecimal.m in Sources */ = {isa = PBXBuildFile; fileRef = F58A3E921E66B62F0086E0EF /* UIColor+Hexadecimal.m */; };
F56CEC4B1E67430000E2FACA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F58A3E7F1E66B62F0086E0EF /* Assets.xcassets */; };
F58A3E3C1E66AEE90086E0EF /* DZNEmptyDataSet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F58A3E321E66AEE90086E0EF /* DZNEmptyDataSet.framework */; };
F58A3E411E66AEE90086E0EF /* ApplicationsSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F58A3E401E66AEE90086E0EF /* ApplicationsSnapshotTests.m */; };
@@ -70,6 +81,20 @@
23BB766D928F8635A201F389 /* Pods_EmptyDataSetTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_EmptyDataSetTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3B3456B9A6D72D48F19A7F61 /* Pods-DZNEmptyDataSetTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DZNEmptyDataSetTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-DZNEmptyDataSetTests/Pods-DZNEmptyDataSetTests.debug.xcconfig"; sourceTree = ""; };
78C5DC4B343BE997FFAA0048 /* Pods_DZNEmptyDataSetTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DZNEmptyDataSetTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7DA71C23286E0CBE00C69885 /* UIScrollView+DZNEmptyExt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIScrollView+DZNEmptyExt.m"; path = "../../Source/UIScrollView+DZNEmptyExt.m"; sourceTree = ""; };
+ 7DA71C24286E0CBE00C69885 /* UIScrollView+DZNEmptyExt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIScrollView+DZNEmptyExt.h"; path = "../../Source/UIScrollView+DZNEmptyExt.h"; sourceTree = ""; };
+ 7DA71C96286EF48200C69885 /* EmptyExt.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EmptyExt.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7DA71C9C286EF48300C69885 /* Applications copy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Applications copy-Info.plist"; path = "/Users/jialunzeng/Documents/DZNEmptyDataSet/DZNEmptyDataSet/Applications copy-Info.plist"; sourceTree = ""; };
+ 7DA71CA4286EF68900C69885 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
+ 7DA71CA6286EF68900C69885 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
+ 7DA71CA7286EF68900C69885 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
+ 7DA71CA8286EF68900C69885 /* Applications-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Applications-Prefix.pch"; sourceTree = ""; };
+ 7DA71CA9286EF68900C69885 /* Storyboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Storyboard.storyboard; sourceTree = ""; };
+ 7DA71CAA286EF68900C69885 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ 7DA71CAB286EF68900C69885 /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MainViewController.h; path = Ext/MainViewController.h; sourceTree = ""; };
+ 7DA71CAC286EF68900C69885 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Ext/AppDelegate.h; sourceTree = ""; };
+ 7DA71CAD286EF68900C69885 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = Ext/AppDelegate.m; sourceTree = ""; };
+ 7DA71CAE286EF68900C69885 /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MainViewController.m; path = Ext/MainViewController.m; sourceTree = ""; };
84189CEC4210484C1F24D3A8 /* Pods-DZNEmptyDataSetTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DZNEmptyDataSetTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-DZNEmptyDataSetTests/Pods-DZNEmptyDataSetTests.release.xcconfig"; sourceTree = ""; };
DC2B63699C936D9C9CDB1740 /* Pods-EmptyDataSetTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-EmptyDataSetTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-EmptyDataSetTests/Pods-EmptyDataSetTests.release.xcconfig"; sourceTree = ""; };
F58A3E321E66AEE90086E0EF /* DZNEmptyDataSet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DZNEmptyDataSet.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -126,6 +151,14 @@
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
+ 7DA71C8A286EF48200C69885 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7DA71C8B286EF48200C69885 /* DZNEmptyDataSet.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
F58A3E2E1E66AEE90086E0EF /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -172,6 +205,32 @@
name = Pods;
sourceTree = "";
};
+ 7DA71C3E286EF19C00C69885 /* Sample - EmptyExt */ = {
+ isa = PBXGroup;
+ children = (
+ 7DA71CAC286EF68900C69885 /* AppDelegate.h */,
+ 7DA71CAD286EF68900C69885 /* AppDelegate.m */,
+ 7DA71CAB286EF68900C69885 /* MainViewController.h */,
+ 7DA71CAE286EF68900C69885 /* MainViewController.m */,
+ 7DA71CA2286EF68900C69885 /* Supporting Files */,
+ );
+ name = "Sample - EmptyExt";
+ sourceTree = "";
+ };
+ 7DA71CA2286EF68900C69885 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 7DA71CA3286EF68900C69885 /* InfoPlist.strings */,
+ 7DA71CA5286EF68900C69885 /* LaunchScreen.storyboard */,
+ 7DA71CA7286EF68900C69885 /* main.m */,
+ 7DA71CA8286EF68900C69885 /* Applications-Prefix.pch */,
+ 7DA71CA9286EF68900C69885 /* Storyboard.storyboard */,
+ 7DA71CAA286EF68900C69885 /* Info.plist */,
+ );
+ name = "Supporting Files";
+ path = "Ext/Supporting Files";
+ sourceTree = "";
+ };
A7CC5E0B0809CA256BDA9067 /* Frameworks */ = {
isa = PBXGroup;
children = (
@@ -188,9 +247,11 @@
F58A3E3F1E66AEE90086E0EF /* DZNEmptyDataSetTests */,
F58A3E641E66B5410086E0EF /* Sample - Applications */,
F5BE15261E713E2100F6FBEA /* Sample - Colors */,
+ 7DA71C3E286EF19C00C69885 /* Sample - EmptyExt */,
F58A3E331E66AEE90086E0EF /* Products */,
242E9BB031D3264D62C731D6 /* Pods */,
A7CC5E0B0809CA256BDA9067 /* Frameworks */,
+ 7DA71C9C286EF48300C69885 /* Applications copy-Info.plist */,
);
sourceTree = "";
};
@@ -201,6 +262,7 @@
F58A3E3B1E66AEE90086E0EF /* DZNEmptyDataSetTests.xctest */,
F58A3E631E66B5410086E0EF /* Applications.app */,
F5BE15251E713E2100F6FBEA /* Colors.app */,
+ 7DA71C96286EF48200C69885 /* EmptyExt.app */,
);
name = Products;
sourceTree = "";
@@ -211,6 +273,8 @@
F58A3E351E66AEE90086E0EF /* DZNEmptyDataSet.h */,
F58A3E4C1E66AF400086E0EF /* UIScrollView+EmptyDataSet.h */,
F58A3E4D1E66AF400086E0EF /* UIScrollView+EmptyDataSet.m */,
+ 7DA71C24286E0CBE00C69885 /* UIScrollView+DZNEmptyExt.h */,
+ 7DA71C23286E0CBE00C69885 /* UIScrollView+DZNEmptyExt.m */,
F58A3E361E66AEE90086E0EF /* Info.plist */,
);
path = DZNEmptyDataSet;
@@ -347,6 +411,7 @@
files = (
F58A3EA31E66B6C70086E0EF /* Applications-Prefix.pch in Headers */,
F58A3E431E66AEE90086E0EF /* DZNEmptyDataSet.h in Headers */,
+ 7DA71C26286E0CBE00C69885 /* UIScrollView+DZNEmptyExt.h in Headers */,
F58A3E4E1E66AF400086E0EF /* UIScrollView+EmptyDataSet.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -354,6 +419,23 @@
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
+ 7DA71C82286EF48200C69885 /* EmptyExt */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7DA71C93286EF48200C69885 /* Build configuration list for PBXNativeTarget "EmptyExt" */;
+ buildPhases = (
+ 7DA71C83286EF48200C69885 /* Sources */,
+ 7DA71C8A286EF48200C69885 /* Frameworks */,
+ 7DA71C8C286EF48200C69885 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = EmptyExt;
+ productName = Applications;
+ productReference = 7DA71C96286EF48200C69885 /* EmptyExt.app */;
+ productType = "com.apple.product-type.application";
+ };
F58A3E311E66AEE90086E0EF /* DZNEmptyDataSet */ = {
isa = PBXNativeTarget;
buildConfigurationList = F58A3E461E66AEE90086E0EF /* Build configuration list for PBXNativeTarget "DZNEmptyDataSet" */;
@@ -473,11 +555,23 @@
F58A3E3A1E66AEE90086E0EF /* DZNEmptyDataSetTests */,
F58A3E621E66B5410086E0EF /* Applications */,
F5BE15241E713E2100F6FBEA /* Colors */,
+ 7DA71C82286EF48200C69885 /* EmptyExt */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
+ 7DA71C8C286EF48200C69885 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7DA71CFA286EFBF600C69885 /* Assets.xcassets in Resources */,
+ 7DA71CB0286EF68900C69885 /* LaunchScreen.storyboard in Resources */,
+ 7DA71CB2286EF68900C69885 /* Storyboard.storyboard in Resources */,
+ 7DA71CAF286EF68900C69885 /* InfoPlist.strings in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
F58A3E301E66AEE90086E0EF /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -565,10 +659,22 @@
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
+ 7DA71C83286EF48200C69885 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7DA71D00286F010700C69885 /* UIColor+Hexadecimal.m in Sources */,
+ 7DA71CB5286EF68900C69885 /* MainViewController.m in Sources */,
+ 7DA71CB4286EF68900C69885 /* AppDelegate.m in Sources */,
+ 7DA71CB1286EF68900C69885 /* main.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
F58A3E2D1E66AEE90086E0EF /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 7DA71C25286E0CBE00C69885 /* UIScrollView+DZNEmptyExt.m in Sources */,
F58A3E4F1E66AF400086E0EF /* UIScrollView+EmptyDataSet.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -628,6 +734,22 @@
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
+ 7DA71CA3286EF68900C69885 /* InfoPlist.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 7DA71CA4286EF68900C69885 /* en */,
+ );
+ name = InfoPlist.strings;
+ sourceTree = "";
+ };
+ 7DA71CA5286EF68900C69885 /* LaunchScreen.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 7DA71CA6286EF68900C69885 /* Base */,
+ );
+ name = LaunchScreen.storyboard;
+ sourceTree = "";
+ };
F58A3E8B1E66B62F0086E0EF /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
@@ -655,6 +777,36 @@
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
+ 7DA71C94286EF48200C69885 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "LaunchImage-3";
+ DEVELOPMENT_TEAM = "";
+ INFOPLIST_FILE = "Applications copy-Info.plist";
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRIVATE_HEADERS_FOLDER_PATH = EmptyExt.app/PrivateHeaders;
+ PRODUCT_BUNDLE_IDENTIFIER = com.dzn.EmptyExt;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 7DA71C95286EF48200C69885 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = "LaunchImage-3";
+ DEVELOPMENT_TEAM = "";
+ INFOPLIST_FILE = "Applications copy-Info.plist";
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRIVATE_HEADERS_FOLDER_PATH = EmptyExt.app/PrivateHeaders;
+ PRODUCT_BUNDLE_IDENTIFIER = com.dzn.EmptyExt;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
F58A3E441E66AEE90086E0EF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -893,6 +1045,15 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
+ 7DA71C93286EF48200C69885 /* Build configuration list for PBXNativeTarget "EmptyExt" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7DA71C94286EF48200C69885 /* Debug */,
+ 7DA71C95286EF48200C69885 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
F58A3E2C1E66AEE90086E0EF /* Build configuration list for PBXProject "DZNEmptyDataSet" */ = {
isa = XCConfigurationList;
buildConfigurations = (
diff --git a/DZNEmptyDataSet/DZNEmptyDataSet.xcodeproj/xcshareddata/xcschemes/EmptyExt.xcscheme b/DZNEmptyDataSet/DZNEmptyDataSet.xcodeproj/xcshareddata/xcschemes/EmptyExt.xcscheme
new file mode 100644
index 00000000..1e9168b4
--- /dev/null
+++ b/DZNEmptyDataSet/DZNEmptyDataSet.xcodeproj/xcshareddata/xcschemes/EmptyExt.xcscheme
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DZNEmptyDataSet/Ext/AppDelegate.h b/DZNEmptyDataSet/Ext/AppDelegate.h
new file mode 100644
index 00000000..d28b0b26
--- /dev/null
+++ b/DZNEmptyDataSet/Ext/AppDelegate.h
@@ -0,0 +1,15 @@
+//
+// AppDelegate.h
+// Applications
+//
+// Created by Ignacio on 6/6/14.
+// Copyright (c) 2014 DZN Labs. All rights reserved.
+//
+
+#import
+
+@interface AppDelegate : UIResponder
+
+@property (strong, nonatomic) UIWindow *window;
+
+@end
diff --git a/DZNEmptyDataSet/Ext/AppDelegate.m b/DZNEmptyDataSet/Ext/AppDelegate.m
new file mode 100644
index 00000000..e61849d3
--- /dev/null
+++ b/DZNEmptyDataSet/Ext/AppDelegate.m
@@ -0,0 +1,21 @@
+//
+// AppDelegate.m
+// Applications
+//
+// Created by Ignacio on 6/6/14.
+// Copyright (c) 2014 DZN Labs. All rights reserved.
+//
+
+#import "AppDelegate.h"
+#import "MainViewController.h"
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ self.window.backgroundColor = [UIColor whiteColor];
+
+ return YES;
+}
+
+@end
diff --git a/DZNEmptyDataSet/Ext/MainViewController.h b/DZNEmptyDataSet/Ext/MainViewController.h
new file mode 100644
index 00000000..1f5b6d25
--- /dev/null
+++ b/DZNEmptyDataSet/Ext/MainViewController.h
@@ -0,0 +1,15 @@
+//
+// MainViewController.h
+// Applications
+//
+// Created by Ignacio on 6/6/14.
+// Copyright (c) 2014 DZN Labs. All rights reserved.
+//
+
+#import
+#import "DetailViewController.h"
+#import "Application.h"
+
+@interface MainViewController : UITableViewController
+
+@end
diff --git a/DZNEmptyDataSet/Ext/MainViewController.m b/DZNEmptyDataSet/Ext/MainViewController.m
new file mode 100644
index 00000000..d8ed7464
--- /dev/null
+++ b/DZNEmptyDataSet/Ext/MainViewController.m
@@ -0,0 +1,113 @@
+//
+// MainViewController.m
+// Applications
+//
+// Created by Ignacio on 6/6/14.
+// Copyright (c) 2014 DZN Labs. All rights reserved.
+//
+
+#import "MainViewController.h"
+#import "UIScrollView+DZNEmptyExt.h"
+#import "UIColor+Hexadecimal.h"
+
+@interface MainViewController ()
+
+@end
+
+@implementation MainViewController
+
+#pragma mark - View lifecycle
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+ self.title = @"EmptyExt";
+
+ self.tableView.tableFooterView = [UIView new];
+ self.tableView.delegate = self;
+ self.tableView.dataSource = self;
+
+ NSString * titleStr = @"Star Your Favorite Files";
+ UIFont * titleFont = [UIFont systemFontOfSize:17.0];
+ UIColor * titleColor = [UIColor colorWithHex:@"25282b"];
+
+ NSString * describeStr = @"Favorites are saved for offline access.";
+ UIFont * describeFont = [UIFont systemFontOfSize:14.5];
+ UIColor * describeColor = [UIColor colorWithHex:@"7b8994"];
+
+ NSString * buttonStr = @"Learn more";
+ UIFont * buttonFont = [UIFont systemFontOfSize:15.0];
+ UIColor * buttonNormalColor = [UIColor colorWithHex:@"007ee5"];
+ UIColor * buttonHighLightColor = [UIColor colorWithHex:@"48a1ea"];
+
+ UIImage * loadingImage = [UIImage imageNamed:@"loading_imgBlue_78x78" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
+
+ CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
+ animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
+ animation.toValue = [NSValue valueWithCATransform3D: CATransform3DMakeRotation(M_PI_2, 0.0, 0.0, 1.0) ];
+ animation.duration = 0.25;
+ animation.cumulative = YES;
+ animation.repeatCount = MAXFLOAT;
+ __weak typeof(self) weakSelf = self;
+ [[[[self.tableView makeEmptyPage:^(DZNEmptyMaker *make) {
+
+ // Configuring the dropbox dataset
+ make.displayScene(@"dropbox")
+ .image([UIImage imageNamed:@"placeholder_dropbox"])
+ .title(titleStr, titleFont, titleColor)
+ .describe(describeStr, describeFont, describeColor)
+ .buttonTitle(buttonStr, buttonFont, buttonNormalColor, UIControlStateNormal)
+ .buttonTitle(buttonStr, buttonFont, buttonHighLightColor, UIControlStateHighlighted)
+ .backgroundColor([UIColor colorWithHex:@"f0f3f5"])
+ .allowScroll(YES)
+ .allowTouch(YES);
+
+ // Configuring the loading dataset
+ make.displayScene(@"loading")
+ .image(loadingImage)
+ .title(titleStr, titleFont, titleColor)
+ .describe(describeStr, describeFont, describeColor)
+ .buttonTitle(buttonStr, buttonFont, buttonNormalColor, UIControlStateNormal)
+ .buttonTitle(buttonStr, buttonFont, buttonHighLightColor, UIControlStateHighlighted)
+ .backgroundColor([UIColor colorWithHex:@"f0f3f5"])
+ .imageAnimation(animation)
+ .allowImageAnimate(YES)
+ .allowScroll(YES)
+ .allowTouch(YES);
+
+ }] emptySceneChange:^(DZNDisplayScene type) {
+ // do something
+ }] emptyViewLifeCycle:^(DZNEmptyViewLifeCycle status) {
+ // do something
+ }] emptyDisplayClick:^(DZNTapType tapType, UIScrollView *scrollView, UIView *view) {
+ // Click to switch scenarios
+ [weakSelf.tableView reloadData: @"loading"];
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ [weakSelf.tableView reloadData: @"dropbox"];
+ });
+ }];
+
+ // Show a view of the Dropbox scene
+ [self.tableView reloadData: @"dropbox"];
+}
+
+#pragma mark - UITableViewDataSource Methods
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
+{
+ return 0;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+ static NSString *cellIdentifier = @"app_cell_identifier";
+ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
+
+ if (!cell) {
+ cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
+ }
+
+ return cell;
+}
+
+@end
diff --git a/DZNEmptyDataSet/Ext/Supporting Files/Applications-Prefix.pch b/DZNEmptyDataSet/Ext/Supporting Files/Applications-Prefix.pch
new file mode 100644
index 00000000..82a2bb45
--- /dev/null
+++ b/DZNEmptyDataSet/Ext/Supporting Files/Applications-Prefix.pch
@@ -0,0 +1,16 @@
+//
+// Prefix header
+//
+// The contents of this file are implicitly included at the beginning of every source file.
+//
+
+#import
+
+#ifndef __IPHONE_5_0
+#warning "This project uses features only available in iOS SDK 5.0 and later."
+#endif
+
+#ifdef __OBJC__
+ #import
+ #import
+#endif
diff --git a/DZNEmptyDataSet/Ext/Supporting Files/Base.lproj/LaunchScreen.storyboard b/DZNEmptyDataSet/Ext/Supporting Files/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 00000000..fdf3f97d
--- /dev/null
+++ b/DZNEmptyDataSet/Ext/Supporting Files/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DZNEmptyDataSet/Ext/Supporting Files/Info.plist b/DZNEmptyDataSet/Ext/Supporting Files/Info.plist
new file mode 100644
index 00000000..7b0138cd
--- /dev/null
+++ b/DZNEmptyDataSet/Ext/Supporting Files/Info.plist
@@ -0,0 +1,45 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ UIAppFonts
+
+ IdealSans-Book-Pro.otf
+ Lato-Regular.ttf
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Storyboard
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UIViewControllerBasedStatusBarAppearance
+
+
+
diff --git a/DZNEmptyDataSet/Ext/Supporting Files/Storyboard.storyboard b/DZNEmptyDataSet/Ext/Supporting Files/Storyboard.storyboard
new file mode 100644
index 00000000..f04d4f15
--- /dev/null
+++ b/DZNEmptyDataSet/Ext/Supporting Files/Storyboard.storyboard
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DZNEmptyDataSet/Ext/Supporting Files/en.lproj/InfoPlist.strings b/DZNEmptyDataSet/Ext/Supporting Files/en.lproj/InfoPlist.strings
new file mode 100644
index 00000000..477b28ff
--- /dev/null
+++ b/DZNEmptyDataSet/Ext/Supporting Files/en.lproj/InfoPlist.strings
@@ -0,0 +1,2 @@
+/* Localized versions of Info.plist keys */
+
diff --git a/DZNEmptyDataSet/Ext/Supporting Files/main.m b/DZNEmptyDataSet/Ext/Supporting Files/main.m
new file mode 100644
index 00000000..ff8a98d5
--- /dev/null
+++ b/DZNEmptyDataSet/Ext/Supporting Files/main.m
@@ -0,0 +1,16 @@
+//
+// main.m
+// Applications
+//
+// Created by Ignacio Romero on 2/28/17.
+// Copyright © 2017 DZN. All rights reserved.
+//
+
+#import
+#import "AppDelegate.h"
+
+int main(int argc, char * argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+ }
+}
diff --git a/README.md b/README.md
index 7494f96b..a3b804aa 100644
--- a/README.md
+++ b/README.md
@@ -279,6 +279,130 @@ depending of which you are using.
You can also call `[self.tableView reloadEmptyDataSet]` to invalidate the current empty state layout and trigger a layout update, bypassing `-reloadData`. This might be useful if you have a lot of logic on your data source that you want to avoid calling, when not needed. `[self.scrollView reloadEmptyDataSet]` is the only way to refresh content when using with UIScrollView.
+## How to use DZNEmptyExt
+
+This DZNEmptyExt is an encapsulation of uiscrollview+emptydataset.
+1、Added scene management functio
+2、Simplify data configuration and method call(similar to masonry)
+
+### Import
+```objc
+#import "UIScrollView+DZNEmptyExt.h"
+```
+Unless you are importing as a framework, then do:
+```objc
+#import
+```
+
+
+### Configure display data
+
+```objc
+// Bind display to scence
+[tableView makeEmptyPage:^(DZNEmptyMaker *make) {
+
+ // Parameter display of default view
+ make.displayScene(@"dropbox")
+ // -------Corresponding to DZNEmptyDataSetSource------
+ .image(/** image */)
+ // Equivalent to attrTitle(/** NSAttributedString */)
+ .title(/** string */, /** font */, /** color */)
+ // Equivalent to attrDescribe(/** NSAttributedString */)
+ .describe(/** string */, /** font */, /** color */)
+ // Equivalent to attrButtonTitle(/** NSAttributedString */)
+ .buttonTitle(/** string */, /** font */, /** color */, /** UIControlState */)
+ .buttonImage(/** image */), /** UIControlState */)
+ .buttonBackImage(/** image */), /** UIControlState */)
+ .imageAnimation(/** animation */)
+ .imageTintColor(/** color */)
+ .backgroundColor(/** color */)
+ .spaceHeight(/** float */)
+ .offset(/** offset */)
+ // -------Corresponding to DZNEmptyDataSetDelegate------
+ .shouldBeForcedToDisplay(/** YES/NO */)
+ .allowImageAnimate(/** YES/NO */)
+ .shouldDisplay(/** YES/NO */)
+ .shouldFadeIn(/** YES/NO */)
+ .allowScroll(/** YES/NO */)
+ .allowTouch(/** YES/NO */);
+
+ // Parameter display of customized view
+ make.displayScene(@"Loading")
+ .customView(/** view */) //Use custom view
+ .shouldBeForcedToDisplay(/** YES/NO */)
+ .allowImageAnimate(/** YES/NO */)
+ .shouldDisplay(/** YES/NO */)
+ .shouldFadeIn(/** YES/NO */)
+ .allowScroll(/** YES/NO */)
+ .allowTouch(/** YES/NO */);
+
+ make.displayScene(@"LoadFailure")
+ .image(/** image */)
+ .title(/** string */, /** font */, /** color */)
+ ...; // Configure data as needed
+
+ make.displayScene(@"NetworkFailure")
+ ...; // Configure data as needed
+
+ ......
+}];
+```
+
+#### Refresh layout
+
+Using [tableview reloaddata] will maintain the current display scene
+
+```objc
+// Do not display empty datasets
+[tableView reloadData: hideEmptyDataSet];
+
+// Refresh the contents of the display string binding
+[tableView reloadData: @"dropbox"];
+[tableView reloadData: @"Loading"];
+[tableView reloadData: @"LoadFailure"];
+[tableView reloadData: @"NetworkFailure"];
+...
+```
+#### Event monitoring(displaySceneChange、LifeCycle、Click/tap )
+
+```objc
+//
+DZNEmptyMaker * emptyMaker = [tableView makeEmptyPage:^(DZNEmptyMaker *make) {
+ // Bind display to scene
+ ......
+}];
+
+[[[emptyMaker emptySceneChange:^(DZNDisplayScene type) {
+ // Callback when changing the current display scene
+ // do something
+}] emptyViewLifeCycle:^(DZNEmptyViewLifeCycle status) {
+ // Callback when the empty page lifecycle method changes
+ // do something
+}] emptyDisplayClick:^(DZNTapType tapType, UIScrollView *scrollView, UIView *view) {
+ // Callback when tap button or view
+ // do something
+}];
+```
+
+#### initialize/reset、update 、add
+
+```objc
+/**
+ Initialize or reset empty page content
+*/
+-(DZNEmptyMaker *)makeEmptyPage:(DZNEmptyMakerBlock)block;
+
+/**
+ add Empty Page content(Existing ones will be overwritten)
+*/
+-(DZNEmptyMaker *)addEmptyPage:(DZNEmptyMakerBlock)block;
+
+/**
+ update Empty Page content(Only configured states can be modified)
+*/
+-(DZNEmptyMaker *)updateEmptyPage:(DZNEmptyMakerBlock)block;
+```
+
## Sample projects
#### Applications
diff --git a/Source/UIScrollView+DZNEmptyExt.h b/Source/UIScrollView+DZNEmptyExt.h
new file mode 100644
index 00000000..0a6bf31a
--- /dev/null
+++ b/Source/UIScrollView+DZNEmptyExt.h
@@ -0,0 +1,315 @@
+//
+// UIScrollView+DZNEmptyExt.h
+// JLEmptyExt
+//
+// Created by Jialun Zeng on 2017/4/21.
+// Copyright © 2017年 com.jl.emptyext. All rights reserved.
+//
+
+#import
+#import
+#import "UIScrollView+EmptyDataSet.h"
+@class DZNEmptyMaker;
+@class DZNEmpty;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol DZNEmptyCustomSource;
+@protocol DZNEmptyDelegate;
+@protocol DZNEmptyDataSource;
+
+typedef NSString * DZNDisplayScene;
+
+// Normal display page (no empty view)
+static DZNDisplayScene hideEmptyDataSet = @"DZNDisplaySceneHideEmptyDataSet";
+
+typedef NS_ENUM(NSInteger, DZNTapType) {
+ // Tells the delegate that the action button was tapped.
+ DZNTapOfButton,
+ // Tells the delegate that the empty dataset view was tapped. Use this method either to resignFirstResponder of a textfield or searchBar.
+ DZNTapOfView,
+};
+
+typedef NS_ENUM(NSInteger, DZNEmptyViewLifeCycle) {
+ DZNEmptyViewWillAppear, // Tells the delegate that the empty data set will appear.
+ DZNEmptyViewDidAppear, // Tells the delegate that the empty data set did appear.
+ DZNEmptyViewWillDisappear, // Tells the delegate that the empty data set will disappear.
+ DZNEmptyViewDidDisappear, // Tells the delegate that the empty data set did disappear.
+};
+
+
+typedef void (^DZNEmptyMakerBlock)(DZNEmptyMaker * make);
+typedef DZNEmpty * _Nonnull (^DZNDefaultStrBlock)(NSString * title, UIFont * font, UIColor * color);
+typedef DZNEmpty * _Nonnull (^DZNButtonStrBlock)(NSString * title, UIFont * font, UIColor * color, UIControlState state);
+typedef DZNEmpty * _Nonnull (^DZNAttrButtonStrBlock)(NSAttributedString * title, UIControlState state);
+typedef DZNEmpty * _Nonnull (^DZNAttrStrBlock)(NSAttributedString * title);
+typedef DZNEmpty * _Nonnull (^DZNButtonImageBlock)(UIImage * img, UIControlState state);
+typedef DZNEmpty * _Nonnull (^DZNImageBlock)(UIImage * img);
+typedef DZNEmpty * _Nonnull (^DZNShowAnimateBlock)(BOOL allow);
+typedef DZNEmpty * _Nonnull (^DZNAnimationBlock)(CAAnimation * animation);
+typedef DZNEmpty * _Nonnull (^DZNFloatBlock)(CGFloat spaceHeight);
+typedef DZNEmpty * _Nonnull (^DZNColorBlock)(UIColor * color);
+typedef DZNEmpty * _Nonnull (^DZNBoolBlock)(BOOL allow);
+typedef DZNEmpty * _Nonnull (^DZNOffsetBlock)(CGFloat offset);
+typedef DZNEmpty * _Nonnull (^DZNCustomBlock)(UIView * view);
+
+
+//_____________________________________________________________________________
+
+#pragma mark public Delegate
+@protocol DZNEmptyDelegate
+
+/**
+ Asks the delegate for scroll permission. Default is NO.
+ */
+@property (nonatomic ,copy) DZNBoolBlock allowScroll;
+
+/**
+ Asks the delegate for touch permission. Default is YES.
+ */
+@property (nonatomic ,copy) DZNBoolBlock allowTouch;
+
+/**
+ Asks the delegate to know if the empty dataset should fade in when displayed. Default is YES.
+ */
+@property (nonatomic ,copy) DZNBoolBlock shouldFadeIn;
+
+/**
+ Asks the delegate to know if the empty dataset should still be displayed when the amount of items is more than 0. Default is NO
+ */
+@property (nonatomic ,copy) DZNBoolBlock shouldBeForcedToDisplay;
+
+/**
+ Asks the delegate to know if the empty dataset should be rendered and displayed. Default is YES.
+ */
+@property (nonatomic ,copy) DZNBoolBlock shouldDisplay;
+
+/**
+ Asks the delegate for image view animation permission. Default is NO.
+ */
+@property (nonatomic, copy) DZNShowAnimateBlock allowImageAnimate;
+
+/**
+ Used to eliminate swift warning instead of @discardableResult
+ */
+- (void)end;
+
+@end
+
+//_____________________________________________________________________________
+
+#pragma mark Custom layout Delegate
+
+@protocol DZNEmptyCustomSource
+
+/**
+ Asks the data source for a custom view to be displayed instead of the default views such as labels, imageview and button. Default is nil.
+ Use this method to show an activity view indicator for loading feedback, or for complete custom empty data set.
+ Returning a custom view will ignore -offsetForEmptyDataSet and -spaceHeightForEmptyDataSet configurations.
+ */
+@property (nonatomic ,copy) DZNCustomBlock customView;
+
+@end
+
+//_____________________________________________________________________________
+
+
+#pragma mark default layout Delegate
+
+@protocol DZNEmptyDataSource
+
+/**
+ Asks the data source for the title of the dataset.
+ The dataset uses a fixed font style by default, if no attributes are set. If you want a different font style, return a attributed string.
+ */
+@property (nonatomic ,copy) DZNDefaultStrBlock title;
+
+/**
+ Asks the data source for the description of the dataset.
+ The dataset uses a fixed font style by default, if no attributes are set. If you want a different font style, return a attributed string.
+ */
+@property (nonatomic ,copy) DZNDefaultStrBlock describe;
+
+/**
+ Asks the data source for the title to be used for the normal button state.
+ The dataset uses a fixed font style by default, if no attributes are set. If you want a different font style, return a attributed string.
+ */
+@property (nonatomic ,copy) DZNButtonStrBlock buttonTitle;
+@property (nonatomic, copy) DZNAttrButtonStrBlock attrButtonTitle;
+
+/**
+ Asks the data source for the image to be used for the specified button state. present the image only without any text
+ */
+@property (nonatomic, copy) DZNButtonImageBlock buttonImage;
+
+/**
+ Asks the data source for a background image to be used for the specified button status
+ There is no default style for this call.
+ */
+@property (nonatomic, copy) DZNButtonImageBlock buttonBackImage;
+
+/**
+ Asks the data source for the title of the dataset.
+ The dataset uses a fixed font style by default, if no attributes are set. If you want a different font style, return a attributed string.
+ */
+
+@property (nonatomic, copy) DZNAttrStrBlock attrTitle;
+
+/**
+ Asks the data source for the description of the dataset.
+ The dataset uses a fixed font style by default, if no attributes are set. If you want a different font style, return a attributed string.
+ */
+@property (nonatomic, copy) DZNAttrStrBlock attrDescribe;
+
+/**
+ Asks the data source for the image of the dataset.
+ */
+@property (nonatomic, copy) DZNImageBlock image;
+
+/**
+ Asks the data source for a vertical space between elements. Default is 11 pts.
+ */
+@property (nonatomic, copy) DZNFloatBlock spaceHeight;
+
+/**
+ Asks the data source for the image animation of the dataset.
+ */
+@property (nonatomic, copy) DZNAnimationBlock imageAnimation;
+
+/**
+ Asks the data source for a offset for vertical and horizontal alignment of the content. Default is CGPointZero.
+ */
+@property (nonatomic ,copy) DZNOffsetBlock offset;
+
+/**
+ Asks the data source for the background color of the dataset. Default is clear color.
+ */
+@property (nonatomic ,copy) DZNColorBlock backgroundColor;
+
+/**
+ Asks the data source for a tint color of the image dataset. Default is nil.
+ */
+@property (nonatomic ,copy) DZNColorBlock imageTintColor;
+
+@end
+
+
+//_______________________________________________________________________________________________________________
+
+
+@interface UIScrollView (DZNEmptyExt)
+
+// get current display scene
+- (DZNDisplayScene)displayScene;
+
+/**
+ reload and Toggle display scene
+
+ @param scene Desired display scene
+ You can directly use strings to represent scene
+ eg: [scrollview reloadData: @"no order"];
+ */
+- (void)reloadData:(DZNDisplayScene)scene;
+
+/**
+ Get "make" in the specified state
+
+ @param displayScene input DZNdisplayScene(NSString)
+ */
+- (DZNEmpty *)getEmptyMake:(DZNDisplayScene)displayScene;
+
+/**
+ Initialize or reset empty page content
+
+ @param block block
+ @return DZNEmptyMaker object
+ */
+-(DZNEmptyMaker *)makeEmptyPage:(DZNEmptyMakerBlock)block;
+
+/**
+ add Empty Page content(Existing ones will be overwritten)
+
+@param block block
+@return DZNEmptyMaker object
+*/
+-(DZNEmptyMaker *)addEmptyPage:(DZNEmptyMakerBlock)block;
+
+/**
+ update Empty Page content(Only configured states can be modified)
+
+@param block block
+@return DZNEmptyMaker object
+*/
+-(DZNEmptyMaker *)updateEmptyPage:(DZNEmptyMakerBlock)block;
+
+@end
+
+
+//_______________________________________________________________________________________________________________
+
+typedef NS_ENUM(NSInteger, DZNEmptyEditType) {
+ DZNEmptyEditTypeMake,
+ DZNEmptyEditTypeUpdate,
+ DZNEmptyEditTypeAdd,
+};
+
+typedef void (^DZNSceneChangeBlock)(DZNDisplayScene type);
+typedef void (^DZNEmptyViewLifeCycleBlock)(DZNEmptyViewLifeCycle status);
+typedef void (^DZNTapBlock)(DZNTapType tapType, UIScrollView * scrollView, UIView * view);
+typedef DZNEmpty * _Nonnull (^DZNdisplaySceneBlock)(DZNDisplayScene type);
+
+
+@interface DZNEmptyMaker : NSObject
+
+@property (nonatomic ,strong) NSMutableDictionary * dataSource;
+@property (nonatomic ,copy) DZNTapBlock tapBlock;
+@property (nonatomic ,copy) DZNEmptyViewLifeCycleBlock lifeCycleBlock;
+@property (nonatomic ,copy) DZNSceneChangeBlock sceneBlock;
+@property (nonatomic ,assign) DZNEmptyEditType editType;
+
+/**
+ You can directly use strings to represent states
+ eg:
+ // Bind display to scene
+ [tableView makeEmptyPage:^(DZNEmptyMaker *make) {
+ make.displayScene(@"no order")
+ ........; // The specific content corresponding to the scene, such as title, picture, button, etc
+
+ make.displayScene(displaySceneNetworkFailure)
+ ........; // The specific content corresponding to the scene, such as title, picture, button, etc
+ }];
+ // reloadData with scene
+ [tableView reloadData: @"no order"]; or [tableView reloadData: displaySceneNetworkFailure];
+ */
+@property (nonatomic ,copy) DZNdisplaySceneBlock displayScene;
+
+/**
+ Callback when changing the current display state
+ */
+-(DZNEmptyMaker *)emptySceneChange:(DZNSceneChangeBlock)block;
+
+
+/**
+ Callback when the empty page lifecycle method changes
+ */
+-(DZNEmptyMaker *)emptyViewLifeCycle:(DZNEmptyViewLifeCycleBlock)block;
+
+
+/**
+ Callback when tap button or view
+
+ @param block block
+ */
+-(DZNEmptyMaker *)emptyDisplayClick:(DZNTapBlock)block;
+
+
+@end
+
+
+//_______________________________________________________________________________________________________________
+
+@interface DZNEmpty : NSObject
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Source/UIScrollView+DZNEmptyExt.m b/Source/UIScrollView+DZNEmptyExt.m
new file mode 100644
index 00000000..a788e2e1
--- /dev/null
+++ b/Source/UIScrollView+DZNEmptyExt.m
@@ -0,0 +1,566 @@
+//
+// UIScrollView+DZNEmptyExt.m
+// JLEmptyExt
+//
+// Created by Jialun Zeng on 2017/4/21.
+// Copyright © 2017年 com.jl.emptyext. All rights reserved.
+//
+
+#import "UIScrollView+DZNEmptyExt.h"
+#import
+
+@implementation UIScrollView (DZNEmptyExt)
+
+static const char typeKey;
+static const char emptyMakerKey;
+
+
+#pragma mark - reload
+
+-(void)reloadData:(DZNDisplayScene)scene{
+
+ [self setScrollViewType: scene];
+
+ self.emptyDataSetSource = self;
+ self.emptyDataSetDelegate = self;
+
+ if ([self isKindOfClass: [UITableView class]]) {
+ UITableView * tableView = (UITableView *)self;
+ [tableView reloadData];
+ }else if ([self isKindOfClass: [UICollectionView class]]){
+ UICollectionView * collectionView = (UICollectionView *)self;
+ [collectionView reloadData];
+ }else{
+ [self reloadEmptyDataSet];
+ }
+
+ DZNEmptyMaker * maker = [self getEmptyMaker];
+
+ if (maker.sceneBlock) {
+ maker.sceneBlock(scene);
+ }
+}
+
+-(DZNEmptyMaker *)makeEmptyPage:(DZNEmptyMakerBlock)block{
+
+ DZNEmptyMaker * maker = [[DZNEmptyMaker alloc] init];
+
+ maker.editType = DZNEmptyEditTypeMake;
+
+ [self setEmptyMaker: maker];
+
+ if (block) {
+ block(maker);
+ }
+
+ return maker;
+}
+
+-(DZNEmptyMaker *)addEmptyPage:(DZNEmptyMakerBlock)block{
+
+ DZNEmptyMaker * maker = [self getEmptyMaker];
+
+ maker.editType = DZNEmptyEditTypeAdd;
+
+ if (block) {
+ block(maker);
+ }
+
+ return maker;
+}
+
+-(DZNEmptyMaker *)updateEmptyPage:(DZNEmptyMakerBlock)block{
+
+ DZNEmptyMaker * maker = [self getEmptyMaker];
+
+ maker.editType = DZNEmptyEditTypeUpdate;
+
+ if (block) {
+ block(maker);
+ }
+
+ return maker;
+}
+
+
+-(DZNDisplayScene)displayScene{
+ return [self getScrollViewType];
+}
+
+
+#pragma mark - save data
+
+
+- (void)setEmptyMaker:(DZNEmptyMaker *)emptyMaker{
+ objc_setAssociatedObject(self, &emptyMakerKey, emptyMaker, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (DZNEmptyMaker *) getEmptyMaker{
+ return objc_getAssociatedObject(self, &emptyMakerKey);
+}
+
+- (void)setScrollViewType:(DZNDisplayScene)scrollViewType{
+ objc_setAssociatedObject(self, &typeKey, scrollViewType, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+- (DZNDisplayScene)getScrollViewType{
+ return objc_getAssociatedObject(self, &typeKey);
+}
+
+//Get the "DZNEmpty" object in the current state
+- (DZNEmpty *)getEmpty{
+ NSMutableDictionary * dataSource = [self getEmptyMaker].dataSource;
+ return [dataSource objectForKey: [NSString stringWithFormat: @"%ld", (long)[self getScrollViewType]]];
+}
+
+- (DZNEmpty *)getEmptyMake:(DZNDisplayScene)displayScene{
+ NSMutableDictionary * dataSource = [self getEmptyMaker].dataSource;
+ return [dataSource objectForKey: [NSString stringWithFormat: @"%ld", (long)displayScene]];
+}
+
+#pragma mark - DZNEmptyDataSetSource
+
+- (UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView
+{
+ return [[self getEmpty] valueForKey: @"Image"];
+}
+
+- (NSAttributedString *)titleForEmptyDataSet:(UIScrollView *)scrollView
+{
+ return [[self getEmpty] valueForKey: @"Title"];
+}
+
+- (NSAttributedString *)descriptionForEmptyDataSet:(UIScrollView *)scrollView
+{
+ return [[self getEmpty] valueForKey: @"Describe"];
+}
+
+- (NSAttributedString *)buttonTitleForEmptyDataSet:(UIScrollView *)scrollView forState:(UIControlState)state
+{
+ DZNEmpty * empty = [self getEmpty];
+
+ NSString * key = [NSString stringWithFormat:@"%lu", (unsigned long)state];
+ return [[empty valueForKey:@"ButtonTitles"] valueForKey: key];
+}
+
+- (UIImage *)buttonImageForEmptyDataSet:(UIScrollView *)scrollView forState:(UIControlState)state
+{
+ DZNEmpty * empty = [self getEmpty];
+
+ NSString * key = [NSString stringWithFormat:@"%lu", (unsigned long)state];
+ return [[empty valueForKey:@"ButtonImages"] valueForKey: key];
+}
+
+- (nullable UIImage *)buttonBackgroundImageForEmptyDataSet:(UIScrollView *)scrollView forState:(UIControlState)state{
+ DZNEmpty * empty = [self getEmpty];
+
+ NSString * key = [NSString stringWithFormat:@"%lu", (unsigned long)state];
+ return [[empty valueForKey:@"ButtonBackImages"] valueForKey: key];
+}
+
+- (CAAnimation *)imageAnimationForEmptyDataSet:(UIScrollView *)scrollView
+{
+ return [[self getEmpty] valueForKey: @"ImageAnimation"];
+}
+
+-(UIView *)customViewForEmptyDataSet:(UIScrollView *)scrollView{
+
+ return [[self getEmpty] valueForKey: @"CustomView"];
+}
+
+- (UIColor *)backgroundColorForEmptyDataSet:(UIScrollView *)scrollView
+{
+ return [[self getEmpty] valueForKey: @"BackgroundColor"];
+}
+
+-(CGFloat)verticalOffsetForEmptyDataSet:(UIScrollView *)scrollView{
+
+ return [[[self getEmpty] valueForKey: @"Offset"] floatValue];
+}
+
+- (CGFloat)spaceHeightForEmptyDataSet:(UIScrollView *)scrollView
+{
+ return [[[self getEmpty] valueForKey: @"SpaceHeight"] floatValue];
+}
+
+- (UIColor *)imageTintColorForEmptyDataSet:(UIScrollView *)scrollView
+{
+ return [[self getEmpty] valueForKey: @"ImageTintColor"];
+}
+
+
+#pragma mark DZNEmptyDataSetDelegate
+
+- (BOOL)emptyDataSetShouldDisplay:(UIScrollView *)scrollView
+{
+ if ([[self getScrollViewType] isEqualToString: hideEmptyDataSet]) return NO;
+ return [[[self getEmpty] valueForKey: @"ShouldDisplay"] boolValue];
+}
+
+- (BOOL)emptyDataSetShouldAllowTouch:(UIScrollView *)scrollView
+{
+ return [[[self getEmpty] valueForKey: @"AllowTouch"] boolValue];
+}
+
+- (BOOL)emptyDataSetShouldAllowScroll:(UIScrollView *)scrollView
+{
+ return [[[self getEmpty] valueForKey: @"AllowScroll"] boolValue];
+}
+
+- (BOOL)emptyDataSetShouldAnimateImageView:(UIScrollView *)scrollView
+{
+ return [[[self getEmpty] valueForKey: @"AllowImageAnimate"] boolValue];
+}
+
+- (BOOL)emptyDataSetShouldFadeIn:(UIScrollView *)scrollView
+{
+ return [[[self getEmpty] valueForKey: @"ShouldFadeIn"] boolValue];
+}
+
+- (BOOL)emptyDataSetShouldBeForcedToDisplay:(UIScrollView *)scrollView
+{
+ return [[[self getEmpty] valueForKey: @"ShouldBeForcedToDisplay"] boolValue];
+}
+
+
+
+- (void)emptyDataSetWillAppear:(UIScrollView *)scrollView{
+ DZNEmptyMaker * maker = [self getEmptyMaker];
+ if (maker.lifeCycleBlock) {
+ maker.lifeCycleBlock(DZNEmptyViewWillAppear);
+ }
+}
+
+- (void)emptyDataSetDidAppear:(UIScrollView *)scrollView{
+ DZNEmptyMaker * maker = [self getEmptyMaker];
+ if (maker.lifeCycleBlock) {
+ maker.lifeCycleBlock(DZNEmptyViewDidAppear);
+ }
+}
+
+- (void)emptyDataSetWillDisappear:(UIScrollView *)scrollView{
+ DZNEmptyMaker * maker = [self getEmptyMaker];
+ if (maker.lifeCycleBlock) {
+ maker.lifeCycleBlock(DZNEmptyViewWillDisappear);
+ }
+}
+
+- (void)emptyDataSetDidDisappear:(UIScrollView *)scrollView{
+ DZNEmptyMaker * maker = [self getEmptyMaker];
+ if (maker.lifeCycleBlock) {
+ maker.lifeCycleBlock(DZNEmptyViewDidDisappear);
+ }
+}
+
+- (void)emptyDataSet:(UIScrollView *)scrollView didTapView:(UIView *)view{
+ DZNEmptyMaker * maker = [self getEmptyMaker];
+ if (maker.tapBlock) {
+ maker.tapBlock(DZNTapOfView, self, view);
+ }
+}
+
+- (void)emptyDataSet:(UIScrollView *)scrollView didTapButton:(UIButton *)button{
+ DZNEmptyMaker * maker = [self getEmptyMaker];
+ if (maker.tapBlock) {
+ maker.tapBlock(DZNTapOfButton, self, button);
+ }
+}
+
+
+@end
+
+
+//_______________________________________________________________________________________________________________
+
+@implementation DZNEmptyMaker
+
+-(NSMutableDictionary *)dataSource{
+ if (!_dataSource) {
+ _dataSource = [[NSMutableDictionary alloc] init];
+ }
+ return _dataSource;
+}
+
+
+-(DZNEmpty * (^)(DZNDisplayScene type))displayScene{
+
+ return ^DZNEmpty *(DZNDisplayScene type){
+
+ DZNEmpty * empty;
+
+ if (self.editType == DZNEmptyEditTypeUpdate) {
+ empty = [self.dataSource objectForKey: [NSString stringWithFormat: @"%ld", (long)type]];
+ }else{
+ empty = [[DZNEmpty alloc] init];
+ [self.dataSource setObject: empty forKey: [NSString stringWithFormat: @"%ld", (long)type]];
+ }
+
+ return empty;
+ };
+}
+
+-(DZNEmptyMaker *)emptySceneChange:(DZNSceneChangeBlock)block{
+ self.sceneBlock = block;
+ return self;
+}
+
+-(DZNEmptyMaker *)emptyViewLifeCycle:(DZNEmptyViewLifeCycleBlock)block{
+ self.lifeCycleBlock = block;
+ return self;
+}
+
+
+-(DZNEmptyMaker *)emptyDisplayClick:(DZNTapBlock)block{
+ self.tapBlock = block;
+ return self;
+}
+
+
+@end
+
+//_______________________________________________________________________________________________________________
+
+@interface DZNEmpty ()
+
+@property (nonatomic ,strong) UIImage * Image;
+@property (nonatomic ,strong) NSMutableDictionary * ButtonImages;
+@property (nonatomic ,strong) NSMutableDictionary * ButtonBackImages;
+@property (nonatomic ,strong) NSNumber * AllowImageAnimate;
+@property (nonatomic ,strong) NSNumber * SpaceHeight;
+@property (nonatomic ,strong) CAAnimation * ImageAnimation;
+@property (nonatomic ,strong) NSAttributedString * Title;
+@property (nonatomic ,strong) NSAttributedString * Describe;
+@property (nonatomic ,strong) NSMutableDictionary * ButtonTitles;
+@property (nonatomic ,strong) NSAttributedString * ButtonTitle;
+@property (nonatomic ,strong) NSAttributedString * ButtonTitleHighlighted;
+@property (nonatomic ,strong) NSNumber * Offset;
+@property (nonatomic ,strong) NSNumber * AllowScroll;
+@property (nonatomic ,strong) NSNumber * AllowTouch;
+@property (nonatomic ,strong) NSNumber * ShouldDisplay;
+@property (nonatomic ,strong) NSNumber * ShouldFadeIn;
+@property (nonatomic ,strong) NSNumber * ShouldBeForcedToDisplay;
+@property (nonatomic ,strong) UIColor * BackgroundColor;
+@property (nonatomic ,strong) UIColor * ImageTintColor;
+@property (nonatomic ,strong) UIView * CustomView;
+
+@end
+
+@implementation DZNEmpty
+
+#pragma mark - init
+- (instancetype)init
+{
+ self = [super init];
+ if (self) {
+ self.Offset = [NSNumber numberWithFloat: 0.0];
+ self.AllowTouch = [NSNumber numberWithBool: YES];
+ self.AllowScroll = [NSNumber numberWithBool: NO];
+ self.ShouldFadeIn = [NSNumber numberWithBool: YES];
+ self.ShouldDisplay = [NSNumber numberWithBool: YES];
+ self.AllowImageAnimate = [NSNumber numberWithBool: NO];
+ self.ShouldBeForcedToDisplay = [NSNumber numberWithBool: NO];
+ self.ButtonBackImages = [[NSMutableDictionary alloc]init];
+ self.ButtonImages = [[NSMutableDictionary alloc]init];
+ self.ButtonTitles = [[NSMutableDictionary alloc]init];
+ }
+ return self;
+}
+
+
+#pragma mark - Custom Empty
+
+-(DZNEmpty * (^)(UIView * view))customView{
+ return ^id(UIView * view){
+ self.CustomView = view;
+ return self;
+ };
+}
+
+
+#pragma mark - 默认的缺省页设置
+
+-(DZNDefaultStrBlock)title{
+ return ^(NSString * title, UIFont * font, UIColor * color){
+ if (title) {
+ if (!font) font = [UIFont systemFontOfSize: 17];
+ if (!color) color = [UIColor lightGrayColor];
+
+ NSDictionary *attributes = @{NSFontAttributeName: font,
+ NSForegroundColorAttributeName: color};
+
+ self.Title = [[NSAttributedString alloc] initWithString: title attributes: attributes];
+ }
+
+ return self;
+ };
+}
+
+-(DZNDefaultStrBlock)describe{
+ return ^(NSString * title, UIFont * font, UIColor * color){
+ if (title) {
+ if (!font) font = [UIFont systemFontOfSize: 17];
+ if (!color) color = [UIColor lightGrayColor];
+
+ NSMutableParagraphStyle *paragraph = [NSMutableParagraphStyle new];
+ paragraph.lineBreakMode = NSLineBreakByWordWrapping;
+ paragraph.alignment = NSTextAlignmentCenter;
+ NSDictionary *attributes = @{NSFontAttributeName: font,
+ NSForegroundColorAttributeName: color,
+ NSParagraphStyleAttributeName: paragraph};
+
+ self.Describe = [[NSAttributedString alloc] initWithString: title attributes: attributes];
+ }
+
+ return self;
+ };
+}
+
+-(DZNButtonStrBlock)buttonTitle{
+ return ^(NSString *title, UIFont * font, UIColor * color, UIControlState state){
+ if (title) {
+ if (!font) font = [UIFont systemFontOfSize: 17];
+ if (!color) color = [UIColor lightGrayColor];
+
+ NSDictionary *attributes = @{NSFontAttributeName: font,
+ NSForegroundColorAttributeName: color};
+
+ NSString * key = [NSString stringWithFormat:@"%lu", (unsigned long)state];
+ NSAttributedString * str = [[NSAttributedString alloc] initWithString: title attributes: attributes];
+
+ self.ButtonTitles[key] = str;
+ }
+
+ return self;
+ };
+}
+
+-(DZNEmpty * (^)(NSAttributedString * title, UIControlState state))attrButtonTitle{
+ return ^id (NSAttributedString * title, UIControlState state){
+ NSString * key = [NSString stringWithFormat:@"%lu", (unsigned long)state];
+ self.ButtonTitles[key] = title;
+ return self;
+ };
+}
+
+-(DZNEmpty * (^)(NSAttributedString * title))attrTitle{
+ return ^id (NSAttributedString * title){
+ self.Title = title;
+ return self;
+ };
+}
+
+-(DZNEmpty * (^)(NSAttributedString * title))attrDescribe{
+ return ^id (NSAttributedString * title){
+ self.Describe = title;
+ return self;
+ };
+}
+
+-(DZNEmpty * (^)(UIImage * img))image{
+ return ^id(UIImage * img){
+ self.Image = img;
+ return self;
+ };
+}
+
+-(DZNEmpty * (^)(UIImage * img, UIControlState state))buttonImage{
+ return ^id(UIImage * img, UIControlState state){
+ NSString * key = [NSString stringWithFormat:@"%lu", (unsigned long)state];
+ self.ButtonImages[key] = img;
+ return self;
+ };
+}
+
+-(DZNEmpty * (^)(UIImage * img, UIControlState state))buttonBackImage{
+ return ^id(UIImage * img, UIControlState state){
+ NSString * key = [NSString stringWithFormat:@"%lu", (unsigned long)state];
+ self.ButtonBackImages[key] = img;
+ return self;
+ };
+}
+
+-(DZNEmpty * (^)(CAAnimation * animation))imageAnimation{
+ return ^id(CAAnimation * animation){
+ self.ImageAnimation = animation;
+ return self;
+ };
+}
+
+-(DZNEmpty * (^)(CGFloat spaceHeight))spaceHeight{
+ return ^id(CGFloat spaceHeight){
+ self.SpaceHeight = [NSNumber numberWithFloat: spaceHeight];
+ return self;
+ };
+}
+
+-(DZNEmpty * (^)(CGFloat offset))offset{
+ return ^id(CGFloat offset){
+ self.Offset = [NSNumber numberWithFloat: offset];
+ return self;
+ };
+}
+
+-(DZNEmpty * (^)(UIColor * color))backgroundColor{
+ return ^id (UIColor * color){
+ self.BackgroundColor = color;
+ return self;
+ };
+}
+
+-(DZNEmpty * (^)(UIColor * color))imageTintColor{
+ return ^id (UIColor * color){
+ self.ImageTintColor = color;
+ return self;
+ };
+}
+
+
+#pragma mark - delegate
+
+-(DZNEmpty * (^)(BOOL allow))allowScroll{
+ return ^id(BOOL allow){
+ self.AllowScroll = [NSNumber numberWithBool: allow];
+ return self;
+ };
+}
+
+-(DZNEmpty * (^)(BOOL allow))allowTouch{
+ return ^id(BOOL allow){
+ self.AllowTouch = [NSNumber numberWithBool: allow];
+ return self;
+ };
+}
+
+-(DZNEmpty * (^)(BOOL should))shouldDisplay{
+ return ^id(BOOL should){
+ self.ShouldDisplay = [NSNumber numberWithBool: should];
+ return self;
+ };
+}
+
+-(DZNEmpty * (^)(BOOL should))shouldFadeIn{
+ return ^id(BOOL should){
+ self.ShouldFadeIn = [NSNumber numberWithBool: should];
+ return self;
+ };
+}
+
+-(DZNEmpty * (^)(BOOL should))shouldBeForcedToDisplay{
+ return ^id(BOOL should){
+ self.ShouldBeForcedToDisplay = [NSNumber numberWithBool: should];
+ return self;
+ };
+}
+
+-(DZNEmpty * (^)(BOOL allow))allowImageAnimate{
+ return ^id(BOOL allow){
+ self.AllowImageAnimate = [NSNumber numberWithBool: allow];
+ return self;
+ };
+}
+
+- (void)end {}
+
+@end
+
+