From b6552dceec2e781bd0a89be5852979465078f255 Mon Sep 17 00:00:00 2001 From: sho yakushiji Date: Tue, 21 Jan 2014 00:11:27 +0900 Subject: [PATCH] Add CLImagePicker --- .gitignore | 3 + CLImageViewerKit.podspec | 14 + .../CLImagePicker.bundle/CLAssetCell.xib | 45 + .../CLImagePicker.bundle/images/btn_clear.png | Bin 0 -> 8385 bytes .../images/btn_clear@2x.png | Bin 0 -> 12930 bytes .../CLImagePicker.bundle/images/btn_edit.png | Bin 0 -> 4898 bytes .../images/btn_edit@2x.png | Bin 0 -> 9352 bytes .../images/btn_selected_off.png | Bin 0 -> 1259 bytes .../images/btn_selected_off@2x.png | Bin 0 -> 2518 bytes .../images/btn_selected_on.png | Bin 0 -> 1666 bytes .../images/btn_selected_on@2x.png | Bin 0 -> 3549 bytes .../CLImagePickerBundle/CLImagePickerBundle.h | 31 + .../CLImagePickerBundle/CLImagePickerBundle.m | 92 ++ .../CLImagePickerController.h | 47 + .../CLImagePickerController.m | 407 ++++++ .../CLImagePickerController.xib | 64 + .../Components/CLAsset.h | 20 + .../Components/CLAsset.m | 39 + .../Components/CLAssetCell.h | 32 + .../Components/CLAssetCell.m | 45 + .../Components/CLAssetCell.xib | 45 + .../CLImagePickerManager.h | 37 + .../CLImagePickerManager.m | 324 +++++ .../CLImageViewerController.h | 72 ++ .../CLImageViewerController.m | 473 +++++++ .../CLImageViewerController.xib | 96 ++ .../Components/CLImageViewerLayout.h | 14 + .../Components/CLImageViewerLayout.m | 109 ++ .../Components/CLZoomingImageCell.h | 18 + .../Components/CLZoomingImageCell.m | 56 + .../project.pbxproj | 1086 +++++++++++++++++ .../contents.xcworkspacedata | 7 + .../CLImagePickerDemo/AppDelegate.h | 15 + .../CLImagePickerDemo/AppDelegate.m | 46 + .../Base.lproj/Main.storyboard | 38 + .../CLImagePickerDemo-Info.plist | 40 + .../CLImagePickerDemo-Prefix.pch | 16 + .../AppIcon.appiconset/Contents.json | 23 + .../LaunchImage.launchimage/Contents.json | 23 + .../CLImagePickerDemo/ViewController.h | 16 + .../CLImagePickerDemo/ViewController.m | 139 +++ .../en.lproj/InfoPlist.strings | 2 + .../CLImagePickerDemo/main.m | 18 + .../CLImagePickerDemoTests-Info.plist | 22 + .../CLImagePickerDemoTests.m | 34 + .../en.lproj/InfoPlist.strings | 2 + Demo/CLImagePickerDemo/Podfile | 5 + 47 files changed, 3615 insertions(+) create mode 100644 Classes/CLImagePicker/CLImagePicker.bundle/CLAssetCell.xib create mode 100644 Classes/CLImagePicker/CLImagePicker.bundle/images/btn_clear.png create mode 100644 Classes/CLImagePicker/CLImagePicker.bundle/images/btn_clear@2x.png create mode 100644 Classes/CLImagePicker/CLImagePicker.bundle/images/btn_edit.png create mode 100644 Classes/CLImagePicker/CLImagePicker.bundle/images/btn_edit@2x.png create mode 100644 Classes/CLImagePicker/CLImagePicker.bundle/images/btn_selected_off.png create mode 100644 Classes/CLImagePicker/CLImagePicker.bundle/images/btn_selected_off@2x.png create mode 100644 Classes/CLImagePicker/CLImagePicker.bundle/images/btn_selected_on.png create mode 100644 Classes/CLImagePicker/CLImagePicker.bundle/images/btn_selected_on@2x.png create mode 100644 Classes/CLImagePicker/CLImagePickerBundle/CLImagePickerBundle.h create mode 100644 Classes/CLImagePicker/CLImagePickerBundle/CLImagePickerBundle.m create mode 100644 Classes/CLImagePicker/CLImagePickerController/CLImagePickerController.h create mode 100644 Classes/CLImagePicker/CLImagePickerController/CLImagePickerController.m create mode 100644 Classes/CLImagePicker/CLImagePickerController/CLImagePickerController.xib create mode 100644 Classes/CLImagePicker/CLImagePickerController/Components/CLAsset.h create mode 100644 Classes/CLImagePicker/CLImagePickerController/Components/CLAsset.m create mode 100644 Classes/CLImagePicker/CLImagePickerController/Components/CLAssetCell.h create mode 100644 Classes/CLImagePicker/CLImagePickerController/Components/CLAssetCell.m create mode 100644 Classes/CLImagePicker/CLImagePickerController/Components/CLAssetCell.xib create mode 100644 Classes/CLImagePicker/CLImagePickerManager/CLImagePickerManager.h create mode 100644 Classes/CLImagePicker/CLImagePickerManager/CLImagePickerManager.m create mode 100644 Classes/CLImagePicker/CLImageViewerController/CLImageViewerController.h create mode 100644 Classes/CLImagePicker/CLImageViewerController/CLImageViewerController.m create mode 100644 Classes/CLImagePicker/CLImageViewerController/CLImageViewerController.xib create mode 100644 Classes/CLImagePicker/CLImageViewerController/Components/CLImageViewerLayout.h create mode 100644 Classes/CLImagePicker/CLImageViewerController/Components/CLImageViewerLayout.m create mode 100644 Classes/CLImagePicker/CLImageViewerController/Components/CLZoomingImageCell.h create mode 100644 Classes/CLImagePicker/CLImageViewerController/Components/CLZoomingImageCell.m create mode 100644 Demo/CLImagePickerDemo/CLImagePickerDemo.xcodeproj/project.pbxproj create mode 100644 Demo/CLImagePickerDemo/CLImagePickerDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Demo/CLImagePickerDemo/CLImagePickerDemo/AppDelegate.h create mode 100644 Demo/CLImagePickerDemo/CLImagePickerDemo/AppDelegate.m create mode 100644 Demo/CLImagePickerDemo/CLImagePickerDemo/Base.lproj/Main.storyboard create mode 100644 Demo/CLImagePickerDemo/CLImagePickerDemo/CLImagePickerDemo-Info.plist create mode 100644 Demo/CLImagePickerDemo/CLImagePickerDemo/CLImagePickerDemo-Prefix.pch create mode 100644 Demo/CLImagePickerDemo/CLImagePickerDemo/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 Demo/CLImagePickerDemo/CLImagePickerDemo/Images.xcassets/LaunchImage.launchimage/Contents.json create mode 100644 Demo/CLImagePickerDemo/CLImagePickerDemo/ViewController.h create mode 100644 Demo/CLImagePickerDemo/CLImagePickerDemo/ViewController.m create mode 100644 Demo/CLImagePickerDemo/CLImagePickerDemo/en.lproj/InfoPlist.strings create mode 100644 Demo/CLImagePickerDemo/CLImagePickerDemo/main.m create mode 100644 Demo/CLImagePickerDemo/CLImagePickerDemoTests/CLImagePickerDemoTests-Info.plist create mode 100644 Demo/CLImagePickerDemo/CLImagePickerDemoTests/CLImagePickerDemoTests.m create mode 100644 Demo/CLImagePickerDemo/CLImagePickerDemoTests/en.lproj/InfoPlist.strings create mode 100644 Demo/CLImagePickerDemo/Podfile diff --git a/.gitignore b/.gitignore index 6e13704..0e1c24d 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,6 @@ DerivedData #CocoaPods Pods +Podfile.lock +*.xcworkspace +develop diff --git a/CLImageViewerKit.podspec b/CLImageViewerKit.podspec index e48f099..3453735 100644 --- a/CLImageViewerKit.podspec +++ b/CLImageViewerKit.podspec @@ -76,4 +76,18 @@ Pod::Spec.new do |s| a.source_files = 'Classes/CLColorPickerView/*.{h,m}' a.dependency 'CLImageViewerKit/UIViewFrame' end + + + + s.subspec 'CLImagePicker' do |a| + a.source_files = 'Classes/CLImagePicker/**/*.{h,m}' + a.public_header_files = 'Classes/CLImagePicker/*/*.h' + a.resources = 'Classes/CLImagePicker/**/*.xib', 'Classes/CLImagePicker/**/*.bundle' + a.dependency 'CLImageViewerKit/UIViewFrame' + a.dependency 'CLImageViewerKit/UIImageUtility' + a.dependency 'CLImageViewerKit/CLZoomingImageView' + a.dependency 'CLImageViewerKit/CLCacheManager' + a.dependency 'CLImageEditor' + end + end diff --git a/Classes/CLImagePicker/CLImagePicker.bundle/CLAssetCell.xib b/Classes/CLImagePicker/CLImagePicker.bundle/CLAssetCell.xib new file mode 100644 index 0000000..9e758cc --- /dev/null +++ b/Classes/CLImagePicker/CLImagePicker.bundle/CLAssetCell.xib @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Classes/CLImagePicker/CLImagePicker.bundle/images/btn_clear.png b/Classes/CLImagePicker/CLImagePicker.bundle/images/btn_clear.png new file mode 100644 index 0000000000000000000000000000000000000000..551ca757701a591f1cf3d286ef85de1ed4dccb5e GIT binary patch literal 8385 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 literal 0 HcmV?d00001 diff --git a/Classes/CLImagePicker/CLImagePicker.bundle/images/btn_clear@2x.png b/Classes/CLImagePicker/CLImagePicker.bundle/images/btn_clear@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b3038f348ca063afadd4387728cef1a39dc8c123 GIT binary patch literal 12930 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 NC3!XYS6PdQ{|DqDa~}Wz literal 0 HcmV?d00001 diff --git a/Classes/CLImagePicker/CLImagePicker.bundle/images/btn_edit.png b/Classes/CLImagePicker/CLImagePicker.bundle/images/btn_edit.png new file mode 100644 index 0000000000000000000000000000000000000000..8b61b7b80082b2e0b132faa00b20ae7a7cdf4c84 GIT binary patch literal 4898 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%0A99kl7?|7e%Y?@f{ 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 literal 0 HcmV?d00001 diff --git a/Classes/CLImagePicker/CLImagePicker.bundle/images/btn_selected_off.png b/Classes/CLImagePicker/CLImagePicker.bundle/images/btn_selected_off.png new file mode 100644 index 0000000000000000000000000000000000000000..d3323ed406132def589c67d5dc665990629c0e8b GIT binary patch literal 1259 zcmVJNRA_OcY5}pri`XL=$*u zjOc?8`sk~FkRc{&P!kiPp@JbHT4_iGCESIGqLF}Yp)}QAmk(<;XSY3j&)%nvw6$Nd zlQa9QS+l-bYi6yPEi+>-V8OjMV7f3*WTs)B$V|hWA+m6~6-rtFGy)F*4+5KjM}V8a z1>g_hI?!!q!_zkIbmb9AYk{YMW}L+RIpTxBU%(~cw3%I-^7vCFBB=>z!%3u#?+5yT z0bm&S{t}=8Sdo$&#yxe+%&yjKN3BF8)d4$!-N4fDx*IqLTm)_a{bn|l>a#G&t_Gd} zp2EWqoX~OLh?)KUpAeC>3}^?Q39ov9W57>l)?Y%;VxR?h5no3DSAoyX?0PAi$`X;Z z5_lVUEWGLh4x3qDDMjOTF2=)i7qAGQn2*ft*TOo=5RtSLco!!z3>-AG<0Wj4>2Cq{ z;p?au_`uBmEYi1d9tmrroeGIhr;`MLnVkprBkEr0=En%Sw6 zb{0Yirvtzc@G$Udk$#1UNLmfN9GWN1tg{v)i^9w<0!Kpgc}W{%eTsUd6_49nz@ggA zs}4!^8Gn5T{DSA7-66Cy5hWsN6|gllJI(A?8ABtwcL488YM)3blrKktF<=9gU9u{Q zc%%hbhA+UAwHRCtk{$*20BdoNud5>VGjI*41D?&(mrF#FfX$(K$;@t-H8?|WJ+K$g z8Q=wF??gE>8v#y-<_1YivUJ8g(m-XVE|ju1A8o+n;rAHOVP$8MnM4Ez3A70H)3884*i&w$m;dIFI%Zq=2 zB&4@x3B`yc<@O-%m8oI}kmLlzLn?O{3?!3DtU0uj#W)t8njvW&m81&rBgJ>Y=t(k0 zB=N$6JXtw5hoZ0A|8@9Qo77FWiHB4gSxNIQVrTXwHW%aG$(otxfHwdneT&y(X%B7( zo=mkn%&aG7T+k;xkAWZ7sv_o*8+b@9PbsU0HGsm?2D}~?Hj>sbKBUe7KSah&<31{D zwJS>~Mx+P0gL|V|=1uTD@LQ_=0`Qik2E2MrCZQkrYJ#_7XbjINka^IG5xGMpe>7(a zg`H2c7DAKPmk>J`d@K~(}_DR}a+R_|^66YO!W9bDBgbgI# z_kVfQm>PKY-~FbHnEki$;}p#H?<12G&Gs)=lN8SOZ;1CAbLR8(Jdv4(c_K3n{{p@z V&4c=O&&~h<002ovPDHLkV1lxEFSq~z literal 0 HcmV?d00001 diff --git a/Classes/CLImagePicker/CLImagePicker.bundle/images/btn_selected_off@2x.png b/Classes/CLImagePicker/CLImagePicker.bundle/images/btn_selected_off@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..497ab9e8544ae9b52cb9bd47178af7b43e2642b2 GIT binary patch literal 2518 zcmai$`#;l*AIFEeE+M(*G8=Pe6f#O!X08=;D`H!;+>_-pmnp~8$}N|Paythfa+yn# z)(}>f9yuY)?JE?y-|MXUI)B0W;q`hx9kH_nW_v7)-Jm-dylu(ucfk2X2NA!gQ z691K$$bm=A=6fDMJj&5G1_Xl0{wo1caf#wVM#G|QJ>yDNN`Gc4U{nV#tKY{^)1c`* zyR*CtwqZKgUGqJ;@3lQ_VWbhD)@;Llv-%nxD|-=nVfhxcY9x2~g5Dbsl0f-(Hf+9D zrAKuli66AUnOa`mV_8`}pVnR0|Bh(dnq)j%OZ>99^_^Q^qbIq6{OfPItBP2-Bk@EU z+TlMyU%4TC2MUv=l6H@)c1ZewC^B15FM-`am{iDajM`U^k#e^W&vcHow0WahAg(Y= zf-4j(;6ZH=9Op}&6x|lYPzk^f(hML1N7BaU;0{QKR+Nm8V)U-SKe!#28NRd3 zJt)jn)#va;7D+rdN;ppaV>$4m>kxsMRO3%6S%?RM zu`${{Eijm8yXNpaQZ>$Fpa*cogr?!~NcfC5tJxTO!B!En7AJ*X83SuYsn3ym1j zXx3nBr(aUTQp*D5pkVYZxeq~zDD`0OHM4*fpqbrf zIQKEnYH{|38I76IlEx&7E}yZo%Xbf!3hj%p=a)1ti<;LhrRX)fh>*LV3Hpe;aQB^T zngVdYedGNBc{Dmg_>smx;$3206~J@7C+LSXPB{D8%qo3O!)33nav0^QdoV&US)8H^ z|BhTA=CQA!kx zv&BuH)~Z~by6u&Vt}`BL-W z^U&L28qU=8p|-&yTto`{I_mW_vb|07GgTY?suY$egO+|ioOBXSY5^V{I`44E$70=~ z>>bvRX5v?X@PsTPUhG>*cy1Y>I`$lXK$MPalW-1qL=#JBE-fqu zZ21-a9(ENZpZ~;zR+ASQNRhY=3yU>S4wz+ zq;srHOuXa6B#C@$XP)=$6^9KuqQv6K@t8;PxHKBQ7rZdf$ha>MDWcaPC5wGbtaW!_ zrFA?J8b&O-wdC@5*toz-AOPa&Wka&<;=@^K#J>3iVLNXsZQ{O(%ECtHPJRYn8tz1* z2)|wuu{#z1XVYKXZF3K86R2bM1*9=!Tf_;AS)&QLxdG|Ry*F_0`)_}j$Q@Beu`0dM z3)w49Y74HoQ(m^u2s-UDW(w2lCUq~lca$TKeHytzFi!{&A_ z5+I#^4=##bwq+ioc~JC&9ye(#Ejs%kV8?JfE9Ncn*_6sDXt00}ZhH_sELBwq>3KT1 z)a#;}*P*`$<7%&bRJxm4?r+I^YyRd}j{N2EavVd6@)+eEo*&$pjNl#UG>s#B3vp=xB9`9`ZD({6B=iA-AkmV7y><(#bzEe~0%yHIex;=4x*K!}{q?;Kb|L z{i_olY0e*XX?^!P6fvFn@E`@RW5|c6FGky}dmMv^1c$~>5oZn7i`|p%1fI%i$Xt-c z#a7OLs-Qy$u#K3_&im(^$$#$9Bi1h-;&US!1BPc4Q@ln{%b_tQ)v{U}_p$nL4rw^) z_vCKoh8-@$b4QD5Z={+u3 zCA>8K&YlNqNgQ3o+Dtsgygd?>^fLMovT2 zVk>|(&>B&5hvw-1brWzvuY!`@cmia#kJ6||&j4hZ>zPrd^sKv_O1XR`mFEQs1+8W` zLHoBRThtynft$O*?+8OihQXu|OQjms>- zEk3Hn1bifufNxazpi(svP+DBsA30pvk2%Uy>3{6J)p;jpqNK4-@jP`Q-3b1*1KN9{ z(b^OZ=OEuYcf({gv0J<@4k^H3{G8Rl_x;Z79yI5@*b$}wz(&e9nR|-T-+{b?M-7BM L>xOQy3rzbzG^(B@ literal 0 HcmV?d00001 diff --git a/Classes/CLImagePicker/CLImagePicker.bundle/images/btn_selected_on.png b/Classes/CLImagePicker/CLImagePicker.bundle/images/btn_selected_on.png new file mode 100644 index 0000000000000000000000000000000000000000..e7868df47b34ef910907f15f41ce9186ad687e12 GIT binary patch literal 1666 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

