├── BookShelf ├── Resources │ ├── en.lproj │ │ ├── InfoPlist.strings │ │ └── ViewController.xib │ ├── Images │ │ ├── 1.png │ │ ├── 2.png │ │ ├── 3.png │ │ ├── 4.png │ │ ├── 1@2x.png │ │ ├── 2@2x.png │ │ ├── 3@2x.png │ │ ├── 4@2x.png │ │ ├── Default.png │ │ ├── Default@2x.png │ │ ├── comments.png │ │ ├── BookShelfCell.png │ │ ├── BookViewChecked.png │ │ ├── Default-568h@2x.png │ │ ├── BookShelfCell@2x.png │ │ ├── BookViewChecked@2x.png │ │ └── from iBooks │ │ │ ├── NavBar~iphone.png │ │ │ ├── Shelf~iphone.png │ │ │ ├── Shelf@2x~iphone.png │ │ │ ├── WoodTile~iphone.png │ │ │ ├── NavBar@2x~iphone.png │ │ │ ├── WoodTile@2x~iphone.png │ │ │ ├── Side Shading-iPhone.png │ │ │ ├── NavBar-Landscape~iphone.png │ │ │ ├── Shelf-Landscape~iphone.png │ │ │ ├── Side Shading-iPhone@2x.png │ │ │ ├── Shelf-Landscape@2x~iphone.png │ │ │ ├── NavBar-Landscape@2x~iphone.png │ │ │ ├── topshelf side shading-iPhone.png │ │ │ └── topshelf side shading-iPhone@2x.png │ └── BookShelf-Info.plist ├── Other │ ├── BookShelf-Prefix.pch │ └── main.m └── Classes │ ├── Useless │ ├── AboveTopView.h │ ├── MyBelowBottomView.h │ ├── MyCellView.h │ ├── BookView.h │ ├── MyBelowBottomView.m │ ├── MyCellView.m │ ├── BookView.m │ └── AboveTopView.m │ ├── Demo │ ├── BelowBottomView.h │ ├── AppDelegate.h │ ├── MyBookView.h │ ├── BookShelfCellView.h │ ├── ViewController.h │ ├── BelowBottomView.m │ ├── MyBookView.m │ ├── AppDelegate.m │ ├── BookShelfCellView.m │ └── ViewController.m │ └── BookShelf │ ├── Public │ ├── GSBookView.h │ ├── GSBookShelfCell.h │ ├── GSBookShelfView.h │ └── GSBookShelfView.m │ ├── Utilities │ ├── NSMutableArray+Rearrange.h │ └── NSMutableArray+Rearrange.m │ └── Private │ ├── GSCellContainerView.h │ ├── GSBookViewContainerView.h │ ├── GSCellContainerView.m │ └── GSBookViewContainerView.m ├── .gitignore ├── BookShelf.podspec ├── LICENSE ├── README.md └── BookShelf.xcodeproj └── project.pbxproj /BookShelf/Resources/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /BookShelf/Resources/Images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/1.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/2.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/3.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/4.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/1@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/1@2x.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/2@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/2@2x.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/3@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/3@2x.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/4@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/4@2x.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/Default.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/Default@2x.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/comments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/comments.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/BookShelfCell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/BookShelfCell.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/BookViewChecked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/BookViewChecked.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/Default-568h@2x.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/BookShelfCell@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/BookShelfCell@2x.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/BookViewChecked@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/BookViewChecked@2x.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/from iBooks/NavBar~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/from iBooks/NavBar~iphone.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/from iBooks/Shelf~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/from iBooks/Shelf~iphone.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/from iBooks/Shelf@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/from iBooks/Shelf@2x~iphone.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/from iBooks/WoodTile~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/from iBooks/WoodTile~iphone.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/from iBooks/NavBar@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/from iBooks/NavBar@2x~iphone.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/from iBooks/WoodTile@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/from iBooks/WoodTile@2x~iphone.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/from iBooks/Side Shading-iPhone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/from iBooks/Side Shading-iPhone.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/from iBooks/NavBar-Landscape~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/from iBooks/NavBar-Landscape~iphone.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/from iBooks/Shelf-Landscape~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/from iBooks/Shelf-Landscape~iphone.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/from iBooks/Side Shading-iPhone@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/from iBooks/Side Shading-iPhone@2x.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/from iBooks/Shelf-Landscape@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/from iBooks/Shelf-Landscape@2x~iphone.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/from iBooks/NavBar-Landscape@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/from iBooks/NavBar-Landscape@2x~iphone.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/from iBooks/topshelf side shading-iPhone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/from iBooks/topshelf side shading-iPhone.png -------------------------------------------------------------------------------- /BookShelf/Resources/Images/from iBooks/topshelf side shading-iPhone@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ultragtx/GSBookShelf/HEAD/BookShelf/Resources/Images/from iBooks/topshelf side shading-iPhone@2x.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | */build/* 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | *.hmap 20 | -------------------------------------------------------------------------------- /BookShelf/Other/BookShelf-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'BookShelf' target in the 'BookShelf' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_4_0 8 | #warning "This project uses features only available in iOS SDK 4.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /BookShelf.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "BookShelf" 3 | s.version = "1.0.0" 4 | s.summary = "An iBooks-styled book shelf for iOS (Animation of drag & drop, insert, remove...)" 5 | s.homepage = "https://github.com/ultragtx/GSBookShelf" 6 | s.license = 'BSD' 7 | s.author = { "ultragtx" => "ultragtx@gmail.com" } 8 | s.source = { :git => "https://github.com/ultragtx/GSBookShelf.git" } 9 | s.platform = :ios, '5.0' 10 | s.source_files = 'BookShelf/Classes/BookShelf/**/*.{h,m}' 11 | s.public_header_files = 'BookShelf/Classes/BookShelf/**/*.h' 12 | s.framework = 'QuartzCore' 13 | s.requires_arc = true 14 | end 15 | -------------------------------------------------------------------------------- /BookShelf/Resources/BookShelf-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFiles 12 | 13 | CFBundleIdentifier 14 | org.footoo.${PRODUCT_NAME:rfc1034identifier} 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | 1.0 27 | LSRequiresIPhoneOS 28 | 29 | UIRequiredDeviceCapabilities 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GSBookShelf and all code associated with it is distributed under a BSD license, as listed below 2 | 3 | Created by Xinrong Guo 4 | Copyright (c) 2012 FoOTOo. All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions 8 | are met: 9 | 10 | Redistributions of source code must retain the above copyright notice, 11 | this list of conditions and the following disclaimer. 12 | 13 | Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | Neither the name of the project's author nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 27 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /BookShelf/Classes/Useless/AboveTopView.h: -------------------------------------------------------------------------------- 1 | /* 2 | AboveTopView.h 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-3-11. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import 37 | 38 | @interface AboveTopView : UIView 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /BookShelf/Classes/Demo/BelowBottomView.h: -------------------------------------------------------------------------------- 1 | /* 2 | BelowBottomView.h 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-3-11. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import 37 | 38 | @interface BelowBottomView : UIView 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /BookShelf/Classes/Useless/MyBelowBottomView.h: -------------------------------------------------------------------------------- 1 | /* 2 | MyBelowBottomView.h 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-3-12. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import 37 | 38 | @interface MyBelowBottomView : UIView 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /BookShelf/Classes/BookShelf/Public/GSBookView.h: -------------------------------------------------------------------------------- 1 | /* 2 | GSBookView.h 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-3-5. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import 37 | 38 | @protocol GSBookView 39 | 40 | @property (nonatomic, strong) NSString *reuseIdentifier; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /BookShelf/Classes/BookShelf/Public/GSBookShelfCell.h: -------------------------------------------------------------------------------- 1 | /* 2 | GSBookShelfCell.h 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-3-5. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import 37 | 38 | @protocol GSBookShelfCell 39 | 40 | @property (nonatomic, strong) NSString *reuseIdentifier; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /BookShelf/Classes/BookShelf/Utilities/NSMutableArray+Rearrange.h: -------------------------------------------------------------------------------- 1 | /* 2 | NSMutableArray+Rearrange.h 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-3-2. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | 37 | #import 38 | 39 | @interface NSMutableArray (Rearrange) 40 | 41 | - (void)moveObjectFromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /BookShelf/Other/main.m: -------------------------------------------------------------------------------- 1 | /* 2 | main.m 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-2-22. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import 37 | 38 | #import "AppDelegate.h" 39 | 40 | int main(int argc, char *argv[]) 41 | { 42 | @autoreleasepool { 43 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /BookShelf/Classes/Useless/MyCellView.h: -------------------------------------------------------------------------------- 1 | /* 2 | NewCellView.h 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-3-124. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import 37 | #import "GSBookShelfCell.h" 38 | 39 | @interface MyCellView : UIView 40 | 41 | @property (nonatomic, strong) NSString *reuseIdentifier; 42 | @property (nonatomic, strong) UILabel *label; // used for debug 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /BookShelf/Classes/Demo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /* 2 | AppDelegate.h 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-2-22. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import 37 | 38 | @class ViewController; 39 | 40 | @interface AppDelegate : UIResponder 41 | 42 | @property (strong, nonatomic) UIWindow *window; 43 | 44 | @property (strong, nonatomic) ViewController *viewController; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /BookShelf/Classes/Demo/MyBookView.h: -------------------------------------------------------------------------------- 1 | /* 2 | NewBookView.h 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-3-12. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import 37 | #import "GSBookView.h" 38 | 39 | @interface MyBookView : UIButton { 40 | UIImageView *_checkedImageView; 41 | } 42 | 43 | @property (nonatomic, strong) NSString *reuseIdentifier; 44 | @property (nonatomic, assign) BOOL selected; 45 | @property (nonatomic, assign) NSInteger index; 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /BookShelf/Classes/Useless/BookView.h: -------------------------------------------------------------------------------- 1 | /* 2 | GSBookView.h 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-2-23. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import 37 | #import "GSBookView.h" 38 | 39 | @interface BookView : UIView { 40 | 41 | UIImage *_image; 42 | 43 | UIButton *_button; 44 | 45 | UIImageView *_checkedImageView; 46 | 47 | } 48 | 49 | @property (nonatomic, strong) UIImage *image; 50 | 51 | @property (nonatomic, strong) NSString *reuseIdentifier; 52 | 53 | @property (nonatomic, strong) UIButton *button; 54 | 55 | @property (nonatomic, assign) BOOL selected; 56 | 57 | @property (nonatomic, assign) NSInteger index; 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /BookShelf/Classes/BookShelf/Utilities/NSMutableArray+Rearrange.m: -------------------------------------------------------------------------------- 1 | /* 2 | NSMutableArray+Rearrange.m 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-3-2. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import "NSMutableArray+Rearrange.h" 37 | 38 | @implementation NSMutableArray (Rearrange) 39 | 40 | - (void)moveObjectFromIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex { 41 | 42 | if (fromIndex != toIndex) { 43 | id __strong obj = [self objectAtIndex:fromIndex]; 44 | [self removeObjectAtIndex:fromIndex]; 45 | if (toIndex >= [self count]) { 46 | [self addObject:obj]; 47 | } 48 | else { 49 | [self insertObject:obj atIndex:toIndex]; 50 | } 51 | } 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /BookShelf/Classes/Demo/BookShelfCellView.h: -------------------------------------------------------------------------------- 1 | /* 2 | GSBookShelfCellView.h 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-2-23. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import 37 | #import "GSBookShelfCell.h" 38 | 39 | typedef enum { 40 | WOOD_PART_1, 41 | WOOD_PART_2 42 | }WoodPart; 43 | 44 | @interface BookShelfCellView : UIView { 45 | UIImageView *_shelfImageView; 46 | UIImageView *_shelfImageViewLandscape; 47 | UIImageView *_woodImageView; 48 | UIImageView *_shadingImageView; 49 | 50 | UIImageView *_sideImageView_left; 51 | UIImageView *_sideImageView_right; 52 | 53 | } 54 | 55 | @property (nonatomic, strong) NSString *reuseIdentifier; 56 | 57 | + (UIImage *)shadingImage; 58 | + (UIImage *)woodImage; 59 | + (UIImage *)shelfImageProtrait; 60 | + (UIImage *)shelfImageLandscape; 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /BookShelf/Classes/Useless/MyBelowBottomView.m: -------------------------------------------------------------------------------- 1 | /* 2 | MyBelowBottomView.m 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-3-12. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import "MyBelowBottomView.h" 37 | #import "MyCellView.h" 38 | 39 | @implementation MyBelowBottomView 40 | 41 | - (id)initWithFrame:(CGRect)frame 42 | { 43 | self = [super initWithFrame:frame]; 44 | if (self) { 45 | MyCellView *cell1 = [[MyCellView alloc] initWithFrame:CGRectMake(0, 0, 320, 125)]; 46 | MyCellView *cell2 = [[MyCellView alloc] initWithFrame:CGRectMake(0, 125, 320, 125)]; 47 | 48 | [self addSubview:cell1]; 49 | [self addSubview:cell2]; 50 | } 51 | return self; 52 | } 53 | 54 | /* 55 | // Only override drawRect: if you perform custom drawing. 56 | // An empty implementation adversely affects performance during animation. 57 | - (void)drawRect:(CGRect)rect 58 | { 59 | // Drawing code 60 | } 61 | */ 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /BookShelf/Classes/BookShelf/Private/GSCellContainerView.h: -------------------------------------------------------------------------------- 1 | /* 2 | CellContainerView.h 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-2-24. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import 37 | 38 | @class GSBookShelfView; 39 | 40 | @interface GSCellContainerView : UIView { 41 | GSBookShelfView __unsafe_unretained *_parentBookShelfView; 42 | 43 | @private 44 | 45 | NSInteger _firstVisibleRow; 46 | NSInteger _lastVisibleRow; 47 | 48 | NSMutableArray *_visibleCells; 49 | NSMutableDictionary *_reuseableCells; 50 | 51 | 52 | } 53 | 54 | @property (nonatomic, unsafe_unretained) GSBookShelfView *parentBookShelfView; 55 | 56 | - (NSArray *)visibleCells; 57 | - (UIView *)cellAtRow:(NSInteger)row; 58 | - (void)reloadData; 59 | - (UIView *)dequeueReuseableCellWithIdentifier:(NSString *)identifier; 60 | - (void)layoutSubviewsWithAvailableRect:(CGRect)availableRect; 61 | 62 | - (void)resizeReuseCells; 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /BookShelf/Classes/Demo/ViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | ViewController.h 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-2-22. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import 37 | #import "GSBookShelfView.h" 38 | 39 | @class MyBelowBottomView; 40 | @class BelowBottomView; 41 | 42 | typedef enum { 43 | BOOK_UNSELECTED, 44 | BOOK_SELECTED 45 | }BookStatus; 46 | 47 | @interface ViewController : UIViewController { 48 | GSBookShelfView *_bookShelfView; 49 | 50 | NSMutableArray *_bookArray; 51 | NSMutableArray *_bookStatus; 52 | 53 | NSMutableIndexSet *_booksIndexsToBeRemoved; 54 | 55 | BOOL _editMode; 56 | 57 | UIBarButtonItem *_editBarButton; 58 | UIBarButtonItem *_cancleBarButton; 59 | UIBarButtonItem *_trashBarButton; 60 | UIBarButtonItem *_addBarButton; 61 | 62 | BelowBottomView *_belowBottomView; 63 | UISearchBar *_searchBar; 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /BookShelf/Classes/Demo/BelowBottomView.m: -------------------------------------------------------------------------------- 1 | /* 2 | BelowBottomView.m 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-3-11. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import "BelowBottomView.h" 37 | 38 | #import "BookShelfCellView.h" 39 | 40 | @implementation BelowBottomView 41 | 42 | - (id)initWithFrame:(CGRect)frame 43 | { 44 | self = [super initWithFrame:frame]; 45 | if (self) { 46 | BookShelfCellView *cell1 = [[BookShelfCellView alloc] initWithFrame:CGRectMake(0, 0, 320, 139)]; 47 | BookShelfCellView *cell2 = [[BookShelfCellView alloc] initWithFrame:CGRectMake(0, 139, 320, 139)]; 48 | 49 | [cell1 setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 50 | [cell2 setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 51 | 52 | [self addSubview:cell1]; 53 | [self addSubview:cell2]; 54 | } 55 | return self; 56 | } 57 | 58 | /* 59 | // Only override drawRect: if you perform custom drawing. 60 | // An empty implementation adversely affects performance during animation. 61 | - (void)drawRect:(CGRect)rect 62 | { 63 | // Drawing code 64 | } 65 | */ 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /BookShelf/Classes/Demo/MyBookView.m: -------------------------------------------------------------------------------- 1 | /* 2 | NewBookView.m 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-3-12. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import "MyBookView.h" 37 | 38 | @implementation MyBookView 39 | 40 | @synthesize reuseIdentifier; 41 | @synthesize selected= _selected; 42 | @synthesize index = _index; 43 | 44 | - (id)initWithFrame:(CGRect)frame 45 | { 46 | self = [super initWithFrame:frame]; 47 | if (self) { 48 | _checkedImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"BookViewChecked.png"]]; 49 | [_checkedImageView setHidden:YES]; 50 | [self addSubview:_checkedImageView]; 51 | 52 | [self addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside]; 53 | } 54 | return self; 55 | } 56 | 57 | - (void)setSelected:(BOOL)selected { 58 | _selected = selected; 59 | if (_selected) { 60 | [_checkedImageView setHidden:NO]; 61 | } 62 | else { 63 | [_checkedImageView setHidden:YES]; 64 | } 65 | } 66 | 67 | - (void)buttonClicked:(id)sender { 68 | [self setSelected:_selected ? NO : YES]; 69 | } 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /BookShelf/Classes/Useless/MyCellView.m: -------------------------------------------------------------------------------- 1 | /* 2 | NewCellView.m 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-3-12. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import "MyCellView.h" 37 | 38 | @implementation MyCellView 39 | 40 | @synthesize reuseIdentifier; 41 | @synthesize label; 42 | 43 | - (id)initWithFrame:(CGRect)frame 44 | { 45 | self = [super initWithFrame:frame]; 46 | if (self) { 47 | UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 125)]; 48 | 49 | [imageView setImage:[UIImage imageNamed:@"BookShelfCell.png"]]; 50 | [self addSubview:imageView]; 51 | 52 | label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 30)]; 53 | [label setTextColor:[UIColor greenColor]]; 54 | [self addSubview:label]; 55 | 56 | [self setBackgroundColor:[UIColor colorWithRed:0 green:1 blue:0 alpha:0.2]]; 57 | 58 | } 59 | return self; 60 | } 61 | 62 | /* 63 | // Only override drawRect: if you perform custom drawing. 64 | // An empty implementation adversely affects performance during animation. 65 | - (void)drawRect:(CGRect)rect 66 | { 67 | // Drawing code 68 | } 69 | */ 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /BookShelf/Classes/Useless/BookView.m: -------------------------------------------------------------------------------- 1 | /* 2 | GSBookView.m 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-2-23. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import "BookView.h" 37 | 38 | @implementation BookView 39 | 40 | @synthesize image = _image; 41 | @synthesize button = _button; 42 | @synthesize reuseIdentifier; 43 | @synthesize selected = _selected; 44 | @synthesize index = _index; 45 | 46 | - (id)initWithFrame:(CGRect)frame 47 | { 48 | self = [super initWithFrame:frame]; 49 | if (self) { 50 | [self setBackgroundColor:[UIColor blueColor]]; 51 | _button = [UIButton buttonWithType:UIButtonTypeCustom]; 52 | [_button setFrame:frame]; 53 | [_button setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth]; 54 | [_button.imageView setContentMode:UIViewContentModeScaleAspectFit]; 55 | [_button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside]; 56 | [self addSubview:_button]; 57 | 58 | _checkedImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"BookViewChecked.png"]]; 59 | [_checkedImageView setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth]; 60 | [_checkedImageView setHidden:YES]; 61 | [_button addSubview:_checkedImageView]; 62 | } 63 | return self; 64 | } 65 | 66 | - (void)setImage:(UIImage *)image { 67 | if ([_image isEqual:image]) { 68 | return; 69 | } 70 | _image = image; 71 | 72 | [_button setImage:_image forState:UIControlStateNormal]; 73 | } 74 | 75 | - (void)setSelected:(BOOL)selected { 76 | _selected = selected; 77 | if (_selected) { 78 | [_checkedImageView setHidden:NO]; 79 | } 80 | else { 81 | [_checkedImageView setHidden:YES]; 82 | } 83 | } 84 | 85 | - (void)buttonClicked:(id)sender { 86 | [self setSelected:_selected ? NO : YES]; 87 | } 88 | 89 | @end 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #GSBookShelf 2 | 3 | An iBooks-inspired bookshelf control. 4 | 5 | Supports animated deletion, reordering, and addition. 6 | 7 | --- 8 | 9 | 14.04.08: **This project won't have any update, using UICollectionView with custom layout can be a better solution.** 10 | 11 | --- 12 | 13 | Attention: 14 | 15 | 1. This code should be compiled with ARC turned on; 16 | 17 | --- 18 | 19 | Features: 20 | 21 | 1. drag & drop 22 | 2. scroll up/down while draging 23 | 3. add & remove animation 24 | 4. custom header (add a search bar or anything you want)5. 25 | 5. **[Update 12.08.26]** support orientation change now and the cell has a simple animtaion when orientation change make this more similar to iBooks, to get more info, take a look at the demo 26 | 27 | --- 28 | 29 | How To: 30 | 31 | 1. Just take a look at the demo. 32 | 2. bookView and shelfCell are just UIViews. So you can cutomize them almost whatever you want. But the frame of each view is fixed, if you want to have different size of bookView, you can try adding your content on a transparent UIView. 33 | 3. To enable reusing for bookViews and cells, add the "GSBookView" / "GSBookShelfCell" protocols. (You'd better do this, perfromance will be a lot better). 34 | 4. **[NEW 12.04.03]** To support oritation change, you should call the reload method and return different values (if necessary) in the delegate method with different orientation. 35 | 5. **[NEW 12.04.03]** For more information about the data GSBookShelf need for layout, take a look at the "[comments.png](https://github.com/ultragtx/GSBookShelf/blob/ReadyTo/BookShelf/comments.png?raw=true)" (also available in the project). 36 | 6. **[NEW 12.05.18]** The books are center-aligend when there are more than one books in a row. If you only have one per row, it's left-aligend, you can set the "cellMargin" to make it center-aligend manually. 37 | 38 | --- 39 | 40 | **WARNING**: 41 | 42 | 1. **[12.08.26]** Some of the images came from iBooks (a little change to the color). Just to show how the code works. PLEASE use your own image in your project. Check [this](http://www.psawesome.com/tutorials/create-an-i-pad-inspired-bookshelf-using-photoshop) and learn how to draw a bookshelf using Photoshop, if you are not good at this. 43 | 44 | 45 | --- 46 | 47 | **Known Issue**: 48 | 49 | 1. Rotation issue part 1 and ~~part 2~~ (check [issue #12](https://github.com/ultragtx/GSBookShelf/issues/12) for description) 50 | 51 | --- 52 | 53 | TODO: 54 | 55 | 1. **[NEW 12.05.14]** Fix [issue 12](https://github.com/ultragtx/GSBookShelf/issues/12) 56 | 2. **[NEW 12.05.18]** Maybe it's better to support left-aligend center-aligend and right-aligend. 57 | 58 | --- 59 | 60 | **Contribute**: 61 | 62 | * Anyone who contribute to this project can receive a License of [AppCode](http://www.jetbrains.com/objc/index.html) (Send me a e-mail if you want one). 63 | 64 | --- 65 | 66 | Updates: 67 | 68 | 1. **[12.08.24]** merge to master 69 | 2. **[12.08.24]** enhance orientation change support 70 | 3. **[12.08.24]** bug fix when delete one which index is bigger than the visibles 71 | 4. **[12.08.26]** orientation change with cell animation(like what iBooks do to the shelf when orientation change). 72 | 5. **[12.08.26]** demo updated 73 | 6. **[12.04.11]** fix issue #12 part 2, orientation change issue 74 | 7. **[13.06.02]** use CADisplay link to replace NSTimer in customizing scroll speed of UIScrollView 75 | 76 | --- 77 | 78 | Demo: 79 | 80 | (Be Patient, some gifs' size > 1M) 81 | 82 | ![image](https://github.com/ultragtx/ultragtx.github.com/blob/master/images/Move_s.gif?raw=true) 83 | ![image](https://github.com/ultragtx/ultragtx.github.com/blob/master/images/Add_s.gif?raw=true) 84 | ![image](https://github.com/ultragtx/ultragtx.github.com/blob/master/images/Delete_s.gif?raw=true) 85 | -------------------------------------------------------------------------------- /BookShelf/Classes/BookShelf/Private/GSBookViewContainerView.h: -------------------------------------------------------------------------------- 1 | /* 2 | BookViewContainerView.h 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-2-24. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import 37 | 38 | 39 | @class GSBookShelfView; 40 | 41 | @protocol GSBookShelfViewDelegate; 42 | @protocol GSBookShelfViewDataSource; 43 | 44 | typedef struct BookViewPostion { 45 | NSInteger row; 46 | NSInteger col; 47 | NSInteger index; 48 | }BookViewPostion; 49 | 50 | @interface GSBookViewContainerView : UIView { 51 | GSBookShelfView __unsafe_unretained *_parentBookShelfView; 52 | 53 | @private 54 | 55 | CGRect _visibleRect; 56 | CGRect _availableRect; 57 | 58 | NSInteger _firstVisibleRow; 59 | NSInteger _lastVisibleRow; 60 | 61 | //NSInteger _firstVisibleIndex; 62 | //NSInteger _lastVisibleIndex; 63 | 64 | NSMutableArray *_visibleBookViews; 65 | NSMutableDictionary *_reuseableBookViews; 66 | 67 | CGFloat _bookViewWidth; 68 | CGFloat _bookViewHeight; 69 | CGFloat _bookViewSpacingWidth; 70 | 71 | // Drag and Drop 72 | BOOL _isDragViewPickedUp; 73 | UIView *_dragView; 74 | BookViewPostion _pickUpPosition; 75 | CGRect _pickUpRect; 76 | BOOL _isDragViewRemovedFromVisibleBookViews; 77 | 78 | BOOL _isBooksMoving; 79 | 80 | // Scroll While Drag 81 | CADisplayLink *_displayLink; 82 | double _lastDragScrollTime; 83 | 84 | // Remove Book 85 | NSMutableIndexSet *_indexsOfBookViewToBeRemoved; 86 | NSMutableIndexSet *_indexsOfBookViewNotShown; 87 | NSMutableArray *_tempVisibleBookViewCollector; 88 | BOOL _isRemoving; 89 | 90 | 91 | } 92 | 93 | @property (nonatomic, unsafe_unretained) GSBookShelfView *parentBookShelfView; 94 | 95 | - (void)reloadData; 96 | 97 | - (NSArray *)visibleBookViews; 98 | - (UIView *)bookViewAtIndex:(NSInteger)index; 99 | 100 | - (void)layoutSubviewsWithAvailableRect:(CGRect)availableRect visibleRect:(CGRect)visibleRect; 101 | 102 | - (UIView *)dequeueReusableBookViewWithIdentifier:(NSString *)identifier; 103 | 104 | - (void)removeBookViewsAtIndexs:(NSIndexSet *)indexs animate:(BOOL)animate; 105 | - (void)insertBookViewsAtIndexs:(NSIndexSet *)indexs animate:(BOOL)animate; 106 | 107 | @end 108 | -------------------------------------------------------------------------------- /BookShelf/Classes/Useless/AboveTopView.m: -------------------------------------------------------------------------------- 1 | /* 2 | AboveTopView.m 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-3-11. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import "AboveTopView.h" 37 | 38 | #define isRetina ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(640, 960), [[UIScreen mainScreen] currentMode].size) : NO) 39 | 40 | @implementation AboveTopView 41 | 42 | - (id)initWithFrame:(CGRect)frame 43 | { 44 | self = [super initWithFrame:frame]; 45 | if (self) { 46 | UIImageView *woodImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 139 * 2)]; 47 | 48 | CGFloat scale = isRetina ? 2.0f : 1.0f; 49 | CGImageRef woodImgRef = CGImageCreateWithImageInRect([[UIImage imageNamed:@"WoodTile-iPhone.png"] CGImage], CGRectMake(0, 0, 320 * scale, 139 * 2 * scale)); 50 | [woodImageView setImage:[UIImage imageWithCGImage:woodImgRef]]; 51 | CGImageRelease(woodImgRef); 52 | [self addSubview:woodImageView]; 53 | 54 | UIImageView *sideImageView_left1 = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 160, 164)]; 55 | [sideImageView_left1 setImage:[UIImage imageNamed:@"topshelf side shading-iPhone.png"]]; 56 | 57 | UIImageView *sideImageView_left2 = [[UIImageView alloc] initWithFrame:CGRectMake(0, 139, 160, 139)]; 58 | [sideImageView_left2 setImage:[UIImage imageNamed:@"SideShading-iPhone.png"]]; 59 | 60 | [self addSubview:sideImageView_left1]; 61 | //[self addSubview:sideImageView_left2]; 62 | 63 | UIImageView *sideImageView_right1 = [[UIImageView alloc] initWithFrame:CGRectMake(160, 0, 160, 164)]; 64 | [sideImageView_right1 setImage:[UIImage imageNamed:@"topshelf side shading-iPhone.png"]]; 65 | [sideImageView_right1 setTransform:CGAffineTransformMakeScale(-1.0, 1.0)]; 66 | 67 | UIImageView *sideImageView_right2 = [[UIImageView alloc] initWithFrame:CGRectMake(160, 139, 160, 139)]; 68 | [sideImageView_right2 setImage:[UIImage imageNamed:@"SideShading-iPhone.png"]]; 69 | [sideImageView_right2 setTransform:CGAffineTransformMakeScale(-1.0, 1.0)]; 70 | 71 | [self addSubview:sideImageView_right1]; 72 | //[self addSubview:sideImageView_right2]; 73 | } 74 | return self; 75 | } 76 | 77 | /* 78 | // Only override drawRect: if you perform custom drawing. 79 | // An empty implementation adversely affects performance during animation. 80 | - (void)drawRect:(CGRect)rect 81 | { 82 | // Drawing code 83 | } 84 | */ 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /BookShelf/Classes/Demo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /* 2 | AppDelegate.m 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-2-22. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import "AppDelegate.h" 37 | 38 | #import "ViewController.h" 39 | 40 | @implementation AppDelegate 41 | 42 | @synthesize window = _window; 43 | @synthesize viewController = _viewController; 44 | 45 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 46 | { 47 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 48 | // Override point for customization after application launch. 49 | self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil]; 50 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:self.viewController]; 51 | self.window.rootViewController = navController; 52 | [self.window makeKeyAndVisible]; 53 | return YES; 54 | } 55 | 56 | - (void)applicationWillResignActive:(UIApplication *)application 57 | { 58 | /* 59 | Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 60 | Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 61 | */ 62 | } 63 | 64 | - (void)applicationDidEnterBackground:(UIApplication *)application 65 | { 66 | /* 67 | Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 68 | If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 69 | */ 70 | } 71 | 72 | - (void)applicationWillEnterForeground:(UIApplication *)application 73 | { 74 | /* 75 | Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 76 | */ 77 | } 78 | 79 | - (void)applicationDidBecomeActive:(UIApplication *)application 80 | { 81 | /* 82 | Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 83 | */ 84 | } 85 | 86 | - (void)applicationWillTerminate:(UIApplication *)application 87 | { 88 | /* 89 | Called when the application is about to terminate. 90 | Save data if appropriate. 91 | See also applicationDidEnterBackground:. 92 | */ 93 | } 94 | 95 | @end 96 | -------------------------------------------------------------------------------- /BookShelf/Resources/en.lproj/ViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1296 5 | 12A269 6 | 2549 7 | 1187 8 | 624.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 1498 12 | 13 | 14 | IBProxyObject 15 | IBUIView 16 | 17 | 18 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 19 | 20 | 21 | PluginDependencyRecalculationVersion 22 | 23 | 24 | 25 | 26 | IBFilesOwner 27 | IBCocoaTouchFramework 28 | 29 | 30 | IBFirstResponder 31 | IBCocoaTouchFramework 32 | 33 | 34 | 35 | 300 36 | {{0, 64}, {320, 416}} 37 | 38 | 39 | 3 40 | MC43NQA 41 | 42 | 2 43 | 44 | 45 | NO 46 | 47 | 48 | NO 49 | 50 | IBCocoaTouchFramework 51 | 52 | 53 | 54 | 55 | 56 | 57 | view 58 | 59 | 60 | 61 | 7 62 | 63 | 64 | 65 | 66 | 67 | 0 68 | 69 | 70 | 71 | 72 | 73 | -1 74 | 75 | 76 | File's Owner 77 | 78 | 79 | -2 80 | 81 | 82 | 83 | 84 | 6 85 | 86 | 87 | 88 | 89 | 90 | 91 | ViewController 92 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 93 | UIResponder 94 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 95 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 96 | 97 | 98 | 99 | 100 | 101 | 7 102 | 103 | 104 | 0 105 | IBCocoaTouchFramework 106 | 107 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 108 | 109 | 110 | YES 111 | 3 112 | 1498 113 | 114 | 115 | -------------------------------------------------------------------------------- /BookShelf/Classes/BookShelf/Public/GSBookShelfView.h: -------------------------------------------------------------------------------- 1 | /* 2 | BookShelfView.h 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-2-22. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import 37 | #import "NSMutableArray+Rearrange.h" 38 | 39 | @class GSBookViewContainerView; 40 | @class GSCellContainerView; 41 | 42 | @protocol GSBookShelfViewDelegate; 43 | @protocol GSBookShelfViewDataSource; 44 | 45 | @interface GSBookShelfView : UIScrollView { 46 | @private 47 | id __unsafe_unretained _dataSource; 48 | 49 | GSBookViewContainerView *_bookViewContainerView; 50 | GSCellContainerView *_cellContainerView; 51 | 52 | UIView *_headerView; 53 | UIView *_aboveTopView; 54 | UIView *_belowBottomView; 55 | 56 | // Function Enabler 57 | 58 | BOOL _dragAndDropEnabled; 59 | BOOL _scrollWhileDragingEnabled; 60 | //BOOL _editModeEnabled; 61 | 62 | // Layout of books and cells 63 | 64 | CGFloat _cellHeight; 65 | CGFloat _cellMargin; 66 | 67 | CGFloat _bookViewBottomOffset; 68 | 69 | CGFloat _shelfShadowHeight; 70 | 71 | NSInteger _numberOfBooksInCell; 72 | 73 | // store the variables to prevent recalculate 74 | NSInteger _numberOfCells; 75 | NSInteger _minNumberOfCells; 76 | CGFloat _contentSizeHeight; 77 | 78 | NSInteger _orientationChangeFlag; 79 | } 80 | 81 | @property (nonatomic, unsafe_unretained) id dataSource; 82 | 83 | @property (nonatomic, readonly) UIView *headerView; 84 | @property (nonatomic, readonly) UIView *aboveTopView; 85 | @property (nonatomic, readonly) UIView *belowBottomView; 86 | 87 | @property (nonatomic, readonly) BOOL dragAndDropEnabled; 88 | @property (nonatomic, assign) BOOL scrollWhileDragingEnabled; 89 | 90 | @property (nonatomic, readonly) CGFloat cellHeight; // height of each cell 91 | @property (nonatomic, readonly) CGFloat cellMargin; // margin of cell where to display the first book 92 | @property (nonatomic, readonly) CGFloat bookViewBottomOffset; // distance from the bottom of bookview to the top of cell, which means where the books should put on the shelf 93 | 94 | @property (nonatomic, readonly) CGFloat shelfShadowHeight; // the shadow heigt of cell (in iBooks the shelf image has a shadow that will cover the cell below it, so if your image of cell has a shadow like this, you can set the shadow's height. If not set it zero 95 | @property (nonatomic, readonly) NSInteger numberOfBooksInCell; 96 | 97 | - (UIView *)dequeueReuseableBookViewWithIdentifier:(NSString *)identifier; 98 | - (UIView *)dequeueReuseableCellViewWithIdentifier:(NSString *)identifier; 99 | 100 | - (NSArray *)visibleBookViews; 101 | - (NSArray *)visibleCells; 102 | - (UIView *)bookViewAtIndex:(NSInteger)index; 103 | - (UIView *)cellAtRow:(NSInteger)row; 104 | //- (UIView *)bookViewAtIndex:(NSInteger)index; 105 | //- (UIView *)cellAtIndex:(NSInteger)index; 106 | 107 | - (void)reloadData; 108 | - (void)oritationChangeReloadData; 109 | 110 | - (void)scrollToRow:(NSInteger)row animate:(BOOL)animate; 111 | 112 | - (void)removeBookViewsAtIndexs:(NSIndexSet *)indexs animate:(BOOL)animate; 113 | - (void)insertBookViewsAtIndexs:(NSIndexSet *)indexs animate:(BOOL)animate; 114 | 115 | - (void)didFinshRotation; 116 | 117 | @end 118 | 119 | @protocol GSBookShelfViewDataSource 120 | 121 | - (NSInteger)numberOfBooksInBookShelfView:(GSBookShelfView *)bookShelfView; // Total number of Books 122 | - (NSInteger)numberOFBooksInCellOfBookShelfView:(GSBookShelfView *)bookShelfView; // Number of books in each cell 123 | 124 | - (UIView *)bookShelfView:(GSBookShelfView *)bookShelfView bookViewAtIndex:(NSInteger)index; 125 | - (UIView *)bookShelfView:(GSBookShelfView *)bookShelfView cellForRow:(NSInteger)row; 126 | 127 | - (UIView *)aboveTopViewOfBookShelfView:(GSBookShelfView *)bookShelfView; // View tha will be shown when you drag down |bookShelfView| and reach the edge. 128 | - (UIView *)belowBottomViewOfBookShelfView:(GSBookShelfView *)bookShelfView; // View tha will be shown when you drag up |bookShelfView| and reach the edge. 129 | 130 | - (UIView *)headerViewOfBookShelfView:(GSBookShelfView *)bookShelfView; // This view will be shown above the first cell. You can return a UISearchBar or something you like. 131 | 132 | // The followings help with the layout of books 133 | // Take a look at the "comments.png" in BookShelf >> Image to understand what are these means 134 | - (CGFloat)cellHeightOfBookShelfView:(GSBookShelfView *)bookShelfView; 135 | - (CGFloat)cellMarginOfBookShelfView:(GSBookShelfView *)bookShelfView; 136 | 137 | - (CGFloat)bookViewHeightOfBookShelfView:(GSBookShelfView *)bookShelfView; 138 | - (CGFloat)bookViewWidthOfBookShelfView:(GSBookShelfView *)bookShelfView; 139 | 140 | - (CGFloat)bookViewBottomOffsetOfBookShelfView:(GSBookShelfView *)bookShelfView; 141 | 142 | // The shadow heigt of cell (in iBooks the shelf image has a shadow that will cover the cell below it, 143 | // so if your image of cell has a shadow like this, you can set it with the shadow's height. If not set it zero 144 | - (CGFloat)cellShadowHeightOfBookShelfView:(GSBookShelfView *)bookShelfView; 145 | 146 | @optional 147 | // Override to support rearranging. 148 | - (void)bookShelfView:(GSBookShelfView *)bookShelfView moveBookFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex; 149 | 150 | @end 151 | 152 | @protocol GSBookShelfViewDelegate 153 | 154 | // no use currently 155 | 156 | @end 157 | -------------------------------------------------------------------------------- /BookShelf/Classes/Demo/BookShelfCellView.m: -------------------------------------------------------------------------------- 1 | /* 2 | GSBookShelfCellView.m 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-2-23. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import "BookShelfCellView.h" 37 | #import 38 | 39 | #define isRetina ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(640, 960), [[UIScreen mainScreen] currentMode].size) : NO) 40 | 41 | @implementation BookShelfCellView 42 | 43 | @synthesize reuseIdentifier; 44 | 45 | static UIImage *shadingImage = nil; 46 | static UIImage *woodImage = nil; 47 | static UIImage *shelfImageProtrait = nil; 48 | static UIImage *shelfImageLandscape = nil; 49 | 50 | + (UIImage *)shadingImage { 51 | if (shadingImage == nil) { 52 | CGFloat scale = isRetina ? 2.0f : 1.0f; 53 | 54 | UIGraphicsBeginImageContext(CGSizeMake(320 * scale, 139 * scale)); 55 | UIImage *shadingImageToDraw = [UIImage imageNamed:@"Side Shading-iPhone.png"]; 56 | [shadingImageToDraw drawInRect:CGRectMake(0, 0, shadingImageToDraw.size.width * scale, shadingImageToDraw.size.height * scale)]; 57 | 58 | CGAffineTransform ctm1 = CGAffineTransformMakeScale(-1.0f, 1.0f); 59 | CGContextConcatCTM(UIGraphicsGetCurrentContext(), ctm1); 60 | [shadingImageToDraw drawInRect:CGRectMake(-320 * scale, 0, shadingImageToDraw.size.width * scale, shadingImageToDraw.size.height * scale)]; 61 | shadingImage = UIGraphicsGetImageFromCurrentImageContext(); 62 | UIGraphicsEndImageContext(); 63 | 64 | shadingImage = [UIImage imageWithCGImage:shadingImage.CGImage scale:scale orientation:UIImageOrientationUp]; 65 | } 66 | return shadingImage; 67 | } 68 | 69 | + (UIImage *)woodImage { 70 | if (woodImage == nil) { 71 | CGFloat scale = isRetina ? 2.0f : 1.0f; 72 | 73 | UIGraphicsBeginImageContext(CGSizeMake(480 * scale, 139 * scale)); 74 | UIImage *woodImageToDraw = [UIImage imageNamed:@"WoodTile.png"]; 75 | [woodImageToDraw drawInRect:CGRectMake(0, 0, woodImageToDraw.size.width * scale, woodImageToDraw.size.width * scale)]; 76 | woodImage = UIGraphicsGetImageFromCurrentImageContext(); 77 | UIGraphicsEndImageContext(); 78 | 79 | woodImage = [UIImage imageWithCGImage:woodImage.CGImage scale:scale orientation:UIImageOrientationUp]; 80 | } 81 | return woodImage; 82 | } 83 | 84 | + (UIImage *)shelfImageProtrait { 85 | if (shelfImageProtrait == nil) { 86 | shelfImageProtrait = [UIImage imageNamed:@"Shelf.png"]; 87 | } 88 | return shelfImageProtrait; 89 | } 90 | 91 | + (UIImage *)shelfImageLandscape { 92 | if (shelfImageLandscape == nil) { 93 | shelfImageLandscape = [UIImage imageNamed:@"Shelf-Landscape.png"]; 94 | } 95 | return shelfImageLandscape; 96 | } 97 | 98 | 99 | 100 | - (UIImage *)partOfImage:(UIImage *)image rect:(CGRect)rect { 101 | UIGraphicsBeginImageContext(CGSizeMake(rect.size.width, rect.size.width)); 102 | [image drawInRect:rect]; 103 | UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext(); 104 | UIGraphicsEndImageContext(); 105 | return resultImage; 106 | } 107 | 108 | 109 | 110 | - (id)initWithFrame:(CGRect)frame { 111 | self = [super initWithFrame:frame]; 112 | if (self) { 113 | [self setBackgroundColor:[UIColor whiteColor]]; 114 | //[self.layer setBorderWidth:2]; 115 | //[self.layer setBorderColor:[[UIColor greenColor] CGColor]]; 116 | 117 | /*// wood 118 | _woodImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 139)]; 119 | 120 | CGFloat scale = isRetina ? 2.0f : 1.0f; 121 | [_woodImageView setImage:[UIImage imageWithCGImage:CGImageCreateWithImageInRect([[UIImage imageNamed:@"WoodTile-iPhone.png"] CGImage], CGRectMake(0, 139 * scale * part, 320 * scale, 139 * scale))]]; 122 | [self addSubview:_woodImageView]; 123 | 124 | _sideImageView_left = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 160, 139)]; 125 | [_sideImageView_left setImage:[UIImage imageNamed:@"SideShading-iPhone.png"]]; 126 | 127 | [self addSubview:_sideImageView_left]; 128 | 129 | _sideImageView_right = [[UIImageView alloc] initWithFrame:CGRectMake(160, 0, 160, 139)]; 130 | [_sideImageView_right setImage:[UIImage imageNamed:@"SideShading-iPhone.png"]]; 131 | [_sideImageView_right setTransform:CGAffineTransformMakeScale(-1.0, 1.0)]; 132 | [self addSubview:_sideImageView_right]; 133 | //[_sideImageView_right.layer setBorderWidth:1]; 134 | //[_sideImageView_right.layer setBorderColor:[[UIColor redColor] CGColor]]; 135 | 136 | 137 | _shelfImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 130 - 23, 320, 87)]; 138 | [_shelfImageView setImage:[UIImage imageNamed:@"Shelf-iPhone.png"]]; 139 | [self addSubview:_shelfImageView];*/ 140 | 141 | _shelfImageView = [[UIImageView alloc] initWithImage:[BookShelfCellView shelfImageProtrait]]; 142 | 143 | _shelfImageViewLandscape = [[UIImageView alloc] initWithImage:[BookShelfCellView shelfImageLandscape]]; 144 | 145 | _woodImageView = [[UIImageView alloc] initWithImage:[BookShelfCellView woodImage]]; 146 | 147 | _shadingImageView = [[UIImageView alloc] initWithImage:[BookShelfCellView shadingImage]]; 148 | //[_shadingImageView setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin]; 149 | 150 | [self addSubview:_woodImageView]; 151 | [self addSubview:_shadingImageView]; 152 | [self addSubview:_shelfImageView]; 153 | [self addSubview:_shelfImageViewLandscape]; 154 | } 155 | return self; 156 | } 157 | 158 | - (void)layoutSubviews { 159 | [super layoutSubviews]; 160 | 161 | [_shadingImageView setFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; 162 | 163 | if (self.frame.size.width <= 320) { 164 | [_shelfImageView setHidden:NO]; 165 | [_shelfImageViewLandscape setHidden:YES]; 166 | } 167 | else { 168 | [_shelfImageView setHidden:YES]; 169 | [_shelfImageViewLandscape setHidden:NO]; 170 | } 171 | [_shelfImageView setFrame:CGRectMake(0, 130 - 23, self.frame.size.width, _shelfImageView.frame.size.height)]; 172 | [_shelfImageViewLandscape setFrame:CGRectMake(0, 130 - 23, self.frame.size.width, _shelfImageViewLandscape.frame.size.height)]; 173 | 174 | } 175 | 176 | @end 177 | -------------------------------------------------------------------------------- /BookShelf/Classes/BookShelf/Private/GSCellContainerView.m: -------------------------------------------------------------------------------- 1 | /* 2 | CellContainerView.m 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-2-24. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import "GSCellContainerView.h" 37 | #import "GSBookShelfView.h" 38 | #import "GSBookShelfCell.h" 39 | #import 40 | 41 | typedef enum { 42 | ADD_TYPE_HEAD, 43 | ADD_TYPE_TAIL 44 | }AddType; 45 | 46 | typedef enum { 47 | RM_TYPE_HEAD, 48 | RM_TYPE_TAIL 49 | }RemoveType; 50 | 51 | @implementation GSCellContainerView 52 | 53 | @synthesize parentBookShelfView = _parentBookShelfView; 54 | 55 | - (id)initWithFrame:(CGRect)frame 56 | { 57 | self = [super initWithFrame:frame]; 58 | if (self) { 59 | _firstVisibleRow = -1; 60 | _lastVisibleRow = -1; 61 | 62 | _reuseableCells = [[NSMutableDictionary alloc] initWithCapacity:0]; 63 | 64 | _visibleCells = [[NSMutableArray alloc] initWithCapacity:0]; 65 | } 66 | return self; 67 | } 68 | 69 | - (void)reloadData { 70 | _firstVisibleRow = -1; 71 | _lastVisibleRow = -1; 72 | 73 | for (UIView *cell in _visibleCells) { 74 | [self addReuseableCell:cell]; 75 | [cell removeFromSuperview]; 76 | } 77 | 78 | [_visibleCells removeAllObjects]; 79 | //[_reuseableCells removeAllObjects]; 80 | } 81 | 82 | - (void)resizeReuseCells { 83 | // Discussion: 84 | // This is a fix of issue #12 part 2 85 | // Resize all the "in store" cells when orientation end. 86 | // When next orientation begin, 87 | // cells that will be reused can animate to the new size 88 | // and issue #12 won't happen. 89 | 90 | for (NSString *key in [_reuseableCells allKeys]) { 91 | NSMutableSet *cellSet = [_reuseableCells objectForKey:key]; 92 | for (UIView *view in cellSet) { 93 | [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, self.frame.size.width, view.frame.size.height)]; 94 | [view layoutSubviews]; 95 | } 96 | } 97 | } 98 | 99 | #pragma mark - Reuse 100 | 101 | - (void)addReuseableCell:(UIView *)cell { 102 | NSString *reuseIdentifier = nil; 103 | if ([cell respondsToSelector:@selector(reuseIdentifier)]) { 104 | reuseIdentifier = [(id)cell reuseIdentifier]; 105 | } 106 | 107 | if (reuseIdentifier == nil) { 108 | return; 109 | } 110 | 111 | NSMutableSet *cellSet = [_reuseableCells objectForKey:reuseIdentifier]; 112 | if (!cellSet) { 113 | cellSet = [[NSMutableSet alloc] initWithCapacity:0]; 114 | [_reuseableCells setObject:cellSet forKey:reuseIdentifier]; 115 | } 116 | //NSLog(@"cellset count: %d", [cellSet count]); 117 | [cellSet addObject:cell]; 118 | } 119 | 120 | - (UIView *)dequeueReuseableCellWithIdentifier:(NSString *)identifier { 121 | NSMutableSet *cellSet = (NSMutableSet *)[_reuseableCells objectForKey:identifier]; 122 | UIView *cell = [cellSet anyObject]; 123 | if (cell) { 124 | [cellSet removeObject:cell]; 125 | } 126 | return cell; 127 | } 128 | 129 | #pragma mark - layout 130 | 131 | - (CGRect)cellRectAtRow:(NSInteger)row { 132 | CGFloat cellHeight = [_parentBookShelfView.dataSource cellHeightOfBookShelfView:_parentBookShelfView]; 133 | return CGRectMake(0, cellHeight * row, self.frame.size.width, cellHeight); 134 | } 135 | 136 | - (void)removeCellWithType:(RemoveType)type { 137 | NSUInteger rmIndex; 138 | switch (type) { 139 | case RM_TYPE_HEAD: 140 | rmIndex = 0; 141 | break; 142 | case RM_TYPE_TAIL: 143 | rmIndex = [_visibleCells count] - 1; 144 | } 145 | UIView *cell = [_visibleCells objectAtIndex:rmIndex]; 146 | [self addReuseableCell:cell]; 147 | [cell removeFromSuperview]; 148 | 149 | [_visibleCells removeObjectAtIndex:rmIndex]; 150 | } 151 | 152 | - (void)addCellAtRow:(NSInteger)row addType:(AddType)type{ 153 | UIView *cell = [_parentBookShelfView.dataSource bookShelfView:_parentBookShelfView cellForRow:row]; 154 | 155 | // Disable animation to make the cell animate properly when orientation change 156 | // 1. Disable animtaion and set position properly 157 | // 2. Enable animatoin and let bounds animate 158 | // Why set anchorPoint? Have a look at the discussion below 159 | [UIView setAnimationsEnabled:NO]; 160 | CGRect newFrame = [self cellRectAtRow:row]; 161 | //NSLog(@"anchorPoint%@", NSStringFromCGPoint(cell.layer.anchorPoint)); 162 | [cell.layer setAnchorPoint:CGPointZero]; 163 | [cell setCenter:CGPointMake(0, newFrame.origin.y)]; 164 | //[cell setCenter:CGPointMake(newFrame.size.width / 2, newFrame.origin.y + newFrame.size.height / 2)]; 165 | [UIView setAnimationsEnabled:YES]; 166 | //[cell.layer setAnchorPoint:CGPointZero]; 167 | [cell setBounds:CGRectMake(0, 0, newFrame.size.width, newFrame.size.height)]; 168 | 169 | /*[UIView setAnimationsEnabled:NO]; 170 | CGRect frame = cell.frame; 171 | [cell.layer setAnchorPoint:CGPointMake(0.5, 0.5)]; 172 | [cell setFrame:frame]; 173 | [UIView setAnimationsEnabled:YES];*/ 174 | 175 | // !!!:CANNOT set anchorPoint back here this may cause bug! 176 | //[cell.layer setAnchorPoint:CGPointMake(0.5, 0.5)]; 177 | // NSLog(@"cell frame:[%@]", NSStringFromCGRect(cell.frame)); 178 | 179 | // Discussion: 180 | // The code above used to be : 181 | // { 182 | // [UIView setAnimationsEnabled:NO]; 183 | // [cell setFrame:CGRectMake(newFrame.origin.x, newFrame.origin.y, cell.frame.size.width, cell.frame.size.height * 2)]; 184 | // [UIView setAnimationsEnabled:YES]; 185 | // [cell setFrame:newFrame]; 186 | // } 187 | // It "should" case the center change immediately and the bounds change with animation. 188 | // I test this outSide and worked well. 189 | // But here it'll have a strange behave -- The center.y also animate. 190 | // I tried to set center and bounds separately but once I put the position outSide the setAnimationsEnabled block, there'll be animation. 191 | // So I do some trick just as what I did above. 192 | // Set anchorPoint to make the bounds change not from the center of the view. 193 | 194 | switch (type) { 195 | case ADD_TYPE_TAIL: 196 | [_visibleCells addObject:cell]; 197 | [self insertSubview:cell atIndex:0]; 198 | break; 199 | case ADD_TYPE_HEAD: 200 | [_visibleCells insertObject:cell atIndex:0]; 201 | [self addSubview:cell]; 202 | break; 203 | } 204 | } 205 | 206 | - (void)layoutSubviewsWithAvailableRect:(CGRect)availableRect { 207 | CGFloat shelfShadowHeight = [_parentBookShelfView.dataSource cellShadowHeightOfBookShelfView:_parentBookShelfView]; 208 | CGFloat newOriginY = fmaxf(availableRect.origin.y - shelfShadowHeight, 0); 209 | CGFloat addHeight = availableRect.origin.y - newOriginY; 210 | availableRect.origin.y = newOriginY; 211 | availableRect.size.height += addHeight; 212 | 213 | NSInteger numberOfBooksInCell = [_parentBookShelfView.dataSource numberOFBooksInCellOfBookShelfView:_parentBookShelfView]; 214 | 215 | NSInteger numberOfBooks = [_parentBookShelfView.dataSource numberOfBooksInBookShelfView:_parentBookShelfView]; 216 | 217 | NSInteger numberOfCells = ceilf((float)numberOfBooks / (float)numberOfBooksInCell); 218 | 219 | NSInteger cellHeight = [_parentBookShelfView.dataSource cellHeightOfBookShelfView:_parentBookShelfView]; 220 | 221 | NSInteger minNumberOfCells = ceilf(_parentBookShelfView.bounds.size.height/ cellHeight); 222 | 223 | NSInteger maxNumberOfCells = MAX(numberOfCells, minNumberOfCells); 224 | 225 | NSInteger firstNeededRow = MAX(0, floorf(CGRectGetMinY(availableRect) / cellHeight)); 226 | NSInteger lastNeededRow = MIN(maxNumberOfCells - 1, floorf(CGRectGetMaxY(availableRect) / cellHeight)); 227 | 228 | if (_firstVisibleRow == -1) { 229 | // First time 230 | for (NSInteger row = firstNeededRow; row <= lastNeededRow; row++) { 231 | // add firstTime 232 | [self addCellAtRow:row addType:ADD_TYPE_TAIL]; 233 | } 234 | } 235 | else { 236 | // Not first time 237 | 238 | if (lastNeededRow < _lastVisibleRow) { 239 | NSInteger rmFromRow = (_firstVisibleRow > lastNeededRow + 1) ? _firstVisibleRow : lastNeededRow + 1; 240 | for (NSInteger row = _lastVisibleRow; row >= rmFromRow; row--) { 241 | // rm from tail of the _visibleBookView 242 | // use reversed row to always remove at tile 243 | [self removeCellWithType:RM_TYPE_TAIL]; 244 | } 245 | } 246 | 247 | if (firstNeededRow < _firstVisibleRow) { 248 | NSInteger addToRow = (_firstVisibleRow - 1 < lastNeededRow) ? _firstVisibleRow - 1 : lastNeededRow; 249 | for (NSInteger row = addToRow; row >= firstNeededRow; row--) { 250 | // add to head of the _visibileBookView 251 | // use reversed row to always add to index 0 252 | [self addCellAtRow:row addType:ADD_TYPE_HEAD]; 253 | } 254 | } 255 | 256 | if (firstNeededRow > _firstVisibleRow) { 257 | NSInteger rmToRow = (_lastVisibleRow <= firstNeededRow - 1) ? _lastVisibleRow : firstNeededRow - 1; 258 | for (NSInteger row = _firstVisibleRow; row <= rmToRow; row++) { 259 | // rm from head 260 | [self removeCellWithType:RM_TYPE_HEAD]; 261 | } 262 | } 263 | 264 | 265 | if (lastNeededRow > _lastVisibleRow) { 266 | NSInteger addFromRow = (_lastVisibleRow + 1 > firstNeededRow) ? _lastVisibleRow + 1 : firstNeededRow; 267 | for (NSInteger row = addFromRow; row <= lastNeededRow; row++) { 268 | // add to tail 269 | [self addCellAtRow:row addType:ADD_TYPE_TAIL]; 270 | } 271 | } 272 | } 273 | 274 | //NSLog(@"visible count:%d", [_visibleCells count]); 275 | _firstVisibleRow = firstNeededRow; 276 | _lastVisibleRow = lastNeededRow; 277 | 278 | } 279 | 280 | - (void)layoutSubviews { 281 | // Do nothing here 282 | // use layoutSubviewsWithavailableRect: instead 283 | } 284 | 285 | #pragma mark - convert 286 | 287 | - (NSInteger)convertToIndexOfVisibleCellsFromRow:(NSInteger)row { 288 | return row - _firstVisibleRow; 289 | } 290 | 291 | #pragma mark - visible 292 | 293 | - (NSArray *)visibleCells { 294 | return _visibleCells; 295 | } 296 | 297 | - (UIView *)cellAtRow:(NSInteger)row { 298 | NSInteger indexOfVisible = [self convertToIndexOfVisibleCellsFromRow:row]; 299 | if (indexOfVisible < 0 || indexOfVisible >= [_visibleCells count]) { 300 | return nil; 301 | } 302 | return [_visibleCells objectAtIndex:indexOfVisible]; 303 | } 304 | 305 | @end 306 | -------------------------------------------------------------------------------- /BookShelf/Classes/BookShelf/Public/GSBookShelfView.m: -------------------------------------------------------------------------------- 1 | /* 2 | BookShelfView.m 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-2-22. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import "GSBookShelfView.h" 37 | #import "GSBookViewContainerView.h" 38 | #import "GSCellContainerView.h" 39 | #import 40 | 41 | @interface GSBookShelfView (Private) 42 | 43 | - (CGRect)visibleRect; 44 | - (void)resetContentSize; 45 | 46 | @end 47 | 48 | @implementation GSBookShelfView 49 | 50 | //@synthesize shelfViewDelegate = _shelfViewDelegate; 51 | @synthesize dataSource = _dataSource; 52 | @synthesize dragAndDropEnabled = _dragAndDropEnabled; 53 | @synthesize scrollWhileDragingEnabled = _scrollWhileDragingEnabled; 54 | @synthesize cellHeight = _cellHeight; 55 | @synthesize cellMargin = _cellMargin; 56 | @synthesize bookViewBottomOffset = _bookViewBottomOffset; 57 | @synthesize shelfShadowHeight = _shelfShadowHeight; 58 | @synthesize numberOfBooksInCell = _numberOfBooksInCell; 59 | 60 | @synthesize headerView = _headerView; 61 | @synthesize aboveTopView = _aboveTopView; 62 | @synthesize belowBottomView = _belowBottomView; 63 | 64 | // init 65 | 66 | - (id)initWithFrame:(CGRect)frame { 67 | self = [super initWithFrame:frame]; 68 | if (self) { 69 | 70 | [super setDelegate:self]; 71 | 72 | _orientationChangeFlag = 0; 73 | 74 | _dragAndDropEnabled = YES; 75 | _scrollWhileDragingEnabled = YES; 76 | 77 | _bookViewContainerView = [[GSBookViewContainerView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, 0)]; 78 | _bookViewContainerView.parentBookShelfView = self; 79 | 80 | _cellContainerView = [[GSCellContainerView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, 0)]; 81 | _cellContainerView.parentBookShelfView = self; 82 | 83 | //[_bookViewContainerView setBackgroundColor:[UIColor colorWithRed:1 green:0 blue:0 alpha:0.2]]; 84 | //[_cellContainerView setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:1 alpha:0.2]]; 85 | //[_bookViewContainerView.layer setBorderWidth:2.0]; 86 | //[_bookViewContainerView.layer setBorderColor:[[UIColor greenColor] CGColor]]; 87 | //[_cellContainerView.layer setBorderWidth:2.0]; 88 | //[_cellContainerView.layer setBorderColor:[[UIColor greenColor] CGColor]]; 89 | 90 | [self addSubview:_cellContainerView]; 91 | [self addSubview:_bookViewContainerView]; 92 | } 93 | return self; 94 | } 95 | 96 | - (void)didMoveToSuperview { 97 | [super didMoveToSuperview]; 98 | 99 | [self reloadData]; 100 | } 101 | 102 | #pragma mark - Accessors 103 | 104 | - (void)setDataSource:(id)dataSource { 105 | _dataSource = dataSource; 106 | if (![_dataSource respondsToSelector:@selector(bookShelfView:moveBookFromIndex:toIndex:)]) { 107 | _dragAndDropEnabled = NO; 108 | } 109 | } 110 | 111 | #pragma mark - Private Methods 112 | 113 | - (CGRect)visibleRect { 114 | // visibleRect for the two container views 115 | CGRect visibleRect = [self bounds]; 116 | CGFloat headerHeight = _headerView.frame.size.height; 117 | visibleRect.size.height -= fmaxf(headerHeight - visibleRect.origin.y, 0.0f); 118 | visibleRect.origin.y = fmaxf(visibleRect.origin.y - headerHeight, 0.0f); 119 | 120 | return visibleRect; 121 | } 122 | 123 | - (CGRect)availableRectFromVisibleRect:(CGRect)visibleRect { 124 | // Discussion: 125 | // visibleRect: the visible rect 126 | // availableRect: highter than the visible rect 127 | // increase size.height to not lost one cell when orientation change from portrait to landscape 128 | // this should be adjusted according to the cell height 129 | 130 | CGRect availableRect = visibleRect; 131 | CGFloat numberOfCellHeights = 1.0f; // how many cellHeight will be added, if set too high, moving a book with scroll may not be smooth. 132 | 133 | availableRect.size.height += fminf(self.contentSize.height - (availableRect.origin.y + availableRect.size.height), [_dataSource cellHeightOfBookShelfView:self] * numberOfCellHeights); 134 | 135 | return availableRect; 136 | } 137 | 138 | - (void)resetContentSize { 139 | NSLog(@"resetContentSize"); 140 | //NSLog(@"resetContentSize"); 141 | 142 | // Use the flowing code beteen /* */ to set a custom position for header 143 | /* 144 | CGFloat headerHeight = 44.0f; 145 | [_headerView setFrame:CGRectMake(0, _headerView.frame.size.height - headerHeight, _headerView.frame.size.width, _headerView.frame.size.height)]; 146 | */ 147 | CGFloat headerHeight = _headerView.frame.size.height; 148 | 149 | NSInteger numberOfBooks = [_dataSource numberOfBooksInBookShelfView:self]; 150 | 151 | _numberOfBooksInCell = [_dataSource numberOFBooksInCellOfBookShelfView:self]; 152 | 153 | _numberOfCells = ceilf((float)numberOfBooks / (float)_numberOfBooksInCell); 154 | 155 | CGRect bounds = [self bounds]; 156 | 157 | _minNumberOfCells = ceilf(bounds.size.height/ _cellHeight); 158 | 159 | 160 | _contentSizeHeight = MAX(_numberOfCells, _minNumberOfCells) * _cellHeight + headerHeight; 161 | 162 | CGPoint newOffset = self.contentOffset; 163 | if (newOffset.y + bounds.size.height > _contentSizeHeight) { 164 | newOffset.y = _contentSizeHeight - bounds.size.height; 165 | //newOffset = CGPointZero; 166 | } 167 | 168 | NSLog(@"new offset %@", NSStringFromCGPoint(newOffset)); 169 | //[UIView setAnimationsEnabled:NO]; 170 | //[self setContentOffset:newOffset animated:NO]; 171 | 172 | //NSLog(@"new offset %@", NSStringFromCGPoint(newOffset)); 173 | 174 | //[self setBounces:NO]; 175 | [self setContentSize:CGSizeMake(self.frame.size.width, _contentSizeHeight)]; 176 | //[UIView setAnimationsEnabled:YES]; 177 | //NSLog(@"setContentSize"); 178 | 179 | 180 | // Set Bounds For the two container view 181 | [_cellContainerView setFrame:CGRectMake(0, 0 + headerHeight, self.contentSize.width, self.contentSize.height - headerHeight)]; 182 | [_bookViewContainerView setFrame:CGRectMake(0, 0 + headerHeight, self.contentSize.width, self.contentSize.height - headerHeight)]; 183 | 184 | [_aboveTopView setFrame:CGRectMake(0, -_aboveTopView.frame.size.height, _aboveTopView.frame.size.width, _aboveTopView.frame.size.height)]; 185 | 186 | [_belowBottomView setFrame:CGRectMake(0, self.contentSize.height, _belowBottomView.frame.size.width, _belowBottomView.frame.size.height)]; 187 | 188 | //NSLog(@"cellContainerView frame:%@", NSStringFromCGRect(_cellContainerView.frame)); 189 | } 190 | 191 | - (void)resetContentOffset { 192 | CGFloat headerHeight = _headerView.frame.size.height; 193 | CGPoint offset = CGPointMake(0, headerHeight); 194 | [self setContentOffset:offset]; 195 | } 196 | 197 | - (void)adjustContentOffset { 198 | CGPoint newOffset = self.contentOffset; 199 | CGRect bounds = [self bounds]; 200 | if (newOffset.y + bounds.size.height > _contentSizeHeight) { 201 | newOffset.y = _contentSizeHeight - bounds.size.height; 202 | } 203 | [self setContentOffset:newOffset animated:NO]; 204 | } 205 | 206 | #pragma mark - Layout 207 | 208 | - (void)layoutSubviews { 209 | //NSLog(@"layout"); 210 | [super layoutSubviews]; 211 | 212 | if (_orientationChangeFlag) { 213 | _orientationChangeFlag = 0; 214 | [_cellContainerView reloadData]; 215 | [_bookViewContainerView reloadData]; 216 | [self resetContentSize]; 217 | } 218 | 219 | CGRect visibleRect = [self visibleRect]; 220 | CGRect availableRect = [self availableRectFromVisibleRect:visibleRect]; 221 | 222 | [_bookViewContainerView layoutSubviewsWithAvailableRect:availableRect visibleRect:visibleRect]; 223 | [_cellContainerView layoutSubviewsWithAvailableRect:availableRect]; 224 | } 225 | 226 | #pragma mark - Public 227 | 228 | - (void)didFinshRotation { 229 | [_cellContainerView resizeReuseCells]; 230 | } 231 | 232 | - (void)oritationChangeReloadData { 233 | // RETURN HERE!!! 234 | _orientationChangeFlag = 1; 235 | return; 236 | /* 237 | // remove these views first, set new and then add back 238 | [_headerView removeFromSuperview]; 239 | [_aboveTopView removeFromSuperview]; 240 | [_belowBottomView removeFromSuperview]; 241 | 242 | _headerView = [_dataSource headerViewOfBookShelfView:self]; 243 | _aboveTopView = [_dataSource aboveTopViewOfBookShelfView:self]; 244 | _belowBottomView = [_dataSource belowBottomViewOfBookShelfView:self]; 245 | 246 | [self insertSubview:_headerView atIndex:0]; 247 | [self insertSubview:_aboveTopView atIndex:0]; 248 | [self insertSubview:_belowBottomView atIndex:0]; 249 | 250 | _cellHeight = [_dataSource cellHeightOfBookShelfView:self]; 251 | _cellMargin = [_dataSource cellMarginOfBookShelfView:self]; 252 | _bookViewBottomOffset = [_dataSource bookViewBottomOffsetOfBookShelfView:self]; 253 | 254 | //[_cellContainerView reloadData]; 255 | [_cellContainerView orientationResetReuse]; 256 | [_bookViewContainerView reloadData]; 257 | [self resetContentSize]; 258 | //[self adjustContentOffset]; 259 | //[self setNeedsLayout]; 260 | */ 261 | } 262 | 263 | - (void)reloadData { 264 | // remove these views first, set new and then add back 265 | [_headerView removeFromSuperview]; 266 | [_aboveTopView removeFromSuperview]; 267 | [_belowBottomView removeFromSuperview]; 268 | 269 | _headerView = [_dataSource headerViewOfBookShelfView:self]; 270 | _aboveTopView = [_dataSource aboveTopViewOfBookShelfView:self]; 271 | _belowBottomView = [_dataSource belowBottomViewOfBookShelfView:self]; 272 | 273 | [self insertSubview:_headerView atIndex:0]; 274 | [self insertSubview:_aboveTopView atIndex:0]; 275 | [self insertSubview:_belowBottomView atIndex:0]; 276 | 277 | _cellHeight = [_dataSource cellHeightOfBookShelfView:self]; 278 | _cellMargin = [_dataSource cellMarginOfBookShelfView:self]; 279 | _bookViewBottomOffset = [_dataSource bookViewBottomOffsetOfBookShelfView:self]; 280 | 281 | [_cellContainerView reloadData]; 282 | [_bookViewContainerView reloadData]; 283 | [self resetContentSize]; 284 | [self resetContentOffset]; 285 | [self setNeedsLayout]; 286 | } 287 | 288 | - (UIView *)dequeueReuseableBookViewWithIdentifier:(NSString *)identifier { 289 | return [_bookViewContainerView dequeueReusableBookViewWithIdentifier:identifier]; 290 | } 291 | 292 | - (UIView *)dequeueReuseableCellViewWithIdentifier:(NSString *)identifier { 293 | return [_cellContainerView dequeueReuseableCellWithIdentifier:identifier]; 294 | } 295 | 296 | - (void)scrollToRow:(NSInteger)row animate:(BOOL)animate { 297 | CGFloat headerHeight = _headerView.frame.size.height; 298 | 299 | row = MAX(row, 0); 300 | row = MIN(row, _numberOfCells - 1); 301 | 302 | CGRect bounds = [self bounds]; 303 | 304 | CGPoint newOffset = CGPointMake(0, row * _cellHeight + headerHeight); 305 | 306 | if (newOffset.y + bounds.size.height > _contentSizeHeight) { 307 | newOffset.y = _contentSizeHeight - bounds.size.height; 308 | } 309 | 310 | [self setContentOffset:newOffset animated:animate]; 311 | } 312 | 313 | - (void)removeBookViewsAtIndexs:(NSIndexSet *)indexs animate:(BOOL)animate; { 314 | [self resetContentSize]; 315 | CGPoint contentOffset = [self contentOffset]; 316 | if (contentOffset.y + self.bounds.size.height > self.contentSize.height) { 317 | contentOffset.y = self.contentSize.height - self.bounds.size.height; 318 | } 319 | [self setContentOffset:contentOffset animated:NO]; 320 | [_bookViewContainerView removeBookViewsAtIndexs:indexs animate:animate]; 321 | } 322 | 323 | - (void)insertBookViewsAtIndexs:(NSIndexSet *)indexs animate:(BOOL)animate { 324 | 325 | [self resetContentSize]; 326 | [_bookViewContainerView insertBookViewsAtIndexs:indexs animate:animate]; 327 | } 328 | 329 | - (NSArray *)visibleBookViews { 330 | return [_bookViewContainerView visibleBookViews]; 331 | } 332 | 333 | - (NSArray *)visibleCells { 334 | return [_cellContainerView visibleCells]; 335 | } 336 | 337 | - (UIView *)bookViewAtIndex:(NSInteger)index { 338 | return [_bookViewContainerView bookViewAtIndex:index]; 339 | } 340 | 341 | - (UIView *)cellAtRow:(NSInteger)row { 342 | return [_cellContainerView cellAtRow:row]; 343 | } 344 | 345 | #pragma mark - test code 346 | 347 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView { 348 | //NSLog(@"****%@", NSStringFromCGPoint(self.contentOffset)); 349 | } 350 | 351 | 352 | 353 | @end 354 | -------------------------------------------------------------------------------- /BookShelf/Classes/Demo/ViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | ViewController.m 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-2-22. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import "ViewController.h" 37 | 38 | #import "MyCellView.h" 39 | #import "MyBookView.h" 40 | #import "BookShelfCellView.h" 41 | #import "BelowBottomView.h" 42 | #import "MyBelowBottomView.h" 43 | #import 44 | 45 | #define CELL_HEIGHT 139.0f 46 | 47 | @implementation ViewController 48 | 49 | - (void)didReceiveMemoryWarning 50 | { 51 | [super didReceiveMemoryWarning]; 52 | // Release any cached data, images, etc that aren't in use. 53 | } 54 | 55 | - (void)initBooks { 56 | NSInteger numberOfBooks = 100; 57 | _bookArray = [[NSMutableArray alloc] initWithCapacity:numberOfBooks]; 58 | _bookStatus = [[NSMutableArray alloc] initWithCapacity:numberOfBooks]; 59 | for (int i = 0; i < numberOfBooks; i++) { 60 | NSNumber *number = [NSNumber numberWithInt:i % 4 + 1]; 61 | [_bookArray addObject:number]; 62 | [_bookStatus addObject:[NSNumber numberWithInt:BOOK_UNSELECTED]]; 63 | } 64 | 65 | _booksIndexsToBeRemoved = [NSMutableIndexSet indexSet]; 66 | } 67 | 68 | - (void)initBarButtons { 69 | _editBarButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(editButtonClicked:)]; 70 | _cancleBarButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancleButtonClicked:)]; 71 | 72 | _trashBarButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(trashButtonClicked:)]; 73 | _addBarButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addButtonClicked:)]; 74 | } 75 | 76 | - (void)switchToNormalMode { 77 | _editMode = NO; 78 | 79 | [self.navigationItem setLeftBarButtonItem:_editBarButton]; 80 | [self.navigationItem setRightBarButtonItem:_addBarButton]; 81 | } 82 | 83 | - (void)switchToEditMode { 84 | _editMode = YES; 85 | [_booksIndexsToBeRemoved removeAllIndexes]; 86 | [self.navigationItem setLeftBarButtonItem:_cancleBarButton]; 87 | [self.navigationItem setRightBarButtonItem:_trashBarButton]; 88 | 89 | for (int i = 0; i < [_bookArray count]; i++) { 90 | [_bookStatus addObject:[NSNumber numberWithInt:BOOK_UNSELECTED]]; 91 | } 92 | 93 | for (MyBookView *bookView in [_bookShelfView visibleBookViews]) { 94 | [bookView setSelected:NO]; 95 | } 96 | } 97 | 98 | #pragma mark - View lifecycle 99 | 100 | - (void)testScrollToRow { 101 | [_bookShelfView scrollToRow:34 animate:YES]; 102 | } 103 | 104 | - (void)viewDidLoad 105 | { 106 | [super viewDidLoad]; 107 | 108 | [self initBarButtons]; 109 | [self switchToNormalMode]; 110 | 111 | [self initBooks]; 112 | 113 | //AboveTopView *aboveTop = [[AboveTopView alloc] initWithFrame:CGRectMake(0, 0, 320, 164)]; 114 | _searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)]; 115 | [_searchBar setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 116 | _belowBottomView = [[BelowBottomView alloc] initWithFrame:CGRectMake(0, 0, 320, CELL_HEIGHT * 2)]; 117 | [_belowBottomView setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 118 | //[_belowBottomView.layer setBorderWidth:2.0]; 119 | //[_belowBottomView.layer setBorderColor:[[UIColor greenColor] CGColor]]; 120 | 121 | //MyBelowBottomView *belowBottom = [[MyBelowBottomView alloc] initWithFrame:CGRectMake(0, 0, 320, CELL_HEIGHT * 2)]; 122 | 123 | _bookShelfView = [[GSBookShelfView alloc] initWithFrame:CGRectMake(0, 0, 320, 460 - 44)]; 124 | [_bookShelfView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; 125 | [_bookShelfView setDataSource:self]; 126 | //[_bookShelfView.layer setBorderWidth:2.0]; 127 | //[_bookShelfView.layer setBorderColor:[[UIColor greenColor] CGColor]]; 128 | //[_bookShelfView setShelfViewDelegate:self]; 129 | 130 | [self.view addSubview:_bookShelfView]; 131 | 132 | //[self performSelector:@selector(testScrollToRow) withObject:self afterDelay:3]; 133 | } 134 | 135 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { 136 | return YES; 137 | } 138 | 139 | - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { 140 | // TODO:only set orientation change flag when protrait to landscape and reverse 141 | [_bookShelfView oritationChangeReloadData]; 142 | } 143 | 144 | - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { 145 | NSLog(@"will animate rotate"); 146 | /*if (UIDeviceOrientationIsLandscape(toInterfaceOrientation)) { 147 | [_bookShelfView setFrame:CGRectMake(0, 0, 480, 320 - 44)]; 148 | } 149 | else { 150 | [_bookShelfView setFrame:CGRectMake(0, 0, 320, 460 - 44)]; 151 | }*/ 152 | NSLog(@"bookShelfViewFrame:%@", NSStringFromCGRect(_bookShelfView.frame)); 153 | //[_bookShelfView reloadData]; 154 | //[_bookShelfView oritationChangeReloadData]; 155 | } 156 | 157 | - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { 158 | NSLog(@"didRotate"); 159 | NSLog(@"bookShelfViewFrame:%@", NSStringFromCGRect(_bookShelfView.frame)); 160 | [_bookShelfView didFinshRotation]; 161 | /*for (UIView *cell in [_bookShelfView visibleCells]) { 162 | CGRect frame = cell.frame; 163 | [cell.layer setAnchorPoint:CGPointMake(0.5, 0.5)]; 164 | [cell setFrame:frame]; 165 | }*/ 166 | } 167 | 168 | #pragma mark GSBookShelfViewDataSource 169 | 170 | - (NSInteger)numberOfBooksInBookShelfView:(GSBookShelfView *)bookShelfView { 171 | return [_bookArray count]; 172 | } 173 | 174 | - (NSInteger)numberOFBooksInCellOfBookShelfView:(GSBookShelfView *)bookShelfView { 175 | UIDeviceOrientation orientation = [UIDevice currentDevice].orientation; 176 | if (UIDeviceOrientationIsLandscape(orientation)) { 177 | return 4; 178 | } 179 | else { 180 | return 3; 181 | } 182 | } 183 | 184 | - (UIView *)bookShelfView:(GSBookShelfView *)bookShelfView bookViewAtIndex:(NSInteger)index { 185 | static NSString *identifier = @"bookView"; 186 | MyBookView *bookView = (MyBookView *)[bookShelfView dequeueReuseableBookViewWithIdentifier:identifier]; 187 | if (bookView == nil) { 188 | bookView = [[MyBookView alloc] initWithFrame:CGRectZero]; 189 | bookView.reuseIdentifier = identifier; 190 | [bookView addTarget:self action:@selector(bookViewClicked:) forControlEvents:UIControlEventTouchUpInside]; 191 | } 192 | [bookView setIndex:index]; 193 | [bookView setSelected:[(NSNumber *)[_bookStatus objectAtIndex:index] intValue]]; 194 | int imageNO = [(NSNumber *)[_bookArray objectAtIndex:index] intValue]; 195 | [bookView setBackgroundImage:[UIImage imageNamed:[NSString stringWithFormat:@"%d.png", imageNO]] forState:UIControlStateNormal]; 196 | return bookView; 197 | } 198 | 199 | - (UIView *)bookShelfView:(GSBookShelfView *)bookShelfView cellForRow:(NSInteger)row { 200 | static NSString *identifier = @"cell"; 201 | /*MyCellView *cellView = (MyCellView *)[bookShelfView dequeueReuseableCellViewWithIdentifier:identifier]; 202 | if (cellView == nil) { 203 | cellView = [[MyCellView alloc] initWithFrame:CGRectZero]; 204 | cellView.reuseIdentifier = identifier; 205 | [cellView.layer setBorderColor:[[UIColor redColor] CGColor]]; 206 | [cellView.layer setBorderWidth:2.0f]; 207 | } 208 | [cellView.label setText:[NSString stringWithFormat:@"row:%d", row]]; 209 | return cellView;*/ 210 | 211 | BookShelfCellView *cellView = (BookShelfCellView *)[bookShelfView dequeueReuseableCellViewWithIdentifier:identifier]; 212 | if (cellView == nil) { 213 | cellView = [[BookShelfCellView alloc] initWithFrame:CGRectZero]; 214 | [cellView setReuseIdentifier:identifier]; 215 | //[cellView.layer setBorderColor:[[UIColor redColor] CGColor]]; 216 | //[cellView.layer setBorderWidth:2.0f]; 217 | } 218 | return cellView; 219 | } 220 | 221 | - (UIView *)aboveTopViewOfBookShelfView:(GSBookShelfView *)bookShelfView { 222 | return nil; 223 | } 224 | 225 | - (UIView *)belowBottomViewOfBookShelfView:(GSBookShelfView *)bookShelfView { 226 | return _belowBottomView; 227 | } 228 | 229 | - (UIView *)headerViewOfBookShelfView:(GSBookShelfView *)bookShelfView { 230 | return _searchBar; 231 | } 232 | 233 | - (CGFloat)cellHeightOfBookShelfView:(GSBookShelfView *)bookShelfView { 234 | return CELL_HEIGHT; 235 | } 236 | 237 | - (CGFloat)cellMarginOfBookShelfView:(GSBookShelfView *)bookShelfView { 238 | return 20.0f; 239 | } 240 | 241 | - (CGFloat)bookViewHeightOfBookShelfView:(GSBookShelfView *)bookShelfView { 242 | return 88.0f; 243 | } 244 | 245 | - (CGFloat)bookViewWidthOfBookShelfView:(GSBookShelfView *)bookShelfView { 246 | return 74.0f; 247 | } 248 | 249 | - (CGFloat)bookViewBottomOffsetOfBookShelfView:(GSBookShelfView *)bookShelfView { 250 | return 123.0f; 251 | } 252 | 253 | - (CGFloat)cellShadowHeightOfBookShelfView:(GSBookShelfView *)bookShelfView { 254 | //return 0.0f; 255 | return 55.0f; 256 | } 257 | 258 | - (void)bookShelfView:(GSBookShelfView *)bookShelfView moveBookFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex { 259 | if ([(NSNumber *)[_bookStatus objectAtIndex:fromIndex] intValue] == BOOK_SELECTED) { 260 | [_booksIndexsToBeRemoved removeIndex:fromIndex]; 261 | [_booksIndexsToBeRemoved addIndex:toIndex]; 262 | } 263 | 264 | [_bookArray moveObjectFromIndex:fromIndex toIndex:toIndex]; 265 | [_bookStatus moveObjectFromIndex:fromIndex toIndex:toIndex]; 266 | 267 | // the bookview is recognized by index in the demo, so change all the indexes of affected bookViews here 268 | // This is just a example, not a good one.In your code, you'd better use a key to recognize the bookView. 269 | // and you won't need to do the following 270 | MyBookView *bookView; 271 | bookView = (MyBookView *)[_bookShelfView bookViewAtIndex:toIndex]; 272 | [bookView setIndex:toIndex]; 273 | if (fromIndex <= toIndex) { 274 | for (int i = fromIndex; i < toIndex; i++) { 275 | bookView = (MyBookView *)[_bookShelfView bookViewAtIndex:i]; 276 | [bookView setIndex:bookView.index - 1]; 277 | } 278 | } 279 | else { 280 | for (int i = toIndex + 1; i <= fromIndex; i++) { 281 | bookView = (MyBookView *)[_bookShelfView bookViewAtIndex:i]; 282 | [bookView setIndex:bookView.index + 1]; 283 | } 284 | } 285 | } 286 | 287 | #pragma mark - BarButtonListener 288 | 289 | - (void)editButtonClicked:(id)sender { 290 | [self switchToEditMode]; 291 | } 292 | 293 | - (void)cancleButtonClicked:(id)sender { 294 | [self switchToNormalMode]; 295 | } 296 | 297 | - (void)trashButtonClicked:(id)sender { 298 | [_bookArray removeObjectsAtIndexes:_booksIndexsToBeRemoved]; 299 | [_bookStatus removeObjectsAtIndexes:_booksIndexsToBeRemoved]; 300 | [_bookShelfView removeBookViewsAtIndexs:_booksIndexsToBeRemoved animate:YES]; 301 | [self switchToNormalMode]; 302 | } 303 | 304 | - (void)addButtonClicked:(id)sender { 305 | int a[6] = {1, 2, 5, 7, 9, 22}; 306 | NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet]; 307 | NSMutableArray *arr = [NSMutableArray array]; 308 | NSMutableArray *stat = [NSMutableArray array]; 309 | for (int i = 0; i < 6; i++) { 310 | [indexSet addIndex:a[i]]; 311 | [arr addObject:[NSNumber numberWithInt:1]]; 312 | [stat addObject:[NSNumber numberWithInt:BOOK_UNSELECTED]]; 313 | } 314 | [_bookArray insertObjects:arr atIndexes:indexSet]; 315 | [_bookStatus insertObjects:stat atIndexes:indexSet]; 316 | [_bookShelfView insertBookViewsAtIndexs:indexSet animate:YES]; 317 | } 318 | 319 | #pragma mark - BookView Listener 320 | 321 | - (void)bookViewClicked:(UIButton *)button { 322 | MyBookView *bookView = (MyBookView *)button; 323 | 324 | if (_editMode) { 325 | NSNumber *status = [NSNumber numberWithInt:bookView.selected]; 326 | [_bookStatus replaceObjectAtIndex:bookView.index withObject:status]; 327 | 328 | if (bookView.selected) { 329 | [_booksIndexsToBeRemoved addIndex:bookView.index]; 330 | } 331 | else { 332 | [_booksIndexsToBeRemoved removeIndex:bookView.index]; 333 | } 334 | } 335 | else { 336 | [bookView setSelected:NO]; 337 | } 338 | } 339 | 340 | @end 341 | -------------------------------------------------------------------------------- /BookShelf.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C15549FD150B90D800D0F3E6 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C15549FC150B90D800D0F3E6 /* QuartzCore.framework */; }; 11 | C182834616633FB600A69C46 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = C182834516633FB600A69C46 /* LICENSE */; }; 12 | C1D6739B14F4D247006D3483 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1D6739A14F4D247006D3483 /* UIKit.framework */; }; 13 | C1D6739D14F4D247006D3483 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1D6739C14F4D247006D3483 /* Foundation.framework */; }; 14 | C1D6739F14F4D247006D3483 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1D6739E14F4D247006D3483 /* CoreGraphics.framework */; }; 15 | FA928C8016DFA0E800D29550 /* GSBookViewContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = FA928C3A16DFA0E800D29550 /* GSBookViewContainerView.m */; }; 16 | FA928C8116DFA0E800D29550 /* GSCellContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = FA928C3C16DFA0E800D29550 /* GSCellContainerView.m */; }; 17 | FA928C8216DFA0E800D29550 /* GSBookShelfView.m in Sources */ = {isa = PBXBuildFile; fileRef = FA928C4016DFA0E800D29550 /* GSBookShelfView.m */; }; 18 | FA928C8316DFA0E800D29550 /* NSMutableArray+Rearrange.m in Sources */ = {isa = PBXBuildFile; fileRef = FA928C4416DFA0E800D29550 /* NSMutableArray+Rearrange.m */; }; 19 | FA928C8416DFA0E800D29550 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FA928C4716DFA0E800D29550 /* AppDelegate.m */; }; 20 | FA928C8516DFA0E800D29550 /* BelowBottomView.m in Sources */ = {isa = PBXBuildFile; fileRef = FA928C4916DFA0E800D29550 /* BelowBottomView.m */; }; 21 | FA928C8616DFA0E800D29550 /* BookShelfCellView.m in Sources */ = {isa = PBXBuildFile; fileRef = FA928C4B16DFA0E800D29550 /* BookShelfCellView.m */; }; 22 | FA928C8716DFA0E800D29550 /* MyBookView.m in Sources */ = {isa = PBXBuildFile; fileRef = FA928C4D16DFA0E800D29550 /* MyBookView.m */; }; 23 | FA928C8816DFA0E800D29550 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FA928C4F16DFA0E800D29550 /* ViewController.m */; }; 24 | FA928C8916DFA0E800D29550 /* AboveTopView.m in Sources */ = {isa = PBXBuildFile; fileRef = FA928C5216DFA0E800D29550 /* AboveTopView.m */; }; 25 | FA928C8A16DFA0E800D29550 /* BookView.m in Sources */ = {isa = PBXBuildFile; fileRef = FA928C5416DFA0E800D29550 /* BookView.m */; }; 26 | FA928C8B16DFA0E800D29550 /* MyBelowBottomView.m in Sources */ = {isa = PBXBuildFile; fileRef = FA928C5616DFA0E800D29550 /* MyBelowBottomView.m */; }; 27 | FA928C8C16DFA0E800D29550 /* MyCellView.m in Sources */ = {isa = PBXBuildFile; fileRef = FA928C5816DFA0E800D29550 /* MyCellView.m */; }; 28 | FA928C8D16DFA0E800D29550 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = FA928C5B16DFA0E800D29550 /* main.m */; }; 29 | FA928C8F16DFA0E800D29550 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FA928C5E16DFA0E800D29550 /* InfoPlist.strings */; }; 30 | FA928C9016DFA0E800D29550 /* ViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = FA928C6016DFA0E800D29550 /* ViewController.xib */; }; 31 | FA928C9116DFA0E800D29550 /* 1.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C6316DFA0E800D29550 /* 1.png */; }; 32 | FA928C9216DFA0E800D29550 /* 1@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C6416DFA0E800D29550 /* 1@2x.png */; }; 33 | FA928C9316DFA0E800D29550 /* 2.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C6516DFA0E800D29550 /* 2.png */; }; 34 | FA928C9416DFA0E800D29550 /* 2@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C6616DFA0E800D29550 /* 2@2x.png */; }; 35 | FA928C9516DFA0E800D29550 /* 3.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C6716DFA0E800D29550 /* 3.png */; }; 36 | FA928C9616DFA0E800D29550 /* 3@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C6816DFA0E800D29550 /* 3@2x.png */; }; 37 | FA928C9716DFA0E800D29550 /* 4.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C6916DFA0E800D29550 /* 4.png */; }; 38 | FA928C9816DFA0E800D29550 /* 4@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C6A16DFA0E800D29550 /* 4@2x.png */; }; 39 | FA928C9916DFA0E800D29550 /* BookShelfCell.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C6B16DFA0E800D29550 /* BookShelfCell.png */; }; 40 | FA928C9A16DFA0E800D29550 /* BookShelfCell@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C6C16DFA0E800D29550 /* BookShelfCell@2x.png */; }; 41 | FA928C9B16DFA0E800D29550 /* BookViewChecked.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C6D16DFA0E800D29550 /* BookViewChecked.png */; }; 42 | FA928C9C16DFA0E800D29550 /* BookViewChecked@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C6E16DFA0E800D29550 /* BookViewChecked@2x.png */; }; 43 | FA928C9D16DFA0E800D29550 /* comments.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C6F16DFA0E800D29550 /* comments.png */; }; 44 | FA928C9E16DFA0E800D29550 /* NavBar-Landscape@2x~iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C7216DFA0E800D29550 /* NavBar-Landscape@2x~iphone.png */; }; 45 | FA928C9F16DFA0E800D29550 /* NavBar-Landscape~iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C7316DFA0E800D29550 /* NavBar-Landscape~iphone.png */; }; 46 | FA928CA016DFA0E800D29550 /* NavBar@2x~iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C7416DFA0E800D29550 /* NavBar@2x~iphone.png */; }; 47 | FA928CA116DFA0E800D29550 /* NavBar~iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C7516DFA0E800D29550 /* NavBar~iphone.png */; }; 48 | FA928CA216DFA0E800D29550 /* Shelf-Landscape@2x~iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C7616DFA0E800D29550 /* Shelf-Landscape@2x~iphone.png */; }; 49 | FA928CA316DFA0E800D29550 /* Shelf-Landscape~iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C7716DFA0E800D29550 /* Shelf-Landscape~iphone.png */; }; 50 | FA928CA416DFA0E800D29550 /* Shelf@2x~iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C7816DFA0E800D29550 /* Shelf@2x~iphone.png */; }; 51 | FA928CA516DFA0E800D29550 /* Shelf~iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C7916DFA0E800D29550 /* Shelf~iphone.png */; }; 52 | FA928CA616DFA0E800D29550 /* Side Shading-iPhone.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C7A16DFA0E800D29550 /* Side Shading-iPhone.png */; }; 53 | FA928CA716DFA0E800D29550 /* Side Shading-iPhone@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C7B16DFA0E800D29550 /* Side Shading-iPhone@2x.png */; }; 54 | FA928CA816DFA0E800D29550 /* topshelf side shading-iPhone.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C7C16DFA0E800D29550 /* topshelf side shading-iPhone.png */; }; 55 | FA928CA916DFA0E800D29550 /* topshelf side shading-iPhone@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C7D16DFA0E800D29550 /* topshelf side shading-iPhone@2x.png */; }; 56 | FA928CAA16DFA0E800D29550 /* WoodTile@2x~iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C7E16DFA0E800D29550 /* WoodTile@2x~iphone.png */; }; 57 | FA928CAB16DFA0E800D29550 /* WoodTile~iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928C7F16DFA0E800D29550 /* WoodTile~iphone.png */; }; 58 | FA928CAF16DFA15800D29550 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928CAE16DFA15800D29550 /* Default-568h@2x.png */; }; 59 | FA928CB216DFA1C700D29550 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928CB016DFA1C700D29550 /* Default.png */; }; 60 | FA928CB316DFA1C700D29550 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FA928CB116DFA1C700D29550 /* Default@2x.png */; }; 61 | /* End PBXBuildFile section */ 62 | 63 | /* Begin PBXFileReference section */ 64 | C1539F4C1510C76A00C6A479 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = ""; }; 65 | C15549FC150B90D800D0F3E6 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 66 | C182834516633FB600A69C46 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 67 | C1D6739614F4D247006D3483 /* BookShelf.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BookShelf.app; sourceTree = BUILT_PRODUCTS_DIR; }; 68 | C1D6739A14F4D247006D3483 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 69 | C1D6739C14F4D247006D3483 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 70 | C1D6739E14F4D247006D3483 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 71 | FA928C3916DFA0E800D29550 /* GSBookViewContainerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GSBookViewContainerView.h; sourceTree = ""; }; 72 | FA928C3A16DFA0E800D29550 /* GSBookViewContainerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GSBookViewContainerView.m; sourceTree = ""; }; 73 | FA928C3B16DFA0E800D29550 /* GSCellContainerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GSCellContainerView.h; sourceTree = ""; }; 74 | FA928C3C16DFA0E800D29550 /* GSCellContainerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GSCellContainerView.m; sourceTree = ""; }; 75 | FA928C3E16DFA0E800D29550 /* GSBookShelfCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GSBookShelfCell.h; sourceTree = ""; }; 76 | FA928C3F16DFA0E800D29550 /* GSBookShelfView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GSBookShelfView.h; sourceTree = ""; }; 77 | FA928C4016DFA0E800D29550 /* GSBookShelfView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GSBookShelfView.m; sourceTree = ""; }; 78 | FA928C4116DFA0E800D29550 /* GSBookView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GSBookView.h; sourceTree = ""; }; 79 | FA928C4316DFA0E800D29550 /* NSMutableArray+Rearrange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableArray+Rearrange.h"; sourceTree = ""; }; 80 | FA928C4416DFA0E800D29550 /* NSMutableArray+Rearrange.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableArray+Rearrange.m"; sourceTree = ""; }; 81 | FA928C4616DFA0E800D29550 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 82 | FA928C4716DFA0E800D29550 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 83 | FA928C4816DFA0E800D29550 /* BelowBottomView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BelowBottomView.h; sourceTree = ""; }; 84 | FA928C4916DFA0E800D29550 /* BelowBottomView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BelowBottomView.m; sourceTree = ""; }; 85 | FA928C4A16DFA0E800D29550 /* BookShelfCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BookShelfCellView.h; sourceTree = ""; }; 86 | FA928C4B16DFA0E800D29550 /* BookShelfCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BookShelfCellView.m; sourceTree = ""; }; 87 | FA928C4C16DFA0E800D29550 /* MyBookView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyBookView.h; sourceTree = ""; }; 88 | FA928C4D16DFA0E800D29550 /* MyBookView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MyBookView.m; sourceTree = ""; }; 89 | FA928C4E16DFA0E800D29550 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 90 | FA928C4F16DFA0E800D29550 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 91 | FA928C5116DFA0E800D29550 /* AboveTopView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AboveTopView.h; sourceTree = ""; }; 92 | FA928C5216DFA0E800D29550 /* AboveTopView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AboveTopView.m; sourceTree = ""; }; 93 | FA928C5316DFA0E800D29550 /* BookView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BookView.h; sourceTree = ""; }; 94 | FA928C5416DFA0E800D29550 /* BookView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BookView.m; sourceTree = ""; }; 95 | FA928C5516DFA0E800D29550 /* MyBelowBottomView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyBelowBottomView.h; sourceTree = ""; }; 96 | FA928C5616DFA0E800D29550 /* MyBelowBottomView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MyBelowBottomView.m; sourceTree = ""; }; 97 | FA928C5716DFA0E800D29550 /* MyCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyCellView.h; sourceTree = ""; }; 98 | FA928C5816DFA0E800D29550 /* MyCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MyCellView.m; sourceTree = ""; }; 99 | FA928C5A16DFA0E800D29550 /* BookShelf-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "BookShelf-Prefix.pch"; sourceTree = ""; }; 100 | FA928C5B16DFA0E800D29550 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 101 | FA928C5D16DFA0E800D29550 /* BookShelf-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "BookShelf-Info.plist"; sourceTree = ""; }; 102 | FA928C5F16DFA0E800D29550 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 103 | FA928C6116DFA0E800D29550 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/ViewController.xib; sourceTree = ""; }; 104 | FA928C6316DFA0E800D29550 /* 1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = 1.png; sourceTree = ""; }; 105 | FA928C6416DFA0E800D29550 /* 1@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "1@2x.png"; sourceTree = ""; }; 106 | FA928C6516DFA0E800D29550 /* 2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = 2.png; sourceTree = ""; }; 107 | FA928C6616DFA0E800D29550 /* 2@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "2@2x.png"; sourceTree = ""; }; 108 | FA928C6716DFA0E800D29550 /* 3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = 3.png; sourceTree = ""; }; 109 | FA928C6816DFA0E800D29550 /* 3@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "3@2x.png"; sourceTree = ""; }; 110 | FA928C6916DFA0E800D29550 /* 4.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = 4.png; sourceTree = ""; }; 111 | FA928C6A16DFA0E800D29550 /* 4@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "4@2x.png"; sourceTree = ""; }; 112 | FA928C6B16DFA0E800D29550 /* BookShelfCell.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = BookShelfCell.png; sourceTree = ""; }; 113 | FA928C6C16DFA0E800D29550 /* BookShelfCell@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "BookShelfCell@2x.png"; sourceTree = ""; }; 114 | FA928C6D16DFA0E800D29550 /* BookViewChecked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = BookViewChecked.png; sourceTree = ""; }; 115 | FA928C6E16DFA0E800D29550 /* BookViewChecked@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "BookViewChecked@2x.png"; sourceTree = ""; }; 116 | FA928C6F16DFA0E800D29550 /* comments.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = comments.png; sourceTree = ""; }; 117 | FA928C7216DFA0E800D29550 /* NavBar-Landscape@2x~iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NavBar-Landscape@2x~iphone.png"; sourceTree = ""; }; 118 | FA928C7316DFA0E800D29550 /* NavBar-Landscape~iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NavBar-Landscape~iphone.png"; sourceTree = ""; }; 119 | FA928C7416DFA0E800D29550 /* NavBar@2x~iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NavBar@2x~iphone.png"; sourceTree = ""; }; 120 | FA928C7516DFA0E800D29550 /* NavBar~iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "NavBar~iphone.png"; sourceTree = ""; }; 121 | FA928C7616DFA0E800D29550 /* Shelf-Landscape@2x~iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Shelf-Landscape@2x~iphone.png"; sourceTree = ""; }; 122 | FA928C7716DFA0E800D29550 /* Shelf-Landscape~iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Shelf-Landscape~iphone.png"; sourceTree = ""; }; 123 | FA928C7816DFA0E800D29550 /* Shelf@2x~iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Shelf@2x~iphone.png"; sourceTree = ""; }; 124 | FA928C7916DFA0E800D29550 /* Shelf~iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Shelf~iphone.png"; sourceTree = ""; }; 125 | FA928C7A16DFA0E800D29550 /* Side Shading-iPhone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Side Shading-iPhone.png"; sourceTree = ""; }; 126 | FA928C7B16DFA0E800D29550 /* Side Shading-iPhone@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Side Shading-iPhone@2x.png"; sourceTree = ""; }; 127 | FA928C7C16DFA0E800D29550 /* topshelf side shading-iPhone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "topshelf side shading-iPhone.png"; sourceTree = ""; }; 128 | FA928C7D16DFA0E800D29550 /* topshelf side shading-iPhone@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "topshelf side shading-iPhone@2x.png"; sourceTree = ""; }; 129 | FA928C7E16DFA0E800D29550 /* WoodTile@2x~iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WoodTile@2x~iphone.png"; sourceTree = ""; }; 130 | FA928C7F16DFA0E800D29550 /* WoodTile~iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "WoodTile~iphone.png"; sourceTree = ""; }; 131 | FA928CAE16DFA15800D29550 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 132 | FA928CB016DFA1C700D29550 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; 133 | FA928CB116DFA1C700D29550 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; 134 | /* End PBXFileReference section */ 135 | 136 | /* Begin PBXFrameworksBuildPhase section */ 137 | C1D6739314F4D247006D3483 /* Frameworks */ = { 138 | isa = PBXFrameworksBuildPhase; 139 | buildActionMask = 2147483647; 140 | files = ( 141 | C15549FD150B90D800D0F3E6 /* QuartzCore.framework in Frameworks */, 142 | C1D6739B14F4D247006D3483 /* UIKit.framework in Frameworks */, 143 | C1D6739D14F4D247006D3483 /* Foundation.framework in Frameworks */, 144 | C1D6739F14F4D247006D3483 /* CoreGraphics.framework in Frameworks */, 145 | ); 146 | runOnlyForDeploymentPostprocessing = 0; 147 | }; 148 | /* End PBXFrameworksBuildPhase section */ 149 | 150 | /* Begin PBXGroup section */ 151 | C1D6738B14F4D247006D3483 = { 152 | isa = PBXGroup; 153 | children = ( 154 | C182834516633FB600A69C46 /* LICENSE */, 155 | C1539F4C1510C76A00C6A479 /* README.md */, 156 | C1D673A014F4D247006D3483 /* BookShelf */, 157 | C1D6739914F4D247006D3483 /* Frameworks */, 158 | C1D6739714F4D247006D3483 /* Products */, 159 | ); 160 | sourceTree = ""; 161 | }; 162 | C1D6739714F4D247006D3483 /* Products */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | C1D6739614F4D247006D3483 /* BookShelf.app */, 166 | ); 167 | name = Products; 168 | sourceTree = ""; 169 | }; 170 | C1D6739914F4D247006D3483 /* Frameworks */ = { 171 | isa = PBXGroup; 172 | children = ( 173 | C15549FC150B90D800D0F3E6 /* QuartzCore.framework */, 174 | C1D6739A14F4D247006D3483 /* UIKit.framework */, 175 | C1D6739C14F4D247006D3483 /* Foundation.framework */, 176 | C1D6739E14F4D247006D3483 /* CoreGraphics.framework */, 177 | ); 178 | name = Frameworks; 179 | sourceTree = ""; 180 | }; 181 | C1D673A014F4D247006D3483 /* BookShelf */ = { 182 | isa = PBXGroup; 183 | children = ( 184 | FA928C3616DFA0E800D29550 /* Classes */, 185 | FA928C5916DFA0E800D29550 /* Other */, 186 | FA928C5C16DFA0E800D29550 /* Resources */, 187 | ); 188 | path = BookShelf; 189 | sourceTree = ""; 190 | }; 191 | FA928C3616DFA0E800D29550 /* Classes */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | FA928C3716DFA0E800D29550 /* BookShelf */, 195 | FA928C4516DFA0E800D29550 /* Demo */, 196 | FA928C5016DFA0E800D29550 /* Useless */, 197 | ); 198 | path = Classes; 199 | sourceTree = ""; 200 | }; 201 | FA928C3716DFA0E800D29550 /* BookShelf */ = { 202 | isa = PBXGroup; 203 | children = ( 204 | FA928C3816DFA0E800D29550 /* Private */, 205 | FA928C3D16DFA0E800D29550 /* Public */, 206 | FA928C4216DFA0E800D29550 /* Utilities */, 207 | ); 208 | path = BookShelf; 209 | sourceTree = ""; 210 | }; 211 | FA928C3816DFA0E800D29550 /* Private */ = { 212 | isa = PBXGroup; 213 | children = ( 214 | FA928C3916DFA0E800D29550 /* GSBookViewContainerView.h */, 215 | FA928C3A16DFA0E800D29550 /* GSBookViewContainerView.m */, 216 | FA928C3B16DFA0E800D29550 /* GSCellContainerView.h */, 217 | FA928C3C16DFA0E800D29550 /* GSCellContainerView.m */, 218 | ); 219 | path = Private; 220 | sourceTree = ""; 221 | }; 222 | FA928C3D16DFA0E800D29550 /* Public */ = { 223 | isa = PBXGroup; 224 | children = ( 225 | FA928C3F16DFA0E800D29550 /* GSBookShelfView.h */, 226 | FA928C4016DFA0E800D29550 /* GSBookShelfView.m */, 227 | FA928C3E16DFA0E800D29550 /* GSBookShelfCell.h */, 228 | FA928C4116DFA0E800D29550 /* GSBookView.h */, 229 | ); 230 | path = Public; 231 | sourceTree = ""; 232 | }; 233 | FA928C4216DFA0E800D29550 /* Utilities */ = { 234 | isa = PBXGroup; 235 | children = ( 236 | FA928C4316DFA0E800D29550 /* NSMutableArray+Rearrange.h */, 237 | FA928C4416DFA0E800D29550 /* NSMutableArray+Rearrange.m */, 238 | ); 239 | path = Utilities; 240 | sourceTree = ""; 241 | }; 242 | FA928C4516DFA0E800D29550 /* Demo */ = { 243 | isa = PBXGroup; 244 | children = ( 245 | FA928C4616DFA0E800D29550 /* AppDelegate.h */, 246 | FA928C4716DFA0E800D29550 /* AppDelegate.m */, 247 | FA928C4816DFA0E800D29550 /* BelowBottomView.h */, 248 | FA928C4916DFA0E800D29550 /* BelowBottomView.m */, 249 | FA928C4A16DFA0E800D29550 /* BookShelfCellView.h */, 250 | FA928C4B16DFA0E800D29550 /* BookShelfCellView.m */, 251 | FA928C4C16DFA0E800D29550 /* MyBookView.h */, 252 | FA928C4D16DFA0E800D29550 /* MyBookView.m */, 253 | FA928C4E16DFA0E800D29550 /* ViewController.h */, 254 | FA928C4F16DFA0E800D29550 /* ViewController.m */, 255 | ); 256 | path = Demo; 257 | sourceTree = ""; 258 | }; 259 | FA928C5016DFA0E800D29550 /* Useless */ = { 260 | isa = PBXGroup; 261 | children = ( 262 | FA928C5116DFA0E800D29550 /* AboveTopView.h */, 263 | FA928C5216DFA0E800D29550 /* AboveTopView.m */, 264 | FA928C5316DFA0E800D29550 /* BookView.h */, 265 | FA928C5416DFA0E800D29550 /* BookView.m */, 266 | FA928C5516DFA0E800D29550 /* MyBelowBottomView.h */, 267 | FA928C5616DFA0E800D29550 /* MyBelowBottomView.m */, 268 | FA928C5716DFA0E800D29550 /* MyCellView.h */, 269 | FA928C5816DFA0E800D29550 /* MyCellView.m */, 270 | ); 271 | path = Useless; 272 | sourceTree = ""; 273 | }; 274 | FA928C5916DFA0E800D29550 /* Other */ = { 275 | isa = PBXGroup; 276 | children = ( 277 | FA928C5A16DFA0E800D29550 /* BookShelf-Prefix.pch */, 278 | FA928C5B16DFA0E800D29550 /* main.m */, 279 | ); 280 | path = Other; 281 | sourceTree = ""; 282 | }; 283 | FA928C5C16DFA0E800D29550 /* Resources */ = { 284 | isa = PBXGroup; 285 | children = ( 286 | FA928C5D16DFA0E800D29550 /* BookShelf-Info.plist */, 287 | FA928C5E16DFA0E800D29550 /* InfoPlist.strings */, 288 | FA928C6016DFA0E800D29550 /* ViewController.xib */, 289 | FA928C6216DFA0E800D29550 /* Images */, 290 | ); 291 | path = Resources; 292 | sourceTree = ""; 293 | }; 294 | FA928C6216DFA0E800D29550 /* Images */ = { 295 | isa = PBXGroup; 296 | children = ( 297 | FA928CB016DFA1C700D29550 /* Default.png */, 298 | FA928CB116DFA1C700D29550 /* Default@2x.png */, 299 | FA928CAE16DFA15800D29550 /* Default-568h@2x.png */, 300 | FA928C6316DFA0E800D29550 /* 1.png */, 301 | FA928C6416DFA0E800D29550 /* 1@2x.png */, 302 | FA928C6516DFA0E800D29550 /* 2.png */, 303 | FA928C6616DFA0E800D29550 /* 2@2x.png */, 304 | FA928C6716DFA0E800D29550 /* 3.png */, 305 | FA928C6816DFA0E800D29550 /* 3@2x.png */, 306 | FA928C6916DFA0E800D29550 /* 4.png */, 307 | FA928C6A16DFA0E800D29550 /* 4@2x.png */, 308 | FA928C6B16DFA0E800D29550 /* BookShelfCell.png */, 309 | FA928C6C16DFA0E800D29550 /* BookShelfCell@2x.png */, 310 | FA928C6D16DFA0E800D29550 /* BookViewChecked.png */, 311 | FA928C6E16DFA0E800D29550 /* BookViewChecked@2x.png */, 312 | FA928C6F16DFA0E800D29550 /* comments.png */, 313 | FA928C7016DFA0E800D29550 /* for test */, 314 | FA928C7116DFA0E800D29550 /* from iBooks */, 315 | ); 316 | path = Images; 317 | sourceTree = ""; 318 | }; 319 | FA928C7016DFA0E800D29550 /* for test */ = { 320 | isa = PBXGroup; 321 | children = ( 322 | ); 323 | path = "for test"; 324 | sourceTree = ""; 325 | }; 326 | FA928C7116DFA0E800D29550 /* from iBooks */ = { 327 | isa = PBXGroup; 328 | children = ( 329 | FA928C7216DFA0E800D29550 /* NavBar-Landscape@2x~iphone.png */, 330 | FA928C7316DFA0E800D29550 /* NavBar-Landscape~iphone.png */, 331 | FA928C7416DFA0E800D29550 /* NavBar@2x~iphone.png */, 332 | FA928C7516DFA0E800D29550 /* NavBar~iphone.png */, 333 | FA928C7616DFA0E800D29550 /* Shelf-Landscape@2x~iphone.png */, 334 | FA928C7716DFA0E800D29550 /* Shelf-Landscape~iphone.png */, 335 | FA928C7816DFA0E800D29550 /* Shelf@2x~iphone.png */, 336 | FA928C7916DFA0E800D29550 /* Shelf~iphone.png */, 337 | FA928C7A16DFA0E800D29550 /* Side Shading-iPhone.png */, 338 | FA928C7B16DFA0E800D29550 /* Side Shading-iPhone@2x.png */, 339 | FA928C7C16DFA0E800D29550 /* topshelf side shading-iPhone.png */, 340 | FA928C7D16DFA0E800D29550 /* topshelf side shading-iPhone@2x.png */, 341 | FA928C7E16DFA0E800D29550 /* WoodTile@2x~iphone.png */, 342 | FA928C7F16DFA0E800D29550 /* WoodTile~iphone.png */, 343 | ); 344 | path = "from iBooks"; 345 | sourceTree = ""; 346 | }; 347 | /* End PBXGroup section */ 348 | 349 | /* Begin PBXNativeTarget section */ 350 | C1D6739514F4D247006D3483 /* BookShelf */ = { 351 | isa = PBXNativeTarget; 352 | buildConfigurationList = C1D673B414F4D247006D3483 /* Build configuration list for PBXNativeTarget "BookShelf" */; 353 | buildPhases = ( 354 | C1D6739214F4D247006D3483 /* Sources */, 355 | C1D6739314F4D247006D3483 /* Frameworks */, 356 | C1D6739414F4D247006D3483 /* Resources */, 357 | ); 358 | buildRules = ( 359 | ); 360 | dependencies = ( 361 | ); 362 | name = BookShelf; 363 | productName = BookShelf; 364 | productReference = C1D6739614F4D247006D3483 /* BookShelf.app */; 365 | productType = "com.apple.product-type.application"; 366 | }; 367 | /* End PBXNativeTarget section */ 368 | 369 | /* Begin PBXProject section */ 370 | C1D6738D14F4D247006D3483 /* Project object */ = { 371 | isa = PBXProject; 372 | attributes = { 373 | LastUpgradeCheck = 0460; 374 | ORGANIZATIONNAME = FoOTOo; 375 | }; 376 | buildConfigurationList = C1D6739014F4D247006D3483 /* Build configuration list for PBXProject "BookShelf" */; 377 | compatibilityVersion = "Xcode 3.2"; 378 | developmentRegion = English; 379 | hasScannedForEncodings = 0; 380 | knownRegions = ( 381 | en, 382 | ); 383 | mainGroup = C1D6738B14F4D247006D3483; 384 | productRefGroup = C1D6739714F4D247006D3483 /* Products */; 385 | projectDirPath = ""; 386 | projectRoot = ""; 387 | targets = ( 388 | C1D6739514F4D247006D3483 /* BookShelf */, 389 | ); 390 | }; 391 | /* End PBXProject section */ 392 | 393 | /* Begin PBXResourcesBuildPhase section */ 394 | C1D6739414F4D247006D3483 /* Resources */ = { 395 | isa = PBXResourcesBuildPhase; 396 | buildActionMask = 2147483647; 397 | files = ( 398 | C182834616633FB600A69C46 /* LICENSE in Resources */, 399 | FA928C8F16DFA0E800D29550 /* InfoPlist.strings in Resources */, 400 | FA928C9016DFA0E800D29550 /* ViewController.xib in Resources */, 401 | FA928C9116DFA0E800D29550 /* 1.png in Resources */, 402 | FA928C9216DFA0E800D29550 /* 1@2x.png in Resources */, 403 | FA928C9316DFA0E800D29550 /* 2.png in Resources */, 404 | FA928C9416DFA0E800D29550 /* 2@2x.png in Resources */, 405 | FA928C9516DFA0E800D29550 /* 3.png in Resources */, 406 | FA928C9616DFA0E800D29550 /* 3@2x.png in Resources */, 407 | FA928C9716DFA0E800D29550 /* 4.png in Resources */, 408 | FA928C9816DFA0E800D29550 /* 4@2x.png in Resources */, 409 | FA928C9916DFA0E800D29550 /* BookShelfCell.png in Resources */, 410 | FA928C9A16DFA0E800D29550 /* BookShelfCell@2x.png in Resources */, 411 | FA928C9B16DFA0E800D29550 /* BookViewChecked.png in Resources */, 412 | FA928C9C16DFA0E800D29550 /* BookViewChecked@2x.png in Resources */, 413 | FA928C9D16DFA0E800D29550 /* comments.png in Resources */, 414 | FA928C9E16DFA0E800D29550 /* NavBar-Landscape@2x~iphone.png in Resources */, 415 | FA928C9F16DFA0E800D29550 /* NavBar-Landscape~iphone.png in Resources */, 416 | FA928CA016DFA0E800D29550 /* NavBar@2x~iphone.png in Resources */, 417 | FA928CA116DFA0E800D29550 /* NavBar~iphone.png in Resources */, 418 | FA928CA216DFA0E800D29550 /* Shelf-Landscape@2x~iphone.png in Resources */, 419 | FA928CA316DFA0E800D29550 /* Shelf-Landscape~iphone.png in Resources */, 420 | FA928CA416DFA0E800D29550 /* Shelf@2x~iphone.png in Resources */, 421 | FA928CA516DFA0E800D29550 /* Shelf~iphone.png in Resources */, 422 | FA928CA616DFA0E800D29550 /* Side Shading-iPhone.png in Resources */, 423 | FA928CA716DFA0E800D29550 /* Side Shading-iPhone@2x.png in Resources */, 424 | FA928CA816DFA0E800D29550 /* topshelf side shading-iPhone.png in Resources */, 425 | FA928CA916DFA0E800D29550 /* topshelf side shading-iPhone@2x.png in Resources */, 426 | FA928CAA16DFA0E800D29550 /* WoodTile@2x~iphone.png in Resources */, 427 | FA928CAB16DFA0E800D29550 /* WoodTile~iphone.png in Resources */, 428 | FA928CAF16DFA15800D29550 /* Default-568h@2x.png in Resources */, 429 | FA928CB216DFA1C700D29550 /* Default.png in Resources */, 430 | FA928CB316DFA1C700D29550 /* Default@2x.png in Resources */, 431 | ); 432 | runOnlyForDeploymentPostprocessing = 0; 433 | }; 434 | /* End PBXResourcesBuildPhase section */ 435 | 436 | /* Begin PBXSourcesBuildPhase section */ 437 | C1D6739214F4D247006D3483 /* Sources */ = { 438 | isa = PBXSourcesBuildPhase; 439 | buildActionMask = 2147483647; 440 | files = ( 441 | FA928C8016DFA0E800D29550 /* GSBookViewContainerView.m in Sources */, 442 | FA928C8116DFA0E800D29550 /* GSCellContainerView.m in Sources */, 443 | FA928C8216DFA0E800D29550 /* GSBookShelfView.m in Sources */, 444 | FA928C8316DFA0E800D29550 /* NSMutableArray+Rearrange.m in Sources */, 445 | FA928C8416DFA0E800D29550 /* AppDelegate.m in Sources */, 446 | FA928C8516DFA0E800D29550 /* BelowBottomView.m in Sources */, 447 | FA928C8616DFA0E800D29550 /* BookShelfCellView.m in Sources */, 448 | FA928C8716DFA0E800D29550 /* MyBookView.m in Sources */, 449 | FA928C8816DFA0E800D29550 /* ViewController.m in Sources */, 450 | FA928C8916DFA0E800D29550 /* AboveTopView.m in Sources */, 451 | FA928C8A16DFA0E800D29550 /* BookView.m in Sources */, 452 | FA928C8B16DFA0E800D29550 /* MyBelowBottomView.m in Sources */, 453 | FA928C8C16DFA0E800D29550 /* MyCellView.m in Sources */, 454 | FA928C8D16DFA0E800D29550 /* main.m in Sources */, 455 | ); 456 | runOnlyForDeploymentPostprocessing = 0; 457 | }; 458 | /* End PBXSourcesBuildPhase section */ 459 | 460 | /* Begin PBXVariantGroup section */ 461 | FA928C5E16DFA0E800D29550 /* InfoPlist.strings */ = { 462 | isa = PBXVariantGroup; 463 | children = ( 464 | FA928C5F16DFA0E800D29550 /* en */, 465 | ); 466 | name = InfoPlist.strings; 467 | sourceTree = ""; 468 | }; 469 | FA928C6016DFA0E800D29550 /* ViewController.xib */ = { 470 | isa = PBXVariantGroup; 471 | children = ( 472 | FA928C6116DFA0E800D29550 /* en */, 473 | ); 474 | name = ViewController.xib; 475 | sourceTree = ""; 476 | }; 477 | /* End PBXVariantGroup section */ 478 | 479 | /* Begin XCBuildConfiguration section */ 480 | C1D673B214F4D247006D3483 /* Debug */ = { 481 | isa = XCBuildConfiguration; 482 | buildSettings = { 483 | ALWAYS_SEARCH_USER_PATHS = NO; 484 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 485 | CLANG_ENABLE_OBJC_ARC = YES; 486 | CLANG_WARN_CONSTANT_CONVERSION = YES; 487 | CLANG_WARN_ENUM_CONVERSION = YES; 488 | CLANG_WARN_INT_CONVERSION = YES; 489 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 490 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 491 | COPY_PHASE_STRIP = NO; 492 | GCC_C_LANGUAGE_STANDARD = gnu99; 493 | GCC_DYNAMIC_NO_PIC = NO; 494 | GCC_OPTIMIZATION_LEVEL = 0; 495 | GCC_PREPROCESSOR_DEFINITIONS = ( 496 | "DEBUG=1", 497 | "$(inherited)", 498 | ); 499 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 500 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 501 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 502 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 503 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 504 | GCC_WARN_UNUSED_VARIABLE = YES; 505 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 506 | SDKROOT = iphoneos; 507 | }; 508 | name = Debug; 509 | }; 510 | C1D673B314F4D247006D3483 /* Release */ = { 511 | isa = XCBuildConfiguration; 512 | buildSettings = { 513 | ALWAYS_SEARCH_USER_PATHS = NO; 514 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 515 | CLANG_ENABLE_OBJC_ARC = YES; 516 | CLANG_WARN_CONSTANT_CONVERSION = YES; 517 | CLANG_WARN_ENUM_CONVERSION = YES; 518 | CLANG_WARN_INT_CONVERSION = YES; 519 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 520 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 521 | COPY_PHASE_STRIP = YES; 522 | GCC_C_LANGUAGE_STANDARD = gnu99; 523 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 524 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 525 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 526 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 527 | GCC_WARN_UNUSED_VARIABLE = YES; 528 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 529 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 530 | SDKROOT = iphoneos; 531 | VALIDATE_PRODUCT = YES; 532 | }; 533 | name = Release; 534 | }; 535 | C1D673B514F4D247006D3483 /* Debug */ = { 536 | isa = XCBuildConfiguration; 537 | buildSettings = { 538 | ARCHS = ( 539 | armv6, 540 | armv7, 541 | ); 542 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 543 | GCC_PREFIX_HEADER = "BookShelf/Other/BookShelf-Prefix.pch"; 544 | GCC_THUMB_SUPPORT = NO; 545 | INFOPLIST_FILE = "$(SRCROOT)/BookShelf/Resources/BookShelf-Info.plist"; 546 | IPHONEOS_DEPLOYMENT_TARGET = 4.0; 547 | PRODUCT_NAME = "$(TARGET_NAME)"; 548 | WRAPPER_EXTENSION = app; 549 | }; 550 | name = Debug; 551 | }; 552 | C1D673B614F4D247006D3483 /* Release */ = { 553 | isa = XCBuildConfiguration; 554 | buildSettings = { 555 | ARCHS = ( 556 | armv6, 557 | armv7, 558 | ); 559 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 560 | GCC_PREFIX_HEADER = "BookShelf/Other/BookShelf-Prefix.pch"; 561 | GCC_THUMB_SUPPORT = NO; 562 | INFOPLIST_FILE = "$(SRCROOT)/BookShelf/Resources/BookShelf-Info.plist"; 563 | IPHONEOS_DEPLOYMENT_TARGET = 4.0; 564 | PRODUCT_NAME = "$(TARGET_NAME)"; 565 | WRAPPER_EXTENSION = app; 566 | }; 567 | name = Release; 568 | }; 569 | /* End XCBuildConfiguration section */ 570 | 571 | /* Begin XCConfigurationList section */ 572 | C1D6739014F4D247006D3483 /* Build configuration list for PBXProject "BookShelf" */ = { 573 | isa = XCConfigurationList; 574 | buildConfigurations = ( 575 | C1D673B214F4D247006D3483 /* Debug */, 576 | C1D673B314F4D247006D3483 /* Release */, 577 | ); 578 | defaultConfigurationIsVisible = 0; 579 | defaultConfigurationName = Release; 580 | }; 581 | C1D673B414F4D247006D3483 /* Build configuration list for PBXNativeTarget "BookShelf" */ = { 582 | isa = XCConfigurationList; 583 | buildConfigurations = ( 584 | C1D673B514F4D247006D3483 /* Debug */, 585 | C1D673B614F4D247006D3483 /* Release */, 586 | ); 587 | defaultConfigurationIsVisible = 0; 588 | defaultConfigurationName = Release; 589 | }; 590 | /* End XCConfigurationList section */ 591 | }; 592 | rootObject = C1D6738D14F4D247006D3483 /* Project object */; 593 | } 594 | -------------------------------------------------------------------------------- /BookShelf/Classes/BookShelf/Private/GSBookViewContainerView.m: -------------------------------------------------------------------------------- 1 | /* 2 | BookViewContainerView.m 3 | BookShelf 4 | 5 | Created by Xinrong Guo on 12-2-24. 6 | Copyright (c) 2012 FoOTOo. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 12 | Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | Neither the name of the project's author nor the names of its 20 | contributors may be used to endorse or promote products derived from 21 | this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #import "GSBookViewContainerView.h" 37 | #import "GSBookShelfView.h" 38 | #import "GSBookView.h" 39 | #import 40 | 41 | #define kRatio_width_spacing 2.5f 42 | #define kRatio_height_width 1.2f 43 | 44 | #define kGrow_animation_duration 0.15 45 | #define kSrink_animation_duration 0.15 46 | 47 | typedef enum { 48 | ADD_TYPE_FIRSTTIME, 49 | ADD_TYPE_HEAD, 50 | ADD_TYPE_TAIL 51 | }AddType; 52 | 53 | typedef enum { 54 | RM_TYPE_HEAD, 55 | RM_TYPE_TAIL 56 | }RemoveType; 57 | 58 | @interface GSBookViewContainerView (Private) 59 | 60 | // reuse 61 | 62 | - (void)addReuseableBookView:(UIView *)bookView; 63 | 64 | // Scroll 65 | - (void)stopScrollTimer; 66 | - (void)scrollIfNecessary; 67 | 68 | // Move 69 | - (void)moveBooksIfNecessary; 70 | 71 | // Animation 72 | - (void)growAnimationAtPoint:(CGPoint)point forView:(UIView *)view; 73 | - (void)animateBookViewToBookViewPostion:(BookViewPostion)toPosition rect:(CGRect)toRect; 74 | 75 | // BookView Rect 76 | - (CGRect)bookViewRectAtBookViewPosition:(BookViewPostion)position; 77 | 78 | @end 79 | 80 | @interface GSBookViewContainerView (Test) 81 | 82 | - (void)checkVisibleBookViewsValid; 83 | @end 84 | 85 | @implementation GSBookViewContainerView 86 | 87 | @synthesize parentBookShelfView = _parentBookShelfView; 88 | 89 | - (id)initWithFrame:(CGRect)frame 90 | { 91 | self = [super initWithFrame:frame]; 92 | if (self) { 93 | 94 | _reuseableBookViews = [[NSMutableDictionary alloc] initWithCapacity:0]; 95 | 96 | _firstVisibleRow = -1; 97 | _lastVisibleRow = -1; 98 | 99 | _visibleBookViews = [[NSMutableArray alloc] initWithCapacity:0]; 100 | 101 | // dragAndDrop 102 | _isDragViewPickedUp = NO; 103 | _isBooksMoving = NO; 104 | _isDragViewRemovedFromVisibleBookViews = NO; 105 | 106 | // Remove 107 | _isRemoving = NO; 108 | _indexsOfBookViewNotShown = [NSMutableIndexSet indexSet]; 109 | _tempVisibleBookViewCollector = [[NSMutableArray alloc] initWithCapacity:0]; 110 | 111 | // GestureRecognizer 112 | UILongPressGestureRecognizer *longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPressGesture:)]; 113 | [self addGestureRecognizer:longPressGestureRecognizer]; 114 | 115 | } 116 | return self; 117 | } 118 | 119 | # pragma mark - Reload 120 | 121 | - (void)calculateLayout { 122 | CGFloat cellWidth = _parentBookShelfView.frame.size.width; 123 | CGFloat cellMargin = _parentBookShelfView.cellMargin; //[_parentBookShelfView.dataSource cellMarginOfBookShelfView:_parentBookShelfView]; 124 | 125 | NSInteger numOfBooksInCell = [_parentBookShelfView.dataSource numberOFBooksInCellOfBookShelfView:_parentBookShelfView]; 126 | 127 | _bookViewWidth = [_parentBookShelfView.dataSource bookViewWidthOfBookShelfView:_parentBookShelfView]; 128 | _bookViewHeight = [_parentBookShelfView.dataSource bookViewHeightOfBookShelfView:_parentBookShelfView]; 129 | 130 | _bookViewSpacingWidth = numOfBooksInCell == 1 ? 0 : (cellWidth - 2 * cellMargin - numOfBooksInCell * _bookViewWidth) / (numOfBooksInCell - 1); 131 | 132 | NSAssert(_bookViewSpacingWidth >= 0, @"invalid book size"); 133 | } 134 | 135 | - (void)reloadData { 136 | [self calculateLayout]; 137 | 138 | // Flags 139 | // visible row 140 | _firstVisibleRow = -1; 141 | _lastVisibleRow = -1; 142 | 143 | // dragAndDrop 144 | _isDragViewPickedUp = NO; 145 | _isBooksMoving = NO; 146 | _isDragViewRemovedFromVisibleBookViews = NO; 147 | 148 | // Remove 149 | _isRemoving = NO; 150 | 151 | for (UIView *view in _visibleBookViews) { 152 | [self addReuseableBookView:view]; 153 | [view removeFromSuperview]; 154 | } 155 | [_visibleBookViews removeAllObjects]; 156 | 157 | //[_reuseableBookViews removeAllObjects]; 158 | } 159 | 160 | #pragma mark - Reuse 161 | 162 | - (void)addReuseableBookView:(UIView *)bookView { 163 | NSString *reuseIdentifier = nil; 164 | if ([bookView respondsToSelector:@selector(reuseIdentifier)]) { 165 | reuseIdentifier = [(id)bookView reuseIdentifier]; 166 | } 167 | 168 | if (reuseIdentifier == nil) { 169 | return; 170 | } 171 | 172 | NSMutableSet *bookViewSet = [_reuseableBookViews objectForKey:reuseIdentifier]; 173 | if (!bookViewSet) { 174 | bookViewSet = [[NSMutableSet alloc] initWithCapacity:0]; 175 | [_reuseableBookViews setObject:bookViewSet forKey:reuseIdentifier]; 176 | } 177 | [bookViewSet addObject:bookView]; 178 | //NSLog(@"bookViewSet count:%d", [bookViewSet count]); 179 | } 180 | 181 | - (UIView *)dequeueReusableBookViewWithIdentifier:(NSString *)identifier { 182 | NSMutableSet *bookViewSet = (NSMutableSet *)[_reuseableBookViews objectForKey:identifier]; 183 | UIView *bookView = [bookViewSet anyObject]; 184 | if (bookView) { 185 | [bookViewSet removeObject:bookView]; 186 | } 187 | return bookView; 188 | } 189 | 190 | #pragma mark - Layout 191 | 192 | - (UIView *)addBookViewAsSubviewWithBookViewPosition:(BookViewPostion)position { 193 | [UIView setAnimationsEnabled:NO]; 194 | UIView *bookView = [_parentBookShelfView.dataSource bookShelfView:_parentBookShelfView bookViewAtIndex:position.index]; 195 | // Take a look at the "Discussion" in removeBookViewWithType: 196 | // Since _dragView won't be removed from supervie, we should not add it or change the frame either. And although the new bookView returned from dataSource have the same position with _dragView, but they are not the same view, so set _dragView to bookView, ignore the bookView returned from dataSource. 197 | if (_isDragViewPickedUp && position.index == _pickUpPosition.index) { 198 | _isDragViewRemovedFromVisibleBookViews = NO; 199 | bookView = _dragView; 200 | } 201 | else { 202 | //bookView.tag = position.index; // set the tag as the index 203 | [bookView setFrame:[self bookViewRectAtBookViewPosition:position]]; 204 | 205 | //NSLog(@"bookView Frame:%@", NSStringFromCGRect(bookView.frame)); 206 | /*if (![_indexsOfBookViewToBeRemoved containsIndex:position.index] && !_isRemoving) { 207 | [self addSubview:bookView]; 208 | }*/ 209 | if (!([_indexsOfBookViewToBeRemoved containsIndex:position.index] || [_indexsOfBookViewNotShown containsIndex:position.index])) { 210 | [self addSubview:bookView]; 211 | } 212 | 213 | } 214 | [UIView setAnimationsEnabled:YES]; 215 | return bookView; 216 | } 217 | 218 | - (void)addBookViewAtBookViewPosition:(BookViewPostion) position addType:(AddType)addType { 219 | 220 | UIView *bookView = [self addBookViewAsSubviewWithBookViewPosition:position]; 221 | 222 | NSMutableArray *visibleBookViews = _isRemoving ? _tempVisibleBookViewCollector : _visibleBookViews; 223 | 224 | switch (addType) { 225 | case ADD_TYPE_FIRSTTIME: 226 | case ADD_TYPE_TAIL: 227 | [visibleBookViews addObject:bookView]; 228 | break; 229 | 230 | case ADD_TYPE_HEAD: 231 | [visibleBookViews insertObject:bookView atIndex:0]; 232 | break; 233 | } 234 | } 235 | 236 | - (void)removeBookViewWithType:(RemoveType)rmType { 237 | NSInteger rmIndex; 238 | switch (rmType) { 239 | case RM_TYPE_HEAD: 240 | rmIndex = 0; 241 | break; 242 | case RM_TYPE_TAIL: 243 | rmIndex = [_visibleBookViews count] - 1; 244 | } 245 | UIView *bookView = [_visibleBookViews objectAtIndex:rmIndex]; 246 | // Discusstion:When Drag And Scroll happends,somtimes _dragView's pickupPosition may have not changed. Then it may be told to be removed from superView, and this will cause the _dragView dissappear. So here we prevent the removeFromSuperview from happening, but still remove it from the _visibleBookViews. _visibleBookViews tells which view is visible except the _dragView, which means _dragView is "invisible" for _visibleBookViews when it's original position scroll out of the _availableRect. 247 | if (_isDragViewPickedUp && bookView == _dragView) { 248 | _isDragViewRemovedFromVisibleBookViews = YES; 249 | } 250 | else { 251 | [self addReuseableBookView:bookView]; 252 | [bookView removeFromSuperview]; 253 | } 254 | [_visibleBookViews removeObjectAtIndex:rmIndex]; 255 | } 256 | 257 | 258 | - (void)layoutSubviewsWithAvailableRect:(CGRect)availableRect visibleRect:(CGRect)visibleRect{ 259 | // To reduce memory usage, we only add visible bookViews to the subviews. So every time it scrolls, we shoud add and remove some bookViews.You can check the sample project (ScrollView Suit >> Tiling) for information. 260 | 261 | // Discussion: the layout sequence is easy to understand. There are 6 situation we should consider. You can draw these condition on a papper to get it more clear. 262 | 263 | // 1. lastNeededRow < _firstVisibleRow 264 | // 2. firstNeededRow < _firstVisibleRow && lastNeededRow > _firstVisibleRow && lastNeededRow < _lastVisibleRow 265 | // 3. firstNeededRow < _firstVisibleRow && lastNeededRow > _lastVisibleRow 266 | // 4. firstNeededRow > _firstVisibleRow && lastNeededRow < _lastVisibleRow 267 | // 5. firstNeededRow > _firstVisibleRow && firstNeededRow < _lastVisibleRow && lastNeededRow > _lastVisibleRow 268 | // 6. firstNeededRow > _lastVisibleRow 269 | 270 | // We deal with these situations with a sequence of operation: 271 | // 1. if (lastNeededRow < _lastVisibleRow) remove some from the tail of _visibleBookViews 272 | // 2. if (firstNeededRow < _firstVisibleRow) add some to the head of _visibleBookViews 273 | // 3. if (firstNeededRow > _firstVisibleRow) remove some from the head of _visibleBookViews 274 | // 4. if (lastNeededRow > _lastVisibleRow) add some to the tail of _visibleBookViews 275 | 276 | // only two of these four steps will happen for each situation. Thanks to these we don't need to consider about where to insert or remove a propper bookView. Just add or remove then at the head or tail. 277 | 278 | 279 | //NSLog(@"bookViewContainer layout"); 280 | //NSLog(@"availableRect %@", NSStringFromCGRect(availableRect)); 281 | _availableRect = availableRect; 282 | _visibleRect = visibleRect; 283 | 284 | NSInteger numberOfBooksInCell = [_parentBookShelfView.dataSource numberOFBooksInCellOfBookShelfView:_parentBookShelfView]; 285 | 286 | NSInteger numberOfBooks = [_parentBookShelfView.dataSource numberOfBooksInBookShelfView:_parentBookShelfView]; 287 | 288 | NSInteger numberOfCells = ceilf((float)numberOfBooks / (float)numberOfBooksInCell); 289 | 290 | NSInteger cellHeight = [_parentBookShelfView.dataSource cellHeightOfBookShelfView:_parentBookShelfView]; 291 | 292 | NSInteger firstNeededRow = MAX(0, floorf(CGRectGetMinY(availableRect) / cellHeight)); 293 | NSInteger lastNeededRow = MIN(numberOfCells - 1, floorf(CGRectGetMaxY(availableRect) / cellHeight)); 294 | 295 | //NSLog(@"\n------------\nfirstNeededRow:%d firstVisibleRow:%d\nlastNeededRow: %d lastVisibleRow: %d\n************", firstNeededRow, _firstVisibleRow, lastNeededRow, _lastVisibleRow); 296 | 297 | // remove and add bookview according to the row 298 | if (_firstVisibleRow == -1) { 299 | // First time 300 | for (NSInteger row = firstNeededRow; row <= lastNeededRow; row++) { 301 | // add firstTime 302 | for (NSInteger col = 0; col < numberOfBooksInCell; col++) { 303 | NSInteger index = row * numberOfBooksInCell + col; 304 | if (index >= numberOfBooks) { 305 | break; 306 | } 307 | BookViewPostion position = {row, col, index}; 308 | [self addBookViewAtBookViewPosition:position addType:ADD_TYPE_FIRSTTIME]; 309 | } 310 | } 311 | } 312 | else { 313 | // Not first time 314 | 315 | if (lastNeededRow < _lastVisibleRow) { 316 | NSInteger rmFromRow = (_firstVisibleRow > lastNeededRow + 1) ? _firstVisibleRow : lastNeededRow + 1; 317 | for (NSInteger row = _lastVisibleRow; row >= rmFromRow; row--) { 318 | // rm from tail of the _visibleBookView 319 | // use reversed row to always remove at tile 320 | for (NSInteger col = numberOfBooksInCell - 1; col >= 0; col--) { 321 | NSInteger index = row * numberOfBooksInCell + col; 322 | if (index < numberOfBooks) { 323 | [self removeBookViewWithType:RM_TYPE_TAIL]; 324 | } 325 | } 326 | } 327 | } 328 | 329 | if (firstNeededRow < _firstVisibleRow) { 330 | NSInteger addToRow = (_firstVisibleRow - 1 < lastNeededRow) ? _firstVisibleRow - 1 : lastNeededRow; 331 | 332 | for (NSInteger row = addToRow; row >= firstNeededRow; row--) { 333 | // add to head of the _visibileBookView 334 | // use reversed row to always add to index 0 335 | for (NSInteger col = numberOfBooksInCell - 1; col >= 0; col--) { 336 | NSInteger index = row * numberOfBooksInCell + col; 337 | if (index < numberOfBooks) { 338 | BookViewPostion position = {row, col, index}; 339 | [self addBookViewAtBookViewPosition:position addType:ADD_TYPE_HEAD]; 340 | } 341 | } 342 | } 343 | } 344 | 345 | if (firstNeededRow > _firstVisibleRow) { 346 | NSInteger rmToRow = (_lastVisibleRow <= firstNeededRow - 1) ? _lastVisibleRow : firstNeededRow - 1; 347 | for (NSInteger row = _firstVisibleRow; row <= rmToRow; row++) { 348 | // rm from head 349 | for (NSInteger col = 0; col < numberOfBooksInCell; col++) { 350 | NSInteger index = row * numberOfBooksInCell + col; 351 | if (index >= numberOfBooks) { 352 | break; 353 | } 354 | [self removeBookViewWithType:RM_TYPE_HEAD]; 355 | } 356 | } 357 | } 358 | 359 | 360 | if (lastNeededRow > _lastVisibleRow) { 361 | NSInteger addFromRow = (_lastVisibleRow + 1 > firstNeededRow) ? _lastVisibleRow + 1 : firstNeededRow; 362 | for (NSInteger row = addFromRow; row <= lastNeededRow; row++) { 363 | // add to tail 364 | for (NSInteger col = 0; col < numberOfBooksInCell; col++) { 365 | NSInteger index = row * numberOfBooksInCell + col; 366 | if (index >= numberOfBooks) { 367 | break; 368 | } 369 | BookViewPostion position = {row, col, index}; 370 | [self addBookViewAtBookViewPosition:position addType:ADD_TYPE_TAIL]; 371 | } 372 | } 373 | } 374 | } 375 | 376 | //[self checkVisibleBookViewsValid]; 377 | //NSLog(@"visible count:%d", [_visibleBookViews count]); 378 | _firstVisibleRow = firstNeededRow; 379 | _lastVisibleRow = lastNeededRow; 380 | } 381 | 382 | - (void)layoutSubviews { 383 | // Do nothing here 384 | // use layoutSubviewsWithavailableRect: instead 385 | } 386 | 387 | #pragma mark - BookViewPosition 388 | 389 | #pragma mark - BookView Rect 390 | 391 | - (NSInteger)convertToIndexFromVisibleBookViewIndex:(NSInteger)index { 392 | // not safe for some events 393 | return _firstVisibleRow * _parentBookShelfView.numberOfBooksInCell + index; 394 | } 395 | 396 | - (BookViewPostion)convertToBookViewPositionFromIndex:(NSInteger)index { 397 | NSInteger row = index / _parentBookShelfView.numberOfBooksInCell; 398 | NSInteger col = index % _parentBookShelfView.numberOfBooksInCell; 399 | BookViewPostion position = {row, col, index}; 400 | return position; 401 | } 402 | 403 | - (NSInteger)converToIndexOfVisibleBookViewsFromBookViewPosition:(BookViewPostion)position { 404 | 405 | NSInteger numberOfBooksInCell = _parentBookShelfView.numberOfBooksInCell; 406 | 407 | NSInteger indexOfVisibleBookViews = numberOfBooksInCell * (position.row - _firstVisibleRow) + position.col; 408 | 409 | return indexOfVisibleBookViews; 410 | } 411 | 412 | - (NSInteger)converToIndexOfVisibleBookViewsFromIndex:(NSInteger)index { 413 | BookViewPostion position = [self convertToBookViewPositionFromIndex:index]; 414 | return [self converToIndexOfVisibleBookViewsFromBookViewPosition:position]; 415 | } 416 | 417 | - (BOOL)isBookViewPositionVisible:(BookViewPostion)position { 418 | NSInteger numberOfBooks = [_parentBookShelfView.dataSource numberOfBooksInBookShelfView:_parentBookShelfView]; 419 | 420 | /*if (position.index < numberOfBooks && position.index >= 0) { 421 | return YES; 422 | }*/ 423 | if (position.row >= _firstVisibleRow && position.row <= _lastVisibleRow && position.index < numberOfBooks && position.index >= 0) { 424 | return YES; 425 | } 426 | 427 | return NO; 428 | } 429 | 430 | - (CGRect)bookViewRectAtBookViewPosition:(BookViewPostion)position { 431 | // Do not need position.index here 432 | CGFloat cellHeight = _parentBookShelfView.cellHeight; 433 | CGFloat bookViewBottomOffset = _parentBookShelfView.bookViewBottomOffset; 434 | CGFloat cellMarginWidth = _parentBookShelfView.cellMargin; 435 | 436 | CGFloat originX = cellMarginWidth + position.col * (_bookViewWidth + _bookViewSpacingWidth); 437 | CGFloat originY = position.row * cellHeight + bookViewBottomOffset - _bookViewHeight; 438 | 439 | return CGRectMake(originX, originY, _bookViewWidth, _bookViewHeight); 440 | } 441 | 442 | - (CGRect)bookViewEffectiveRectAtBookViewPosition:(BookViewPostion)position { 443 | CGFloat cellHeight = _parentBookShelfView.cellHeight; 444 | CGFloat bookViewBottomOffset = _parentBookShelfView.bookViewBottomOffset; 445 | CGFloat cellMarginWidth = _parentBookShelfView.cellMargin; 446 | 447 | NSInteger numberOfBooksInCell = _parentBookShelfView.numberOfBooksInCell; 448 | 449 | CGFloat originX = position.col * (_bookViewWidth + _bookViewSpacingWidth) + (position.col > 0 ? (cellMarginWidth - _bookViewSpacingWidth / 2) : 0); 450 | 451 | CGFloat effectiveWidth = _bookViewWidth + _bookViewSpacingWidth + ((position.col == 0 || position.col == numberOfBooksInCell - 1) ? (cellMarginWidth - _bookViewSpacingWidth / 2) : 0); 452 | 453 | CGFloat originY = position.row * cellHeight + bookViewBottomOffset - _bookViewHeight; 454 | 455 | return CGRectMake(originX, originY, effectiveWidth, _bookViewHeight); 456 | } 457 | 458 | - (BookViewPostion)bookViewPositionAtPoint:(CGPoint)point { 459 | // Always return a valid BookViewPosition 460 | CGFloat cellHeight = _parentBookShelfView.cellHeight; 461 | 462 | NSInteger currentRow = floorf(point.y / cellHeight); 463 | 464 | CGFloat cellMarginWidth = _parentBookShelfView.cellMargin; 465 | 466 | CGFloat firstColWidth = cellMarginWidth + _bookViewWidth + _bookViewSpacingWidth / 2; 467 | CGFloat middleColWidth = _bookViewWidth + _bookViewSpacingWidth; 468 | 469 | NSInteger numberOfBooksInCell = _parentBookShelfView.numberOfBooksInCell; 470 | 471 | NSInteger currentCol; 472 | 473 | if (point.x < firstColWidth) { 474 | currentCol = 0; 475 | } 476 | else { 477 | currentCol = MIN(floorf((point.x - firstColWidth) / middleColWidth) + 1, numberOfBooksInCell - 1); 478 | } 479 | 480 | BookViewPostion position = {currentRow, currentCol, currentRow * numberOfBooksInCell + currentCol}; 481 | 482 | //NSLog(@"position [%d] [%d]", currentRow, currentCol); 483 | 484 | return position; 485 | } 486 | 487 | - (CGRect)bookViewRectAtPoint:(CGPoint)point { 488 | // Return an CGRectZero if the point is not in any bookView's frame 489 | BookViewPostion position = [self bookViewPositionAtPoint:point]; 490 | CGRect bookViewRect = [self bookViewRectAtBookViewPosition:position]; 491 | 492 | if (!CGRectContainsPoint(bookViewRect, point)) { 493 | bookViewRect = CGRectZero; 494 | } 495 | 496 | return bookViewRect; 497 | } 498 | 499 | - (UIView *)bookViewAtPoint:(CGPoint)point { 500 | UIView *bookView = nil; 501 | 502 | BookViewPostion position = [self bookViewPositionAtPoint:point]; 503 | CGRect bookViewRect = [self bookViewRectAtBookViewPosition:position]; 504 | 505 | if (!CGRectEqualToRect(bookViewRect, CGRectZero) && [self isBookViewPositionVisible:position]) { 506 | // a valid bookViewRect 507 | NSInteger indexOfVisibleBookViews = [self converToIndexOfVisibleBookViewsFromBookViewPosition:position]; 508 | 509 | bookView = [_visibleBookViews objectAtIndex:indexOfVisibleBookViews]; 510 | } 511 | return bookView; 512 | } 513 | 514 | #pragma mark - Gesture Recognizer 515 | 516 | - (void)handleLongPressGesture:(UILongPressGestureRecognizer *)gestureRecognizer { 517 | 518 | if (gestureRecognizer.state == UIGestureRecognizerStateBegan) { 519 | CGPoint touchPoint = [gestureRecognizer locationInView:self]; 520 | BOOL dragAndDropEnable = _parentBookShelfView.dragAndDropEnabled; 521 | if (dragAndDropEnable) { 522 | 523 | BookViewPostion position = [self bookViewPositionAtPoint:touchPoint]; 524 | CGRect bookViewRect = [self bookViewRectAtBookViewPosition:position]; 525 | 526 | if (CGRectContainsPoint(bookViewRect, touchPoint) && [self isBookViewPositionVisible:position]) { 527 | NSInteger indexOfVisibleBookViews = [self converToIndexOfVisibleBookViewsFromBookViewPosition:position]; 528 | _dragView = [_visibleBookViews objectAtIndex:indexOfVisibleBookViews]; 529 | [self bringSubviewToFront:_dragView]; 530 | [self growAnimationAtPoint:touchPoint forView:_dragView]; 531 | 532 | _pickUpPosition = position; 533 | _pickUpRect = bookViewRect; 534 | _isDragViewPickedUp = YES; 535 | _isDragViewRemovedFromVisibleBookViews = NO; 536 | } 537 | } 538 | } 539 | else if (gestureRecognizer.state == UIGestureRecognizerStateChanged) { 540 | if (_isDragViewPickedUp) { 541 | CGPoint touchPoint = [gestureRecognizer locationInView:self]; 542 | _dragView.center = touchPoint; 543 | [self moveBooksIfNecessary]; 544 | [self scrollIfNecessary]; 545 | 546 | } 547 | } 548 | /*else if (gestureRecognizer.state == UIGestureRecognizerStateEnded) { 549 | if (_isDragViewPickedUp) { 550 | [UIView animateWithDuration:0.3 551 | delay:0.0 552 | options:UIViewAnimationCurveLinear | UIViewAnimationOptionLayoutSubviews 553 | animations:^{ 554 | _dragView.frame = _pickUpRect; 555 | } 556 | completion:^(BOOL finished) { 557 | _isDragViewPickedUp = NO; 558 | }]; 559 | 560 | 561 | } 562 | [self stopScrollTimer]; 563 | }*/ 564 | else { 565 | if (_isDragViewPickedUp) { 566 | [UIView animateWithDuration:0.3 567 | delay:0.0 568 | options:UIViewAnimationCurveLinear | UIViewAnimationOptionLayoutSubviews 569 | animations:^{ 570 | //_dragView.frame = _pickUpRect; 571 | _dragView.transform = CGAffineTransformIdentity; 572 | _dragView.center = CGPointMake(CGRectGetMidX(_pickUpRect), CGRectGetMidY(_pickUpRect)); 573 | } 574 | completion:^(BOOL finished) { 575 | _isDragViewPickedUp = NO; 576 | if (_isDragViewRemovedFromVisibleBookViews) { 577 | [self addReuseableBookView:_dragView]; 578 | [_dragView removeFromSuperview]; 579 | } 580 | _dragView = nil; 581 | }]; 582 | 583 | 584 | } 585 | [self stopScrollTimer]; 586 | } 587 | 588 | } 589 | 590 | #pragma mark - Scroll While Draging 591 | 592 | #define kScroll_trigger_dis 40.0f 593 | #define kScroll_dis_scale 27 594 | #define kScroll_max_speed 20 595 | 596 | - (void)stopScrollTimer { 597 | [_displayLink removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; 598 | [_displayLink invalidate]; 599 | _displayLink = nil; 600 | } 601 | 602 | - (void)scrollIfNecessary { 603 | if (_parentBookShelfView.scrollWhileDragingEnabled) { 604 | [self stopScrollTimer]; 605 | 606 | CGFloat distanceFromTop = _dragView.center.y - _visibleRect.origin.y; 607 | if (distanceFromTop < kScroll_trigger_dis || distanceFromTop > _visibleRect.size.height - kScroll_trigger_dis) { 608 | _lastDragScrollTime = CACurrentMediaTime(); // Note: See http://stackoverflow.com/questions/358207/iphone-how-to-get-current-milliseconds for speed comparation 609 | _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(dragScroll:)]; 610 | [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; 611 | } 612 | } 613 | } 614 | 615 | // Not used currently 616 | - (BOOL)canScroll:(BOOL)isScrollUp { 617 | if (isScrollUp) { 618 | if (_parentBookShelfView.contentOffset.y <= 0) { 619 | return NO; 620 | } 621 | } 622 | else { 623 | if (_parentBookShelfView.contentOffset.y + _visibleRect.size.height >=_parentBookShelfView.contentSize.height) { 624 | return NO; 625 | } 626 | } 627 | return YES; 628 | } 629 | 630 | - (CGFloat)safeHorizontalScrollDistanceWithDistance:(CGFloat)distance isScrollUp:(BOOL)isScrollUp { 631 | if (isScrollUp) { 632 | CGFloat maxDis = _parentBookShelfView.contentOffset.y; 633 | return MIN(maxDis, distance); 634 | } 635 | else { 636 | CGFloat maxDis = _parentBookShelfView.contentSize.height - (_parentBookShelfView.contentOffset.y + _visibleRect.size.height); 637 | return MIN(maxDis, distance); 638 | } 639 | } 640 | 641 | - (void)dragScroll:(NSTimer *)timer { 642 | BOOL isScrollUp; 643 | CGFloat distanceFromTop = _dragView.center.y - _visibleRect.origin.y; 644 | double timeSinceLastScroll = CACurrentMediaTime() - _lastDragScrollTime; // Around 0.015 645 | CGFloat scrollDistance = 0; 646 | double rate; // Between 0 to 40 647 | 648 | if (distanceFromTop < kScroll_trigger_dis) { 649 | isScrollUp = YES; 650 | rate = (kScroll_trigger_dis - distanceFromTop); 651 | } 652 | else { 653 | isScrollUp = NO; 654 | rate = (kScroll_trigger_dis - (_visibleRect.size.height - distanceFromTop)); 655 | } 656 | 657 | 658 | scrollDistance = rate * timeSinceLastScroll * kScroll_dis_scale; // Between 0 to around 20 659 | scrollDistance = [self safeHorizontalScrollDistanceWithDistance:scrollDistance isScrollUp:isScrollUp]; 660 | if (scrollDistance >= 1) { 661 | // Actually it won't scroll when the distance is below 1 662 | // Also the contentOffset is always interger 663 | // so there's no difference betteen scroll 1.0 and 1.4/1.9 ?? 664 | // we round the float to integer to get the best fit value <<- is this necessary ? 665 | scrollDistance = roundf(scrollDistance); 666 | scrollDistance = MIN(scrollDistance, kScroll_max_speed); 667 | 668 | CGPoint newOffset = _parentBookShelfView.contentOffset; 669 | newOffset.y = newOffset.y + (isScrollUp ? -scrollDistance : scrollDistance); 670 | [_parentBookShelfView setContentOffset:newOffset]; 671 | 672 | CGPoint newDragViewCenter = _dragView.center; 673 | newDragViewCenter.y = newDragViewCenter.y + (isScrollUp ? -scrollDistance : scrollDistance); 674 | _dragView.center = newDragViewCenter; 675 | [self moveBooksIfNecessary]; 676 | 677 | // Refresh time only when it really scrolled 678 | _lastDragScrollTime = CACurrentMediaTime(); 679 | } 680 | } 681 | 682 | #pragma mark - Move 683 | 684 | - (void)moveBooksIfNecessary { 685 | [self bringSubviewToFront:_dragView]; 686 | BookViewPostion position = [self bookViewPositionAtPoint:_dragView.center]; 687 | CGRect bookViewRect = [self bookViewRectAtBookViewPosition:position]; 688 | CGRect bookviewEffectiveRect = [self bookViewEffectiveRectAtBookViewPosition:position]; 689 | 690 | //NSLog(@"[0] %@", NSStringFromCGPoint(_dragView.center)); 691 | //NSLog(@"[1] %@", NSStringFromCGRect(bookViewRect)); 692 | //NSLog(@"[2] %@", NSStringFromCGRect(bookviewEffectiveRect)); 693 | 694 | if (CGRectContainsPoint(bookviewEffectiveRect, _dragView.center) && [self isBookViewPositionVisible:position]) { 695 | //NSLog(@"contain"); 696 | if (!CGRectEqualToRect(bookViewRect, _pickUpRect)) { 697 | // Rerange _visibleBookViews 698 | //NSLog(@"Rerange"); 699 | [self animateBookViewToBookViewPostion:position rect:bookViewRect]; 700 | } 701 | } 702 | } 703 | 704 | - (void)moveBookView:(UIView *)bookView steps:(NSInteger)steps { 705 | BookViewPostion position = [self bookViewPositionAtPoint:bookView.center]; 706 | NSInteger nPerCell = _parentBookShelfView.numberOfBooksInCell; 707 | CGFloat horizontalDisPerStep = _bookViewWidth + _bookViewSpacingWidth; 708 | CGFloat verticalDisPerStep = _parentBookShelfView.cellHeight; 709 | 710 | NSInteger horizontalSteps = ((position.col + steps) % nPerCell + nPerCell) % nPerCell - position.col; 711 | NSInteger verticalSteps = floorf((position.col + steps) / (float) nPerCell); 712 | CGFloat newCenterX = bookView.center.x + horizontalSteps * horizontalDisPerStep; 713 | CGFloat newCenterY = bookView.center.y + verticalSteps * verticalDisPerStep; 714 | bookView.center = CGPointMake(newCenterX, newCenterY); 715 | } 716 | 717 | #pragma mark - Animation 718 | 719 | - (void)growAnimationAtPoint:(CGPoint)point forView:(UIView *)view { 720 | [UIView animateWithDuration:kGrow_animation_duration 721 | delay:0.0 722 | options:UIViewAnimationCurveLinear | UIViewAnimationOptionLayoutSubviews 723 | animations:^{ 724 | view.transform = CGAffineTransformMakeScale(1.2, 1.2); 725 | view.center = point; 726 | } 727 | completion:NULL]; 728 | } 729 | 730 | - (void)shrinkAnimationToPoint:(CGPoint)point forView:(UIView *)view { 731 | 732 | } 733 | 734 | - (void)animateBookViewToBookViewPostion:(BookViewPostion)toPosition rect:(CGRect)toRect { 735 | if (!_isBooksMoving) { 736 | BOOL shouldRemoveHeadOrTailFromVisibleBookViews = NO; 737 | if (_isDragViewRemovedFromVisibleBookViews) { 738 | // Take a look at the "Discussion" in removeBookViewWithType: 739 | // Discussion: if the _dragView is "invisible". _dragView maybe insert into the _visibleBookViews and the head or tail in _visibleBookViews should be removedFromSuperview to keep the _visibleBookViews contains only bookViews in visible rows. 740 | _isDragViewRemovedFromVisibleBookViews = NO; 741 | shouldRemoveHeadOrTailFromVisibleBookViews = YES; 742 | } 743 | 744 | if (_pickUpPosition.index < toPosition.index) { 745 | // drag forward/down 746 | 747 | NSInteger fromIndexOfVisibleBookViews = [self converToIndexOfVisibleBookViewsFromBookViewPosition:_pickUpPosition]; 748 | NSInteger toIndexOfVisibleBookViews = [self converToIndexOfVisibleBookViewsFromBookViewPosition:toPosition]; 749 | 750 | NSInteger indexOfBookViewToBeRemoved = MAX(0, fromIndexOfVisibleBookViews); 751 | UIView *bookViewToRemove = [_visibleBookViews objectAtIndex:indexOfBookViewToBeRemoved]; 752 | 753 | [UIView animateWithDuration:0.3 754 | delay:0.0 755 | options:UIViewAnimationCurveLinear | UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionLayoutSubviews 756 | animations:^{ 757 | _isBooksMoving = YES; 758 | 759 | assert(toIndexOfVisibleBookViews < [_visibleBookViews count]); 760 | for (NSInteger index = MAX(0, fromIndexOfVisibleBookViews + 1); index <= MIN(toIndexOfVisibleBookViews, [_visibleBookViews count] - 1); index++) { 761 | UIView *bookView = [_visibleBookViews objectAtIndex:index]; 762 | [self moveBookView:bookView steps:-1]; 763 | } 764 | 765 | [_visibleBookViews removeObjectAtIndex:indexOfBookViewToBeRemoved]; 766 | [_visibleBookViews insertObject:_dragView atIndex:toIndexOfVisibleBookViews]; 767 | 768 | if ([_parentBookShelfView.dataSource respondsToSelector:@selector(bookShelfView:moveBookFromIndex:toIndex:)]) { 769 | [_parentBookShelfView.dataSource bookShelfView:_parentBookShelfView moveBookFromIndex:_pickUpPosition.index toIndex:toPosition.index]; 770 | } 771 | 772 | _pickUpPosition = toPosition; 773 | _pickUpRect = toRect; 774 | } 775 | completion:^(BOOL finished) { 776 | _isBooksMoving = NO; 777 | if (shouldRemoveHeadOrTailFromVisibleBookViews) { 778 | [bookViewToRemove removeFromSuperview]; 779 | } 780 | 781 | }]; 782 | 783 | } 784 | 785 | 786 | else { 787 | // drag backward/up 788 | 789 | NSInteger fromIndexOfVisibleBookViews = [self converToIndexOfVisibleBookViewsFromBookViewPosition:_pickUpPosition]; 790 | NSInteger toIndexOfVisibleBookViews = [self converToIndexOfVisibleBookViewsFromBookViewPosition:toPosition]; 791 | 792 | NSInteger indexOfBookViewToBeRemoved = MIN([_visibleBookViews count] - 1, fromIndexOfVisibleBookViews); 793 | UIView *bookViewToRemove = [_visibleBookViews objectAtIndex:indexOfBookViewToBeRemoved]; 794 | 795 | [UIView animateWithDuration:0.3 796 | delay:0.0 797 | options:UIViewAnimationCurveLinear | UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionLayoutSubviews 798 | animations:^{ 799 | _isBooksMoving = YES; 800 | 801 | assert(toIndexOfVisibleBookViews >= 0); 802 | for (NSInteger index = MAX(0, toIndexOfVisibleBookViews); index <= MIN(fromIndexOfVisibleBookViews - 1, [_visibleBookViews count] - 1); index++) { 803 | UIView *bookView = [_visibleBookViews objectAtIndex:index]; 804 | [self moveBookView:bookView steps:1]; 805 | } 806 | 807 | [_visibleBookViews removeObjectAtIndex:indexOfBookViewToBeRemoved]; 808 | [_visibleBookViews insertObject:_dragView atIndex:toIndexOfVisibleBookViews]; 809 | 810 | if ([_parentBookShelfView.dataSource respondsToSelector:@selector(bookShelfView:moveBookFromIndex:toIndex:)]) { 811 | [_parentBookShelfView.dataSource bookShelfView:_parentBookShelfView moveBookFromIndex:_pickUpPosition.index toIndex:toPosition.index]; 812 | } 813 | 814 | _pickUpPosition = toPosition; 815 | _pickUpRect = toRect; 816 | } 817 | completion:^(BOOL finished) { 818 | _isBooksMoving = NO; 819 | if (shouldRemoveHeadOrTailFromVisibleBookViews) { 820 | [bookViewToRemove removeFromSuperview]; 821 | } 822 | 823 | }]; 824 | } 825 | } 826 | } 827 | 828 | #pragma mark - Delete and Add 829 | 830 | - (void)removeBookViewsAtIndexs:(NSIndexSet *)indexs animate:(BOOL)animate; { 831 | // The animation Sequence is: 832 | // 1. make bookViews disappear (a scale to (0.001, 0.001) in fact) 833 | // 2. because some rows may be removed, we will set the contentOffset to a propper postition 834 | // 3. move bookViews to fill blank 835 | 836 | // Discussion 1: _parentBookShelfView's remove.... method did step 2 above before coming in to the current method. Seems the layoutSubviews called by setContentOffset(step 2) should occour before step 1. But the true is:layoutSubvies occour after step 1. I think it's "runloop" that cause this. Animation was set and then main thread enter next loop and layoutSubviews occour.(I'm not so sure about this.) 837 | 838 | // Discussion 2: 839 | // step 1. in the first animation we scale the bookViews to be removed. The current visible bookVie will move to some position in step 3 so we record the steps for each visible bookView(stepsArray), and record the positions(indexs) they will move to(_indexsOfBookViewNotShown). 840 | // step 2. in the layoutSubviews. we add all new added bookView to _tempVisibleBookViewCollector instead of _visibleBookViews to keep _visibleBookViews "clean"(contains only bookViews showed in step 1). And check if the added bookview index is in _indexsOfBookViewNotShown (not add them to subviews). After layoutSubviews, the contentOffset has been set properly, and the proper bookViews will show up with some blank waiting for some bookViews moving to. 841 | // step 3. This is simple, just let each bookViews move with the steps record in stepsArray. After all animation. We clean the Arrays and Sets and refresh the current contents to make some bookView visible and keep everything go back to normal status. 842 | 843 | _isRemoving = YES; 844 | _indexsOfBookViewToBeRemoved = [[NSMutableIndexSet alloc] initWithIndexSet:indexs]; 845 | 846 | NSMutableArray *stepsArray = [[NSMutableArray alloc] initWithCapacity:[_visibleBookViews count]]; 847 | 848 | // Record the bookViews to be remvoed 849 | [UIView animateWithDuration:animate ? 0.15 : 0.0 850 | delay:0.0 851 | options:UIViewAnimationCurveLinear | UIViewAnimationOptionLayoutSubviews 852 | animations:^{ 853 | // Dissmiss BookView 854 | //NSLog(@"disappear animation"); 855 | 856 | __block NSInteger steps = 0; 857 | __block NSInteger moveFromIndex = 0; 858 | 859 | [indexs enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) { 860 | BookViewPostion position = [self convertToBookViewPositionFromIndex:index]; 861 | NSInteger indexOfVisibleBookViews = [self converToIndexOfVisibleBookViewsFromBookViewPosition:position]; 862 | if (indexOfVisibleBookViews >= 0) { 863 | if (indexOfVisibleBookViews >= [_visibleBookViews count]) { 864 | *stop = YES; 865 | // added on 12.08.24 fix deletion when deletion index bigger than max visible index 866 | // not increse steps, balance with steps++ 867 | steps--; 868 | } 869 | else { 870 | // shrink 871 | UIView *bookView = [_visibleBookViews objectAtIndex:indexOfVisibleBookViews]; 872 | bookView.transform = CGAffineTransformMakeScale(0.001f, 0.001f); 873 | 874 | // record _indexsOfBookViewNotShown 875 | BOOL overVisible = indexOfVisibleBookViews >= [_visibleBookViews count]; 876 | NSInteger moveToIndex = overVisible ? [_visibleBookViews count] - 1 : indexOfVisibleBookViews; 877 | while (moveFromIndex <= moveToIndex) { 878 | NSInteger realIndex = [self convertToIndexFromVisibleBookViewIndex:moveFromIndex] - steps; 879 | [_indexsOfBookViewNotShown addIndex:realIndex]; 880 | 881 | [stepsArray addObject:[NSNumber numberWithInt:-steps]]; 882 | 883 | moveFromIndex++; 884 | } 885 | } 886 | } 887 | 888 | steps++; 889 | 890 | //NSLog(@"index not shown: %@", [_indexsOfBookViewNotShown description]); 891 | }]; 892 | while (moveFromIndex < [_visibleBookViews count]) { 893 | NSInteger realIndex = [self convertToIndexFromVisibleBookViewIndex:moveFromIndex] - steps; 894 | [_indexsOfBookViewNotShown addIndex:realIndex]; 895 | 896 | [stepsArray addObject:[NSNumber numberWithInt:-steps]]; 897 | 898 | moveFromIndex++; 899 | } 900 | }completion:^(BOOL finished) { 901 | //NSLog(@"disappear animation completion"); 902 | 903 | [UIView animateWithDuration:animate ? 0.3 : 0.0 904 | delay:0.01 905 | options:UIViewAnimationOptionCurveLinear 906 | animations:^ { 907 | //NSLog(@"move animation"); 908 | for (int i = 0; i < [_visibleBookViews count]; i++) { 909 | UIView *bookView = [_visibleBookViews objectAtIndex:i]; 910 | [self moveBookView:bookView steps:[(NSNumber *)[stepsArray objectAtIndex:i] intValue]]; 911 | } 912 | return; 913 | } 914 | completion:^(BOOL finished) { 915 | //NSLog(@"move animation completion"); 916 | [_indexsOfBookViewToBeRemoved removeAllIndexes]; 917 | [_indexsOfBookViewNotShown removeAllIndexes]; 918 | 919 | _isRemoving = NO; 920 | for (UIView *view in _tempVisibleBookViewCollector) { 921 | [view removeFromSuperview]; 922 | } 923 | [_tempVisibleBookViewCollector removeAllObjects]; 924 | 925 | for (UIView *bookView in _visibleBookViews) { 926 | [bookView removeFromSuperview]; 927 | } 928 | [_visibleBookViews removeAllObjects]; 929 | _firstVisibleRow = -1; 930 | _lastVisibleRow = -1; 931 | [_parentBookShelfView setNeedsLayout]; 932 | }]; 933 | }]; 934 | } 935 | 936 | 937 | - (void)insertBookViewsAtIndexs:(NSIndexSet *)indexs animate:(BOOL)animate; { 938 | // The animation Sequence is: 939 | // 1. move to get blanks for bookViews will be added 940 | // 2. show the added bookViews 941 | 942 | // Discussion: 943 | // step.1 we count from first insert index to the real index in _visibleBookView to calculte the steps of bookView in _visibleBookViews will move. 944 | // before animation in step 2.we get bookView from datasource and set the scale to (0.001,0.001) without animation 945 | // then in the animation, we set the bookView's scale to (1,1) to "show" the bookView and then refresh the _visibleBookView as we did in removeBookViewsAtIndexs:animate: 946 | [UIView animateWithDuration:animate ? 0.3 : 0.0 947 | delay:0.0 948 | options:UIViewAnimationOptionCurveLinear 949 | animations:^{ 950 | __block NSInteger steps = 0; 951 | __block NSInteger moveFromIndex = 0; 952 | __block NSInteger lastIndexInIndexs = -1; 953 | __block NSInteger tempIndex = 0; 954 | 955 | [indexs enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) { 956 | NSInteger diff = index - lastIndexInIndexs; 957 | 958 | if (diff > 1) { 959 | if (lastIndexInIndexs < 0) { 960 | // first enumerate 961 | tempIndex = index; 962 | } 963 | else { 964 | tempIndex = moveFromIndex + diff - 1; 965 | } 966 | while (moveFromIndex < tempIndex) { 967 | BookViewPostion position = [self convertToBookViewPositionFromIndex:moveFromIndex]; 968 | NSInteger indexOfVisibleBookViews = [self converToIndexOfVisibleBookViewsFromBookViewPosition:position]; 969 | if (indexOfVisibleBookViews > (NSInteger)[_visibleBookViews count] - 1) { 970 | *stop = YES; 971 | break; 972 | } 973 | else if (indexOfVisibleBookViews >= 0) { 974 | UIView *bookView = [_visibleBookViews objectAtIndex:indexOfVisibleBookViews]; 975 | [self moveBookView:bookView steps:steps]; 976 | } 977 | moveFromIndex++; 978 | } 979 | } 980 | steps++; 981 | lastIndexInIndexs = index; 982 | }]; 983 | while (YES) { 984 | BookViewPostion position = [self convertToBookViewPositionFromIndex:moveFromIndex]; 985 | NSInteger indexOfVisibleBookViews = [self converToIndexOfVisibleBookViewsFromBookViewPosition:position]; 986 | if (indexOfVisibleBookViews > (NSInteger)[_visibleBookViews count] - 1) { 987 | break; 988 | } 989 | else if (indexOfVisibleBookViews >= 0) { 990 | UIView *bookView = [_visibleBookViews objectAtIndex:indexOfVisibleBookViews]; 991 | [self moveBookView:bookView steps:steps]; 992 | } 993 | moveFromIndex++; 994 | } 995 | } 996 | completion:^(BOOL finished) { 997 | NSMutableArray *tempBookViewArray = [[NSMutableArray alloc] initWithCapacity:0]; 998 | [indexs enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) { 999 | BookViewPostion position = [self convertToBookViewPositionFromIndex:index]; 1000 | if (position.row > _lastVisibleRow) { 1001 | *stop = YES; 1002 | } 1003 | else if (position.row >= _firstVisibleRow) { 1004 | UIView *bookView = [_parentBookShelfView.dataSource bookShelfView:_parentBookShelfView bookViewAtIndex:index]; 1005 | CGRect bookViewFrame = [self bookViewRectAtBookViewPosition:position]; 1006 | [bookView setFrame:bookViewFrame]; 1007 | [self addSubview:bookView]; 1008 | bookView.transform = CGAffineTransformMakeScale(0.001f, 0.001f); 1009 | 1010 | [tempBookViewArray addObject:bookView]; 1011 | } 1012 | }]; 1013 | [UIView animateWithDuration:animate ? 0.25 : 0.0 1014 | delay:0.0 1015 | options:UIViewAnimationCurveEaseOut | UIViewAnimationOptionLayoutSubviews 1016 | animations:^{ 1017 | for (UIView *bookView in tempBookViewArray) { 1018 | bookView.transform = CGAffineTransformMakeScale(1.0f, 1.0f); 1019 | } 1020 | } 1021 | completion:^(BOOL finished) { 1022 | for (UIView *bookView in tempBookViewArray) { 1023 | [bookView removeFromSuperview]; 1024 | [self addReuseableBookView:bookView]; 1025 | } 1026 | [tempBookViewArray removeAllObjects]; 1027 | 1028 | for (UIView *bookView in _visibleBookViews) { 1029 | [bookView removeFromSuperview]; 1030 | [self addReuseableBookView:bookView]; 1031 | } 1032 | [_visibleBookViews removeAllObjects]; 1033 | _firstVisibleRow = -1; 1034 | _lastVisibleRow = -1; 1035 | [_parentBookShelfView setNeedsLayout]; 1036 | }]; 1037 | 1038 | }]; 1039 | } 1040 | 1041 | #pragma mark - visible 1042 | 1043 | - (NSArray *)visibleBookViews { 1044 | return _visibleBookViews; 1045 | } 1046 | 1047 | - (UIView *)bookViewAtIndex:(NSInteger)index { 1048 | NSInteger indexOfVisible = [self converToIndexOfVisibleBookViewsFromIndex:index]; 1049 | if (indexOfVisible < 0 || indexOfVisible >= [_visibleBookViews count]) { 1050 | return nil; 1051 | } 1052 | return [_visibleBookViews objectAtIndex:indexOfVisible]; 1053 | } 1054 | 1055 | #pragma mark - test 1056 | 1057 | - (void)checkVisibleBookViewsValid { 1058 | //NSLog(@"---------------------------"); 1059 | int i = ((UIView *)[_visibleBookViews objectAtIndex:0]).tag; 1060 | for (UIView *view in _visibleBookViews) { 1061 | if (i != view.tag) { 1062 | NSLog(@"$$$$$$ checkVisibleBookViewsValid error"); 1063 | } 1064 | i++; 1065 | } 1066 | //NSLog(@"***************************"); 1067 | } 1068 | 1069 | @end 1070 | --------------------------------------------------------------------------------