From 1ec42c4f5a1eca0f7dec2e763d7ea972d9203b94 Mon Sep 17 00:00:00 2001 From: HarrisonXi Date: Wed, 22 Nov 2017 16:58:45 +0800 Subject: [PATCH] update to version 0.1.0: 1. fix a problem of reuseIdentifier matching during dequeue 2. add a new feature "autoAddSubview" 3. add 2 new public properties: visibleItems & inScreenVisibleItems 4. optimize codes of scrollViewDelegate forwarding --- .gitignore | 35 + LazyScroll.podspec | 12 +- LazyScrollView.xcodeproj/project.pbxproj | 301 -------- .../contents.xcworkspacedata | 7 - .../UserInterfaceState.xcuserstate | Bin 15702 -> 0 bytes .../xcschemes/LazyScrollView.xcscheme | 80 --- .../xcschemes/xcschememanagement.plist | 22 - LazyScrollView/Info.plist | 24 - LazyScrollView/TMMuiLazyScrollView.h | 93 ++- LazyScrollView/TMMuiLazyScrollView.m | 666 +++++++++--------- .../TMMuiLazyScrollViewCellProtocol.h | 32 + LazyScrollView/TMMuiRectModel.h | 21 + LazyScrollView/TMMuiRectModel.m | 12 + LazyScrollView/TMUtils.h | 52 ++ LazyScrollView/TMUtils.m | 183 +++++ .../project.pbxproj | 111 ++- .../UserInterfaceState.xcuserstate | Bin 16904 -> 0 bytes .../xcdebugger/Breakpoints_v2.xcbkptlist | 5 - .../xcschemes/LazyScrollViewDemo.xcscheme | 91 --- .../xcschemes/xcschememanagement.plist | 22 - .../LazyScrollViewDemo/AppDelegate.h | 3 +- .../LazyScrollViewDemo/AppDelegate.m | 3 +- .../LazyScrollViewDemo/ViewController.h | 3 +- .../LazyScrollViewDemo/ViewController.m | 93 ++- LazyScrollViewDemo/Podfile | 6 + README.md | 69 +- 26 files changed, 881 insertions(+), 1065 deletions(-) create mode 100644 .gitignore delete mode 100644 LazyScrollView.xcodeproj/project.pbxproj delete mode 100644 LazyScrollView.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 LazyScrollView.xcodeproj/project.xcworkspace/xcuserdata/xiaoxia.xcuserdatad/UserInterfaceState.xcuserstate delete mode 100644 LazyScrollView.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcschemes/LazyScrollView.xcscheme delete mode 100644 LazyScrollView.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 LazyScrollView/Info.plist create mode 100644 LazyScrollView/TMMuiLazyScrollViewCellProtocol.h create mode 100644 LazyScrollView/TMMuiRectModel.h create mode 100644 LazyScrollView/TMMuiRectModel.m create mode 100644 LazyScrollView/TMUtils.h create mode 100644 LazyScrollView/TMUtils.m delete mode 100644 LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/project.xcworkspace/xcuserdata/xiaoxia.xcuserdatad/UserInterfaceState.xcuserstate delete mode 100644 LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist delete mode 100644 LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcschemes/LazyScrollViewDemo.xcscheme delete mode 100644 LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 LazyScrollViewDemo/Podfile diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8f6e9a9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# Xcode + +## Build generated +build/ +DerivedData/ + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ + +## Other +*.moved-aside +*.xccheckout +*.xcscmblueprint + +## Obj-C/Swift specific +*.hmap +*.ipa +*.dSYM.zip +*.dSYM + +# CocoaPods +Pods/ +Podfile.lock + +# Demo +*Demo/*.xcworkspace + diff --git a/LazyScroll.podspec b/LazyScroll.podspec index 07677bd..4e3cf4b 100644 --- a/LazyScroll.podspec +++ b/LazyScroll.podspec @@ -1,17 +1,21 @@ Pod::Spec.new do |s| s.name = "LazyScroll" - s.version = "0.0.2" + s.version = "0.1.0" s.summary = "A ScrollView to resolve the problem of reusability of views." + s.description = <<-DESC It reply an another way to control reuse in a ScrollView, it depends on give a special reuse identifier to every view controlled in LazyScrollView. DESC + s.homepage = "https://github.com/alibaba/LazyScrollView" s.license = {:type => 'MIT'} - s.author = { "fydx" => "lbgg918@gmail.com" } + s.author = { "fydx" => "lbgg918@gmail.com", + "HarrisonXi" => "gpra8764@gmail.com"} + s.platform = :ios s.ios.deployment_target = "5.0" - s.source = { :git => "https://github.com/alibaba/LazyScrollView.git", :tag => "0.0.2" } - s.source_files = "LazyScrollView/TMMuiLazyScrollView.{h,m}" + s.source = { :git => "https://github.com/alibaba/LazyScrollView.git", :tag => "0.1.0" } + s.source_files = "LazyScrollView/*.{h,m}" s.requires_arc = true end diff --git a/LazyScrollView.xcodeproj/project.pbxproj b/LazyScrollView.xcodeproj/project.pbxproj deleted file mode 100644 index 44b9d95..0000000 --- a/LazyScrollView.xcodeproj/project.pbxproj +++ /dev/null @@ -1,301 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 70D7C6281E642747008B76C6 /* TMMuiLazyScrollView.h in Headers */ = {isa = PBXBuildFile; fileRef = 70D7C6261E642747008B76C6 /* TMMuiLazyScrollView.h */; }; - 70D7C6291E642747008B76C6 /* TMMuiLazyScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 70D7C6271E642747008B76C6 /* TMMuiLazyScrollView.m */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 70D7C6171E642600008B76C6 /* LazyScrollView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LazyScrollView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 70D7C61B1E642600008B76C6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 70D7C6261E642747008B76C6 /* TMMuiLazyScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TMMuiLazyScrollView.h; sourceTree = ""; }; - 70D7C6271E642747008B76C6 /* TMMuiLazyScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TMMuiLazyScrollView.m; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 70D7C6131E642600008B76C6 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 70D7C60D1E642600008B76C6 = { - isa = PBXGroup; - children = ( - 70D7C6191E642600008B76C6 /* LazyScrollView */, - 70D7C6181E642600008B76C6 /* Products */, - ); - sourceTree = ""; - }; - 70D7C6181E642600008B76C6 /* Products */ = { - isa = PBXGroup; - children = ( - 70D7C6171E642600008B76C6 /* LazyScrollView.framework */, - ); - name = Products; - sourceTree = ""; - }; - 70D7C6191E642600008B76C6 /* LazyScrollView */ = { - isa = PBXGroup; - children = ( - 70D7C6261E642747008B76C6 /* TMMuiLazyScrollView.h */, - 70D7C6271E642747008B76C6 /* TMMuiLazyScrollView.m */, - 70D7C61B1E642600008B76C6 /* Info.plist */, - ); - path = LazyScrollView; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 70D7C6141E642600008B76C6 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 70D7C6281E642747008B76C6 /* TMMuiLazyScrollView.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 70D7C6161E642600008B76C6 /* LazyScrollView */ = { - isa = PBXNativeTarget; - buildConfigurationList = 70D7C61F1E642600008B76C6 /* Build configuration list for PBXNativeTarget "LazyScrollView" */; - buildPhases = ( - 70D7C6121E642600008B76C6 /* Sources */, - 70D7C6131E642600008B76C6 /* Frameworks */, - 70D7C6141E642600008B76C6 /* Headers */, - 70D7C6151E642600008B76C6 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = LazyScrollView; - productName = LazyScrollView; - productReference = 70D7C6171E642600008B76C6 /* LazyScrollView.framework */; - productType = "com.apple.product-type.framework"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 70D7C60E1E642600008B76C6 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0820; - ORGANIZATIONNAME = taobao; - TargetAttributes = { - 70D7C6161E642600008B76C6 = { - CreatedOnToolsVersion = 8.2.1; - DevelopmentTeam = PBH63ZAR55; - ProvisioningStyle = Automatic; - }; - }; - }; - buildConfigurationList = 70D7C6111E642600008B76C6 /* Build configuration list for PBXProject "LazyScrollView" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 70D7C60D1E642600008B76C6; - productRefGroup = 70D7C6181E642600008B76C6 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 70D7C6161E642600008B76C6 /* LazyScrollView */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 70D7C6151E642600008B76C6 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 70D7C6121E642600008B76C6 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 70D7C6291E642747008B76C6 /* TMMuiLazyScrollView.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 70D7C61D1E642600008B76C6 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 70D7C61E1E642600008B76C6 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 70D7C6201E642600008B76C6 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_IDENTITY = ""; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = PBH63ZAR55; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = LazyScrollView/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = tmall.LazyScrollView; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - }; - name = Debug; - }; - 70D7C6211E642600008B76C6 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_IDENTITY = ""; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = PBH63ZAR55; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = LazyScrollView/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = tmall.LazyScrollView; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 70D7C6111E642600008B76C6 /* Build configuration list for PBXProject "LazyScrollView" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 70D7C61D1E642600008B76C6 /* Debug */, - 70D7C61E1E642600008B76C6 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 70D7C61F1E642600008B76C6 /* Build configuration list for PBXNativeTarget "LazyScrollView" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 70D7C6201E642600008B76C6 /* Debug */, - 70D7C6211E642600008B76C6 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 70D7C60E1E642600008B76C6 /* Project object */; -} diff --git a/LazyScrollView.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/LazyScrollView.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index ae84a54..0000000 --- a/LazyScrollView.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/LazyScrollView.xcodeproj/project.xcworkspace/xcuserdata/xiaoxia.xcuserdatad/UserInterfaceState.xcuserstate b/LazyScrollView.xcodeproj/project.xcworkspace/xcuserdata/xiaoxia.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 0b62ddf62bd122f94addcdb01fbfdb9dfd04d6b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15702 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 diff --git a/LazyScrollView.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcschemes/LazyScrollView.xcscheme b/LazyScrollView.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcschemes/LazyScrollView.xcscheme deleted file mode 100644 index b1491c5..0000000 --- a/LazyScrollView.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcschemes/LazyScrollView.xcscheme +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/LazyScrollView.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcschemes/xcschememanagement.plist b/LazyScrollView.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 1487c61..0000000 --- a/LazyScrollView.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - SchemeUserState - - LazyScrollView.xcscheme - - orderHint - 0 - - - SuppressBuildableAutocreation - - 70D7C6161E642600008B76C6 - - primary - - - - - diff --git a/LazyScrollView/Info.plist b/LazyScrollView/Info.plist deleted file mode 100644 index fbe1e6b..0000000 --- a/LazyScrollView/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/LazyScrollView/TMMuiLazyScrollView.h b/LazyScrollView/TMMuiLazyScrollView.h index 8fa3689..fac8074 100644 --- a/LazyScrollView/TMMuiLazyScrollView.h +++ b/LazyScrollView/TMMuiLazyScrollView.h @@ -2,50 +2,24 @@ // TMMuiLazyScrollView.h // LazyScrollView // -// Copyright (c) 2015 tmall. All rights reserved. +// Copyright (c) 2015-2017 Alibaba. All rights reserved. // #import +#import "TMMuiLazyScrollViewCellProtocol.h" +#import "TMMuiRectModel.h" -#define DEFAULT_REUSE_IDENTIFIER @"reuseIdentifier" - -//If the view in LazyScrollView implement this protocol, view can do something in its lifecycle. -@protocol TMMuiLazyScrollViewCellProtocol - -@optional -// if call dequeueReusableItemWithIdentifier to get a reuseable view,the same as "prepareForReuse" in UITableViewCell -- (void)mui_prepareForReuse; -// When view enter the visible area of LazyScrollView ,call this method. -// First 'times' is 0 -- (void)mui_didEnterWithTimes:(NSUInteger)times; -// When we need render the view, call this method. -// The difference between this method and 'mui_didEnterWithTimes' is there is a buffer area in LazyScrollView(RenderBufferWindow), first we will call 'mui_afterGetView'. -- (void)mui_afterGetView; - -@end -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * It is a view model that holding information of view. At least holding absoluteRect and muiID. - */ -@interface TMMuiRectModel: NSObject - -// A rect that relative to the scroll view. -@property (nonatomic, assign) CGRect absoluteRect; - -// A uniq string that identify a model. -@property (nonatomic, copy, nonnull) NSString *muiID; +@class TMMuiLazyScrollView; -@end /** - * A UIView category required by LazyScrollView. + A UIView category required by LazyScrollView. */ -@interface UIView(TMMui) - -// A uniq string that identify a view, require to be same as muiID of the model. -@property (nonatomic, copy, nonnull) NSString *muiID; +@interface UIView (TMMuiLazyScrollView) +// A uniq string that identify a view, require to +// be same as muiID of the model. +@property (nonatomic, copy, nullable) NSString *muiID; // A string used to identify a view that is reusable. @property (nonatomic, copy, nullable) NSString *reuseIdentifier; @@ -54,26 +28,24 @@ @end +//**************************************************************** -// This protocol represents the data model object. -@class TMMuiLazyScrollView; +/** + This protocol represents the data model object. + */ @protocol TMMuiLazyScrollViewDataSource @required -- (NSUInteger)numberOfItemInScrollView:(nonnull TMMuiLazyScrollView *)scrollView; // 0 by default. - -//////////////////////////////////////////////////////////////////////////////////////////////////// +// 0 by default. +- (NSUInteger)numberOfItemInScrollView:(nonnull TMMuiLazyScrollView *)scrollView; // Return the view model by spcial index. - (nonnull TMMuiRectModel *)scrollView:(nonnull TMMuiLazyScrollView *)scrollView rectModelAtIndex:(NSUInteger)index; - -/** - * You should render the item view here. And the view is probably . Item view display. You should - * *always* try to reuse views by setting each view's reuseIdentifier and querying for available - * reusable views with dequeueReusableItemWithIdentifier: - */ -- (nullable UIView *)scrollView:(nonnull TMMuiLazyScrollView *)scrollView itemByMuiID:(nonnull NSString *)muiID; +// You should render the item view here. +// You should ALWAYS try to reuse views by setting each view's reuseIdentifier. +- (nonnull UIView *)scrollView:(nonnull TMMuiLazyScrollView *)scrollView + itemByMuiID:(nonnull NSString *)muiID; @end @@ -81,20 +53,35 @@ @end +//**************************************************************** + +@interface TMMuiLazyScrollView : UIScrollView -@interface TMMuiLazyScrollView : UIScrollView +@property (nonatomic, weak, nullable) id dataSource; -@property (nonatomic, weak, nullable) id dataSource; +// Default value is NO. +@property (nonatomic, assign) BOOL autoAddSubview; -// Get Visible Views -@property (nonatomic, strong, readonly, nonnull) NSMutableSet *visibleItems; +// Items which has been added to LazyScrollView. +@property (nonatomic, strong, readonly, nonnull) NSSet *visibleItems; +// Items which is in the visible screen area. +// It is a sub set of "visibleItems". +@property (nonatomic, strong, readonly, nonnull) NSSet *inScreenVisibleItems; // reloads everything from scratch and redisplays visible views. - (void)reloadData; -// Get reuseable view by reuseIdentifier. If cannot find reuseable view by reuseIdentifier, here will return nil. -- (nullable UIView *)dequeueReusableItemWithIdentifier:(nonnull NSString *)reuseIdentifier; // Remove all subviews and reuseable views. - (void)removeAllLayouts; + +// Get reuseable view by reuseIdentifier. If cannot find reuseable +// view by reuseIdentifier, here will return nil. +- (nullable UIView *)dequeueReusableItemWithIdentifier:(nonnull NSString *)identifier; +// Get reuseable view by reuseIdentifier and muiID. +// MuiID has higher priority. +- (nullable UIView *)dequeueReusableItemWithIdentifier:(nonnull NSString *)identifier + muiID:(nullable NSString *)muiID; + // After call this method, the times of mui_didEnterWithTimes will start from 0 - (void)resetViewEnterTimes; + @end diff --git a/LazyScrollView/TMMuiLazyScrollView.m b/LazyScrollView/TMMuiLazyScrollView.m index cd2f2fc..84e6e88 100644 --- a/LazyScrollView/TMMuiLazyScrollView.m +++ b/LazyScrollView/TMMuiLazyScrollView.m @@ -2,115 +2,106 @@ // TMMuiLazyScrollView.m // LazyScrollView // -// Copyright (c) 2015 tmall. All rights reserved. +// Copyright (c) 2015-2017 Alibaba. All rights reserved. // -#define RenderBufferWindow 20.f - #import "TMMuiLazyScrollView.h" #import +#import "TMUtils.h" -@implementation TMMuiRectModel - -@end +#define RenderBufferWindow 20.f -//Here is a category implementation required by LazyScrollView. -@implementation UIView(TMMui) +@implementation UIView(TMMuiLazyScrollView) - (instancetype)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier { - self = [self initWithFrame:frame]; - if (self) - { + if (self = [self initWithFrame:frame]) { self.reuseIdentifier = reuseIdentifier; } return self; } -- (void)setReuseIdentifier:(NSString *)reuseIdentifier +- (NSString *)reuseIdentifier { - objc_setAssociatedObject(self, @"reuseIdentifier", reuseIdentifier, OBJC_ASSOCIATION_COPY_NONATOMIC); + return objc_getAssociatedObject(self, @"tm_reuseIdentifier"); } -- (NSString *)reuseIdentifier +- (void)setReuseIdentifier:(NSString *)reuseIdentifier { - NSString *reuseIdentifier = objc_getAssociatedObject(self, @"reuseIdentifier"); - return reuseIdentifier; + objc_setAssociatedObject(self, @"tm_reuseIdentifier", reuseIdentifier, OBJC_ASSOCIATION_COPY_NONATOMIC); } - (NSString *)muiID { - return objc_getAssociatedObject(self, @"muiID"); + return objc_getAssociatedObject(self, @"tm_muiID"); } - (void)setMuiID:(NSString *)muiID { - objc_setAssociatedObject(self, @"muiID", muiID, OBJC_ASSOCIATION_COPY_NONATOMIC); + objc_setAssociatedObject(self, @"tm_muiID", muiID, OBJC_ASSOCIATION_COPY_NONATOMIC); } @end -@interface TMMuiLazyScrollViewObserver: NSObject -@property (nonatomic, weak) TMMuiLazyScrollView *lazyScrollView; -@end - +//**************************************************************** -@interface TMMuiLazyScrollView() - -// Store Visible Views -@property (nonatomic, strong, readwrite) NSMutableSet *visibleItems; +@interface TMMuiLazyScrollView() { + NSMutableSet *_visibleItems; + NSMutableSet *_inScreenVisibleItems; +} -// Store reuseable cells by reuseIdentifier. The key is reuseIdentifier of views , value is an array that contains reuseable cells. -@property (nonatomic,strong)NSMutableDictionary *recycledIdentifierItemsDic; +// Store reuseable cells by reuseIdentifier. The key is reuseIdentifier +// of views , value is an array that contains reuseable cells. +@property (nonatomic, strong) NSMutableDictionary *recycledIdentifierItemsDic; +// Store reuseable cells by muiID. +@property (nonatomic, strong) NSMutableDictionary *recycledMuiIDItemsDic; // Store view models (TMMuiRectModel). @property (nonatomic, strong) NSMutableArray *itemsFrames; -// ScrollView delegate,store outer scrollDelegate here. -// Because of lazyscrollview need calculate what views should be shown in scrollDidScroll. -@property (nonatomic,weak) id lazyScrollViewDelegate; +// ScrollView delegate, store original scrollDelegate here. +// Because of lazyscrollview need calculate what views should be shown +// in scrollDidScroll. +@property (nonatomic, weak) id lazyScrollViewDelegate; // View Model sorted by Top Edge. @property (nonatomic, strong) NSArray *modelsSortedByTop; - // View Model sorted by Bottom Edge. @property (nonatomic, strong) NSArray *modelsSortedByBottom; // Store view models below contentOffset of ScrollView @property (nonatomic, strong) NSMutableSet *firstSet; - -// Store view models above contentOffset + ScrollView.height of ScrollView +// Store view models above contentOffset + height of ScrollView @property (nonatomic, strong) NSMutableSet *secondSet; -// record contentOffset of scrollview in previous time that calculate views to show -@property (nonatomic, assign) CGPoint lastScrollOffset; +// Record contentOffset of scrollview in previous time that calculate +// views to show +@property (nonatomic, assign) CGPoint lastScrollOffset; -// record current muiID of visible view for calculate. -@property (nonatomic, strong) NSString *currentVisibleItemMuiID; +// Record current muiID of visible view for calculate. +// Will be used for dequeueReusableItem methods. +@property (nonatomic, strong) NSString *currentVisibleItemMuiID; // It is used to store views need to assign new value after reload. -@property (nonatomic, strong) NSMutableSet *shouldReloadItems; +@property (nonatomic, strong) NSMutableSet *shouldReloadItems; -// Record in screen visible muiID +// Record muiIDs of visible items. Used for calc enter times. @property (nonatomic, strong) NSSet *muiIDOfVisibleViews; -// Store the times of view entered the screen , the key is muiiD +// Store the times of view entered the screen, the key is muiID. @property (nonatomic, strong) NSMutableDictionary *enterDict; -// Store last time visible muiID -@property (nonatomic, strong) NSMutableSet *lastVisiblemuiID; +// Store last time visible muiID. Used for calc enter times. +@property (nonatomic, strong) NSMutableSet *lastVisibleMuiID; @end +//**************************************************************** @implementation TMMuiLazyScrollView --(NSMutableDictionary *)enterDict -{ - if (nil == _enterDict) { - _enterDict = [[NSMutableDictionary alloc]init]; - } - return _enterDict; -} +@dynamic visibleItems, inScreenVisibleItems; + +#pragma mark - Getter & Setter - (NSMutableSet *)shouldReloadItems { @@ -120,202 +111,165 @@ - (NSMutableSet *)shouldReloadItems return _shouldReloadItems; } -- (void)setFrame:(CGRect)frame +- (NSArray *)modelsSortedByTop { - if (!CGRectEqualToRect(frame, self.frame)) - { - [super setFrame:frame]; + if (!_modelsSortedByTop){ + _modelsSortedByTop = [[NSArray alloc] init]; } + return _modelsSortedByTop; } -- (id)initWithFrame:(CGRect)frame +- (NSArray *)modelsSortedByBottom { - self = [super initWithFrame:frame]; - if (self) - { - self.clipsToBounds = YES; - self.autoresizesSubviews = NO; - self.showsHorizontalScrollIndicator = NO; - self.showsVerticalScrollIndicator = NO; - _recycledIdentifierItemsDic = [[NSMutableDictionary alloc] init]; - _visibleItems = [[NSMutableSet alloc] init]; - _itemsFrames = [[NSMutableArray alloc] init]; - _firstSet = [[NSMutableSet alloc] initWithCapacity:30]; - _secondSet = [[NSMutableSet alloc] initWithCapacity:30]; - super.delegate = self; - + if (!_modelsSortedByBottom) { + _modelsSortedByBottom = [[NSArray alloc]init]; } - return self; -} - -- (void)dealloc -{ - _dataSource = nil; - self.delegate = nil; - [_recycledIdentifierItemsDic removeAllObjects],_recycledIdentifierItemsDic = nil; - [_visibleItems removeAllObjects],_visibleItems = nil; - [_itemsFrames removeAllObjects],_itemsFrames = nil; - [_firstSet removeAllObjects],_firstSet = nil; - [_secondSet removeAllObjects],_secondSet = nil; - _modelsSortedByTop = nil; - _modelsSortedByBottom = nil; - + return _modelsSortedByBottom; } -//replace UIScrollDelegate to TMMuiLazyScrollViewDelegate for insert code in scrollDidScroll . --(void)setDelegate:(id)delegate +- (NSMutableDictionary *)enterDict { - if (!delegate) - { - [super setDelegate:nil]; - _lazyScrollViewDelegate = nil; - } - else - { - [super setDelegate:self]; - _lazyScrollViewDelegate = delegate; + if (nil == _enterDict) { + _enterDict = [[NSMutableDictionary alloc]init]; } + return _enterDict; } --(void)scrollViewDidScroll:(UIScrollView *)scrollView +- (NSMutableDictionary *)recycledMuiIDItemsDic { - // Scroll can trigger LazyScrollView calculate which views should be shown. - // Calcuting Action will cost some time , so here is a butter for reducing times of calculating. - CGFloat currentY = scrollView.contentOffset.y; - CGFloat buffer = RenderBufferWindow / 2; - if (buffer < ABS(currentY - self.lastScrollOffset.y)) { - self.lastScrollOffset = scrollView.contentOffset; - [self assembleSubviews]; - [self findViewsInVisibleRect]; - - } - if (self.lazyScrollViewDelegate && [self.lazyScrollViewDelegate conformsToProtocol:@protocol(UIScrollViewDelegate)] && [self.lazyScrollViewDelegate respondsToSelector:@selector(scrollViewDidScroll:)]) - { - [self.lazyScrollViewDelegate scrollViewDidScroll:self]; + if(nil == _recycledMuiIDItemsDic) { + _recycledMuiIDItemsDic = [[NSMutableDictionary alloc]init]; } - + return _recycledMuiIDItemsDic; } -- (void)scrollViewDidZoom:(UIScrollView *)scrollView NS_AVAILABLE_IOS(3_2) +- (NSSet *)inScreenVisibleItems { - if (self.lazyScrollViewDelegate && [self.lazyScrollViewDelegate conformsToProtocol:@protocol(UIScrollViewDelegate)] && [self.lazyScrollViewDelegate respondsToSelector:@selector(scrollViewDidZoom:)]) - { - [self.lazyScrollViewDelegate scrollViewDidZoom:self]; - } + return [_inScreenVisibleItems copy]; } -- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView +- (NSSet *)visibleItems { - if (self.lazyScrollViewDelegate && [self.lazyScrollViewDelegate conformsToProtocol:@protocol(UIScrollViewDelegate)] && [self.lazyScrollViewDelegate respondsToSelector:@selector(scrollViewWillBeginDragging:)]) - { - [self.lazyScrollViewDelegate scrollViewWillBeginDragging:self]; - } + return [_visibleItems copy]; } -- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset NS_AVAILABLE_IOS(5_0) +- (void)setFrame:(CGRect)frame { - if (self.lazyScrollViewDelegate && [self.lazyScrollViewDelegate conformsToProtocol:@protocol(UIScrollViewDelegate)] && [self.lazyScrollViewDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) - { - [self.lazyScrollViewDelegate scrollViewWillEndDragging:self withVelocity:velocity targetContentOffset:targetContentOffset]; + if (!CGRectEqualToRect(frame, self.frame)) { + [super setFrame:frame]; } } -- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate +- (void)setDelegate:(id)delegate { - if (self.lazyScrollViewDelegate && [self.lazyScrollViewDelegate conformsToProtocol:@protocol(UIScrollViewDelegate)] && [self.lazyScrollViewDelegate respondsToSelector:@selector(scrollViewDidEndDragging:willDecelerate:)]) - { - [self.lazyScrollViewDelegate scrollViewDidEndDragging:self willDecelerate:decelerate]; + if (!delegate) { + [super setDelegate:nil]; + _lazyScrollViewDelegate = nil; + } else { + _lazyScrollViewDelegate = delegate; + [super setDelegate:self]; } } -- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView -{ - if (self.lazyScrollViewDelegate && [self.lazyScrollViewDelegate conformsToProtocol:@protocol(UIScrollViewDelegate)] && [self.lazyScrollViewDelegate respondsToSelector:@selector(scrollViewWillBeginDecelerating:)]) - { - [self.lazyScrollViewDelegate scrollViewWillBeginDecelerating:self]; - } -} +#pragma mark - Lifecycle -- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView +- (id)initWithFrame:(CGRect)frame { - if (self.lazyScrollViewDelegate && [self.lazyScrollViewDelegate conformsToProtocol:@protocol(UIScrollViewDelegate)] && [self.lazyScrollViewDelegate respondsToSelector:@selector(scrollViewDidEndDecelerating:)]) - { - [self.lazyScrollViewDelegate scrollViewDidEndDecelerating:self]; + if (self = [super initWithFrame:frame]) { + self.clipsToBounds = YES; + self.autoresizesSubviews = NO; + self.showsHorizontalScrollIndicator = NO; + self.showsVerticalScrollIndicator = NO; + _recycledIdentifierItemsDic = [[NSMutableDictionary alloc] init]; + _visibleItems = [[NSMutableSet alloc] init]; + _inScreenVisibleItems = [[NSMutableSet alloc] init]; + _itemsFrames = [[NSMutableArray alloc] init]; + _firstSet = [[NSMutableSet alloc] initWithCapacity:30]; + _secondSet = [[NSMutableSet alloc] initWithCapacity:30]; + [super setDelegate:self]; } + return self; } -- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView +- (void)dealloc { - if (self.lazyScrollViewDelegate && [self.lazyScrollViewDelegate conformsToProtocol:@protocol(UIScrollViewDelegate)] && [self.lazyScrollViewDelegate respondsToSelector:@selector(scrollViewDidEndScrollingAnimation:)]) - { - [self.lazyScrollViewDelegate scrollViewDidEndScrollingAnimation:self]; - } + _dataSource = nil; + [super setDelegate:nil]; + _lazyScrollViewDelegate = nil; } -- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView -{ - if (self.lazyScrollViewDelegate && [self.lazyScrollViewDelegate conformsToProtocol:@protocol(UIScrollViewDelegate)] && [self.lazyScrollViewDelegate respondsToSelector:@selector(viewForZoomingInScrollView:)]) - { - return [self.lazyScrollViewDelegate viewForZoomingInScrollView:self]; - } - return nil; -} +#pragma mark - ScrollViewDelegate -- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view NS_AVAILABLE_IOS(3_2) +- (void)didScroll { - if (self.lazyScrollViewDelegate && [self.lazyScrollViewDelegate conformsToProtocol:@protocol(UIScrollViewDelegate)] && [self.lazyScrollViewDelegate respondsToSelector:@selector(scrollViewWillBeginZooming:withView:)]) - { - [self.lazyScrollViewDelegate scrollViewWillBeginZooming:self withView:view]; + // Calculate which views should be shown. + // Calcuting will cost some time, so here is a buffer for reducing + // times of calculating. + CGFloat currentY = self.contentOffset.y; + CGFloat buffer = RenderBufferWindow / 2; + if (buffer < ABS(currentY - self.lastScrollOffset.y)) { + self.lastScrollOffset = self.contentOffset; + [self assembleSubviews]; + [self findViewsInVisibleRect]; } + } - -- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { - if (self.lazyScrollViewDelegate && [self.lazyScrollViewDelegate conformsToProtocol:@protocol(UIScrollViewDelegate)] && [self.lazyScrollViewDelegate respondsToSelector:@selector(scrollViewDidEndZooming:withView:atScale:)]) - { - [self.lazyScrollViewDelegate scrollViewDidEndZooming:self withView:view atScale:scale]; + [self didScroll]; + + if (self.lazyScrollViewDelegate && + [self.lazyScrollViewDelegate conformsToProtocol:@protocol(UIScrollViewDelegate)] && + [self.lazyScrollViewDelegate respondsToSelector:@selector(scrollViewDidScroll:)]) { + [self.lazyScrollViewDelegate scrollViewDidScroll:self]; } } - -- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView +- (id)forwardingTargetForSelector:(SEL)aSelector { - if (self.lazyScrollViewDelegate && [self.lazyScrollViewDelegate conformsToProtocol:@protocol(UIScrollViewDelegate)] && [self.lazyScrollViewDelegate respondsToSelector:@selector(scrollViewShouldScrollToTop:)]) - { - return [self.lazyScrollViewDelegate scrollViewShouldScrollToTop:self]; + if (self.lazyScrollViewDelegate) { + struct objc_method_description md = protocol_getMethodDescription(@protocol(UIScrollViewDelegate), aSelector, NO, YES); + if (NULL != md.name) { + return self.lazyScrollViewDelegate; + } } - return self.scrollsToTop; + return [super forwardingTargetForSelector:aSelector]; } -- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView +- (BOOL)respondsToSelector:(SEL)aSelector { - if (self.lazyScrollViewDelegate && [self.lazyScrollViewDelegate conformsToProtocol:@protocol(UIScrollViewDelegate)] && [self.lazyScrollViewDelegate respondsToSelector:@selector(scrollViewDidScrollToTop:)]) - { - [self.lazyScrollViewDelegate scrollViewDidScrollToTop:self]; + BOOL result = [super respondsToSelector:aSelector]; + if (NO == result && self.lazyScrollViewDelegate) { + struct objc_method_description md = protocol_getMethodDescription(@protocol(UIScrollViewDelegate), aSelector, NO, YES); + if (NULL != md.name) { + result = [self.lazyScrollViewDelegate respondsToSelector:aSelector]; + } } + return result; } + +#pragma mark - Core Logic + // Do Binary search here to find index in view model array. --(NSUInteger) binarySearchForIndex:(NSArray *)frameArray baseLine:(CGFloat)baseLine isFromTop:(BOOL)fromTop +- (NSUInteger)binarySearchForIndex:(NSArray *)frameArray baseLine:(CGFloat)baseLine isFromTop:(BOOL)fromTop { NSInteger min = 0 ; - NSInteger max = frameArray.count -1; - NSInteger mid = ceilf((CGFloat)(min + max) / 2.f); + NSInteger max = frameArray.count - 1; + NSInteger mid = ceilf((min + max) * 0.5f); while (mid > min && mid < max) { - CGRect rect = [(TMMuiRectModel *)[frameArray objectAtIndex:mid] absoluteRect]; + CGRect rect = [(TMMuiRectModel *)[frameArray tm_safeObjectAtIndex:mid] absRect]; // For top if(fromTop) { CGFloat itemTop = CGRectGetMinY(rect); if (itemTop <= baseLine) { - CGRect nextItemRect = [(TMMuiRectModel *)[frameArray objectAtIndex:mid + 1] absoluteRect]; + CGRect nextItemRect = [(TMMuiRectModel *)[frameArray tm_safeObjectAtIndex:mid + 1] absRect]; CGFloat nextTop = CGRectGetMinY(nextItemRect); if (nextTop > baseLine) { - mid ++; break; } min = mid; - } - else { + } else { max = mid; } } @@ -323,231 +277,222 @@ -(NSUInteger) binarySearchForIndex:(NSArray *)frameArray baseLine:(CGFloat)baseL else { CGFloat itemBottom = CGRectGetMaxY(rect); if (itemBottom >= baseLine) { - CGRect nextItemRect = [(TMMuiRectModel *)[frameArray objectAtIndex:mid + 1] absoluteRect]; + CGRect nextItemRect = [(TMMuiRectModel *)[frameArray tm_safeObjectAtIndex:mid + 1] absRect]; CGFloat nextBottom = CGRectGetMaxY(nextItemRect); if (nextBottom < baseLine) { - mid ++; break; } min = mid; - } - else { + } else { max = mid; } } mid = ceilf((CGFloat)(min + max) / 2.f); } - return mid; } // Get which views should be shown in LazyScrollView. -// The kind of Inner Elements In NSSet is NSNumber , containing index of view model array; --(NSSet *)showingItemIndexSetFrom :(CGFloat)startY to:(CGFloat)endY +// The kind of values In NSSet is muiID. +- (NSSet *)showingItemIndexSetFrom:(CGFloat)startY to:(CGFloat)endY { - if ( !self.modelsSortedByBottom || !self.modelsSortedByTop ) { - [self creatScrollViewIndex]; - } NSUInteger endBottomIndex = [self binarySearchForIndex:self.modelsSortedByBottom baseLine:startY isFromTop:NO]; [self.firstSet removeAllObjects]; - if (self.modelsSortedByBottom && self.modelsSortedByBottom.count > 0) { - for (NSUInteger i = 0; i <= endBottomIndex; i++) { - TMMuiRectModel *model = [self.modelsSortedByBottom objectAtIndex:i]; - if (model != nil) { - [self.firstSet addObject:model.muiID]; - } + for (NSUInteger i = 0; i <= endBottomIndex; i++) { + TMMuiRectModel *model = [self.modelsSortedByBottom tm_safeObjectAtIndex:i]; + if (model != nil) { + [self.firstSet addObject:model.muiID]; } } + NSUInteger endTopIndex = [self binarySearchForIndex:self.modelsSortedByTop baseLine:endY isFromTop:YES]; [self.secondSet removeAllObjects]; - if (self.modelsSortedByTop && self.modelsSortedByTop.count > 0) { - for (NSInteger i = 0; i <= endTopIndex; i++) { - TMMuiRectModel *model = [self.modelsSortedByTop objectAtIndex:i]; - if (model != nil) { - [self.secondSet addObject:model.muiID]; - } + for (NSInteger i = 0; i <= endTopIndex; i++) { + TMMuiRectModel *model = [self.modelsSortedByTop tm_safeObjectAtIndex:i]; + if (model != nil) { + [self.secondSet addObject:model.muiID]; } } + [self.firstSet intersectSet:self.secondSet]; return [self.firstSet copy]; } --(NSArray *)modelsSortedByTop -{ - if (!_modelsSortedByTop){ - _modelsSortedByTop = [[NSArray alloc] init]; - } - return _modelsSortedByTop; -} - --(NSArray *)modelsSortedByBottom -{ - if (!_modelsSortedByBottom) { - _modelsSortedByBottom = [[NSArray alloc]init]; - } - return _modelsSortedByBottom; -} - -// Get view models from delegate . Create to indexes for sorting. +// Get view models from delegate. Create to indexes for sorting. - (void)creatScrollViewIndex { NSUInteger count = 0; - [self.itemsFrames removeAllObjects]; - if(self.dataSource && [self.dataSource conformsToProtocol:@protocol(TMMuiLazyScrollViewDataSource)] && - [self.dataSource respondsToSelector:@selector(numberOfItemInScrollView:)]) { + if (self.dataSource && + [self.dataSource conformsToProtocol:@protocol(TMMuiLazyScrollViewDataSource)] && + [self.dataSource respondsToSelector:@selector(numberOfItemInScrollView:)]) { count = [self.dataSource numberOfItemInScrollView:self]; } + [self.itemsFrames removeAllObjects]; for (NSUInteger i = 0 ; i< count ; i++) { TMMuiRectModel *rectmodel; - if(self.dataSource - &&[self.dataSource conformsToProtocol:@protocol(TMMuiLazyScrollViewDataSource)] - &&[self.dataSource respondsToSelector:@selector(scrollView: rectModelAtIndex:)]) - { + if (self.dataSource && + [self.dataSource conformsToProtocol:@protocol(TMMuiLazyScrollViewDataSource)] && + [self.dataSource respondsToSelector:@selector(scrollView: rectModelAtIndex:)]) { rectmodel = [self.dataSource scrollView:self rectModelAtIndex:i]; - if (rectmodel.muiID.length == 0) - { - rectmodel.muiID = [NSString stringWithFormat:@"%lu",(unsigned long)i]; + if (rectmodel.muiID.length == 0) { + rectmodel.muiID = [NSString stringWithFormat:@"%lu", (unsigned long)i]; } } - - [self.itemsFrames addObject:rectmodel]; + [self.itemsFrames tm_safeAddObject:rectmodel]; } - self.modelsSortedByTop = [self.itemsFrames sortedArrayUsingComparator:^NSComparisonResult(id obj1 ,id obj2) - { - CGRect rect1 = [(TMMuiRectModel *) obj1 absoluteRect]; - CGRect rect2 = [(TMMuiRectModel *) obj2 absoluteRect]; - - if (rect1.origin.y < rect2.origin.y) { - return NSOrderedAscending; - } - else if (rect1.origin.y > rect2.origin.y) { - return NSOrderedDescending; - } - else { - return NSOrderedSame; - } - }]; - self.modelsSortedByBottom = [self.itemsFrames sortedArrayUsingComparator:^NSComparisonResult(id obj1 ,id obj2) - { - CGRect rect1 = [(TMMuiRectModel *) obj1 absoluteRect]; - CGRect rect2 = [(TMMuiRectModel *) obj2 absoluteRect]; - CGFloat bottom1 = CGRectGetMaxY(rect1); - CGFloat bottom2 = CGRectGetMaxY(rect2); - - if (bottom1 > bottom2) { - return NSOrderedAscending ; - } - else if (bottom1 < bottom2) { - return NSOrderedDescending; - } - else { - return NSOrderedSame; - } - }]; + self.modelsSortedByTop = [self.itemsFrames sortedArrayUsingComparator:^NSComparisonResult(id obj1 ,id obj2) { + CGRect rect1 = [(TMMuiRectModel *) obj1 absRect]; + CGRect rect2 = [(TMMuiRectModel *) obj2 absRect]; + if (rect1.origin.y < rect2.origin.y) { + return NSOrderedAscending; + } else if (rect1.origin.y > rect2.origin.y) { + return NSOrderedDescending; + } else { + return NSOrderedSame; + } + }]; + + self.modelsSortedByBottom = [self.itemsFrames sortedArrayUsingComparator:^NSComparisonResult(id obj1 ,id obj2) { + CGRect rect1 = [(TMMuiRectModel *) obj1 absRect]; + CGRect rect2 = [(TMMuiRectModel *) obj2 absRect]; + CGFloat bottom1 = CGRectGetMaxY(rect1); + CGFloat bottom2 = CGRectGetMaxY(rect2); + if (bottom1 > bottom2) { + return NSOrderedAscending; + } else if (bottom1 < bottom2) { + return NSOrderedDescending; + } else { + return NSOrderedSame; + } + }]; } + - (void)findViewsInVisibleRect { NSMutableSet *itemViewSet = [self.muiIDOfVisibleViews mutableCopy]; - [itemViewSet minusSet:self.lastVisiblemuiID]; - for (UIView *view in self.visibleItems) { + [itemViewSet minusSet:self.lastVisibleMuiID]; + for (UIView *view in _visibleItems) { if (view && [itemViewSet containsObject:view.muiID]) { - if ([view conformsToProtocol:@protocol(TMMuiLazyScrollViewCellProtocol)] && [view respondsToSelector:@selector(mui_didEnterWithTimes:)]) { + if ([view conformsToProtocol:@protocol(TMMuiLazyScrollViewCellProtocol)] && + [view respondsToSelector:@selector(mui_didEnterWithTimes:)]) { NSUInteger times = 0; - if ([self.enterDict objectForKey:view.muiID] != nil) { - times = [[self.enterDict objectForKey:view.muiID] unsignedIntegerValue] + 1; + if ([self.enterDict tm_safeObjectForKey:view.muiID] != nil) { + times = [self.enterDict tm_integerForKey:view.muiID] + 1; } NSNumber *showTimes = [NSNumber numberWithUnsignedInteger:times]; - [self.enterDict setObject:showTimes forKey:view.muiID]; + [self.enterDict tm_safeSetObject:showTimes forKey:view.muiID]; [(UIView *)view mui_didEnterWithTimes:times]; } } } - self.lastVisiblemuiID = [self.muiIDOfVisibleViews copy]; + self.lastVisibleMuiID = [self.muiIDOfVisibleViews copy]; } -// A simple method to make view that should be shown show in LazyScrollView + +// A simple method to show view that should be shown in LazyScrollView. - (void)assembleSubviews { - CGRect visibleBounds = self.bounds; - // Visible area adding buffer to form a area that need to calculate which view should be shown. - CGFloat minY = CGRectGetMinY(visibleBounds) - RenderBufferWindow; - CGFloat maxY = CGRectGetMaxY(visibleBounds) + RenderBufferWindow; - [self assembleSubviewsForReload:NO minY:minY maxY:maxY]; + CGRect visibleBounds = self.bounds; + CGFloat minY = CGRectGetMinY(visibleBounds) - RenderBufferWindow; + CGFloat maxY = CGRectGetMaxY(visibleBounds) + RenderBufferWindow; + [self assembleSubviewsForReload:NO minY:minY maxY:maxY]; } - (void)assembleSubviewsForReload:(BOOL)isReload minY:(CGFloat)minY maxY:(CGFloat)maxY { - NSSet *itemShouldShowSet = [self showingItemIndexSetFrom:minY to:maxY]; self.muiIDOfVisibleViews = [self showingItemIndexSetFrom:CGRectGetMinY(self.bounds) to:CGRectGetMaxY(self.bounds)]; - + NSMutableSet *recycledItems = [[NSMutableSet alloc] init]; - //For recycling . Find which views should not in visible area. - NSSet *visibles = [self.visibleItems copy]; - for (UIView *view in visibles) - { - //Make sure whether the view should be shown. + // For recycling. Find which views should not in visible area. + NSSet *visibles = [_visibleItems copy]; + for (UIView *view in visibles) { + // Make sure whether the view should be shown. BOOL isToShow = [itemShouldShowSet containsObject:view.muiID]; - //If this view should be recycled and the length of its reuseidentifier over 0 - if (!isToShow && view.reuseIdentifier.length > 0) - { - //Then recycle the view. - NSMutableSet *recycledIdentifierSet = [self recycledIdentifierSet:view.reuseIdentifier]; - [recycledIdentifierSet addObject:view]; - [view removeFromSuperview]; - [recycledItems addObject:view]; - } - else if (isReload && view.muiID) { + if (!isToShow) { + if ([view respondsToSelector:@selector(mui_didLeave)]){ + [(UIView *)view mui_didLeave]; + } + // If this view should be recycled and the length of its reuseidentifier is over 0. + if (view.reuseIdentifier.length > 0) { + // Then recycle the view. + NSMutableSet *recycledIdentifierSet = [self recycledIdentifierSet:view.reuseIdentifier]; + [recycledIdentifierSet addObject:view]; + view.hidden = YES; + [recycledItems addObject:view]; + // Also add to muiID recycle dict. + [self.recycledMuiIDItemsDic tm_safeSetObject:view forKey:view.muiID]; + } else if(isReload && view.muiID) { + // Need to reload unreusable views. + [self.shouldReloadItems addObject:view.muiID]; + } + } else if (isReload && view.muiID) { [self.shouldReloadItems addObject:view.muiID]; } + } - [self.visibleItems minusSet:recycledItems]; + [_visibleItems minusSet:recycledItems]; [recycledItems removeAllObjects]; - //For creare new view. - for (NSString *muiID in itemShouldShowSet) - { + // Creare new view. + for (NSString *muiID in itemShouldShowSet) { BOOL shouldReload = isReload || [self.shouldReloadItems containsObject:muiID]; - if(![self isCellVisible:muiID] || [self.shouldReloadItems containsObject:muiID]) - { - if (self.dataSource && [self.dataSource conformsToProtocol:@protocol(TMMuiLazyScrollViewDataSource)] && - [self.dataSource respondsToSelector:@selector(scrollView: itemByMuiID:)]) - { + if (![self isCellVisible:muiID] || [self.shouldReloadItems containsObject:muiID]) { + if (self.dataSource && + [self.dataSource conformsToProtocol:@protocol(TMMuiLazyScrollViewDataSource)] && + [self.dataSource respondsToSelector:@selector(scrollView:itemByMuiID:)]) { + // Create view by dataSource. + // If you call dequeue method in your dataSource, the currentVisibleItemMuiID + // will be used for searching reusable view. if (shouldReload) { self.currentVisibleItemMuiID = muiID; } - else { - self.currentVisibleItemMuiID = nil; - } - // Create view by delegate. UIView *viewToShow = [self.dataSource scrollView:self itemByMuiID:muiID]; - // Call afterGetView + self.currentVisibleItemMuiID = nil; + // Call afterGetView. if ([viewToShow conformsToProtocol:@protocol(TMMuiLazyScrollViewCellProtocol)] && [viewToShow respondsToSelector:@selector(mui_afterGetView)]) { [(UIView *)viewToShow mui_afterGetView]; } - if (viewToShow) - { + if (viewToShow) { viewToShow.muiID = muiID; - if (![self.visibleItems containsObject:viewToShow]) { - [self.visibleItems addObject:viewToShow]; + viewToShow.hidden = NO; + if (![_visibleItems containsObject:viewToShow]) { + [_visibleItems addObject:viewToShow]; + } + if (self.autoAddSubview) { + if (viewToShow.superview != self) { + if (viewToShow.superview) { + [viewToShow removeFromSuperview]; + } + [self addSubview:viewToShow]; + } } } } [self.shouldReloadItems removeObject:muiID]; } } + [_inScreenVisibleItems removeAllObjects]; + for (UIView *view in _visibleItems) { + if ([view isKindOfClass:[UIView class]] && view.superview) { + CGRect absRect = [view.superview convertRect:view.frame toView:self]; + if ((absRect.origin.y + absRect.size.height >= CGRectGetMinY(self.bounds)) && + (absRect.origin.y <= CGRectGetMaxY(self.bounds))) { + [_inScreenVisibleItems addObject:view]; + } + } + } } -// Find NSSet accroding to reuse identifier , if not , then create one. +// Get NSSet accroding to reuse identifier. - (NSMutableSet *)recycledIdentifierSet:(NSString *)reuseIdentifier; { - if (reuseIdentifier.length == 0) - { + if (reuseIdentifier.length == 0) { return nil; } - NSMutableSet *result = [self.recycledIdentifierItemsDic objectForKey:reuseIdentifier]; + NSMutableSet *result = [self.recycledIdentifierItemsDic tm_safeObjectForKey:reuseIdentifier]; if (result == nil) { result = [[NSMutableSet alloc] init]; [self.recycledIdentifierItemsDic setObject:result forKey:reuseIdentifier]; @@ -555,45 +500,86 @@ - (NSMutableSet *)recycledIdentifierSet:(NSString *)reuseIdentifier; return result; } -//reloads everything and redisplays visible views. +// Reloads everything and redisplays visible views. - (void)reloadData { [self creatScrollViewIndex]; if (self.itemsFrames.count > 0) { CGRect visibleBounds = self.bounds; - //Add buffer for rendering CGFloat minY = CGRectGetMinY(visibleBounds) - RenderBufferWindow; CGFloat maxY = CGRectGetMaxY(visibleBounds) + RenderBufferWindow; [self assembleSubviewsForReload:YES minY:minY maxY:maxY]; [self findViewsInVisibleRect]; } + +} + +// Remove all subviews and reuseable views. +- (void)removeAllLayouts +{ + NSSet *visibles = _visibleItems; + for (UIView *view in visibles) { + NSMutableSet *recycledIdentifierSet = [self recycledIdentifierSet:view.reuseIdentifier]; + [recycledIdentifierSet addObject:view]; + view.hidden = YES; + } + [_visibleItems removeAllObjects]; + [_recycledIdentifierItemsDic removeAllObjects]; + [_recycledMuiIDItemsDic removeAllObjects]; +} + +// To acquire an already allocated view that can be reused by reuse identifier. +- (UIView *)dequeueReusableItemWithIdentifier:(NSString *)identifier +{ + return [self dequeueReusableItemWithIdentifier:identifier muiID:nil]; } // To acquire an already allocated view that can be reused by reuse identifier. -// If can't find one , here will return nil. -- (nullable UIView *)dequeueReusableItemWithIdentifier:(NSString *)identifier +// Use muiID for higher priority. +- (UIView *)dequeueReusableItemWithIdentifier:(NSString *)identifier muiID:(NSString *)muiID { UIView *view = nil; + if (self.currentVisibleItemMuiID) { - NSSet *visibles = self.visibleItems; + NSSet *visibles = _visibleItems; for (UIView *v in visibles) { - if ([v.muiID isEqualToString:self.currentVisibleItemMuiID]) { + if ([v.muiID isEqualToString:self.currentVisibleItemMuiID] && [v.reuseIdentifier isEqualToString:identifier]) { view = v; break; } } + } else if(muiID && [muiID isKindOfClass:[NSString class]] && muiID.length > 0) { + // Try to get reusable view from muiID dict. + view = [self.recycledMuiIDItemsDic tm_safeObjectForKey:muiID class:[UIView class]]; + if (view && view.reuseIdentifier.length > 0 && [view.reuseIdentifier isEqualToString:identifier]) + { + NSMutableSet *recycledIdentifierSet = [self recycledIdentifierSet:identifier]; + if (muiID && [muiID isKindOfClass:[NSString class]] && muiID.length > 0) { + [self.recycledMuiIDItemsDic removeObjectForKey:muiID]; + } + [recycledIdentifierSet removeObject:view]; + view.gestureRecognizers = nil; + } else { + view = nil; + } } + if (nil == view) { NSMutableSet *recycledIdentifierSet = [self recycledIdentifierSet:identifier]; view = [recycledIdentifierSet anyObject]; - if (view) - { - //if exist reusable view , remove it from recycledSet. + if (view && view.reuseIdentifier.length > 0) { + // If exist reusable view, remove it from recycledSet and recycledMuiIDItemsDic. + if (view.muiID && [view.muiID isKindOfClass:[NSString class]] && view.muiID.length > 0) { + [self.recycledMuiIDItemsDic removeObjectForKey:view.muiID]; + } [recycledIdentifierSet removeObject:view]; - //Then remove all gesture recognizers of it. + // Then remove all gesture recognizers of it. view.gestureRecognizers = nil; + } else { + view = nil; } } + if ([view conformsToProtocol:@protocol(TMMuiLazyScrollViewCellProtocol)] && [view respondsToSelector:@selector(mui_prepareForReuse)]) { [(UIView *)view mui_prepareForReuse]; } @@ -601,14 +587,12 @@ - (nullable UIView *)dequeueReusableItemWithIdentifier:(NSString *)identifier } //Make sure whether the view is visible accroding to muiID. --(BOOL)isCellVisible: (NSString *)muiID { - +- (BOOL)isCellVisible:(NSString *)muiID +{ BOOL result = NO; - NSSet *visibles = [self.visibleItems copy]; - for (UIView *view in visibles) - { - if ([view.muiID isEqualToString:muiID]) - { + NSSet *visibles = [_visibleItems copy]; + for (UIView *view in visibles) { + if ([view.muiID isEqualToString:muiID]) { result = YES; break; } @@ -616,24 +600,10 @@ -(BOOL)isCellVisible: (NSString *)muiID { return result; } -// Remove all subviews and reuseable views. -- (void)removeAllLayouts -{ - NSSet *visibles = self.visibleItems; - for (UIView *view in visibles) { - NSMutableSet *recycledIdentifierSet = [self recycledIdentifierSet:view.reuseIdentifier]; - [recycledIdentifierSet addObject:view]; - [view removeFromSuperview]; - } - [_visibleItems removeAllObjects]; - [_recycledIdentifierItemsDic removeAllObjects]; -} - --(void)resetViewEnterTimes +- (void)resetViewEnterTimes { [self.enterDict removeAllObjects]; - self.lastVisiblemuiID = nil; + self.lastVisibleMuiID = nil; } -@end - +@end diff --git a/LazyScrollView/TMMuiLazyScrollViewCellProtocol.h b/LazyScrollView/TMMuiLazyScrollViewCellProtocol.h new file mode 100644 index 0000000..3404304 --- /dev/null +++ b/LazyScrollView/TMMuiLazyScrollViewCellProtocol.h @@ -0,0 +1,32 @@ +// +// TMMuiLazyScrollViewCellProtocol.h +// LazyScrollView +// +// Copyright (c) 2017 Alibaba. All rights reserved. +// + +/** + If the view in LazyScrollView implement this protocol, + view can do something in its lifecycle. + */ +@protocol TMMuiLazyScrollViewCellProtocol + +@optional +// Will be called if call dequeueReusableItemWithIdentifier +// to get a reuseable view, the same as "prepareForReuse" +// in UITableViewCell. +- (void)mui_prepareForReuse; +// When view enter the visible area of LazyScrollView, +// call this method. +// First 'times' is 0. +- (void)mui_didEnterWithTimes:(NSUInteger)times; +// When we need render the view, call this method. +// The difference between this method and +// 'mui_didEnterWithTimes' is there is a buffer area +// in LazyScrollView(RenderBufferWindow). +- (void)mui_afterGetView; +// When the view is out of screen, this method will be +// called. +- (void)mui_didLeave; + +@end diff --git a/LazyScrollView/TMMuiRectModel.h b/LazyScrollView/TMMuiRectModel.h new file mode 100644 index 0000000..200e020 --- /dev/null +++ b/LazyScrollView/TMMuiRectModel.h @@ -0,0 +1,21 @@ +// +// TMMuiRectModel.h +// LazyScrollView +// +// Copyright (c) 2017 Alibaba. All rights reserved. +// + +#import + +/** + It is a view model that holding information of view. + At least holding absRect and muiID. + */ +@interface TMMuiRectModel : NSObject + +// A rect that relative to the scroll view. +@property (nonatomic,assign) CGRect absRect; +// A uniq string that identify a model. +@property (nonatomic,copy) NSString *muiID; + +@end diff --git a/LazyScrollView/TMMuiRectModel.m b/LazyScrollView/TMMuiRectModel.m new file mode 100644 index 0000000..9023d27 --- /dev/null +++ b/LazyScrollView/TMMuiRectModel.m @@ -0,0 +1,12 @@ +// +// TMMuiRectModel.m +// LazyScrollView +// +// Copyright (c) 2017 Alibaba. All rights reserved. +// + +#import "TMMuiRectModel.h" + +@implementation TMMuiRectModel + +@end diff --git a/LazyScrollView/TMUtils.h b/LazyScrollView/TMUtils.h new file mode 100644 index 0000000..4b32793 --- /dev/null +++ b/LazyScrollView/TMUtils.h @@ -0,0 +1,52 @@ +// +// TMUtils.h +// LazyScrollView +// +// Copyright (c) 2017 Alibaba. All rights reserved. +// + +#import + +@interface NSArray (TMUtil) + +- (id)tm_safeObjectAtIndex:(NSUInteger)index; +- (id)tm_safeObjectAtIndex:(NSUInteger)index class:(Class)aClass; + +- (bool)tm_boolAtIndex:(NSUInteger)index; +- (CGFloat)tm_floatAtIndex:(NSUInteger)index; +- (NSInteger)tm_integerAtIndex:(NSUInteger)index; +- (NSString *)tm_stringAtIndex:(NSUInteger)index; +- (NSDictionary *)tm_dictionaryAtIndex:(NSUInteger)index; +- (NSArray *)tm_arrayAtIndex:(NSUInteger)index; + +@end + +@interface NSMutableArray (TMUtil) + +- (void)tm_safeAddObject:(id)anObject; +- (void)tm_safeInsertObject:(id)anObject atIndex:(NSUInteger)index; + +@end + +@interface NSDictionary (TMUtil) + +- (id)tm_safeObjectForKey:(id)key; +- (id)tm_safeObjectForKey:(id)key class:(Class)aClass; + +- (bool)tm_boolForKey:(id)key; +- (CGFloat)tm_floatForKey:(id)key; +- (NSInteger)tm_integerForKey:(id)key; +- (NSString *)tm_stringForKey:(id)key; +- (NSDictionary *)tm_dictionaryForKey:(id)key; +- (NSArray *)tm_arrayForKey:(id)key; + +- (id)tm_safeValueForKey:(NSString *)key; +- (void)tm_safeSetValue:(id)value forKey:(NSString *)key; + +@end + +@interface NSMutableDictionary (TMUtil) + +- (void)tm_safeSetObject:(id)anObject forKey:(id)key; + +@end diff --git a/LazyScrollView/TMUtils.m b/LazyScrollView/TMUtils.m new file mode 100644 index 0000000..e1a3d48 --- /dev/null +++ b/LazyScrollView/TMUtils.m @@ -0,0 +1,183 @@ +// +// TMUtils.m +// LazyScrollView +// +// Copyright (c) 2017 Alibaba. All rights reserved. +// + +#import "TMUtils.h" + +@implementation NSArray (TMUtil) + +- (id)tm_safeObjectAtIndex:(NSUInteger)index +{ + if (index >= [self count]) { + return nil; + } + id value = [self objectAtIndex:index]; + if (value == [NSNull null]) { + return nil; + } + return value; +} + +- (id)tm_safeObjectAtIndex:(NSUInteger)index class:(Class)aClass +{ + id value = [self tm_safeObjectAtIndex:index]; + if ([value isKindOfClass:aClass]) { + return value; + } + return nil; +} + +- (bool)tm_boolAtIndex:(NSUInteger)index +{ + id value = [self tm_safeObjectAtIndex:index]; + if ([value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[NSString class]]) { + return [value boolValue]; + } + return NO; +} + +- (CGFloat)tm_floatAtIndex:(NSUInteger)index +{ + id value = [self tm_safeObjectAtIndex:index]; + if ([value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[NSString class]]) { + return [value floatValue]; + } + return 0; +} + +- (NSInteger)tm_integerAtIndex:(NSUInteger)index +{ + id value = [self tm_safeObjectAtIndex:index]; + if ([value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[NSString class]]) { + return [value integerValue]; + } + return 0; +} + +- (NSString *)tm_stringAtIndex:(NSUInteger)index +{ + return [self tm_safeObjectAtIndex:index class:[NSString class]]; +} + +- (NSDictionary *)tm_dictionaryAtIndex:(NSUInteger)index +{ + return [self tm_safeObjectAtIndex:index class:[NSDictionary class]]; +} + +- (NSArray *)tm_arrayAtIndex:(NSUInteger)index +{ + return [self tm_safeObjectAtIndex:index class:[NSArray class]]; +} + +@end + +@implementation NSMutableArray (TMUtil) + +- (void)tm_safeAddObject:(id)anObject +{ + if (anObject) { + [self addObject:anObject]; + } +} + +- (void)tm_safeInsertObject:(id)anObject atIndex:(NSUInteger)index +{ + if (anObject && index <= self.count) { + [self insertObject:anObject atIndex:index]; + } +} + +@end + +@implementation NSDictionary (TMUtil) + +- (id)tm_safeObjectForKey:(id)key +{ + if (key == nil) { + return nil; + } + id value = [self objectForKey:key]; + if (value == [NSNull null]) { + return nil; + } + return value; +} + +- (id)tm_safeObjectForKey:(id)key class:(Class)aClass +{ + id value = [self tm_safeObjectForKey:key]; + if ([value isKindOfClass:aClass]) { + return value; + } + return nil; +} + +- (bool)tm_boolForKey:(id)key +{ + id value = [self tm_safeObjectForKey:key]; + if ([value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[NSString class]]) { + return [value boolValue]; + } + return NO; +} + +- (CGFloat)tm_floatForKey:(id)key +{ + id value = [self tm_safeObjectForKey:key]; + if ([value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[NSString class]]) { + return [value floatValue]; + } + return 0; +} + +- (NSInteger)tm_integerForKey:(id)key +{ + id value = [self tm_safeObjectForKey:key]; + if ([value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[NSString class]]) { + return [value integerValue]; + } + return 0; +} + +- (NSString *)tm_stringForKey:(id)key +{ + return [self tm_safeObjectForKey:key class:[NSString class]]; +} + +- (NSDictionary *)tm_dictionaryForKey:(id)key +{ + return [self tm_safeObjectForKey:key class:[NSDictionary class]]; +} + +- (NSArray *)tm_arrayForKey:(id)key +{ + return [self tm_safeObjectForKey:key class:[NSArray class]]; +} + +- (id)tm_safeValueForKey:(NSString *)key +{ + return [self tm_safeObjectForKey:key]; +} + +- (void)tm_safeSetValue:(id)value forKey:(NSString *)key +{ + if (key && [key isKindOfClass:[NSString class]]) { + [self setValue:value forKey:key]; + } +} + +@end + +@implementation NSMutableDictionary (TMUtil) + +- (void)tm_safeSetObject:(id)anObject forKey:(id)key +{ + if (key && anObject) { + [self setObject:anObject forKey:key]; + } +} + +@end diff --git a/LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/project.pbxproj b/LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/project.pbxproj index c57d17d..d098f34 100644 --- a/LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/project.pbxproj +++ b/LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/project.pbxproj @@ -13,7 +13,7 @@ 70D7C6411E6427CD008B76C6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 70D7C63F1E6427CD008B76C6 /* Main.storyboard */; }; 70D7C6431E6427CD008B76C6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 70D7C6421E6427CD008B76C6 /* Assets.xcassets */; }; 70D7C6461E6427CD008B76C6 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 70D7C6441E6427CD008B76C6 /* LaunchScreen.storyboard */; }; - 70D7C64F1E6428EC008B76C6 /* TMMuiLazyScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 70D7C64E1E6428EC008B76C6 /* TMMuiLazyScrollView.m */; }; + F0517B48C8AEA67EB7DAF979 /* libPods-LazyScrollViewDemo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ECD1FF81519CA31F379C5611 /* libPods-LazyScrollViewDemo.a */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -27,8 +27,9 @@ 70D7C6421E6427CD008B76C6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 70D7C6451E6427CD008B76C6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 70D7C6471E6427CD008B76C6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 70D7C64D1E6428EC008B76C6 /* TMMuiLazyScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TMMuiLazyScrollView.h; path = ../../LazyScrollView/TMMuiLazyScrollView.h; sourceTree = ""; }; - 70D7C64E1E6428EC008B76C6 /* TMMuiLazyScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TMMuiLazyScrollView.m; path = ../../LazyScrollView/TMMuiLazyScrollView.m; sourceTree = ""; }; + 8584A0928BAA1136A3EA481D /* Pods-LazyScrollViewDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LazyScrollViewDemo.release.xcconfig"; path = "Pods/Target Support Files/Pods-LazyScrollViewDemo/Pods-LazyScrollViewDemo.release.xcconfig"; sourceTree = ""; }; + A5C4C9124EC9215291495727 /* Pods-LazyScrollViewDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LazyScrollViewDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LazyScrollViewDemo/Pods-LazyScrollViewDemo.debug.xcconfig"; sourceTree = ""; }; + ECD1FF81519CA31F379C5611 /* libPods-LazyScrollViewDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-LazyScrollViewDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -36,17 +37,29 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F0517B48C8AEA67EB7DAF979 /* libPods-LazyScrollViewDemo.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 03B4679B891B589AF7A68BBB /* Pods */ = { + isa = PBXGroup; + children = ( + A5C4C9124EC9215291495727 /* Pods-LazyScrollViewDemo.debug.xcconfig */, + 8584A0928BAA1136A3EA481D /* Pods-LazyScrollViewDemo.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; 70D7C62A1E6427CD008B76C6 = { isa = PBXGroup; children = ( 70D7C6351E6427CD008B76C6 /* LazyScrollViewDemo */, 70D7C6341E6427CD008B76C6 /* Products */, + 03B4679B891B589AF7A68BBB /* Pods */, + A48E16FBDA7CA19039D2164B /* Frameworks */, ); sourceTree = ""; }; @@ -65,8 +78,6 @@ 70D7C63A1E6427CD008B76C6 /* AppDelegate.m */, 70D7C63C1E6427CD008B76C6 /* ViewController.h */, 70D7C63D1E6427CD008B76C6 /* ViewController.m */, - 70D7C64D1E6428EC008B76C6 /* TMMuiLazyScrollView.h */, - 70D7C64E1E6428EC008B76C6 /* TMMuiLazyScrollView.m */, 70D7C63F1E6427CD008B76C6 /* Main.storyboard */, 70D7C6421E6427CD008B76C6 /* Assets.xcassets */, 70D7C6441E6427CD008B76C6 /* LaunchScreen.storyboard */, @@ -84,6 +95,14 @@ name = "Supporting Files"; sourceTree = ""; }; + A48E16FBDA7CA19039D2164B /* Frameworks */ = { + isa = PBXGroup; + children = ( + ECD1FF81519CA31F379C5611 /* libPods-LazyScrollViewDemo.a */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -91,9 +110,12 @@ isa = PBXNativeTarget; buildConfigurationList = 70D7C64A1E6427CD008B76C6 /* Build configuration list for PBXNativeTarget "LazyScrollViewDemo" */; buildPhases = ( + 598A8EE8D51846140BDD239E /* [CP] Check Pods Manifest.lock */, 70D7C62F1E6427CD008B76C6 /* Sources */, 70D7C6301E6427CD008B76C6 /* Frameworks */, 70D7C6311E6427CD008B76C6 /* Resources */, + 3A6A0E9BEC57FAC92138C123 /* [CP] Embed Pods Frameworks */, + FBE925B995B81EED4A638B2E /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -110,12 +132,11 @@ 70D7C62B1E6427CD008B76C6 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0820; + LastUpgradeCheck = 0910; ORGANIZATIONNAME = taobao; TargetAttributes = { 70D7C6321E6427CD008B76C6 = { CreatedOnToolsVersion = 8.2.1; - DevelopmentTeam = PBH63ZAR55; ProvisioningStyle = Automatic; }; }; @@ -151,6 +172,57 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 3A6A0E9BEC57FAC92138C123 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LazyScrollViewDemo/Pods-LazyScrollViewDemo-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 598A8EE8D51846140BDD239E /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-LazyScrollViewDemo-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + FBE925B995B81EED4A638B2E /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LazyScrollViewDemo/Pods-LazyScrollViewDemo-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 70D7C62F1E6427CD008B76C6 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -158,7 +230,6 @@ files = ( 70D7C63E1E6427CD008B76C6 /* ViewController.m in Sources */, 70D7C63B1E6427CD008B76C6 /* AppDelegate.m in Sources */, - 70D7C64F1E6428EC008B76C6 /* TMMuiLazyScrollView.m in Sources */, 70D7C6381E6427CD008B76C6 /* main.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -194,7 +265,9 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -202,7 +275,11 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -225,7 +302,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -241,7 +318,9 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -249,7 +328,11 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -266,7 +349,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; @@ -275,10 +358,12 @@ }; 70D7C64B1E6427CD008B76C6 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = A5C4C9124EC9215291495727 /* Pods-LazyScrollViewDemo.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = PBH63ZAR55; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = LazyScrollViewDemo/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = tmall.LazyScrollViewDemo; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -287,10 +372,12 @@ }; 70D7C64C1E6427CD008B76C6 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 8584A0928BAA1136A3EA481D /* Pods-LazyScrollViewDemo.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = PBH63ZAR55; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = LazyScrollViewDemo/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = tmall.LazyScrollViewDemo; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/project.xcworkspace/xcuserdata/xiaoxia.xcuserdatad/UserInterfaceState.xcuserstate b/LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/project.xcworkspace/xcuserdata/xiaoxia.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 17c1bd6738a33ff469d06d00557c59fa2944cce9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16904 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 diff --git a/LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist deleted file mode 100644 index fe2b454..0000000 --- a/LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcschemes/LazyScrollViewDemo.xcscheme b/LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcschemes/LazyScrollViewDemo.xcscheme deleted file mode 100644 index 17f9c28..0000000 --- a/LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcschemes/LazyScrollViewDemo.xcscheme +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcschemes/xcschememanagement.plist b/LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 9fa51ea..0000000 --- a/LazyScrollViewDemo/LazyScrollViewDemo.xcodeproj/xcuserdata/xiaoxia.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - SchemeUserState - - LazyScrollViewDemo.xcscheme - - orderHint - 0 - - - SuppressBuildableAutocreation - - 70D7C6321E6427CD008B76C6 - - primary - - - - - diff --git a/LazyScrollViewDemo/LazyScrollViewDemo/AppDelegate.h b/LazyScrollViewDemo/LazyScrollViewDemo/AppDelegate.h index 1f4f753..2f24573 100644 --- a/LazyScrollViewDemo/LazyScrollViewDemo/AppDelegate.h +++ b/LazyScrollViewDemo/LazyScrollViewDemo/AppDelegate.h @@ -2,8 +2,7 @@ // AppDelegate.h // LazyScrollViewDemo // -// Created by xiaoxia on 2017/2/27. -// Copyright © 2017年 taobao. All rights reserved. +// Copyright (c) 2017 Alibaba. All rights reserved. // #import diff --git a/LazyScrollViewDemo/LazyScrollViewDemo/AppDelegate.m b/LazyScrollViewDemo/LazyScrollViewDemo/AppDelegate.m index e618432..756607b 100644 --- a/LazyScrollViewDemo/LazyScrollViewDemo/AppDelegate.m +++ b/LazyScrollViewDemo/LazyScrollViewDemo/AppDelegate.m @@ -2,8 +2,7 @@ // AppDelegate.m // LazyScrollViewDemo // -// Created by xiaoxia on 2017/2/27. -// Copyright © 2017年 taobao. All rights reserved. +// Copyright (c) 2017 Alibaba. All rights reserved. // #import "AppDelegate.h" diff --git a/LazyScrollViewDemo/LazyScrollViewDemo/ViewController.h b/LazyScrollViewDemo/LazyScrollViewDemo/ViewController.h index fc4a136..793ce05 100644 --- a/LazyScrollViewDemo/LazyScrollViewDemo/ViewController.h +++ b/LazyScrollViewDemo/LazyScrollViewDemo/ViewController.h @@ -2,8 +2,7 @@ // ViewController.h // LazyScrollViewDemo // -// Created by xiaoxia on 2017/2/27. -// Copyright © 2017年 taobao. All rights reserved. +// Copyright (c) 2017 Alibaba. All rights reserved. // #import diff --git a/LazyScrollViewDemo/LazyScrollViewDemo/ViewController.m b/LazyScrollViewDemo/LazyScrollViewDemo/ViewController.m index a20261e..797f190 100644 --- a/LazyScrollViewDemo/LazyScrollViewDemo/ViewController.m +++ b/LazyScrollViewDemo/LazyScrollViewDemo/ViewController.m @@ -1,14 +1,15 @@ // // ViewController.m -// LazyScrollView +// LazyScrollViewDemo // -// Copyright (c) 2015年 tmall. All rights reserved. +// Copyright (c) 2017 Alibaba. All rights reserved. // #import "ViewController.h" -#import "TMMuiLazyScrollView.h" +#import -@interface LazyScrollViewCustomView : UILabel + +@interface LazyScrollViewCustomView : UILabel @end @@ -16,62 +17,62 @@ @implementation LazyScrollViewCustomView - (void)mui_prepareForReuse { - NSLog(@"%@", [NSString stringWithFormat:@"%@ - Prepare For Reuse",self.text]); + NSLog(@"%@ - Prepare For Reuse", self.text); } - (void)mui_didEnterWithTimes:(NSUInteger)times { - NSLog(@"%@", [NSString stringWithFormat:@"%@ - Did Enter With Times - %lu",self.text,(unsigned long)times]); + NSLog(@"%@ - Did Enter With Times - %zd", self.text, times); } - (void)mui_afterGetView { - NSLog(@"%@", [NSString stringWithFormat:@"%@ - AfterGetView",self.text]); + NSLog(@"%@ - AfterGetView", self.text); } + @end -@interface ViewController () -{ +@interface ViewController () { NSMutableArray * rectArray; } + @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; - //STEP 1 . Create LazyScrollView - TMMuiLazyScrollView *scrollview = [[TMMuiLazyScrollView alloc]init]; + + // STEP 1 . Create LazyScrollView + TMMuiLazyScrollView *scrollview = [[TMMuiLazyScrollView alloc] init]; scrollview.frame = self.view.bounds; scrollview.dataSource = self; - [self.view addSubview:scrollview]; + // Here is frame array for test. + // LazyScrollView must know every rect before rending. + rectArray = [[NSMutableArray alloc] init]; - //Here is frame array for test. - //LazyScrollView must know every rect before rending. - rectArray = [[NSMutableArray alloc] init]; - - //Create a single column layout with 5 elements; - for (int i = 0; i < 5 ; i++) { - [rectArray addObject:[NSValue valueWithCGRect:CGRectMake(10, i *80 + 2 , self.view.bounds.size.width-20, 80-2)]]; + // Create a single column layout with 5 elements; + for (int i = 0; i < 5; i++) { + [rectArray addObject:[NSValue valueWithCGRect:CGRectMake(10, i * 80 + 2 , self.view.bounds.size.width - 20, 80 - 2)]]; } - //Create a double column layout with 10 elements; - for (int i = 0; i < 10 ; i++) { - [rectArray addObject:[NSValue valueWithCGRect:CGRectMake((i%2)*self.view.bounds.size.width/2 + 3, 410 + i/2 *80 + 2 , self.view.bounds.size.width/2 -3, 80 - 2)]]; + // Create a double column layout with 10 elements; + for (int i = 0; i < 10; i++) { + [rectArray addObject:[NSValue valueWithCGRect:CGRectMake((i % 2) * self.view.bounds.size.width / 2 + 3, 410 + i / 2 * 80 + 2 , self.view.bounds.size.width / 2 - 3, 80 - 2)]]; } - //Create a trible column layout with 15 elements; - for (int i = 0; i < 15 ; i++) { - [rectArray addObject:[NSValue valueWithCGRect:CGRectMake((i%3)*self.view.bounds.size.width/3 + 1, 820 + i/3 *80 + 2 , self.view.bounds.size.width/3 -3, 80 - 2)]]; + // Create a trible column layout with 15 elements; + for (int i = 0; i < 15; i++) { + [rectArray addObject:[NSValue valueWithCGRect:CGRectMake((i % 3) * self.view.bounds.size.width / 3 + 1, 820 + i / 3 * 80 + 2 , self.view.bounds.size.width / 3 - 3, 80 - 2)]]; } scrollview.contentSize = CGSizeMake(CGRectGetWidth(self.view.bounds), 1230); - //STEP 3 reload LazyScrollView - [scrollview reloadData]; + // STEP 3 reload LazyScrollView + [scrollview reloadData]; } -//STEP 2 implement datasource delegate. +// STEP 2 implement datasource delegate. - (NSUInteger)numberOfItemInScrollView:(TMMuiLazyScrollView *)scrollView { return rectArray.count; @@ -79,52 +80,46 @@ - (NSUInteger)numberOfItemInScrollView:(TMMuiLazyScrollView *)scrollView - (TMMuiRectModel *)scrollView:(TMMuiLazyScrollView *)scrollView rectModelAtIndex:(NSUInteger)index { - CGRect rect = [(NSValue *)[rectArray objectAtIndex:index]CGRectValue]; - TMMuiRectModel *rectModel = [[TMMuiRectModel alloc]init]; - rectModel.absoluteRect = rect; - rectModel.muiID = [NSString stringWithFormat:@"%ld",index]; + CGRect rect = [(NSValue *)[rectArray objectAtIndex:index] CGRectValue]; + TMMuiRectModel *rectModel = [[TMMuiRectModel alloc] init]; + rectModel.absRect = rect; + rectModel.muiID = [NSString stringWithFormat:@"%zd", index]; return rectModel; } - (UIView *)scrollView:(TMMuiLazyScrollView *)scrollView itemByMuiID:(NSString *)muiID { - //Find view that is reuseable first. + // Find view that is reuseable first. LazyScrollViewCustomView *label = (LazyScrollViewCustomView *)[scrollView dequeueReusableItemWithIdentifier:@"testView"]; NSInteger index = [muiID integerValue]; - if (!label) - { - label = [[LazyScrollViewCustomView alloc]initWithFrame:[(NSValue *)[rectArray objectAtIndex:index]CGRectValue]]; + if (!label) { + label = [[LazyScrollViewCustomView alloc]initWithFrame:[(NSValue *)[rectArray objectAtIndex:index] CGRectValue]]; label.textAlignment = NSTextAlignmentCenter; label.reuseIdentifier = @"testView"; } - label.frame = [(NSValue *)[rectArray objectAtIndex:index]CGRectValue]; - label.text = [NSString stringWithFormat:@"%lu",(unsigned long)index]; + label.frame = [(NSValue *)[rectArray objectAtIndex:index] CGRectValue]; + label.text = [NSString stringWithFormat:@"%zd", index]; label.backgroundColor = [self randomColor]; [scrollView addSubview:label]; label.userInteractionEnabled = YES; - [label addGestureRecognizer:[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(click:)]]; + [label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(click:)]]; return label; } #pragma mark - Private -- (UIColor *) randomColor +- (UIColor *)randomColor { - CGFloat hue = ( arc4random() % 256 / 256.0 ); //0.0 to 1.0 - CGFloat saturation = ( arc4random() % 128 / 256.0 ) + 0.5; // 0.5 to 1.0,away from white - CGFloat brightness = ( arc4random() % 128 / 256.0 ) + 0.5; //0.5 to 1.0,away from black + CGFloat hue = ( arc4random() % 256 / 256.0 ); // 0.0 to 1.0 + CGFloat saturation = ( arc4random() % 128 / 256.0 ) + 0.5; // 0.5 to 1.0, away from white + CGFloat brightness = ( arc4random() % 128 / 256.0 ) + 0.5; // 0.5 to 1.0, away from black return [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1]; - } - (void)click:(UIGestureRecognizer *)recognizer { LazyScrollViewCustomView *label = (LazyScrollViewCustomView *)recognizer.view; - - NSLog(@"Click - %@",label.muiID); + NSLog(@"Click - %@", label.muiID); } - - - @end diff --git a/LazyScrollViewDemo/Podfile b/LazyScrollViewDemo/Podfile new file mode 100644 index 0000000..5f82496 --- /dev/null +++ b/LazyScrollViewDemo/Podfile @@ -0,0 +1,6 @@ +source "https://github.com/CocoaPods/Specs.git" + +target 'LazyScrollViewDemo' do + platform :ios, '8.0' + pod 'LazyScroll', :path=>'../' +end diff --git a/README.md b/README.md index 17140ca..85fd154 100644 --- a/README.md +++ b/README.md @@ -1,86 +1,73 @@ -# LazyScrollView +[![CocoaPods](https://img.shields.io/cocoapods/v/LazyScroll.svg)]() [![CocoaPods](https://img.shields.io/cocoapods/p/LazyScroll.svg)]() [![CocoaPods](https://img.shields.io/cocoapods/l/LazyScroll.svg)]() -[中文说明](http://pingguohe.net/2016/01/31/lazyscroll.html) +# LazyScrollView -[中文Demo说明](http://pingguohe.net/2017/03/02/lazyScrollView-demo.html) +[中文说明](http://pingguohe.net/2016/01/31/lazyscroll.html) [中文Demo说明](http://pingguohe.net/2017/03/02/lazyScrollView-demo.html) -> 依赖LazyScrollView, 我们创建了一个模块化页面UI解决方案,详情可见 [https://github.com/alibaba/tangram-ios](https://github.com/alibaba/tangram-ios). +> 依赖 LazyScrollView,我们创建了一个模块化页面UI解决方案,详情可见 [Tangram-iOS](https://github.com/alibaba/tangram-ios)。 -LazyScrollView is an iOS ScrollView , to resolve the problem of reusability of views. +LazyScrollView is an iOS ScrollView , to resolve the problem of reusability of views. -We reply an another way to control reuse in a ScrollView, it depends on give a special reuse identifier to every view controlled in LazyScrollView. +We reply another way to control reuse in a ScrollView, it depends on give a special reuse identifier to every view controlled in LazyScrollView. -Comparing to UITableView , LazyScrollView can easily create different layout , instead of the single row flow layout. +Comparing to UITableView, LazyScrollView can easily create different layout, instead of the single row flow layout. -Comparing to UICollectionView , LazyScrollView can create views without Grid layout , and provides a easier way to create different kinds of layous in a ScrollView . +Comparing to UICollectionView, LazyScrollView can create views without Grid layout, and provides a easier way to create different kinds of layous in a ScrollView. -The system requirement is iOS 5+ +The system requirement is iOS 5+. -> We create a modular UI solution for building native page dynamically based on `LazyScrollView`, you can see more info from this repo : [https://github.com/alibaba/tangram-ios](https://github.com/alibaba/tangram-ios) +> We create a modular UI solution for building native page dynamically based on `LazyScrollView`, you can see more info from this repo: [Tangram-iOS](https://github.com/alibaba/tangram-ios) # Installation -LazyScroll is available as `LazyScroll` in cocoapods +LazyScroll is available as `LazyScroll` in CocoaPods. -``` - pod 'LazyScroll' -``` + pod 'LazyScroll' -If you don't want to use cocoapods, you can also manually add the files in `LazyScrollView` folder into your Xcode project +If you don't want to use cocoapods, you can also manually add the files in `LazyScrollView` folder into your Xcode project. # Usage #import "TMMuiLazyScrollView.h" - Then , create LazyScrollView +Then, create LazyScrollView: ```objectivec TMMuiLazyScrollView *scrollview = [[TMMuiLazyScrollView alloc]init]; scrollview.frame = self.view.bounds; ``` -next implement`TMMuiLazyScrollViewDataSource` +Next, implement `TMMuiLazyScrollViewDataSource`: ```objectivec @protocol TMMuiLazyScrollViewDataSource + @required -//number of item om scrollView + +// Number of items in scrollView. - (NSUInteger)numberOfItemInScrollView:(TMMuiLazyScrollView *)scrollView; -//return view model (TMMuiRectModel) by index + +// Return the view model (TMMuiRectModel) by index. - (TMMuiRectModel *)scrollView:(TMMuiLazyScrollView *)scrollView rectModelAtIndex:(NSUInteger)index; -//return view by the unique string that identify a model(muiID) . You should render the item view here. And the view is probably . Item view display. You should always try to reuse views by setting each view's reuseIdentifier and querying for available reusable views with dequeueReusableItemWithIdentifier: + +// Return view by the unique string that identify a model (muiID). +// You should render the item view here. +// You should ALWAYS try to reuse views by setting each view's reuseIdentifier. - (UIView *)scrollView:(TMMuiLazyScrollView *)scrollView itemByMuiID:(NSString *)muiID; + @end ``` -next , set datasource delegate of LazyScrollView +Next, set datasource of LazyScrollView: ```objectivec scrollview.dataSource = self; ``` -finally , do reload +Finally, do reload: ```objectivec [scrollview reloadData]; ``` - To view detailed usage , please clone the repo and open project to see demo. - -# License - -LazyScroll is releasd under MIT license . - -```` -The MIT License - -Copyright (c) 2017 Alibaba - -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. - -```` - +To view detailed usage, please clone the repo and open the demo project.