A8*w=E5h#89N+)h za|oVwbu~6?HMILQQNm6lCY_(L^1#skEgeIivlojVYBG|n#BdEVU@?W=%4_n25k#lte|~mvKE)mB3t6^baXZ-AevphE#Jv3 z$?&8DCJz*rrN2D$NQ(c)caR1Q)?;MXe57L0bZ$mX3qNa$ZhUsAi@*E9GoWd5`F`j;5~)gpInziEm16!1I46P7m5i<0RqK;l0=JU^&jH(@rQ2;((;*ysKBq@ zaXlW1vVGy61I5Wi#I=b|AKR10E$3BzL4jW@+?MBAEE^BLQoPq<#fd9DwvnLQQa3Y! zmQ!9M234^-Vc%g^LC0s8Z|L0`iVj7Oaim3(YZsy*hgRWx9YxDs(TyTh>AEt=$RSCD zO4!?BPz%Q=8~yY2uB^iu8lFe#<=Mk-msL?4lEa!i-_xg|kSDO29})84pP*O6qM7C* zqdvF!C?1KWPj6P03?qek(p1Hm5d8=LJI(xm*4g+=60^D;X#5bIeUsM!2D&DYCT$nQ F{{frkuOR>c literal 0 HcmV?d00001 diff --git a/Classes/CLImagePicker/CLImagePickerBundle/CLImagePickerBundle.h b/Classes/CLImagePicker/CLImagePickerBundle/CLImagePickerBundle.h new file mode 100644 index 0000000..ae56d67 --- /dev/null +++ b/Classes/CLImagePicker/CLImagePickerBundle/CLImagePickerBundle.h @@ -0,0 +1,31 @@ +// +// CLImagePickerBundle.h +// +// Created by sho yakushiji on 2014/01/17. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import + +@class CLImageEditor; +@protocol CLImagePickerBundleDelegate; + +@interface CLImagePickerBundle : NSObject + ++ (void)setDelegate:(id)delegate; ++ (void)setBundleName:(NSString*)bundleName; + + ++ (NSString*)bundleName; ++ (NSBundle*)bundle; ++ (UIImage*)imageNamed:(NSString*)path; ++ (CLImageEditor*)imageEditor; + +@end + + +@protocol CLImagePickerBundleDelegate +@optional +- (CLImageEditor*)imageEditorForImagePicker; + +@end diff --git a/Classes/CLImagePicker/CLImagePickerBundle/CLImagePickerBundle.m b/Classes/CLImagePicker/CLImagePickerBundle/CLImagePickerBundle.m new file mode 100644 index 0000000..63a3e3b --- /dev/null +++ b/Classes/CLImagePicker/CLImagePickerBundle/CLImagePickerBundle.m @@ -0,0 +1,92 @@ +// +// CLImagePickerBundle.m +// +// Created by sho yakushiji on 2014/01/17. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import "CLImagePickerBundle.h" + +#import + +@interface CLImagePickerBundle() +@property (nonatomic, weak) id delegate; +@property (nonatomic, strong) NSString *bundleName; +@end + +@implementation CLImagePickerBundle + +#pragma mark - singleton pattern + +static id _sharedInstance = nil; + ++ (CLImagePickerBundle*)instance +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _sharedInstance = [[self alloc] init]; + }); + return _sharedInstance; +} + ++ (id)allocWithZone:(NSZone *)zone +{ + @synchronized(self) { + if (_sharedInstance == nil) { + _sharedInstance = [super allocWithZone:zone]; + return _sharedInstance; + } + } + return nil; +} + +- (id)copyWithZone:(NSZone *)zone +{ + return self; +} + +- (id)init +{ + self = [super init]; + if (self) { + self.bundleName = @"CLImagePicker"; + } + return self; +} + +#pragma mark- claas methods + ++ (void)setDelegate:(id)delegate +{ + self.instance.delegate = delegate; +} + ++ (void)setBundleName:(NSString*)bundleName +{ + self.instance.bundleName = bundleName; +} + ++ (NSString*)bundleName +{ + return self.instance.bundleName; +} + ++ (NSBundle*)bundle +{ + return [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:self.bundleName ofType:@"bundle"]]; +} + ++ (UIImage*)imageNamed:(NSString*)path +{ + return [UIImage imageNamed:[NSString stringWithFormat:@"%@.bundle/%@", self.bundleName, path]]; +} + ++ (CLImageEditor*)imageEditor +{ + if([self.instance.delegate respondsToSelector:@selector(imageEditorForImagePicker)]){ + return [self.instance.delegate imageEditorForImagePicker]; + } + return [CLImageEditor new]; +} + +@end diff --git a/Classes/CLImagePicker/CLImagePickerController/CLImagePickerController.h b/Classes/CLImagePicker/CLImagePickerController/CLImagePickerController.h new file mode 100644 index 0000000..f5ed735 --- /dev/null +++ b/Classes/CLImagePicker/CLImagePickerController/CLImagePickerController.h @@ -0,0 +1,47 @@ +// +// CLImagePickerController.h +// +// Created by sho yakushiji on 2014/01/09. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import + +@protocol CLImagePickerControllerDelegate; + + +@interface CLImagePickerController : UIViewController +{ + IBOutlet __weak UICollectionView *_collectionView; + IBOutlet __weak UINavigationBar *_navigationBar; +} +@property (nonatomic, weak) id delegate; + +- (void)setSelectedURLs:(NSArray*)selectedURLs; + +- (IBAction)pushedDoneBtn:(id)sender; +- (IBAction)pushedCancelBtn:(id)sender; + +@end + + + +@protocol CLImagePickerControllerDelegate +@required + +- (void)imagePickerController:(CLImagePickerController *)picker didTouchOriginalImage:(UIImage*)image withAssetURL:(NSURL*)url; +- (void)imagePickerController:(CLImagePickerController *)picker didEditImage:(UIImage*)image withAssetURL:(NSURL*)url; +- (void)imagePickerController:(CLImagePickerController *)picker didRemoveEdittedImageWithAssetURL:(NSURL*)url; + +- (BOOL)imagePickerController:(CLImagePickerController *)picker isEdittedImageWithAssetURL:(NSURL*)url; + + +- (UIImage*)imagePickerController:(CLImagePickerController *)picker thumnailImageForAssetURL:(NSURL*)url; +- (UIImage*)imagePickerController:(CLImagePickerController *)picker fullScreenImageForAssetURL:(NSURL*)url; + +- (void)imagePickerController:(CLImagePickerController *)picker didFinishPickingMediaWithSelectedAssetURLs:(NSArray*)selectedURLs; + +@optional +- (void)imagePickerControllerDidCancel:(CLImagePickerController *)picker; + +@end diff --git a/Classes/CLImagePicker/CLImagePickerController/CLImagePickerController.m b/Classes/CLImagePicker/CLImagePickerController/CLImagePickerController.m new file mode 100644 index 0000000..00aa509 --- /dev/null +++ b/Classes/CLImagePicker/CLImagePickerController/CLImagePickerController.m @@ -0,0 +1,407 @@ +// +// CLImagePickerController.m +// +// Created by sho yakushiji on 2014/01/09. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import "CLImagePickerController.h" + +#import "UIView+Frame.h" +#import "CLCacheManager.h" +#import "CLAssetCell.h" +#import "CLImagePickerBundle.h" +#import "CLImageViewerController.h" + +NSString * const CLAssetCellReuseIdentifier = @"AssetCell"; + + +@interface CLImagePickerController () + +@end + + +@implementation CLImagePickerController +{ + ALAssetsLibrary *_library; + NSMutableArray *_assets; + ALAssetsGroup *_currentGroup; + + NSMutableOrderedSet *_selectedURLs; +} + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + _selectedURLs = [NSMutableOrderedSet new]; + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + NSString *nibName = NSLocalizedStringWithDefaultValue(@"CLAssetCell_NibName", nil, [CLImagePickerBundle bundle], @"CLAssetCell", @""); + [_collectionView registerNib:[UINib nibWithNibName:nibName bundle:nil] forCellWithReuseIdentifier:CLAssetCellReuseIdentifier]; + _collectionView.alwaysBounceVertical = YES; + _collectionView.contentInset = UIEdgeInsetsMake(_navigationBar.bottom, 0, 0, 0); + _collectionView.allowsMultipleSelection = YES; + + if([self respondsToSelector:@selector(automaticallyAdjustsScrollViewInsets)]){ + self.automaticallyAdjustsScrollViewInsets = NO; + } + + [self initAssets]; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (void)setSelectedURLs:(NSArray*)selectedURLs +{ + _selectedURLs = [[NSMutableOrderedSet alloc] initWithArray:selectedURLs]; +} + +#pragma mark- Caching + +- (UIImage*)originalImageForAsset:(CLAsset*)asset +{ + return asset.fullScreenImage; +} + +- (UIImage*)thumnailForAsset:(CLAsset*)asset +{ + UIImage *image = [self.delegate imagePickerController:self thumnailImageForAssetURL:asset.assetURL]; + if(image==nil){ + image = asset.thumnail; + } + return image; +} + +- (UIImage*)fullScreenImageForAsset:(CLAsset*)asset +{ + UIImage *image = [self.delegate imagePickerController:self fullScreenImageForAssetURL:asset.assetURL]; + if(image==nil){ + image = asset.fullScreenImage; + } + return image; +} + +#pragma mark- Assets + +- (void)initAssets +{ + _library = [ALAssetsLibrary new]; + + [_library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos + usingBlock:^(ALAssetsGroup *group, BOOL *stop){ + if(group){ + _currentGroup = group; + } + else{ + [self loadAssetsFromCurrentGroup]; + } + } + failureBlock:^(NSError *error){ + NSLog(@"%@", error.localizedDescription); + } + ]; +} + +- (void)loadAssetsFromCurrentGroup +{ + if(_assets==nil){ + _assets = [NSMutableArray array]; + } + [_assets removeAllObjects]; + + _navigationBar.topItem.title = [_currentGroup valueForProperty:ALAssetsGroupPropertyName]; + + [_currentGroup enumerateAssetsUsingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop){ + if(asset){ + NSArray *array = [asset valueForProperty:ALAssetPropertyRepresentations]; + NSString *representation = (array.count>0) ? [array objectAtIndex:0]:nil; + + if(representation.length>0 && [[asset valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypePhoto]){ + [_assets addObject:[[CLAsset alloc] initWithAsset:asset]]; + } + } + else{ + [_collectionView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES]; + } + }]; +} + +- (CLAsset*)assetAtIndex:(NSUInteger)index +{ + if(index<_assets.count){ + return _assets[_assets.count - index - 1]; + } + return nil; +} + +#pragma mark- Settings + +- (UIBarPosition)positionForBar:(id )bar +{ + return UIBarPositionTopAttached; +} + +- (BOOL)shouldAutorotate +{ + return NO; +} + +- (NSUInteger)supportedInterfaceOrientations +{ + return UIInterfaceOrientationMaskPortrait; +} + +#pragma mark- Button actions + +- (IBAction)pushedDoneBtn:(id)sender +{ + [self.delegate imagePickerController:self didFinishPickingMediaWithSelectedAssetURLs:_selectedURLs.array]; +} + +- (IBAction)pushedCancelBtn:(id)sender +{ + if([self.delegate respondsToSelector:@selector(imagePickerControllerDidCancel:)]){ + [self.delegate imagePickerControllerDidCancel:self]; + } + else{ + [self dismissViewControllerAnimated:YES completion:nil]; + } +} + +#pragma mark- CLAssetCell delegate + +- (void)cellDidPushSelectButton:(CLAssetCell *)cell +{ + NSIndexPath *indexPath = [_collectionView indexPathForCell:cell]; + CLAsset *asset = [self assetAtIndex:indexPath.item]; + + if(cell.selected){ + [_collectionView deselectItemAtIndexPath:indexPath animated:NO]; + + [_selectedURLs removeObject:asset.assetURL]; + } + else{ + [_collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone]; + + [_selectedURLs addObject:asset.assetURL]; + [self.delegate imagePickerController:self didTouchOriginalImage:asset.fullScreenImage withAssetURL:asset.assetURL]; + } +} + +#pragma mark- UICollectionView + +- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView +{ + return 1; +} + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section +{ + return _assets.count; +} + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath +{ + UICollectionViewCell *cell = [_collectionView dequeueReusableCellWithReuseIdentifier:CLAssetCellReuseIdentifier forIndexPath:indexPath]; + + if([cell isKindOfClass:[CLAssetCell class]]){ + CLAsset *asset = [self assetAtIndex:indexPath.item]; + + CLAssetCell *_cell = (CLAssetCell*)cell; + _cell.delegate = self; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + UIImage *image = [self thumnailForAsset:asset]; + dispatch_async(dispatch_get_main_queue(), ^{ + _cell.image = image; + }); + }); + + BOOL selected = [_selectedURLs containsObject:asset.assetURL]; + if(_cell.selected != selected){ + if(selected){ + [_collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone]; + } + else{ + [_collectionView deselectItemAtIndexPath:indexPath animated:NO]; + } + _cell.selected = selected; + } + + } + + return cell; +} + +- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath +{ + UICollectionViewCell* cell = [collectionView cellForItemAtIndexPath:indexPath]; + cell.contentView.alpha = 0.6; +} + +- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath +{ + UICollectionViewCell* cell = [collectionView cellForItemAtIndexPath:indexPath]; + cell.contentView.alpha = 1; +} + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath +{ + //UICollectionViewCell* cell = [collectionView cellForItemAtIndexPath:indexPath]; + [collectionView deselectItemAtIndexPath:indexPath animated:NO]; + + [self showImageViewerWithIndex:indexPath.item]; +} + +- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath +{ + //UICollectionViewCell* cell = [collectionView cellForItemAtIndexPath:indexPath]; + [collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone]; + + [self showImageViewerWithIndex:indexPath.item]; +} + +#pragma mark- CLImageViewerController + +- (void)showImageViewerWithIndex:(NSInteger)index +{ + NSString *nibName = NSLocalizedStringWithDefaultValue(@"CLImageViewerController_NibName", nil, [CLImagePickerBundle bundle], @"CLImageViewerController", @""); + + CLImageViewerController *viewer = [[CLImageViewerController alloc] initWithNibName:nibName bundle:nil]; + viewer.dataSource = self; + viewer.delegate = self; + + [viewer showInViewController:self withIndex:index]; +} + +#pragma mark DataSource + +- (NSInteger)imageViewerControllerNumberOfImages:(CLImageViewerController*)viewer +{ + return _assets.count; +} + +- (UIImage*)imageViewerController:(CLImageViewerController*)viewer originalImageAtIndex:(NSInteger)index +{ + return [self originalImageForAsset:[self assetAtIndex:index]]; +} + +- (UIImage*)imageViewerController:(CLImageViewerController*)viewer thumnailImageAtIndex:(NSInteger)index +{ + return [self thumnailForAsset:[self assetAtIndex:index]]; +} + +- (UIImage*)imageViewerController:(CLImageViewerController*)viewer fullScreenImageAtIndex:(NSInteger)index +{ + return [self fullScreenImageForAsset:[self assetAtIndex:index]]; +} + +- (BOOL)imageViewerController:(CLImageViewerController*)viewer isSelectedImageAtIndex:(NSInteger)index +{ + CLAsset *asset = [self assetAtIndex:index]; + return [_selectedURLs containsObject:asset.assetURL]; +} + +- (BOOL)imageViewerController:(CLImageViewerController*)viewer isEditedImageAtIndex:(NSInteger)index +{ + CLAsset *asset = [self assetAtIndex:index]; + return [self.delegate imagePickerController:self isEdittedImageWithAssetURL:asset.assetURL]; +} + +- (void)imageViewerController:(CLImageViewerController*)viewer didSelectImageAtIndex:(NSInteger)index +{ + [_collectionView selectItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0] animated:NO scrollPosition:UICollectionViewScrollPositionNone]; + + CLAsset *asset = [self assetAtIndex:index]; + [_selectedURLs addObject:asset.assetURL]; + + [self.delegate imagePickerController:self didTouchOriginalImage:asset.fullScreenImage withAssetURL:asset.assetURL]; +} + +- (void)imageViewerController:(CLImageViewerController*)viewer didDeSelectImageAtIndex:(NSInteger)index +{ + [_collectionView deselectItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0] animated:NO]; + + CLAsset *asset = [self assetAtIndex:index]; + [_selectedURLs removeObject:asset.assetURL]; +} + +- (void)imageViewerController:(CLImageViewerController *)viewer willEditImageAtIndex:(NSInteger)index +{ + CLAsset *asset = [self assetAtIndex:index]; + [self.delegate imagePickerController:self didTouchOriginalImage:asset.fullScreenImage withAssetURL:asset.assetURL]; +} + +- (void)imageViewerController:(CLImageViewerController*)viewer didEditImageAtIndex:(NSInteger)index edittedImage:(UIImage*)image +{ + CLAsset *asset = [self assetAtIndex:index]; + [self.delegate imagePickerController:self didEditImage:image withAssetURL:asset.assetURL]; + + CLAssetCell *cell = (CLAssetCell*)[_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; + if(cell){ + cell.image = [self thumnailForAsset:[self assetAtIndex:index]]; + } +} + +- (void)imageViewerController:(CLImageViewerController*)viewer didRemoveEdittedImageAtIndex:(NSInteger)index +{ + CLAsset *asset = [self assetAtIndex:index]; + [self.delegate imagePickerController:self didRemoveEdittedImageWithAssetURL:asset.assetURL]; +} + +#pragma mark Delegate + +- (UIImageView*)imageViewerController:(CLImageViewerController*)viewer imageViewAtIndex:(NSInteger)index +{ + CLAssetCell *cell = (CLAssetCell*)[_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; + return cell.imageView; +} + +- (void)imageViewerController:(CLImageViewerController*)viewer willAppearWithIndex:(NSInteger)index +{ + CLAssetCell *cell = (CLAssetCell*)[_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; + cell.hidden = YES; +} + +- (void)imageViewerController:(CLImageViewerController*)viewer didAppearWithIndex:(NSInteger)index +{ + CLAssetCell *cell = (CLAssetCell*)[_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; + cell.hidden = NO; +} + +- (void)imageViewerController:(CLImageViewerController*)viewer willDismissWithIndex:(NSInteger)index +{ + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index inSection:0]; + CLAssetCell *cell = (CLAssetCell*)[_collectionView cellForItemAtIndexPath:indexPath]; + + if(cell==nil){ + [_collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionNone animated:NO]; + } +} + +- (BOOL)imageViewerController:(CLImageViewerController *)viewer readyToDismissWithIndex:(NSInteger)index +{ + CLAssetCell *cell = (CLAssetCell*)[_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; + cell.hidden = YES; + + return (cell!=nil); +} + +- (void)imageViewerController:(CLImageViewerController*)viewer didDismissWithIndex:(NSInteger)index +{ + CLAssetCell *cell = (CLAssetCell*)[_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; + cell.hidden = NO; +} + +@end diff --git a/Classes/CLImagePicker/CLImagePickerController/CLImagePickerController.xib b/Classes/CLImagePicker/CLImagePickerController/CLImagePickerController.xib new file mode 100644 index 0000000..c38df76 --- /dev/null +++ b/Classes/CLImagePicker/CLImagePickerController/CLImagePickerController.xib @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Classes/CLImagePicker/CLImagePickerController/Components/CLAsset.h b/Classes/CLImagePicker/CLImagePickerController/Components/CLAsset.h new file mode 100644 index 0000000..0b92cd3 --- /dev/null +++ b/Classes/CLImagePicker/CLImagePickerController/Components/CLAsset.h @@ -0,0 +1,20 @@ +// +// CLAsset.h +// +// Created by sho yakushiji on 2014/01/10. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import + +#import + +@interface CLAsset : NSObject + +- (id)initWithAsset:(ALAsset*)asset; + +- (NSURL*)assetURL; +- (UIImage*)thumnail; +- (UIImage*)fullScreenImage; + +@end diff --git a/Classes/CLImagePicker/CLImagePickerController/Components/CLAsset.m b/Classes/CLImagePicker/CLImagePickerController/Components/CLAsset.m new file mode 100644 index 0000000..14bf8c0 --- /dev/null +++ b/Classes/CLImagePicker/CLImagePickerController/Components/CLAsset.m @@ -0,0 +1,39 @@ +// +// CLAsset.m +// +// Created by sho yakushiji on 2014/01/10. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import "CLAsset.h" + +@implementation CLAsset +{ + ALAsset *_asset; +} + +- (id)initWithAsset:(ALAsset *)asset +{ + self = [super init]; + if(self){ + _asset = asset; + } + return self; +} + +- (NSURL*)assetURL +{ + return [[_asset valueForProperty:ALAssetPropertyURLs] objectForKey:[[_asset defaultRepresentation] UTI]]; +} + +- (UIImage*)thumnail +{ + return [UIImage imageWithCGImage:[_asset aspectRatioThumbnail]]; +} + +- (UIImage*)fullScreenImage +{ + return [UIImage imageWithCGImage:[[_asset defaultRepresentation] fullScreenImage]]; +} + +@end diff --git a/Classes/CLImagePicker/CLImagePickerController/Components/CLAssetCell.h b/Classes/CLImagePicker/CLImagePickerController/Components/CLAssetCell.h new file mode 100644 index 0000000..7ac3520 --- /dev/null +++ b/Classes/CLImagePicker/CLImagePickerController/Components/CLAssetCell.h @@ -0,0 +1,32 @@ +// +// CLAssetCell.h +// +// Created by sho yakushiji on 2014/01/10. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import + +#import "CLAsset.h" + +@protocol CLAssetCellDelegate; + +@interface CLAssetCell : UICollectionViewCell +{ + IBOutlet __weak UIImageView *_imageView; + IBOutlet __weak UIButton *_selectBtn; +} +@property (nonatomic, weak) id delegate; +@property (nonatomic, readonly) UIImageView *imageView; + +- (IBAction)pushedSelectBtn:(id)sender; +- (void)setImage:(UIImage*)image; + +@end + + +@protocol CLAssetCellDelegate +@required +- (void)cellDidPushSelectButton:(CLAssetCell*)cell; + +@end diff --git a/Classes/CLImagePicker/CLImagePickerController/Components/CLAssetCell.m b/Classes/CLImagePicker/CLImagePickerController/Components/CLAssetCell.m new file mode 100644 index 0000000..75edb81 --- /dev/null +++ b/Classes/CLImagePicker/CLImagePickerController/Components/CLAssetCell.m @@ -0,0 +1,45 @@ +// +// CLAssetCell.m +// +// Created by sho yakushiji on 2014/01/10. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import "CLAssetCell.h" + +@implementation CLAssetCell +{ + +} + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + + } + return self; +} + +- (UIImageView*)imageView +{ + return _imageView; +} + +- (void)setImage:(UIImage*)image +{ + _imageView.image = image; +} + +- (void)setSelected:(BOOL)selected +{ + [super setSelected:selected]; + _selectBtn.selected = selected; +} + +- (IBAction)pushedSelectBtn:(id)sender +{ + [self.delegate cellDidPushSelectButton:self]; +} + +@end diff --git a/Classes/CLImagePicker/CLImagePickerController/Components/CLAssetCell.xib b/Classes/CLImagePicker/CLImagePickerController/Components/CLAssetCell.xib new file mode 100644 index 0000000..9e758cc --- /dev/null +++ b/Classes/CLImagePicker/CLImagePickerController/Components/CLAssetCell.xib @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Classes/CLImagePicker/CLImagePickerManager/CLImagePickerManager.h b/Classes/CLImagePicker/CLImagePickerManager/CLImagePickerManager.h new file mode 100644 index 0000000..d23af5b --- /dev/null +++ b/Classes/CLImagePicker/CLImagePickerManager/CLImagePickerManager.h @@ -0,0 +1,37 @@ +// +// CLImagePickerManager.h +// +// Created by sho yakushiji on 2014/01/14. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import + +#import "CLImageViewerController.h" + +@protocol CLImagePickerManagerDelegate; + +@interface CLImagePickerManager : NSObject + +@property (nonatomic, weak) id delegate; +@property (nonatomic, readonly) NSUInteger numberOfSelectedImages; + ++ (CLImagePickerManager*)managerWithDelegate:(UIViewController*)delegate; + +- (UIViewController*)pickerViewController; + +- (UIImage*)thumnailImageAtIndex:(NSUInteger)index; +- (UIImage*)fullScreenImageAtIndex:(NSUInteger)index; + +- (void)showImageViewerInViewController:(UIViewController*)controller withIndex:(NSUInteger)index; +//- (void)removeImageAtIndex:(NSUInteger)index; + +@end + + +@protocol CLImagePickerManagerDelegate +@optional +- (void)imagePickerManagerWillDismissImagePicker:(CLImagePickerManager*)manager canceled:(BOOL)canceled; +- (void)imagePickerManagerDidDismissImagePicker:(CLImagePickerManager*)manager canceled:(BOOL)canceled; + +@end \ No newline at end of file diff --git a/Classes/CLImagePicker/CLImagePickerManager/CLImagePickerManager.m b/Classes/CLImagePicker/CLImagePickerManager/CLImagePickerManager.m new file mode 100644 index 0000000..216ac15 --- /dev/null +++ b/Classes/CLImagePicker/CLImagePickerManager/CLImagePickerManager.m @@ -0,0 +1,324 @@ +// +// CLImagePickerManager.m +// +// Created by sho yakushiji on 2014/01/14. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import "CLImagePickerManager.h" + +#import "UIImage+Utility.h" +#import "CLCacheManager.h" +#import "CLImagePickerBundle.h" +#import "CLImagePickerController.h" +#import "CLImageViewerController.h" + + +@interface CLImagePickerManager() + +@end + +@implementation CLImagePickerManager +{ + CLCacheManager *_cacheManager; + NSMutableOrderedSet *_selectedURLs; +} + +#pragma mark- weak singleton pattern + +static __weak id _sharedInstance = nil; + ++ (CLImagePickerManager*)managerWithDelegate:(UIViewController*)delegate; +{ + CLImagePickerManager *instance = _sharedInstance; + if(instance==nil){ + instance = [[CLImagePickerManager alloc] init]; + } + + _sharedInstance = instance; + instance.delegate = delegate; + + return instance; +} + ++ (id)allocWithZone:(NSZone *)zone +{ + @synchronized(self) { + id instance = _sharedInstance; + if (instance == nil) { + instance = [super allocWithZone:zone]; + _sharedInstance = instance; + return _sharedInstance; + } + } + return nil; +} + +- (id)copyWithZone:(NSZone *)zone +{ + return self; +} + +- (id)init +{ + self = [super init]; + if(self){ + _cacheManager = [CLCacheManager managerWithIdentifier:NSStringFromClass(self.class)]; + [_cacheManager removeCacheDirectory]; + + _selectedURLs = [NSMutableOrderedSet new]; + } + return self; +} + +- (void)dealloc +{ + [_cacheManager removeCacheDirectory]; +} + +- (NSUInteger)numberOfSelectedImages +{ + return _selectedURLs.count; +} + +#pragma mark- Caching + +- (NSURL*)edittedImageURLForURL:(NSURL*)url +{ + return [NSURL URLWithString:[NSString stringWithFormat:@"%@_editted", url.absoluteString]]; +} + +- (NSURL*)thumnailURLForURL:(NSURL*)url +{ + return [NSURL URLWithString:[NSString stringWithFormat:@"%@_thumnail", url.absoluteString]]; +} + +- (void)storeImage:(UIImage*)image forURL:(NSURL*)url +{ + NSData *data = UIImagePNGRepresentation(image); + [_cacheManager storeData:data forURL:url storeMemoryCache:NO]; +} + +- (BOOL)existsImageForURL:(NSURL*)url +{ + return [_cacheManager existsDataForURL:url]; +} + +- (void)cacheImage:(UIImage*)image forURL:(NSURL*)url +{ + CGFloat ratio = MAX(255.0/image.size.width, 255.0/image.size.height); + UIImage *thumnailImage = [image aspectFill:CGSizeMake(ratio*image.size.width, ratio*image.size.height)]; + NSURL *thumnailURL = [self thumnailURLForURL:url]; + + [self storeImage:thumnailImage forURL:thumnailURL]; + [self storeImage:image forURL:url]; +} + +- (void)removeCachedImageForURL:(NSURL*)url +{ + [_cacheManager removeCacheForURL:url]; + [_cacheManager removeCacheForURL:[self thumnailURLForURL:url]]; +} + +- (UIImage*)cachedImageWithURL:(NSURL*)url +{ + return [_cacheManager imageWithURL:url storeMemoryCache:NO]; +} + +#pragma mark- Get Image + +- (UIImage*)thumnailImageForURL:(NSURL*)url +{ + NSURL *edittedThumnailURL = [self thumnailURLForURL:[self edittedImageURLForURL:url]]; + if([self existsImageForURL:edittedThumnailURL]){ + return [self cachedImageWithURL:edittedThumnailURL]; + } + return [self cachedImageWithURL:[self thumnailURLForURL:url]]; +} + +- (UIImage*)fullScreenImageForURL:(NSURL*)url +{ + NSURL *edittedImageURL = [self edittedImageURLForURL:url]; + if([self existsImageForURL:edittedImageURL]){ + return [self cachedImageWithURL:edittedImageURL]; + } + return [self cachedImageWithURL:url]; +} + +- (UIImage*)thumnailImageAtIndex:(NSUInteger)index +{ + if(index<_selectedURLs.count){ + return [self thumnailImageForURL:[_selectedURLs objectAtIndex:index]]; + } + return nil; +} + +- (UIImage*)fullScreenImageAtIndex:(NSUInteger)index +{ + if(index<_selectedURLs.count){ + return [self fullScreenImageForURL:[_selectedURLs objectAtIndex:index]]; + } + return nil; +} + +#pragma mark- CLImagePickerController + +-(UIViewController*)pickerViewController +{ + NSString *nibName = NSLocalizedStringWithDefaultValue(@"CLImagePickerController_NibName", nil, [CLImagePickerBundle bundle], @"CLImagePickerController", @""); + + CLImagePickerController *picker = [[CLImagePickerController alloc] initWithNibName:nibName bundle:nil]; + picker.delegate = self; + picker.selectedURLs = _selectedURLs.array; + + return picker; +} + +- (void)dismissPickerViewController:(CLImagePickerController*)picker canceled:(BOOL)canceled +{ + if([self.delegate respondsToSelector:@selector(imagePickerManagerWillDismissImagePicker:canceled:)]){ + [self.delegate imagePickerManagerWillDismissImagePicker:self canceled:canceled]; + } + + [picker dismissViewControllerAnimated:YES completion:^{ + if([self.delegate respondsToSelector:@selector(imagePickerManagerDidDismissImagePicker:canceled:)]){ + [self.delegate imagePickerManagerDidDismissImagePicker:self canceled:canceled]; + } + }]; +} + +#pragma mark Delegate + +- (void)imagePickerController:(CLImagePickerController *)picker didTouchOriginalImage:(UIImage *)image withAssetURL:(NSURL *)url +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + if(![self existsImageForURL:url]){ + [self cacheImage:image forURL:url]; + } + }); +} + +- (void)imagePickerController:(CLImagePickerController *)picker didEditImage:(UIImage*)image withAssetURL:(NSURL*)url +{ + [self cacheImage:image forURL:[self edittedImageURLForURL:url]]; +} + +- (void)imagePickerController:(CLImagePickerController *)picker didRemoveEdittedImageWithAssetURL:(NSURL*)url +{ + [self removeCachedImageForURL:[self edittedImageURLForURL:url]]; +} + +- (BOOL)imagePickerController:(CLImagePickerController *)picker isEdittedImageWithAssetURL:(NSURL*)url +{ + return [self existsImageForURL:[self edittedImageURLForURL:url]]; +} + +- (UIImage*)imagePickerController:(CLImagePickerController *)picker thumnailImageForAssetURL:(NSURL*)url +{ + return [self thumnailImageForURL:url]; +} + +- (UIImage*)imagePickerController:(CLImagePickerController *)picker fullScreenImageForAssetURL:(NSURL*)url +{ + return [self fullScreenImageForURL:url]; +} + +- (void)imagePickerController:(CLImagePickerController *)picker didFinishPickingMediaWithSelectedAssetURLs:(NSArray*)selectedURLs +{ + _selectedURLs = [[NSMutableOrderedSet alloc] initWithArray:selectedURLs]; + [self dismissPickerViewController:picker canceled:NO]; +} + +- (void)imagePickerControllerDidCancel:(CLImagePickerController *)picker +{ + [self dismissPickerViewController:picker canceled:NO]; +} + +#pragma mark- CLImageViewerController + +- (void)showImageViewerInViewController:(UIViewController*)controller withIndex:(NSUInteger)index +{ + if(_selectedURLs.count>0){ + NSString *nibName = NSLocalizedStringWithDefaultValue(@"CLImageViewerController_NibName", nil, [CLImagePickerBundle bundle], @"CLImageViewerController", @""); + + CLImageViewerController *viewer = [[CLImageViewerController alloc] initWithNibName:nibName bundle:nil]; + viewer.dataSource = self; + viewer.delegate = controller; + + [viewer showInViewController:controller withIndex:index]; + } +} + +#pragma mark DataSource + +- (NSInteger)imageViewerControllerNumberOfImages:(CLImageViewerController*)viewer +{ + return _selectedURLs.count; +} + +- (UIImage*)imageViewerController:(CLImageViewerController*)viewer originalImageAtIndex:(NSInteger)index +{ + if(index<_selectedURLs.count){ + return [self cachedImageWithURL:[_selectedURLs objectAtIndex:index]]; + } + return nil; +} + +- (UIImage*)imageViewerController:(CLImageViewerController*)viewer thumnailImageAtIndex:(NSInteger)index +{ + return [self thumnailImageAtIndex:index]; +} + +- (UIImage*)imageViewerController:(CLImageViewerController*)viewer fullScreenImageAtIndex:(NSInteger)index +{ + return [self fullScreenImageAtIndex:index]; +} + +- (BOOL)imageViewerController:(CLImageViewerController*)viewer isSelectedImageAtIndex:(NSInteger)index +{ + return YES; +} + +- (BOOL)imageViewerController:(CLImageViewerController*)viewer isEditedImageAtIndex:(NSInteger)index +{ + if(index<_selectedURLs.count){ + return [self existsImageForURL:[self edittedImageURLForURL:[_selectedURLs objectAtIndex:index]]]; + } + return NO; +} + +- (void)imageViewerController:(CLImageViewerController*)viewer didSelectImageAtIndex:(NSInteger)index +{ + +} + +- (void)imageViewerController:(CLImageViewerController*)viewer didDeSelectImageAtIndex:(NSInteger)index +{ + [_selectedURLs removeObjectAtIndex:index]; + [viewer removeImageAtIndex:index]; + + if(_selectedURLs.count==0){ + [viewer dismissFromParentViewController]; + } +} + +- (void)imageViewerController:(CLImageViewerController *)viewer willEditImageAtIndex:(NSInteger)index +{ + +} + +- (void)imageViewerController:(CLImageViewerController*)viewer didEditImageAtIndex:(NSInteger)index edittedImage:(UIImage*)image +{ + if(index<_selectedURLs.count){ + [self cacheImage:image forURL:[self edittedImageURLForURL:[_selectedURLs objectAtIndex:index]]]; + } +} + +- (void)imageViewerController:(CLImageViewerController*)viewer didRemoveEdittedImageAtIndex:(NSInteger)index +{ + if(index<_selectedURLs.count){ + [self removeCachedImageForURL:[self edittedImageURLForURL:[_selectedURLs objectAtIndex:index]]]; + } +} + +@end diff --git a/Classes/CLImagePicker/CLImageViewerController/CLImageViewerController.h b/Classes/CLImagePicker/CLImageViewerController/CLImageViewerController.h new file mode 100644 index 0000000..782f621 --- /dev/null +++ b/Classes/CLImagePicker/CLImageViewerController/CLImageViewerController.h @@ -0,0 +1,72 @@ +// +// CLImageViewerController.h +// +// Created by sho yakushiji on 2014/01/15. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import + + +@protocol CLImageViewerControllerDataSource; +@protocol CLImageViewerControllerDelegate; + + +@interface CLImageViewerController : UIViewController +{ + IBOutlet __weak UIView *_backgroundView; + IBOutlet __weak UIView *_foregroundView; + IBOutlet __weak UICollectionView *_collectionView; + + IBOutlet __weak UIButton *_selectBtn; + IBOutlet __weak UIButton *_editCancelBtn; +} +@property (nonatomic, weak) id dataSource; +@property (nonatomic, weak) id delegate; + +- (void)showInViewController:(UIViewController*)controller withIndex:(NSInteger)index; +- (void)dismissFromParentViewController; + +- (void)removeImageAtIndex:(NSInteger)index; + +- (IBAction)pushedSelectBtn:(id)sender; +- (IBAction)pushedEditBtn:(id)sender; +- (IBAction)pushedClearEditBtn:(id)sender; + +@end + + + + +@protocol CLImageViewerControllerDataSource +@required +- (NSInteger)imageViewerControllerNumberOfImages:(CLImageViewerController*)viewer; +- (UIImage*)imageViewerController:(CLImageViewerController*)viewer originalImageAtIndex:(NSInteger)index; +- (UIImage*)imageViewerController:(CLImageViewerController*)viewer thumnailImageAtIndex:(NSInteger)index; +- (UIImage*)imageViewerController:(CLImageViewerController*)viewer fullScreenImageAtIndex:(NSInteger)index; + +- (BOOL)imageViewerController:(CLImageViewerController*)viewer isSelectedImageAtIndex:(NSInteger)index; +- (BOOL)imageViewerController:(CLImageViewerController*)viewer isEditedImageAtIndex:(NSInteger)index; + +- (void)imageViewerController:(CLImageViewerController*)viewer didSelectImageAtIndex:(NSInteger)index; +- (void)imageViewerController:(CLImageViewerController*)viewer didDeSelectImageAtIndex:(NSInteger)index; + +- (void)imageViewerController:(CLImageViewerController*)viewer willEditImageAtIndex:(NSInteger)index; +- (void)imageViewerController:(CLImageViewerController*)viewer didEditImageAtIndex:(NSInteger)index edittedImage:(UIImage*)image; +- (void)imageViewerController:(CLImageViewerController*)viewer didRemoveEdittedImageAtIndex:(NSInteger)index; + +@end + + +@protocol CLImageViewerControllerDelegate +@optional + +- (UIImageView*)imageViewerController:(CLImageViewerController*)viewer imageViewAtIndex:(NSInteger)index; + +- (void)imageViewerController:(CLImageViewerController*)viewer willAppearWithIndex:(NSInteger)index; +- (void)imageViewerController:(CLImageViewerController*)viewer didAppearWithIndex:(NSInteger)index; +- (void)imageViewerController:(CLImageViewerController*)viewer willDismissWithIndex:(NSInteger)index; +- (BOOL)imageViewerController:(CLImageViewerController*)viewer readyToDismissWithIndex:(NSInteger)index; +- (void)imageViewerController:(CLImageViewerController*)viewer didDismissWithIndex:(NSInteger)index; + +@end diff --git a/Classes/CLImagePicker/CLImageViewerController/CLImageViewerController.m b/Classes/CLImagePicker/CLImageViewerController/CLImageViewerController.m new file mode 100644 index 0000000..a3551d2 --- /dev/null +++ b/Classes/CLImagePicker/CLImageViewerController/CLImageViewerController.m @@ -0,0 +1,473 @@ +// +// CLImageViewerController.m +// +// Created by sho yakushiji on 2014/01/15. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import "CLImageViewerController.h" + +#import +#import "UIView+Frame.h" +#import "CLZoomingImageCell.h" +#import "CLImageViewerLayout.h" +#import "CLImagePickerBundle.h" + +NSString * const CLZoomingImageCellReuseIdentifier = @"ZoomingImageCell"; + + +@interface CLImageViewerController () + + +@property (nonatomic, assign) NSInteger currentPageIndex; + +@end + + +@implementation CLImageViewerController +{ + void(^_removeImageBlock)(); +} + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + _currentPageIndex = -1; + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + [_collectionView registerClass:[CLZoomingImageCell class] forCellWithReuseIdentifier:CLZoomingImageCellReuseIdentifier]; + _collectionView.alwaysBounceHorizontal = YES; + _collectionView.allowsMultipleSelection = YES; + _collectionView.backgroundColor = [UIColor clearColor]; + _collectionView.collectionViewLayout = [[CLImageViewerLayout alloc] initWithCellSize:self.view.frame.size]; + + UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(viewDidPan:)]; + pan.maximumNumberOfTouches = 1; + [_foregroundView addGestureRecognizer:pan]; + + UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(viewDidTap:)]; + [_foregroundView addGestureRecognizer:tap]; + + [_foregroundView addGestureRecognizer:_collectionView.panGestureRecognizer]; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; +} + +#pragma mark- View transition + +- (UIImageView*)imageViewAtIndex:(NSInteger)index +{ + UIImageView *imageView = nil; + if([self.delegate respondsToSelector:@selector(imageViewerController:imageViewAtIndex:)]){ + imageView = [self.delegate imageViewerController:self imageViewAtIndex:self.currentPageIndex]; + } + return imageView; +} + +- (void)copyImageViewInfo:(UIImageView*)fromView toView:(UIImageView*)toView containedImage:(BOOL)contained +{ + CGAffineTransform transform = fromView.transform; + fromView.transform = CGAffineTransformIdentity; + + toView.transform = CGAffineTransformIdentity; + toView.frame = [toView.superview convertRect:fromView.frame fromView:fromView.superview]; + toView.transform = transform; + toView.contentMode = fromView.contentMode; + toView.clipsToBounds = fromView.clipsToBounds; + toView.layer.cornerRadius = fromView.layer.cornerRadius; + if(contained){ toView.image = fromView.image; } + + fromView.transform = transform; +} + +- (void)showInViewController:(UIViewController*)controller withIndex:(NSInteger)index +{ + [controller addChildViewController:self]; + [self didMoveToParentViewController:controller]; + + self.view.frame = controller.view.bounds; + [controller.view addSubview:self.view]; + + [_collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO]; + self.currentPageIndex = index; + + UIImageView *fromView = [self imageViewAtIndex:index]; + UIImageView *animateView = nil; + if(fromView){ + animateView = [UIImageView new]; + [self.view addSubview:animateView]; + [self copyImageViewInfo:fromView toView:animateView containedImage:YES]; + } + + _collectionView.hidden = (animateView!=nil); + _collectionView.alpha = 0; + _backgroundView.alpha = 0; + _foregroundView.hidden = YES; + _foregroundView.alpha = 0; + + if([self.delegate respondsToSelector:@selector(imageViewerController:willAppearWithIndex:)]){ + [self.delegate imageViewerController:self willAppearWithIndex:index]; + } + [self showWithAnimateView:animateView]; +} + +- (void)showWithAnimateView:(UIImageView*)animateView +{ + [UIView animateWithDuration:0.25 + delay:0 + options:UIViewAnimationOptionCurveEaseInOut + animations:^{ + _backgroundView.alpha = 1; + _collectionView.alpha = 1; + + if(animateView){ + CGSize size = animateView.image.size; + CGFloat ratio = MIN(self.view.frame.size.width / size.width, self.view.frame.size.height / size.height); + CGFloat W = ratio * size.width; + CGFloat H = ratio * size.height; + animateView.transform = CGAffineTransformIdentity; + animateView.frame = CGRectMake((self.view.width-W)/2, (self.view.height-H)/2, W, H); + } + } + completion:^(BOOL finished) { + _collectionView.hidden = NO; + [animateView removeFromSuperview]; + + if([self.delegate respondsToSelector:@selector(imageViewerController:didAppearWithIndex:)]){ + [self.delegate imageViewerController:self didAppearWithIndex:self.currentPageIndex]; + } + + _foregroundView.hidden = NO; + [UIView animateWithDuration:0.25 animations:^{ _foregroundView.alpha = 1; }]; + } + ]; +} + +- (void)prepareToDismiss +{ + _foregroundView.hidden = YES; + + if([self.delegate respondsToSelector:@selector(imageViewerController:willDismissWithIndex:)]){ + [self.delegate imageViewerController:self willDismissWithIndex:self.currentPageIndex]; + } +} + +- (void)dismissFromParentViewControllerWithZoomingCell:(CLZoomingImageCell*)cell +{ + if([self.delegate respondsToSelector:@selector(imageViewerController:readyToDismissWithIndex:)]){ + if(![self.delegate imageViewerController:self readyToDismissWithIndex:self.currentPageIndex]){ + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.01 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + [self dismissFromParentViewControllerWithZoomingCell:cell]; + }); + return; + } + } + + UIImageView *fromView = cell.imageView; + UIImageView *toView = [self imageViewAtIndex:self.currentPageIndex]; + + UIImageView *animateView = nil; + if(fromView && toView){ + animateView = [UIImageView new]; + [self.view addSubview:animateView]; + [self copyImageViewInfo:fromView toView:animateView containedImage:NO]; + animateView.image = cell.imageView.image; + } + + _collectionView.hidden = (animateView!=nil); + + [self willMoveToParentViewController:nil]; + [self dismissWithAnimateView:animateView targetView:toView]; +} + +- (void)dismissWithAnimateView:(UIImageView*)animateView targetView:(UIImageView*)targetView +{ + [UIView animateWithDuration:0.25 + delay:0 + options:UIViewAnimationOptionCurveEaseInOut + animations:^{ + _backgroundView.alpha = 0; + _collectionView.alpha = 0; + + if(animateView){ + if(targetView){ + [self copyImageViewInfo:targetView toView:animateView containedImage:NO]; + } + else{ + animateView.left = -animateView.width; + } + } + } + completion:^(BOOL finished) { + [self.view removeFromSuperview]; + [self removeFromParentViewController]; + + if([self.delegate respondsToSelector:@selector(imageViewerController:didDismissWithIndex:)]){ + [self.delegate imageViewerController:self didDismissWithIndex:self.currentPageIndex]; + } + } + ]; +} + +- (void)dismissFromParentViewController +{ + [self prepareToDismiss]; + [self dismissFromParentViewControllerWithZoomingCell:self.presentingCell]; +} + +- (void)currentPageDidChange +{ + _selectBtn.selected = [self.dataSource imageViewerController:self isSelectedImageAtIndex:self.currentPageIndex]; + [self setClearBtnHidden:![self.dataSource imageViewerController:self isEditedImageAtIndex:self.currentPageIndex]]; +} + +- (void)setClearBtnHidden:(BOOL)hidden +{ + [UIView animateWithDuration:0.25 + animations:^{ + if(hidden){ + _editCancelBtn.alpha = 0; + } + else{ + _editCancelBtn.alpha = 1; + } + } + completion:^(BOOL finished) { + } + ]; +} + +#pragma mark- Properties + +- (void)setCurrentPageIndex:(NSInteger)currentPageIndex +{ + if(currentPageIndex != _currentPageIndex){ + _currentPageIndex = currentPageIndex; + [self currentPageDidChange]; + } +} + +- (CLZoomingImageCell*)presentingCell +{ + NSInteger index = self.currentPageIndex; + return (CLZoomingImageCell*)[_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:0]]; +} + +#pragma mark- Item + +- (void)removeImageAtIndex:(NSInteger)index +{ + NSInteger N = [_collectionView numberOfItemsInSection:0]; + if(index==N-1 && index>0){ + [_collectionView setContentOffset:CGPointMake(_collectionView.contentOffset.x-10, _collectionView.contentOffset.y) animated:NO]; + if(N==2){ + [_collectionView setContentOffset:CGPointMake(_collectionView.width*(index-1), _collectionView.contentOffset.y) animated:YES]; + } + } + + [_collectionView performBatchUpdates:^ + { + [_collectionView deleteItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:index inSection:0]]]; + } + completion:^(BOOL finished) { + if(finished){ + _currentPageIndex = (_collectionView.contentOffset.x + _collectionView.width/2) / _collectionView.width; + [self currentPageDidChange]; + } + } + ]; +} + +#pragma mark- Button actions + +- (IBAction)pushedSelectBtn:(id)sender +{ + if(_selectBtn.selected){ + if([self.dataSource respondsToSelector:@selector(imageViewerController:didDeSelectImageAtIndex:)]){ + [self.dataSource imageViewerController:self didDeSelectImageAtIndex:self.currentPageIndex]; + } + } + else{ + if([self.dataSource respondsToSelector:@selector(imageViewerController:didSelectImageAtIndex:)]){ + [self.dataSource imageViewerController:self didSelectImageAtIndex:self.currentPageIndex]; + } + } + _selectBtn.selected = !_selectBtn.selected; +} + +- (IBAction)pushedEditBtn:(id)sender +{ + if([self.dataSource respondsToSelector:@selector(imageViewerController:willEditImageAtIndex:)]){ + [self.dataSource imageViewerController:self willEditImageAtIndex:self.currentPageIndex]; + } + + CLImageEditor *editor = [CLImagePickerBundle imageEditor]; + editor.delegate = self; + [editor showInViewController:self withImageView:self.presentingCell.imageView]; +} + +- (IBAction)pushedClearEditBtn:(id)sender +{ + if([self.dataSource respondsToSelector:@selector(imageViewerController:didEditImageAtIndex:edittedImage:)]){ + UIImage *originalImage = [self.dataSource imageViewerController:self originalImageAtIndex:self.currentPageIndex]; + self.presentingCell.fullScreenImage = originalImage; + [self.dataSource imageViewerController:self didRemoveEdittedImageAtIndex:self.currentPageIndex]; + } + [self setClearBtnHidden:YES]; +} + +#pragma mark- CLImageEditor + +- (void)imageEditor:(CLImageEditor *)editor willDismissWithImageView:(UIImageView *)imageView canceled:(BOOL)canceled +{ + self.presentingCell.fullScreenImage = imageView.image; +} + +- (void)imageEditor:(CLImageEditor *)editor didDismissWithImageView:(UIImageView *)imageView canceled:(BOOL)canceled +{ + if(!canceled){ + if([self.dataSource respondsToSelector:@selector(imageViewerController:didEditImageAtIndex:edittedImage:)]){ + [self.dataSource imageViewerController:self didEditImageAtIndex:self.currentPageIndex edittedImage:imageView.image]; + } + [self setClearBtnHidden:NO]; + } +} + +#pragma mark- UIScrollView + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView +{ + if(scrollView==_collectionView){ + self.currentPageIndex = (_collectionView.contentOffset.x + _collectionView.width/2) / _collectionView.width; + } +} + +#pragma mark- UICollectionView + +- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView +{ + return 1; +} + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section +{ + return [self.dataSource imageViewerControllerNumberOfImages:self]; +} + +- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath +{ + return self.view.frame.size; + //return CGSizeMake(_collectionView.width, _collectionView.height-_collectionView.contentInset.top-_collectionView.contentInset.bottom); +} + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath +{ + UICollectionViewCell *cell = [_collectionView dequeueReusableCellWithReuseIdentifier:CLZoomingImageCellReuseIdentifier forIndexPath:indexPath]; + + if([cell isKindOfClass:[CLZoomingImageCell class]]){ + CLZoomingImageCell *_cell = (CLZoomingImageCell*)cell; + _cell.thumnailImage = [self.dataSource imageViewerController:self thumnailImageAtIndex:indexPath.item]; + + [_foregroundView addGestureRecognizer:_cell.scrollView.panGestureRecognizer]; + [_foregroundView addGestureRecognizer:_cell.scrollView.pinchGestureRecognizer]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + UIImage *image = [self.dataSource imageViewerController:self fullScreenImageAtIndex:indexPath.item]; + dispatch_async(dispatch_get_main_queue(), ^{ + _cell.fullScreenImage = image; + }); + }); + } + + return cell; +} + +- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath +{ + if([cell isKindOfClass:[CLZoomingImageCell class]]){ + CLZoomingImageCell *_cell = (CLZoomingImageCell*)cell; + [_foregroundView removeGestureRecognizer:_cell.scrollView.panGestureRecognizer]; + [_foregroundView removeGestureRecognizer:_cell.scrollView.pinchGestureRecognizer]; + } +} + +- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath +{ + //UICollectionViewCell* cell = [collectionView cellForItemAtIndexPath:indexPath]; +} + +- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath +{ + //UICollectionViewCell* cell = [collectionView cellForItemAtIndexPath:indexPath]; +} + +#pragma mark- Gesture events + +- (void)viewDidTap:(UIPanGestureRecognizer*)sender +{ + [self dismissFromParentViewController]; +} + +- (void)viewDidPan:(UIPanGestureRecognizer*)sender +{ + static UIImageView *animateView = nil; + static BOOL ready = NO; + + if(sender.state == UIGestureRecognizerStateBegan){ + CLZoomingImageCell *cell = self.presentingCell; + + if(cell.imageView && !cell.isViewing){ + animateView = [UIImageView new]; + [self.view addSubview:animateView]; + [self copyImageViewInfo:cell.imageView toView:animateView containedImage:YES]; + + _collectionView.hidden = YES; + [self prepareToDismiss]; + } + } + + if(!ready){ + if([self.delegate respondsToSelector:@selector(imageViewerController:readyToDismissWithIndex:)]){ + ready = [self.delegate imageViewerController:self readyToDismissWithIndex:self.currentPageIndex]; + } + else{ + ready = YES; + } + } + + if(animateView && ready){ + if(sender.state == UIGestureRecognizerStateEnded){ + if(_backgroundView.alpha>0.5){ + [self showWithAnimateView:animateView]; + } + else{ + UIImageView *target = [self imageViewAtIndex:self.currentPageIndex]; + [self dismissWithAnimateView:animateView targetView:target]; + } + animateView = nil; + ready = NO; + } + else{ + CGPoint p = [sender translationInView:self.view]; + + CGAffineTransform transform = CGAffineTransformMakeTranslation(0, p.y); + transform = CGAffineTransformScale(transform, 1 - fabs(p.y)/1000, 1 - fabs(p.y)/1000); + animateView.transform = transform; + + CGFloat r = 1-fabs(p.y)/200; + _backgroundView.alpha = MAX(0, MIN(1, r)); + } + } +} + +@end diff --git a/Classes/CLImagePicker/CLImageViewerController/CLImageViewerController.xib b/Classes/CLImagePicker/CLImageViewerController/CLImageViewerController.xib new file mode 100644 index 0000000..35fa259 --- /dev/null +++ b/Classes/CLImagePicker/CLImageViewerController/CLImageViewerController.xib @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Classes/CLImagePicker/CLImageViewerController/Components/CLImageViewerLayout.h b/Classes/CLImagePicker/CLImageViewerController/Components/CLImageViewerLayout.h new file mode 100644 index 0000000..2712084 --- /dev/null +++ b/Classes/CLImagePicker/CLImageViewerController/Components/CLImageViewerLayout.h @@ -0,0 +1,14 @@ +// +// CLImageViewerLayout.h +// +// Created by sho yakushiji on 2014/01/20. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import + +@interface CLImageViewerLayout : UICollectionViewLayout + +- (id)initWithCellSize:(CGSize)size; + +@end diff --git a/Classes/CLImagePicker/CLImageViewerController/Components/CLImageViewerLayout.m b/Classes/CLImagePicker/CLImageViewerController/Components/CLImageViewerLayout.m new file mode 100644 index 0000000..cb3db6c --- /dev/null +++ b/Classes/CLImagePicker/CLImageViewerController/Components/CLImageViewerLayout.m @@ -0,0 +1,109 @@ +// +// CLImageViewerLayout.m +// +// Created by sho yakushiji on 2014/01/20. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import "CLImageViewerLayout.h" + +#import "UIView+Frame.h" + +@interface CLImageViewerLayout() +@property (nonatomic, assign) CGSize cellSize; +@property (nonatomic, readonly) NSInteger numberOfCells; +@end + + +@implementation CLImageViewerLayout +{ + NSMutableArray *_deleteIndexPaths; +} + +- (id)initWithCellSize:(CGSize)size +{ + self = [super init]; + if(self){ + self.cellSize = size; + } + return self; +} + +- (NSInteger)numberOfCells +{ + return [self.collectionView numberOfItemsInSection:0]; +} + +- (void)prepareLayout +{ + +} + +-(CGSize)collectionViewContentSize +{ + CGSize size = CGSizeMake(self.collectionView.width*self.numberOfCells, self.collectionView.height); + return size; +} + +- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path +{ + UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:path]; + attributes.size = self.cellSize; + attributes.center = CGPointMake((path.item+0.5)*self.collectionView.width, self.collectionView.height/2); + + return attributes; +} + +-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect +{ + NSMutableArray* attributes = [NSMutableArray array]; + for (NSInteger i=0 ; i + +@interface CLZoomingImageCell : UICollectionViewCell + +@property (nonatomic, strong) UIImage *thumnailImage; +@property (nonatomic, strong) UIImage *fullScreenImage; +@property (nonatomic, readonly) UIScrollView *scrollView; +@property (nonatomic, readonly) UIImageView *imageView; +@property (nonatomic, readonly) BOOL isViewing; + +@end diff --git a/Classes/CLImagePicker/CLImageViewerController/Components/CLZoomingImageCell.m b/Classes/CLImagePicker/CLImageViewerController/Components/CLZoomingImageCell.m new file mode 100644 index 0000000..af6a5cd --- /dev/null +++ b/Classes/CLImagePicker/CLImageViewerController/Components/CLZoomingImageCell.m @@ -0,0 +1,56 @@ +// +// CLZoomingImageCell.m +// +// Created by sho yakushiji on 2014/01/15. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import "CLZoomingImageCell.h" + +#import "CLZoomingImageView.h" + +@implementation CLZoomingImageCell +{ + CLZoomingImageView *_zoomingView; +} + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + _zoomingView = [[CLZoomingImageView alloc] initWithFrame:self.bounds]; + [self.contentView addSubview:_zoomingView]; + } + return self; +} + +- (UIScrollView*)scrollView +{ + return _zoomingView.scrollView; +} + +- (UIImageView*)imageView +{ + return _zoomingView.imageView; +} + +- (BOOL)isViewing +{ + return _zoomingView.isViewing; +} + +- (void)setThumnailImage:(UIImage *)thumnailImage +{ + _thumnailImage = thumnailImage; + _fullScreenImage = nil; + _zoomingView.image = thumnailImage; +} + +- (void)setFullScreenImage:(UIImage *)fullScreenImage +{ + _thumnailImage = nil; + _fullScreenImage = fullScreenImage; + _zoomingView.image = fullScreenImage; +} + +@end diff --git a/Demo/CLImagePickerDemo/CLImagePickerDemo.xcodeproj/project.pbxproj b/Demo/CLImagePickerDemo/CLImagePickerDemo.xcodeproj/project.pbxproj new file mode 100644 index 0000000..922077a --- /dev/null +++ b/Demo/CLImagePickerDemo/CLImagePickerDemo.xcodeproj/project.pbxproj @@ -0,0 +1,1086 @@ + + + + + archiveVersion + 1 + classes + + objectVersion + 46 + objects + + 07C0AB32DB884A5999CE028B + + buildActionMask + 2147483647 + files + + inputPaths + + isa + PBXShellScriptBuildPhase + name + Copy Pods Resources + outputPaths + + runOnlyForDeploymentPostprocessing + 0 + shellPath + /bin/sh + shellScript + "${SRCROOT}/Pods/Pods-resources.sh" + + showEnvVarsInLog + 0 + + 0B4B399AF25E4151A6FD6684 + + fileRef + BB94EE4D9728440AB6E92DC8 + isa + PBXBuildFile + + 0E4014D9FCC94415B78E5662 + + buildActionMask + 2147483647 + files + + inputPaths + + isa + PBXShellScriptBuildPhase + name + Check Pods Manifest.lock + outputPaths + + runOnlyForDeploymentPostprocessing + 0 + shellPath + /bin/sh + shellScript + diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null +if [[ $? != 0 ]] ; then + cat << EOM +error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation. +EOM + exit 1 +fi + + showEnvVarsInLog + 0 + + 64DFC31A6C274D87A73A9602 + + includeInIndex + 1 + isa + PBXFileReference + lastKnownFileType + text.xcconfig + name + Pods.xcconfig + path + Pods/Pods.xcconfig + sourceTree + <group> + + AD31AB49188D67610083616C + + children + + AD31AB5B188D67610083616C + AD31AB7A188D67610083616C + AD31AB54188D67610083616C + AD31AB53188D67610083616C + 64DFC31A6C274D87A73A9602 + + isa + PBXGroup + sourceTree + <group> + + AD31AB4A188D67610083616C + + attributes + + LastUpgradeCheck + 0500 + ORGANIZATIONNAME + CALACULU + TargetAttributes + + AD31AB72188D67610083616C + + TestTargetID + AD31AB51188D67610083616C + + + + buildConfigurationList + AD31AB4D188D67610083616C + compatibilityVersion + Xcode 3.2 + developmentRegion + English + hasScannedForEncodings + 0 + isa + PBXProject + knownRegions + + en + Base + + mainGroup + AD31AB49188D67610083616C + productRefGroup + AD31AB53188D67610083616C + projectDirPath + + projectReferences + + projectRoot + + targets + + AD31AB51188D67610083616C + AD31AB72188D67610083616C + + + AD31AB4D188D67610083616C + + buildConfigurations + + AD31AB82188D67610083616C + AD31AB83188D67610083616C + + defaultConfigurationIsVisible + 0 + defaultConfigurationName + Release + isa + XCConfigurationList + + AD31AB4E188D67610083616C + + buildActionMask + 2147483647 + files + + AD31AB6C188D67610083616C + AD31AB66188D67610083616C + AD31AB62188D67610083616C + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + AD31AB4F188D67610083616C + + buildActionMask + 2147483647 + files + + AD31AB58188D67610083616C + AD31AB5A188D67610083616C + AD31AB56188D67610083616C + 0B4B399AF25E4151A6FD6684 + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + AD31AB50188D67610083616C + + buildActionMask + 2147483647 + files + + AD31AB6E188D67610083616C + AD31AB60188D67610083616C + AD31AB69188D67610083616C + + isa + PBXResourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + AD31AB51188D67610083616C + + buildConfigurationList + AD31AB84188D67610083616C + buildPhases + + 0E4014D9FCC94415B78E5662 + AD31AB4E188D67610083616C + AD31AB4F188D67610083616C + AD31AB50188D67610083616C + 07C0AB32DB884A5999CE028B + + buildRules + + dependencies + + isa + PBXNativeTarget + name + CLImagePickerDemo + productName + CLImagePickerDemo + productReference + AD31AB52188D67610083616C + productType + com.apple.product-type.application + + AD31AB52188D67610083616C + + explicitFileType + wrapper.application + includeInIndex + 0 + isa + PBXFileReference + path + CLImagePickerDemo.app + sourceTree + BUILT_PRODUCTS_DIR + + AD31AB53188D67610083616C + + children + + AD31AB52188D67610083616C + AD31AB73188D67610083616C + + isa + PBXGroup + name + Products + sourceTree + <group> + + AD31AB54188D67610083616C + + children + + AD31AB55188D67610083616C + AD31AB57188D67610083616C + AD31AB59188D67610083616C + AD31AB74188D67610083616C + BB94EE4D9728440AB6E92DC8 + + isa + PBXGroup + name + Frameworks + sourceTree + <group> + + AD31AB55188D67610083616C + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + Foundation.framework + path + System/Library/Frameworks/Foundation.framework + sourceTree + SDKROOT + + AD31AB56188D67610083616C + + fileRef + AD31AB55188D67610083616C + isa + PBXBuildFile + + AD31AB57188D67610083616C + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + CoreGraphics.framework + path + System/Library/Frameworks/CoreGraphics.framework + sourceTree + SDKROOT + + AD31AB58188D67610083616C + + fileRef + AD31AB57188D67610083616C + isa + PBXBuildFile + + AD31AB59188D67610083616C + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + UIKit.framework + path + System/Library/Frameworks/UIKit.framework + sourceTree + SDKROOT + + AD31AB5A188D67610083616C + + fileRef + AD31AB59188D67610083616C + isa + PBXBuildFile + + AD31AB5B188D67610083616C + + children + + AD31AB64188D67610083616C + AD31AB65188D67610083616C + AD31AB67188D67610083616C + AD31AB6A188D67610083616C + AD31AB6B188D67610083616C + AD31AB6D188D67610083616C + AD31AB5C188D67610083616C + + isa + PBXGroup + path + CLImagePickerDemo + sourceTree + <group> + + AD31AB5C188D67610083616C + + children + + AD31AB5D188D67610083616C + AD31AB5E188D67610083616C + AD31AB61188D67610083616C + AD31AB63188D67610083616C + + isa + PBXGroup + name + Supporting Files + sourceTree + <group> + + AD31AB5D188D67610083616C + + isa + PBXFileReference + lastKnownFileType + text.plist.xml + path + CLImagePickerDemo-Info.plist + sourceTree + <group> + + AD31AB5E188D67610083616C + + children + + AD31AB5F188D67610083616C + + isa + PBXVariantGroup + name + InfoPlist.strings + sourceTree + <group> + + AD31AB5F188D67610083616C + + isa + PBXFileReference + lastKnownFileType + text.plist.strings + name + en + path + en.lproj/InfoPlist.strings + sourceTree + <group> + + AD31AB60188D67610083616C + + fileRef + AD31AB5E188D67610083616C + isa + PBXBuildFile + + AD31AB61188D67610083616C + + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + main.m + sourceTree + <group> + + AD31AB62188D67610083616C + + fileRef + AD31AB61188D67610083616C + isa + PBXBuildFile + + AD31AB63188D67610083616C + + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + CLImagePickerDemo-Prefix.pch + sourceTree + <group> + + AD31AB64188D67610083616C + + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + AppDelegate.h + sourceTree + <group> + + AD31AB65188D67610083616C + + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + AppDelegate.m + sourceTree + <group> + + AD31AB66188D67610083616C + + fileRef + AD31AB65188D67610083616C + isa + PBXBuildFile + + AD31AB67188D67610083616C + + children + + AD31AB68188D67610083616C + + isa + PBXVariantGroup + name + Main.storyboard + sourceTree + <group> + + AD31AB68188D67610083616C + + isa + PBXFileReference + lastKnownFileType + file.storyboard + name + Base + path + Base.lproj/Main.storyboard + sourceTree + <group> + + AD31AB69188D67610083616C + + fileRef + AD31AB67188D67610083616C + isa + PBXBuildFile + + AD31AB6A188D67610083616C + + isa + PBXFileReference + lastKnownFileType + sourcecode.c.h + path + ViewController.h + sourceTree + <group> + + AD31AB6B188D67610083616C + + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + ViewController.m + sourceTree + <group> + + AD31AB6C188D67610083616C + + fileRef + AD31AB6B188D67610083616C + isa + PBXBuildFile + + AD31AB6D188D67610083616C + + isa + PBXFileReference + lastKnownFileType + folder.assetcatalog + path + Images.xcassets + sourceTree + <group> + + AD31AB6E188D67610083616C + + fileRef + AD31AB6D188D67610083616C + isa + PBXBuildFile + + AD31AB6F188D67610083616C + + buildActionMask + 2147483647 + files + + AD31AB81188D67610083616C + + isa + PBXSourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + AD31AB70188D67610083616C + + buildActionMask + 2147483647 + files + + AD31AB75188D67610083616C + AD31AB77188D67610083616C + AD31AB76188D67610083616C + + isa + PBXFrameworksBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + AD31AB71188D67610083616C + + buildActionMask + 2147483647 + files + + AD31AB7F188D67610083616C + + isa + PBXResourcesBuildPhase + runOnlyForDeploymentPostprocessing + 0 + + AD31AB72188D67610083616C + + buildConfigurationList + AD31AB87188D67610083616C + buildPhases + + AD31AB6F188D67610083616C + AD31AB70188D67610083616C + AD31AB71188D67610083616C + + buildRules + + dependencies + + AD31AB79188D67610083616C + + isa + PBXNativeTarget + name + CLImagePickerDemoTests + productName + CLImagePickerDemoTests + productReference + AD31AB73188D67610083616C + productType + com.apple.product-type.bundle.unit-test + + AD31AB73188D67610083616C + + explicitFileType + wrapper.cfbundle + includeInIndex + 0 + isa + PBXFileReference + path + CLImagePickerDemoTests.xctest + sourceTree + BUILT_PRODUCTS_DIR + + AD31AB74188D67610083616C + + isa + PBXFileReference + lastKnownFileType + wrapper.framework + name + XCTest.framework + path + Library/Frameworks/XCTest.framework + sourceTree + DEVELOPER_DIR + + AD31AB75188D67610083616C + + fileRef + AD31AB74188D67610083616C + isa + PBXBuildFile + + AD31AB76188D67610083616C + + fileRef + AD31AB55188D67610083616C + isa + PBXBuildFile + + AD31AB77188D67610083616C + + fileRef + AD31AB59188D67610083616C + isa + PBXBuildFile + + AD31AB78188D67610083616C + + containerPortal + AD31AB4A188D67610083616C + isa + PBXContainerItemProxy + proxyType + 1 + remoteGlobalIDString + AD31AB51188D67610083616C + remoteInfo + CLImagePickerDemo + + AD31AB79188D67610083616C + + isa + PBXTargetDependency + target + AD31AB51188D67610083616C + targetProxy + AD31AB78188D67610083616C + + AD31AB7A188D67610083616C + + children + + AD31AB80188D67610083616C + AD31AB7B188D67610083616C + + isa + PBXGroup + path + CLImagePickerDemoTests + sourceTree + <group> + + AD31AB7B188D67610083616C + + children + + AD31AB7C188D67610083616C + AD31AB7D188D67610083616C + + isa + PBXGroup + name + Supporting Files + sourceTree + <group> + + AD31AB7C188D67610083616C + + isa + PBXFileReference + lastKnownFileType + text.plist.xml + path + CLImagePickerDemoTests-Info.plist + sourceTree + <group> + + AD31AB7D188D67610083616C + + children + + AD31AB7E188D67610083616C + + isa + PBXVariantGroup + name + InfoPlist.strings + sourceTree + <group> + + AD31AB7E188D67610083616C + + isa + PBXFileReference + lastKnownFileType + text.plist.strings + name + en + path + en.lproj/InfoPlist.strings + sourceTree + <group> + + AD31AB7F188D67610083616C + + fileRef + AD31AB7D188D67610083616C + isa + PBXBuildFile + + AD31AB80188D67610083616C + + isa + PBXFileReference + lastKnownFileType + sourcecode.c.objc + path + CLImagePickerDemoTests.m + sourceTree + <group> + + AD31AB81188D67610083616C + + fileRef + AD31AB80188D67610083616C + isa + PBXBuildFile + + AD31AB82188D67610083616C + + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + ARCHS + $(ARCHS_STANDARD_INCLUDING_64_BIT) + CLANG_CXX_LANGUAGE_STANDARD + gnu++0x + CLANG_CXX_LIBRARY + libc++ + CLANG_ENABLE_MODULES + YES + CLANG_ENABLE_OBJC_ARC + YES + CLANG_WARN_BOOL_CONVERSION + YES + CLANG_WARN_CONSTANT_CONVERSION + YES + CLANG_WARN_DIRECT_OBJC_ISA_USAGE + YES_ERROR + CLANG_WARN_EMPTY_BODY + YES + CLANG_WARN_ENUM_CONVERSION + YES + CLANG_WARN_INT_CONVERSION + YES + CLANG_WARN_OBJC_ROOT_CLASS + YES_ERROR + CLANG_WARN__DUPLICATE_METHOD_MATCH + YES + CODE_SIGN_IDENTITY[sdk=iphoneos*] + iPhone Developer + COPY_PHASE_STRIP + NO + GCC_C_LANGUAGE_STANDARD + gnu99 + GCC_DYNAMIC_NO_PIC + NO + GCC_OPTIMIZATION_LEVEL + 0 + GCC_PREPROCESSOR_DEFINITIONS + + DEBUG=1 + $(inherited) + + GCC_SYMBOLS_PRIVATE_EXTERN + NO + GCC_WARN_64_TO_32_BIT_CONVERSION + YES + GCC_WARN_ABOUT_RETURN_TYPE + YES_ERROR + GCC_WARN_UNDECLARED_SELECTOR + YES + GCC_WARN_UNINITIALIZED_AUTOS + YES + GCC_WARN_UNUSED_FUNCTION + YES + GCC_WARN_UNUSED_VARIABLE + YES + IPHONEOS_DEPLOYMENT_TARGET + 7.0 + ONLY_ACTIVE_ARCH + YES + SDKROOT + iphoneos + + isa + XCBuildConfiguration + name + Debug + + AD31AB83188D67610083616C + + buildSettings + + ALWAYS_SEARCH_USER_PATHS + NO + ARCHS + $(ARCHS_STANDARD_INCLUDING_64_BIT) + CLANG_CXX_LANGUAGE_STANDARD + gnu++0x + CLANG_CXX_LIBRARY + libc++ + CLANG_ENABLE_MODULES + YES + CLANG_ENABLE_OBJC_ARC + YES + CLANG_WARN_BOOL_CONVERSION + YES + CLANG_WARN_CONSTANT_CONVERSION + YES + CLANG_WARN_DIRECT_OBJC_ISA_USAGE + YES_ERROR + CLANG_WARN_EMPTY_BODY + YES + CLANG_WARN_ENUM_CONVERSION + YES + CLANG_WARN_INT_CONVERSION + YES + CLANG_WARN_OBJC_ROOT_CLASS + YES_ERROR + CLANG_WARN__DUPLICATE_METHOD_MATCH + YES + CODE_SIGN_IDENTITY[sdk=iphoneos*] + iPhone Developer + COPY_PHASE_STRIP + YES + ENABLE_NS_ASSERTIONS + NO + GCC_C_LANGUAGE_STANDARD + gnu99 + GCC_WARN_64_TO_32_BIT_CONVERSION + YES + GCC_WARN_ABOUT_RETURN_TYPE + YES_ERROR + GCC_WARN_UNDECLARED_SELECTOR + YES + GCC_WARN_UNINITIALIZED_AUTOS + YES + GCC_WARN_UNUSED_FUNCTION + YES + GCC_WARN_UNUSED_VARIABLE + YES + IPHONEOS_DEPLOYMENT_TARGET + 7.0 + SDKROOT + iphoneos + VALIDATE_PRODUCT + YES + + isa + XCBuildConfiguration + name + Release + + AD31AB84188D67610083616C + + buildConfigurations + + AD31AB85188D67610083616C + AD31AB86188D67610083616C + + defaultConfigurationIsVisible + 0 + isa + XCConfigurationList + + AD31AB85188D67610083616C + + baseConfigurationReference + 64DFC31A6C274D87A73A9602 + buildSettings + + ASSETCATALOG_COMPILER_APPICON_NAME + AppIcon + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME + LaunchImage + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + CLImagePickerDemo/CLImagePickerDemo-Prefix.pch + INFOPLIST_FILE + CLImagePickerDemo/CLImagePickerDemo-Info.plist + PRODUCT_NAME + $(TARGET_NAME) + WRAPPER_EXTENSION + app + + isa + XCBuildConfiguration + name + Debug + + AD31AB86188D67610083616C + + baseConfigurationReference + 64DFC31A6C274D87A73A9602 + buildSettings + + ASSETCATALOG_COMPILER_APPICON_NAME + AppIcon + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME + LaunchImage + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + CLImagePickerDemo/CLImagePickerDemo-Prefix.pch + INFOPLIST_FILE + CLImagePickerDemo/CLImagePickerDemo-Info.plist + PRODUCT_NAME + $(TARGET_NAME) + WRAPPER_EXTENSION + app + + isa + XCBuildConfiguration + name + Release + + AD31AB87188D67610083616C + + buildConfigurations + + AD31AB88188D67610083616C + AD31AB89188D67610083616C + + defaultConfigurationIsVisible + 0 + isa + XCConfigurationList + + AD31AB88188D67610083616C + + buildSettings + + ARCHS + $(ARCHS_STANDARD_INCLUDING_64_BIT) + BUNDLE_LOADER + $(BUILT_PRODUCTS_DIR)/CLImagePickerDemo.app/CLImagePickerDemo + FRAMEWORK_SEARCH_PATHS + + $(SDKROOT)/Developer/Library/Frameworks + $(inherited) + $(DEVELOPER_FRAMEWORKS_DIR) + + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + CLImagePickerDemo/CLImagePickerDemo-Prefix.pch + GCC_PREPROCESSOR_DEFINITIONS + + DEBUG=1 + $(inherited) + + INFOPLIST_FILE + CLImagePickerDemoTests/CLImagePickerDemoTests-Info.plist + PRODUCT_NAME + $(TARGET_NAME) + TEST_HOST + $(BUNDLE_LOADER) + WRAPPER_EXTENSION + xctest + + isa + XCBuildConfiguration + name + Debug + + AD31AB89188D67610083616C + + buildSettings + + ARCHS + $(ARCHS_STANDARD_INCLUDING_64_BIT) + BUNDLE_LOADER + $(BUILT_PRODUCTS_DIR)/CLImagePickerDemo.app/CLImagePickerDemo + FRAMEWORK_SEARCH_PATHS + + $(SDKROOT)/Developer/Library/Frameworks + $(inherited) + $(DEVELOPER_FRAMEWORKS_DIR) + + GCC_PRECOMPILE_PREFIX_HEADER + YES + GCC_PREFIX_HEADER + CLImagePickerDemo/CLImagePickerDemo-Prefix.pch + INFOPLIST_FILE + CLImagePickerDemoTests/CLImagePickerDemoTests-Info.plist + PRODUCT_NAME + $(TARGET_NAME) + TEST_HOST + $(BUNDLE_LOADER) + WRAPPER_EXTENSION + xctest + + isa + XCBuildConfiguration + name + Release + + BB94EE4D9728440AB6E92DC8 + + explicitFileType + archive.ar + includeInIndex + 0 + isa + PBXFileReference + path + libPods.a + sourceTree + BUILT_PRODUCTS_DIR + + + rootObject + AD31AB4A188D67610083616C + + diff --git a/Demo/CLImagePickerDemo/CLImagePickerDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Demo/CLImagePickerDemo/CLImagePickerDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..9234d08 --- /dev/null +++ b/Demo/CLImagePickerDemo/CLImagePickerDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Demo/CLImagePickerDemo/CLImagePickerDemo/AppDelegate.h b/Demo/CLImagePickerDemo/CLImagePickerDemo/AppDelegate.h new file mode 100644 index 0000000..17a6983 --- /dev/null +++ b/Demo/CLImagePickerDemo/CLImagePickerDemo/AppDelegate.h @@ -0,0 +1,15 @@ +// +// AppDelegate.h +// CLImagePickerDemo +// +// Created by sho yakushiji on 2014/01/20. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + +@end diff --git a/Demo/CLImagePickerDemo/CLImagePickerDemo/AppDelegate.m b/Demo/CLImagePickerDemo/CLImagePickerDemo/AppDelegate.m new file mode 100644 index 0000000..be3a93f --- /dev/null +++ b/Demo/CLImagePickerDemo/CLImagePickerDemo/AppDelegate.m @@ -0,0 +1,46 @@ +// +// AppDelegate.m +// CLImagePickerDemo +// +// Created by sho yakushiji on 2014/01/20. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import "AppDelegate.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + // Override point for customization after application launch. + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application +{ + // 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. + // 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. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application +{ + // 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. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application +{ + // 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. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application +{ + // 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. +} + +- (void)applicationWillTerminate:(UIApplication *)application +{ + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +@end diff --git a/Demo/CLImagePickerDemo/CLImagePickerDemo/Base.lproj/Main.storyboard b/Demo/CLImagePickerDemo/CLImagePickerDemo/Base.lproj/Main.storyboard new file mode 100644 index 0000000..0324dad --- /dev/null +++ b/Demo/CLImagePickerDemo/CLImagePickerDemo/Base.lproj/Main.storyboard @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Demo/CLImagePickerDemo/CLImagePickerDemo/CLImagePickerDemo-Info.plist b/Demo/CLImagePickerDemo/CLImagePickerDemo/CLImagePickerDemo-Info.plist new file mode 100644 index 0000000..7a8cf60 --- /dev/null +++ b/Demo/CLImagePickerDemo/CLImagePickerDemo/CLImagePickerDemo-Info.plist @@ -0,0 +1,40 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + jp.calaculu.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Demo/CLImagePickerDemo/CLImagePickerDemo/CLImagePickerDemo-Prefix.pch b/Demo/CLImagePickerDemo/CLImagePickerDemo/CLImagePickerDemo-Prefix.pch new file mode 100644 index 0000000..82a2bb4 --- /dev/null +++ b/Demo/CLImagePickerDemo/CLImagePickerDemo/CLImagePickerDemo-Prefix.pch @@ -0,0 +1,16 @@ +// +// Prefix header +// +// The contents of this file are implicitly included at the beginning of every source file. +// + +#import + +#ifndef __IPHONE_5_0 +#warning "This project uses features only available in iOS SDK 5.0 and later." +#endif + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/Demo/CLImagePickerDemo/CLImagePickerDemo/Images.xcassets/AppIcon.appiconset/Contents.json b/Demo/CLImagePickerDemo/CLImagePickerDemo/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..a396706 --- /dev/null +++ b/Demo/CLImagePickerDemo/CLImagePickerDemo/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/CLImagePickerDemo/CLImagePickerDemo/Images.xcassets/LaunchImage.launchimage/Contents.json b/Demo/CLImagePickerDemo/CLImagePickerDemo/Images.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 0000000..c79ebd3 --- /dev/null +++ b/Demo/CLImagePickerDemo/CLImagePickerDemo/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "subtype" : "retina4", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Demo/CLImagePickerDemo/CLImagePickerDemo/ViewController.h b/Demo/CLImagePickerDemo/CLImagePickerDemo/ViewController.h new file mode 100644 index 0000000..2f77742 --- /dev/null +++ b/Demo/CLImagePickerDemo/CLImagePickerDemo/ViewController.h @@ -0,0 +1,16 @@ +// +// ViewController.h +// CLImagePickerDemo +// +// Created by sho yakushiji on 2014/01/09. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import + +@interface ViewController : UIViewController + + +- (IBAction)pushedBtn:(id)sender; + +@end diff --git a/Demo/CLImagePickerDemo/CLImagePickerDemo/ViewController.m b/Demo/CLImagePickerDemo/CLImagePickerDemo/ViewController.m new file mode 100644 index 0000000..322172a --- /dev/null +++ b/Demo/CLImagePickerDemo/CLImagePickerDemo/ViewController.m @@ -0,0 +1,139 @@ +// +// ViewController.m +// CLImagePickerDemo +// +// Created by sho yakushiji on 2014/01/09. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import "ViewController.h" + +#import "CLImagePickerManager.h" + +@interface ViewController () + +@end + +@implementation ViewController +{ + CLImagePickerManager *_manager; + NSMutableArray *_thumnails; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view, typically from a nib. + + _manager = [CLImagePickerManager managerWithDelegate:self]; + _thumnails = [NSMutableArray array]; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (IBAction)pushedBtn:(id)sender +{ + [self presentViewController:_manager.pickerViewController animated:YES completion:nil]; +} + +- (void)resetImageViews +{ + for(UIView *view in _thumnails){ [view removeFromSuperview]; } + [_thumnails removeAllObjects]; + + if(_manager.numberOfSelectedImages==0){ return; } + + CGPoint center = self.view.center; + CGFloat da = 2*M_PI/_manager.numberOfSelectedImages; + + for(NSInteger index=0; index<_manager.numberOfSelectedImages; ++index){ + UIImageView *view = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)]; + view.contentMode = UIViewContentModeScaleAspectFill; + view.layer.cornerRadius = view.frame.size.width/2; + view.clipsToBounds = YES; + + view.center = CGPointMake(center.x + 120*cos(da*index + M_PI), center.y + 120*sin(da*index + M_PI)); + view.tag = index; + + view.userInteractionEnabled = YES; + [view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(thumnailDidTapped:)]]; + + [self.view insertSubview:view atIndex:0]; + [_thumnails addObject:view]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + UIImage *image = [_manager thumnailImageAtIndex:index]; + dispatch_async(dispatch_get_main_queue(), ^{ + view.image = image; + }); + }); + + } +} + +- (void)thumnailDidTapped:(UITapGestureRecognizer*)sender +{ + [_manager showImageViewerInViewController:self withIndex:sender.view.tag]; +} + +#pragma CLImagePickerManagerDelegate + +- (void)imagePickerManagerWillDismissImagePicker:(CLImagePickerManager *)manager canceled:(BOOL)canceled +{ + if(!canceled){ + [self resetImageViews]; + } +} + +- (void)imagePickerManagerDidDismissImagePicker:(CLImagePickerManager *)manager canceled:(BOOL)canceled +{ + +} + +#pragma mark- CLImageViewerControllerDelegate + +- (UIImageView*)imageViewerController:(CLImageViewerController*)viewer imageViewAtIndex:(NSInteger)index +{ + if(index<_thumnails.count){ + return _thumnails[index]; + } + return nil; +} + +- (void)imageViewerController:(CLImageViewerController*)viewer willAppearWithIndex:(NSInteger)index +{ + +} + +- (void)imageViewerController:(CLImageViewerController*)viewer didAppearWithIndex:(NSInteger)index +{ + +} + +- (void)imageViewerController:(CLImageViewerController*)viewer willDismissWithIndex:(NSInteger)index +{ + [self resetImageViews]; +} + +- (BOOL)imageViewerController:(CLImageViewerController *)viewer readyToDismissWithIndex:(NSInteger)index +{ + if(index<_thumnails.count){ + UIView *view = _thumnails[index]; + view.hidden = YES; + } + return YES; +} + +- (void)imageViewerController:(CLImageViewerController*)viewer didDismissWithIndex:(NSInteger)index +{ + if(index<_thumnails.count){ + UIView *view = _thumnails[index]; + view.hidden = NO; + } +} + +@end diff --git a/Demo/CLImagePickerDemo/CLImagePickerDemo/en.lproj/InfoPlist.strings b/Demo/CLImagePickerDemo/CLImagePickerDemo/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Demo/CLImagePickerDemo/CLImagePickerDemo/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Demo/CLImagePickerDemo/CLImagePickerDemo/main.m b/Demo/CLImagePickerDemo/CLImagePickerDemo/main.m new file mode 100644 index 0000000..042f952 --- /dev/null +++ b/Demo/CLImagePickerDemo/CLImagePickerDemo/main.m @@ -0,0 +1,18 @@ +// +// main.m +// CLImagePickerDemo +// +// Created by sho yakushiji on 2014/01/20. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import + +#import "AppDelegate.h" + +int main(int argc, char * argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/Demo/CLImagePickerDemo/CLImagePickerDemoTests/CLImagePickerDemoTests-Info.plist b/Demo/CLImagePickerDemo/CLImagePickerDemoTests/CLImagePickerDemoTests-Info.plist new file mode 100644 index 0000000..7430c4e --- /dev/null +++ b/Demo/CLImagePickerDemo/CLImagePickerDemoTests/CLImagePickerDemoTests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + jp.calaculu.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/Demo/CLImagePickerDemo/CLImagePickerDemoTests/CLImagePickerDemoTests.m b/Demo/CLImagePickerDemo/CLImagePickerDemoTests/CLImagePickerDemoTests.m new file mode 100644 index 0000000..4fe282e --- /dev/null +++ b/Demo/CLImagePickerDemo/CLImagePickerDemoTests/CLImagePickerDemoTests.m @@ -0,0 +1,34 @@ +// +// CLImagePickerDemoTests.m +// CLImagePickerDemoTests +// +// Created by sho yakushiji on 2014/01/20. +// Copyright (c) 2014年 CALACULU. All rights reserved. +// + +#import + +@interface CLImagePickerDemoTests : XCTestCase + +@end + +@implementation CLImagePickerDemoTests + +- (void)setUp +{ + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown +{ + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testExample +{ + XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); +} + +@end diff --git a/Demo/CLImagePickerDemo/CLImagePickerDemoTests/en.lproj/InfoPlist.strings b/Demo/CLImagePickerDemo/CLImagePickerDemoTests/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Demo/CLImagePickerDemo/CLImagePickerDemoTests/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Demo/CLImagePickerDemo/Podfile b/Demo/CLImagePickerDemo/Podfile new file mode 100644 index 0000000..826ab28 --- /dev/null +++ b/Demo/CLImagePickerDemo/Podfile @@ -0,0 +1,5 @@ + +platform :ios, '7.0' + +pod 'CLImageViewerKit/CLImagePicker', :path => '../../' +pod 'CLImageEditor', :git => 'https://github.com/yackle/CLImageEditor', :branch => "develop"