├── .gitignore
├── .travis.yml
├── LZAlbum.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── LZAlbum.xccheckout
└── xcshareddata
│ └── xcschemes
│ ├── LZAlbum.xcscheme
│ └── LZAlbumTests.xcscheme
├── LZAlbum.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── LZAlbum.xccheckout
├── LZAlbum
├── Base.lproj
│ └── LaunchScreen.xib
├── FPSObject.h
├── FPSObject.m
├── Images.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Info.plist
├── album
│ ├── LZAlbumCreateVC.h
│ ├── LZAlbumCreateVC.m
│ ├── LZAlbumCreateVC.xib
│ ├── LZAlbumVC.h
│ └── LZAlbumVC.m
├── base
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── LZCommon.h
│ └── LZMacros.h
├── main.m
├── manager
│ ├── LZAlbumManager.h
│ └── LZAlbumManager.m
├── model
│ ├── LZAlbum.h
│ ├── LZAlbum.m
│ ├── LZAlbumComment.h
│ ├── LZAlbumComment.m
│ ├── avobject
│ │ ├── AVUser+MCCustomUser.h
│ │ ├── AVUser+MCCustomUser.m
│ │ ├── LCAlbum.h
│ │ ├── LCAlbum.m
│ │ ├── LZAVObjectHeader.h
│ │ ├── LZComment.h
│ │ └── LZComment.m
│ └── form
│ │ ├── LZEntryForm.h
│ │ ├── LZEntryForm.m
│ │ ├── LZLoginForm.h
│ │ ├── LZLoginForm.m
│ │ ├── LZRegisterForm.h
│ │ └── LZRegisterForm.m
├── resources
│ ├── AlbumAddBtn@2x.png
│ ├── AlbumAddBtnHL@2x.png
│ ├── AlbumFlagMark@2x.png
│ ├── AlbumHeaderBackgrounImage@2x.png
│ ├── AlbumInformationLikeHL@2x.png
│ ├── AlbumInformationLikeHL@3x.png
│ ├── AlbumOperateMore@2x.png
│ ├── AlbumOperateMoreHL@2x.png
│ ├── Album_like_icon@2x.png
│ ├── Album_likes_comments_background@2x.png
│ └── album_add_photo@2x.png
├── ui
│ ├── AsyncView.h
│ ├── AsyncView.m
│ ├── LZBaseTC.h
│ ├── LZBaseTC.m
│ ├── LZBaseVC.h
│ ├── LZBaseVC.m
│ ├── LZEntryFormController.h
│ ├── LZEntryFormController.m
│ └── views
│ │ ├── AsyncRichTextView.h
│ │ ├── AsyncRichTextView.m
│ │ ├── AsyncView.h
│ │ ├── AsyncView.m
│ │ ├── LZAlbumCollectionFlowLayout.h
│ │ ├── LZAlbumCollectionFlowLayout.m
│ │ ├── LZAlbumCommentTableViewCell.h
│ │ ├── LZAlbumCommentTableViewCell.m
│ │ ├── LZAlbumLikesCommentsView.h
│ │ ├── LZAlbumLikesCommentsView.m
│ │ ├── LZAlbumOperationView.h
│ │ ├── LZAlbumOperationView.m
│ │ ├── LZAlbumPhotoCollectionViewCell.h
│ │ ├── LZAlbumPhotoCollectionViewCell.m
│ │ ├── LZAlbumReplyView.h
│ │ ├── LZAlbumReplyView.m
│ │ ├── LZAlbumRichTextView.h
│ │ ├── LZAlbumRichTextView.m
│ │ ├── LZAlbumTableViewCell.h
│ │ ├── LZAlbumTableViewCell.m
│ │ ├── LZInputAccessoryView.h
│ │ ├── LZInputAccessoryView.m
│ │ └── test.png
└── vendor
│ ├── PathCover
│ ├── Resources
│ │ ├── MenuBackground@2x.png
│ │ ├── circle.png
│ │ ├── circle@2x.png
│ │ ├── meicon.png
│ │ └── pullrefresh.aif
│ ├── XHPathCover.h
│ ├── XHPathCover.m
│ ├── XHSoundManager.h
│ ├── XHSoundManager.m
│ ├── XHWaterDropRefresh.h
│ └── XHWaterDropRefresh.m
│ ├── XHImageViewer
│ ├── XHImageViewer.h
│ ├── XHImageViewer.m
│ ├── XHViewState.h
│ ├── XHViewState.m
│ ├── XHZoomingImageView.h
│ └── XHZoomingImageView.m
│ └── XHPhotographyHelper
│ ├── XHPhotographyHelper.h
│ └── XHPhotographyHelper.m
├── LZAlbumTests
├── Info.plist
├── LZAlbumManagerTest.m
├── LZAlbumTest.m
├── LZBaseTest.h
└── LZBaseTest.m
├── Podfile
├── README-cn.md
├── README.md
├── package.sh
└── test.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | .DS_Store
3 | build/
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | !default.xcworkspace
13 | xcuserdata
14 | *.moved-aside
15 | *.mobileprovision
16 | DerivedData
17 | .idea/
18 | # Pods - for those of you who use CocoaPods
19 | Pods
20 | Podfile.lock
21 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | xcode_workspace: LZAlbum.xcworkspace
3 | xcode_scheme: LZAlbum
4 |
--------------------------------------------------------------------------------
/LZAlbum.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/LZAlbum.xcodeproj/project.xcworkspace/xcshareddata/LZAlbum.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | 4F124B68-4C02-48C4-AF0C-03B0F8279820
9 | IDESourceControlProjectName
10 | LZAlbum
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | 3BA74ADB239A84502FA731E3A3498C5FDD907AF3
14 | github.com:lzwjava/MCAlbum.git
15 |
16 | IDESourceControlProjectPath
17 | LZAlbum.xcodeproj
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | 3BA74ADB239A84502FA731E3A3498C5FDD907AF3
21 | ../..
22 |
23 | IDESourceControlProjectURL
24 | github.com:lzwjava/MCAlbum.git
25 | IDESourceControlProjectVersion
26 | 111
27 | IDESourceControlProjectWCCIdentifier
28 | 3BA74ADB239A84502FA731E3A3498C5FDD907AF3
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | 3BA74ADB239A84502FA731E3A3498C5FDD907AF3
36 | IDESourceControlWCCName
37 | LZAlbum
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/LZAlbum.xcodeproj/xcshareddata/xcschemes/LZAlbum.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
48 |
54 |
55 |
56 |
57 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
79 |
81 |
87 |
88 |
89 |
90 |
91 |
92 |
98 |
100 |
106 |
107 |
108 |
109 |
111 |
112 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/LZAlbum.xcodeproj/xcshareddata/xcschemes/LZAlbumTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
55 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
74 |
80 |
81 |
82 |
83 |
85 |
86 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/LZAlbum.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/LZAlbum.xcworkspace/xcshareddata/LZAlbum.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | 54E3E103-9FC3-4B29-B7C5-5445BD964DBF
9 | IDESourceControlProjectName
10 | LZAlbum
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | 3BA74ADB239A84502FA731E3A3498C5FDD907AF3
14 | github.com:lzwjava/MCAlbum.git
15 |
16 | IDESourceControlProjectPath
17 | LZAlbum.xcworkspace
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | 3BA74ADB239A84502FA731E3A3498C5FDD907AF3
21 | ..
22 |
23 | IDESourceControlProjectURL
24 | github.com:lzwjava/MCAlbum.git
25 | IDESourceControlProjectVersion
26 | 111
27 | IDESourceControlProjectWCCIdentifier
28 | 3BA74ADB239A84502FA731E3A3498C5FDD907AF3
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | 3BA74ADB239A84502FA731E3A3498C5FDD907AF3
36 | IDESourceControlWCCName
37 | LZAlbum
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/LZAlbum/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/LZAlbum/FPSObject.h:
--------------------------------------------------------------------------------
1 | //
2 | // FPSObject.h
3 | // LearnObjective-C
4 | //
5 | // Created by donghuan1 on 16/8/19.
6 | // Copyright © 2016年 Dwight. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FPSObject : NSObject
12 | @end
13 |
14 | /**
15 | CADisplayLink
16 | A CADisplayLink object is a timer object that allows your application to synchronize its drawing to the refresh rate of the display.
17 | CADisplayLink是一种定时器,系统的每一帧刷新时都会被调用。
18 |
19 | CADisplayLink中的timestamp是系统每次调用时的系统时间戳,通过计算两次时间戳的间隔,可以得到每一帧所花费的时间,既可以获取当前每秒能刷新多少帧。
20 | */
21 |
--------------------------------------------------------------------------------
/LZAlbum/FPSObject.m:
--------------------------------------------------------------------------------
1 | //
2 | // FPSObject.m
3 | // LearnObjective-C
4 | //
5 | // Created by donghuan1 on 16/8/19.
6 | // Copyright © 2016年 Dwight. All rights reserved.
7 | //
8 |
9 | #import "FPSObject.h"
10 | #import
11 | #import
12 | #import "JDStatusBarNotification.h"
13 | @interface FPSObject()
14 | {
15 | //定时器
16 | CADisplayLink *linkTimer;
17 |
18 | //用于计算平均值的数组
19 | CFTimeInterval *fpsBuffer;
20 | //用于计算平均值的数组大小
21 | int fpsBufferSize;
22 |
23 | //计算一次fps的间隔
24 | int refreshSeconds;
25 | //计算一次fps间隔用的临时变量
26 | int refreshCounter;
27 | int count;
28 | //用于记录上一次的时间戳
29 | CFTimeInterval lastTimeStamp;
30 |
31 | //
32 | NSInteger currentSeconds;
33 | NSInteger currentCount;
34 |
35 | UILabel *showFPs;
36 | }
37 | @end
38 |
39 | @implementation FPSObject
40 |
41 | - (instancetype)init
42 | {
43 | self = [super init];
44 | if (self) {
45 | linkTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(update:)];
46 |
47 | fpsBufferSize = 10;
48 | fpsBuffer = malloc(sizeof(CFTimeInterval)*fpsBufferSize);
49 | fpsBufferSize -= 1;
50 | refreshSeconds = 10;
51 | refreshCounter = 0;
52 |
53 | lastTimeStamp = CFAbsoluteTimeGetCurrent();
54 | //添加到当前runloop中
55 | [linkTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
56 | showFPs = [[UILabel alloc]initWithFrame:CGRectMake(10, 30, 150, 40)];
57 | showFPs.textColor = [UIColor whiteColor];
58 | showFPs.font = [UIFont systemFontOfSize:12];
59 | showFPs.text = @"0";
60 | // [[UIApplication sharedApplication].delegate.window addSubview:showFPs];
61 |
62 |
63 |
64 | }
65 | return self;
66 | }
67 |
68 | /**
69 | * @brief 带字符串参数的方法.
70 |
71 | */
72 | - (void)update:(CADisplayLink *)timer
73 | {
74 | count ++;
75 | if (count >200) {
76 | count = 1;
77 | }
78 |
79 |
80 | for (int i = fpsBufferSize - 1; i > 0; i--) {
81 | fpsBuffer[i] = fpsBuffer[i-1];
82 | }
83 | fpsBuffer[0] = timer.timestamp - lastTimeStamp;
84 | lastTimeStamp = timer.timestamp;
85 |
86 | double maxTime = 0;
87 | double averTimeSum = 0;
88 | double averTime = 0;
89 |
90 | for (int i = 0; i < fpsBufferSize; i++)
91 | {
92 | maxTime = MAX(fpsBuffer[i],maxTime);
93 | averTimeSum += fpsBuffer[i];
94 | }
95 |
96 | averTime = averTimeSum / fpsBufferSize;
97 |
98 | refreshCounter ++;
99 |
100 | if (refreshCounter%refreshSeconds == 0) {
101 | refreshCounter = 0;
102 | NSString *info = [NSString stringWithFormat:@"current:%.1f---aver:%.1f",roundf(1.f/maxTime),round(1.f/averTime)];
103 | [JDStatusBarNotification showWithStatus:info styleName:JDStatusBarStyleDark];
104 |
105 | }
106 |
107 |
108 | }
109 |
110 | @end
111 |
--------------------------------------------------------------------------------
/LZAlbum/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/LZAlbum/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | NSAppTransportSecurity
26 |
27 | NSExceptionDomains
28 |
29 | clouddn.com
30 |
31 | NSIncludesSubdomains
32 |
33 | NSTemporaryExceptionAllowsInsecureHTTPLoads
34 |
35 |
36 |
37 |
38 | UILaunchStoryboardName
39 | LaunchScreen
40 | UIRequiredDeviceCapabilities
41 |
42 | armv7
43 |
44 | UISupportedInterfaceOrientations
45 |
46 | UIInterfaceOrientationPortrait
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/LZAlbum/album/LZAlbumCreateVC.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbumCreateVC.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/4/1.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZBaseVC.h"
10 | #import "LZAlbumVC.h"
11 |
12 | @interface LZAlbumCreateVC : LZBaseVC
13 |
14 | @property (nonatomic,strong) LZAlbumVC* albumVC;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/LZAlbum/album/LZAlbumCreateVC.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbumCreateVC.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/4/1.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZAlbumCreateVC.h"
10 | #import "XHPhotographyHelper.h"
11 | #import "LZAlbumManager.h"
12 | #import "LZAlbumPhotoCollectionViewCell.h"
13 | #import "AppDelegate.h"
14 |
15 | static CGFloat kLZAlbumCreateVCPhotoSize = 60;
16 |
17 | @interface LZAlbumCreateVC ()
18 |
19 | @property (weak, nonatomic) IBOutlet UITextField *contentTextField;
20 |
21 | @property (weak, nonatomic) IBOutlet UICollectionView *photoCollectionView;
22 |
23 | @property (nonatomic,strong) NSMutableArray* selectPhotos;
24 |
25 | @property (strong,nonatomic) XHPhotographyHelper* photographyHelper;
26 |
27 | @end
28 |
29 | static NSString* photoCellIndentifier=@"cell";
30 |
31 | @implementation LZAlbumCreateVC
32 |
33 | - (void)viewDidLoad {
34 | [super viewDidLoad];
35 | self.title=@"新建";
36 | UIBarButtonItem *createItem=[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(createFeed)];
37 | self.navigationItem.rightBarButtonItem = createItem;
38 | self.navigationItem.leftBarButtonItem=[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(dismiss)];
39 | [self.photoCollectionView registerClass:[LZAlbumPhotoCollectionViewCell class] forCellWithReuseIdentifier:photoCellIndentifier];
40 | }
41 |
42 | -(void)dismiss{
43 | [self dismissViewControllerAnimated:YES completion:nil];
44 | }
45 |
46 | -(void)createFeed{
47 | if(self.contentTextField.text.length!=0 || self.selectPhotos.count!=0){
48 | WEAKSELF
49 | [self showProgress];
50 | [self runInGlobalQueue:^{
51 | NSError* error;
52 | [[LZAlbumManager manager] createAlbumWithText:self.contentTextField.text photos:self.selectPhotos error:&error];
53 | [weakSelf runInMainQueue:^{
54 | [weakSelf hideProgress];
55 | if(error==nil){
56 | [_albumVC refresh];
57 | [weakSelf dismiss];
58 | }else{
59 | [weakSelf alertError:error];
60 | }
61 | }];
62 | }];
63 | }else{
64 | [self alert:@"请完善内容"];
65 | }
66 | }
67 |
68 | #pragma mark - Propertys
69 | -(XHPhotographyHelper*)photographyHelper{
70 | if(_photographyHelper==nil){
71 | _photographyHelper=[[XHPhotographyHelper alloc] init];
72 | }
73 | return _photographyHelper;
74 | }
75 |
76 | - (void)didReceiveMemoryWarning {
77 | [super didReceiveMemoryWarning];
78 | }
79 |
80 | -(NSMutableArray*)selectPhotos{
81 | if(_selectPhotos==nil){
82 | _selectPhotos=[NSMutableArray array];
83 | }
84 | return _selectPhotos;
85 | }
86 |
87 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
88 | if(self.selectPhotos.count==9){
89 | return self.selectPhotos.count;
90 | }else{
91 | return self.selectPhotos.count+1;
92 | }
93 | }
94 |
95 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
96 | LZAlbumPhotoCollectionViewCell* cell=(LZAlbumPhotoCollectionViewCell*)[collectionView dequeueReusableCellWithReuseIdentifier:photoCellIndentifier forIndexPath:indexPath];
97 | if(indexPath.row==self.selectPhotos.count){
98 | cell.photoImageView.image=[UIImage imageNamed:@"AlbumAddBtn"];
99 | cell.photoImageView.highlightedImage=[UIImage imageNamed:@"AlbumAddBtnHL"];
100 | return cell;
101 | }else{
102 | cell.photoImageView.image=self.selectPhotos[indexPath.row];
103 | cell.photoImageView.highlightedImage=nil;
104 | return cell;
105 | }
106 | }
107 |
108 | #pragma mark - Delegate
109 | -(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
110 | return CGSizeMake(kLZAlbumCreateVCPhotoSize, kLZAlbumCreateVCPhotoSize);
111 | }
112 |
113 | -(BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath{
114 | return YES;
115 | }
116 |
117 | -(void)addImage:(UIImage*)image{
118 | [self.selectPhotos addObject:image];
119 | [self.photoCollectionView reloadData];
120 | }
121 |
122 | -(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
123 | if(indexPath.row==_selectPhotos.count){
124 | [self.photographyHelper showOnPickerViewControllerSourceType:UIImagePickerControllerSourceTypePhotoLibrary onViewController:self compled:^(UIImage *image, NSDictionary *editingInfo) {
125 | if (image) {
126 | [self addImage:image];
127 | } else {
128 | if (!editingInfo)
129 | return ;
130 | image=[editingInfo valueForKey:UIImagePickerControllerOriginalImage];
131 | if(image){
132 | [self addImage:image];
133 | }
134 | }
135 | }];
136 | }
137 | }
138 |
139 | @end
140 |
--------------------------------------------------------------------------------
/LZAlbum/album/LZAlbumCreateVC.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/LZAlbum/album/LZAlbumVC.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCClassAlbumVC.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/24.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZBaseTC.h"
10 | #import "FPSObject.h"
11 | @interface LZAlbumVC : LZBaseTC
12 | @property (nonatomic,strong)FPSObject *fps;
13 | -(void)refresh;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/LZAlbum/album/LZAlbumVC.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbumVC.m
3 | //
4 | // Created by lzw on 15/3/24.
5 | // Copyright (c) 2015年 lzw. All rights reserved.
6 | //
7 |
8 | #import "LZAlbumVC.h"
9 | #import "XHPathCover.h"
10 | #import "LZAlbumTableViewCell.h"
11 | #import "LZAlbumOperationView.h"
12 | #import "LZAlbumReplyView.h"
13 | #import "LZAlbumCreateVC.h"
14 | #import
15 | #import "LZAlbumManager.h"
16 | #import "AVUser+MCCustomUser.h"
17 | #import
18 | #import "AsyncRichTextView.h"
19 |
20 | #define ShowNew
21 |
22 | @interface LZAlbumVC ()
23 |
24 | @property (nonatomic,strong) XHPathCover *albumHeaderPathCover;
25 |
26 | @property (nonatomic,strong) LZAlbumOperationView *albumOperationView;
27 |
28 | @property (nonatomic,strong) LZAlbumReplyView *albumReplyView;
29 |
30 | @property (nonatomic,strong) NSIndexPath *selectedIndexPath;
31 |
32 | @property (nonatomic,strong) NSMutableArray *lcAlbums;
33 |
34 | @property (nonatomic,strong) NSIndexPath *commentSelectedIndexPath;
35 |
36 | @end
37 |
38 | @implementation LZAlbumVC
39 |
40 | #pragma mark - life cycle
41 |
42 | - (void)viewDidLoad {
43 | [super viewDidLoad];
44 | [self.view addSubview:self.tableView];
45 | [self.view addSubview:self.albumReplyView];
46 |
47 | self.title=@"朋友圈";
48 | self.navigationItem.rightBarButtonItem=[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"album_add_photo"] style:UIBarButtonItemStylePlain target:self action:@selector(onAddAlbumButtonClicked)];
49 | self.tableView.tableHeaderView=self.albumHeaderPathCover;
50 | [[LZAlbumManager manager] addUserToCache:[AVUser currentUser]];
51 | _fps = [[FPSObject alloc]init];
52 | [self refresh];
53 | }
54 |
55 | -(void)refresh{
56 |
57 | DLog(@"refresh");
58 | [self showNetworkIndicator];
59 | WEAKSELF
60 | //dhmark - LoadData
61 | [[LZAlbumManager manager] findAlbumWithBlock:^(NSArray *lcAlbums, NSError *error) {
62 | [weakSelf hideNetworkIndicator];
63 | [weakSelf.albumHeaderPathCover stopRefresh];
64 | if([weakSelf filterError:error]){
65 | DLog(@"found");
66 | _lcAlbums=[lcAlbums mutableCopy];
67 | NSMutableArray* albums=[NSMutableArray array];
68 | for(LCAlbum* lcAlbum in lcAlbums){
69 | [albums addObject:[self showAlbumFromLCAlbum:lcAlbum]];
70 | }
71 | weakSelf.dataSource=albums;
72 | [weakSelf.tableView reloadData];
73 | }
74 | }];
75 | }
76 | //dhmark - model factory
77 | -(LZAlbum*)showAlbumFromLCAlbum:(LCAlbum*)lcAlbum{
78 | LZAlbum* album=[[LZAlbum alloc] init];
79 | album.username=lcAlbum.creator.username;
80 | AVFile* avatarFile=[lcAlbum.creator objectForKey:KEY_AVATAR];
81 | album.avatarUrl=avatarFile.url;
82 | album.albumShareContent=lcAlbum.albumContent;
83 | NSMutableArray* photos=[NSMutableArray array];
84 | for(AVFile* photoFile in lcAlbum.albumPhotos){
85 | int photoSize = kLZAlbumPhotoSize * [UIScreen mainScreen].scale;
86 | NSString *thumbnailUrl = [photoFile getThumbnailURLWithScaleToFit:YES width:photoSize height:photoSize];
87 | LZPhoto *photo = [LZPhoto photoWithOriginUrl:photoFile.url thumbnailUrl:thumbnailUrl];
88 | [photos addObject:photo];
89 | }
90 | album.albumSharePhotos=photos;
91 | NSMutableArray* digNames=[NSMutableArray array];
92 | for(AVUser *digUser in lcAlbum.digUsers){
93 | if (digUser.username.length > 0) {
94 | [digNames addObject:digUser.username];
95 | }
96 | }
97 | album.albumShareLikes=digNames;
98 | NSMutableArray* albumComments=[NSMutableArray array];
99 | for(LZComment* comment in lcAlbum.comments){
100 | if (comment != nil && ![comment isEqual:[NSNull null]]) {
101 | LZAlbumComment* albumComment=[[LZAlbumComment alloc] init];
102 | albumComment.fromUsername = comment.commentUser.username;
103 | albumComment.toUsername = comment.toUser.username;
104 | albumComment.commentContent=comment.commentContent;
105 | [albumComments addObject:albumComment];
106 | }
107 | }
108 | album.albumShareComments=albumComments;
109 | album.albumShareTimestamp=lcAlbum.createdAt;
110 |
111 | album.rowHeight = [LZAlbumTableViewCell calculateCellHeightWithAlbum:album];
112 | album.contentHeight = [LZAlbumRichTextView getContentLabelHeightWithAlbum:album];
113 | album.collectionHeight = [LZAlbumRichTextView getPhotoCollectionViewHeightWithAlbum:album];
114 | album.commentsHeight = [LZAlbumLikesCommentsView caculateLikesCommentsViewHeightWithAlbum:album];
115 | //只和数据相关的必要计算,在网络加载时就计算好。
116 |
117 | return album;
118 | }
119 |
120 | - (void)didReceiveMemoryWarning {
121 | [super didReceiveMemoryWarning];
122 | }
123 |
124 |
125 | #pragma mark - views
126 |
127 | -(XHPathCover*)albumHeaderPathCover{
128 | if(_albumHeaderPathCover==nil){
129 | _albumHeaderPathCover=[[XHPathCover alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), 200)];
130 | [_albumHeaderPathCover setBackgroundImage:[UIImage imageNamed:@"AlbumHeaderBackgrounImage"]];
131 | AVUser* user=[AVUser currentUser];
132 | AVFile* avatar=[user objectForKey:KEY_AVATAR];
133 | [_albumHeaderPathCover.avatarButton sd_setImageWithURL:[NSURL URLWithString:avatar.url] forState:UIControlStateNormal];
134 | [_albumHeaderPathCover setInfo:@{XHUserNameKey:user.username}];
135 | _albumHeaderPathCover.isZoomingEffect=YES;
136 | WEAKSELF
137 | [_albumHeaderPathCover setHandleRefreshEvent:^{
138 | [weakSelf refresh];
139 | }];
140 |
141 | [_albumHeaderPathCover setHandleTapBackgroundImageEvent:^{
142 | DLog(@"tab background");
143 | }];
144 | }
145 | return _albumHeaderPathCover;
146 | }
147 |
148 | -(LZAlbumOperationView*)albumOperationView{
149 | if(_albumOperationView==nil){
150 | _albumOperationView=[LZAlbumOperationView initialOperationView];
151 | _albumOperationView.albumOperationViewDelegate=self;
152 | }
153 | return _albumOperationView;
154 | }
155 |
156 | -(LZAlbumReplyView*)albumReplyView{
157 | if(_albumReplyView==nil){
158 | _albumReplyView=[[LZAlbumReplyView alloc] initWithFrame:CGRectZero];
159 | _albumReplyView.albumReplyViewDelegate=self;
160 | }
161 | return _albumReplyView;
162 | }
163 |
164 | -(void)reloadLCAlbum:(LCAlbum*)lcAlbum AtIndexPath:(NSIndexPath*)indexPath{
165 | [self.lcAlbums replaceObjectAtIndex:indexPath.row withObject:lcAlbum];
166 | LZAlbum* album=[self showAlbumFromLCAlbum:lcAlbum];
167 | [self.dataSource replaceObjectAtIndex:indexPath.row withObject:album];
168 | [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
169 | }
170 |
171 | -(void)addLike{
172 | LCAlbum* lcAlbum=self.lcAlbums[self.selectedIndexPath.row];
173 | [[LZAlbumManager manager] digOrCancelDigOfAlbum:lcAlbum block:^(BOOL succeeded, NSError *error) {
174 | if([self filterError:error]){
175 | [self reloadLCAlbum:lcAlbum AtIndexPath:self.selectedIndexPath];
176 | }
177 | }];
178 | }
179 |
180 | -(void)albumOperationView:(LZAlbumOperationView *)albumOperationView didClickOfType:(MCAlbumOperationType)operationType{
181 | if(operationType==MCAlbumOperationTypeLike){
182 | [self addLike];
183 | }else{
184 | [self.albumReplyView show];
185 | }
186 | [albumOperationView dismiss];
187 | }
188 |
189 | -(void)albumReplyView:(LZAlbumReplyView *)albumReplyView didReply:(NSString *)text{
190 | LCAlbum* lcAlbum=self.lcAlbums[self.selectedIndexPath.row];
191 | AVUser* toUser;
192 | if(_commentSelectedIndexPath==nil){
193 | toUser = nil;
194 | }else{
195 | LZComment* comment=lcAlbum.comments[_commentSelectedIndexPath.row];
196 | toUser=comment.commentUser;
197 | }
198 |
199 | [self showProgress];
200 | [[LZAlbumManager manager] commentToUser:toUser AtAlbum:lcAlbum content:text block:^(BOOL succeeded, NSError *error) {
201 | [self hideProgress];
202 | if([self filterError:error]){
203 | [self reloadLCAlbum:lcAlbum AtIndexPath:self.selectedIndexPath];
204 | [self.albumReplyView finishReply];
205 | }
206 | }];
207 | }
208 |
209 | #pragma mark - scroll view delegate
210 | -(void)scrollViewDidScroll:(UIScrollView *)scrollView{
211 | [_albumHeaderPathCover scrollViewDidScroll:scrollView];
212 | }
213 |
214 | -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
215 | [_albumHeaderPathCover scrollViewDidEndDragging:scrollView willDecelerate:decelerate];
216 | }
217 |
218 | -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
219 | [_albumOperationView dismiss];
220 |
221 | [self.albumReplyView dismiss];
222 |
223 | [_albumHeaderPathCover scrollViewWillBeginDragging:scrollView];
224 | }
225 |
226 | -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
227 | [_albumHeaderPathCover scrollViewDidEndDecelerating:scrollView];
228 | }
229 |
230 | #pragma mark - action
231 | -(void)onAddAlbumButtonClicked{
232 | LZAlbumCreateVC* albumCreateVC=[[LZAlbumCreateVC alloc] init];
233 | albumCreateVC.albumVC=self;
234 | UINavigationController* nav=[[UINavigationController alloc] initWithRootViewController:albumCreateVC];
235 | nav.navigationBar.barStyle = UIBarStyleBlack;
236 | [self.navigationController presentViewController:nav animated:YES completion:nil];
237 | }
238 |
239 | #pragma mark - tableview delegate
240 |
241 |
242 |
243 | -(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
244 | #ifdef ShowNew
245 | LZAlbum *album = self.dataSource[indexPath.row];
246 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"test"];
247 | if (cell == nil) {
248 | cell = [[UITableViewCell alloc]init];
249 | }
250 |
251 | AsyncRichTextView *textview = [[AsyncRichTextView alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, album.rowHeight) Album:album];
252 | [cell.contentView addSubview:textview];
253 | return cell;
254 | #else
255 | static NSString* cellIdentifer=@"albumTableViewCellIdentifier";
256 | LZAlbumTableViewCell* albumTableViewCell= [tableView dequeueReusableCellWithIdentifier:cellIdentifer];
257 | if(albumTableViewCell==nil){
258 | albumTableViewCell=[[LZAlbumTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifer];
259 | }
260 | albumTableViewCell.albumTableViewCellDelegate=self;
261 | albumTableViewCell.indexPath=indexPath;
262 | albumTableViewCell.currentAlbum=self.dataSource[indexPath.row];
263 | return albumTableViewCell;
264 | #endif
265 |
266 |
267 | }
268 |
269 | -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
270 | #ifdef ShowNew
271 | return [self.dataSource[indexPath.row] rowHeight];
272 | #else
273 | return [LZAlbumTableViewCell calculateCellHeightWithAlbum:self.dataSource[indexPath.row]];
274 | #endif
275 |
276 |
277 | }
278 |
279 | #pragma mark - Cell Delegate
280 |
281 | -(void)didCommentButtonClick:(UIButton *)button indexPath:(NSIndexPath *)indexPath{
282 | if(self.albumOperationView.shouldShowed==YES){
283 | [self.albumOperationView dismiss];
284 | return;
285 | }
286 | CGRect rectInTablew=[self.tableView rectForRowAtIndexPath:indexPath];
287 | CGFloat originY=rectInTablew.origin.y+button.frame.origin.y;
288 | CGRect targeRect=CGRectMake(button.frame.origin.x, originY, CGRectGetWidth(button.frame), CGRectGetHeight(button.frame));
289 | _commentSelectedIndexPath=nil;
290 | _selectedIndexPath=indexPath;
291 | [self.albumOperationView showAtView:self.tableView rect:targeRect];
292 | }
293 |
294 | -(void)didSelectCommentAtCellIndexPath:(NSIndexPath *)cellIndexPath commentIndexPath:(NSIndexPath *)commentIndexPath{
295 | LCAlbum* lcAlbum=self.lcAlbums[cellIndexPath.row];
296 | LZComment* comment=lcAlbum.comments[commentIndexPath.row];
297 | if ([comment.commentUser isEqual:[AVUser currentUser]]) {
298 | // Todo 显示是否删除
299 | return;
300 | }
301 | _commentSelectedIndexPath=commentIndexPath;
302 | _selectedIndexPath=cellIndexPath;
303 | [self.albumReplyView show];
304 | }
305 |
306 | #pragma mark - Data Propertys
307 |
308 | @end
309 |
--------------------------------------------------------------------------------
/LZAlbum/base/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // MCAlbum
4 | //
5 | // Created by lzw on 15/4/28.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 | -(void)toNextController;
16 |
17 |
18 | @end
19 |
20 |
--------------------------------------------------------------------------------
/LZAlbum/base/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // MCAlbum
4 | //
5 | // Created by lzw on 15/4/28.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 | #import "LCAlbum.h"
11 | #import "LZComment.h"
12 | #import "LZEntryFormController.h"
13 | #import "LZAlbumVC.h"
14 | #import "FPSObject.h"
15 | @interface AppDelegate ()
16 |
17 | @end
18 |
19 | @implementation AppDelegate
20 |
21 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
22 |
23 | [LCAlbum registerSubclass];
24 | [LZComment registerSubclass];
25 | [AVOSCloud setApplicationId:@"0y463z4tk9wk4zbtkq4qn21kshdm9zetj8mkouiqkaoovn4e" clientKey:@"j9de7xoza1gbvkbp0b6qudz10s9lkwsxqll2nvwrjfty3a58"];
26 | [AVAnalytics trackAppOpenedWithLaunchOptions:launchOptions];
27 | [AVOSCloud setLastModifyEnabled:YES];
28 | [AVOSCloud setNetworkTimeoutInterval:30];
29 | [[AVInstallation currentInstallation] saveInBackground];
30 |
31 | #ifdef DEBUG
32 | [AVAnalytics setAnalyticsEnabled:NO];
33 | [AVOSCloud setAllLogsEnabled:YES];
34 | #endif
35 |
36 | UIColor* tintColor=[UIColor colorWithRed:0.071 green:0.060 blue:0.086 alpha:1.000];
37 | if([[UIDevice currentDevice].systemVersion floatValue]>=7.0){
38 | [UINavigationBar appearance].barTintColor=tintColor;
39 | [UINavigationBar appearance].tintColor=[UIColor whiteColor];
40 | }else{
41 | [UINavigationBar appearance].tintColor=tintColor;
42 | }
43 | [UINavigationBar appearance].titleTextAttributes=@{NSForegroundColorAttributeName:[UIColor whiteColor],NSFontAttributeName:[UIFont boldSystemFontOfSize:17]};
44 | [application setStatusBarStyle:UIStatusBarStyleLightContent];
45 |
46 | self.window=[[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
47 | self.window.backgroundColor=[UIColor whiteColor];
48 | [self.window makeKeyAndVisible];
49 | [self toNextController];
50 |
51 | return YES;
52 | }
53 |
54 | - (void)toNextController {
55 | UIViewController* nextVC;
56 | if([AVUser currentUser]){
57 | nextVC=[[LZAlbumVC alloc] init];
58 | }else{
59 | nextVC=[[LZEntryFormController alloc] init];
60 | }
61 | UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:nextVC];
62 | nav.navigationBar.barStyle = UIBarStyleBlack;
63 | self.window.rootViewController = nav;
64 | }
65 |
66 | - (void)applicationWillResignActive:(UIApplication *)application {
67 | }
68 |
69 | - (void)applicationDidEnterBackground:(UIApplication *)application {
70 | }
71 |
72 | - (void)applicationWillEnterForeground:(UIApplication *)application {
73 | }
74 |
75 | - (void)applicationDidBecomeActive:(UIApplication *)application {
76 | }
77 |
78 | - (void)applicationWillTerminate:(UIApplication *)application {
79 | }
80 |
81 | @end
82 |
--------------------------------------------------------------------------------
/LZAlbum/base/LZCommon.h:
--------------------------------------------------------------------------------
1 | //
2 | // CNCommon.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/10.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #ifndef LZAlbum_MCCommon_h
10 | #define LZAlbum_MCCommon_h
11 |
12 | #import
13 | #import "LZMacros.h"
14 |
15 | #endif
16 |
--------------------------------------------------------------------------------
/LZAlbum/base/LZMacros.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCMacros.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/26.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #ifndef LZAlbum_MCMacros_h
10 | #define LZAlbum_MCMacros_h
11 |
12 | #ifdef DEBUG
13 | # define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
14 | #else
15 | # define DLog(...)
16 | #endif
17 |
18 | #define WEAKSELF typeof(self) __weak weakSelf=self;
19 |
20 | #define RGB(R,G,B) [UIColor colorWithRed:(R)/255.0f green:(G)/255.0f blue:(B)/255.0f alpha:1.0f]
21 | #define RGBA(R,G,B,A) [UIColor colorWithRed:(R)/255.0f green:(G)/255.0f blue:(B)/255.0f alpha:(A)/255]
22 |
23 |
24 | #endif
25 |
--------------------------------------------------------------------------------
/LZAlbum/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // MCAlbum
4 | //
5 | // Created by lzw on 15/4/28.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/LZAlbum/manager/LZAlbumManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // LZAlbumManager.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/4/1.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LCAlbum.h"
10 | #import "LZComment.h"
11 |
12 | @interface LZAlbumManager : NSObject
13 |
14 | + (LZAlbumManager *)manager;
15 |
16 | - (void)createAlbumWithText:(NSString*)text photos:(NSArray*)photos error:(NSError**)error;
17 |
18 | -(void)findAlbumWithBlock:(AVArrayResultBlock)block;
19 |
20 | - (void)addUserToCache:(AVUser *)user;
21 |
22 | -(void)commentToUser:(AVUser *)toUser AtAlbum:(LCAlbum*)album content:(NSString*)content block:(AVBooleanResultBlock)block;
23 |
24 | -(void)digOrCancelDigOfAlbum:(LCAlbum *)album block:(AVBooleanResultBlock)block;
25 |
26 | - (void)deleteUnusedFiles;
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/LZAlbum/manager/LZAlbumManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCFeedManager.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/4/1.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZAlbumManager.h"
10 |
11 | @interface LZAlbumManager()
12 |
13 | @property (nonatomic, strong) NSMutableDictionary *cachedUsers;
14 |
15 | @end
16 |
17 | @implementation LZAlbumManager
18 |
19 | + (LZAlbumManager *)manager {
20 | static LZAlbumManager *albumManager;
21 | static dispatch_once_t onceToken;
22 | dispatch_once(&onceToken, ^{
23 | albumManager = [[LZAlbumManager alloc] init];
24 | });
25 | return albumManager;
26 | }
27 |
28 | - (instancetype)init {
29 | self = [super init];
30 | if (self) {
31 | self.cachedUsers = [NSMutableDictionary dictionary];
32 | }
33 | return self;
34 | }
35 |
36 | - (void)createAlbumWithText:(NSString *)text photos:(NSArray *)photos error:(NSError **)error {
37 | if (text == nil) {
38 | text = @"";
39 | }
40 | NSMutableArray *photoFiles = [NSMutableArray array];
41 | NSError *theError;
42 | for (UIImage *photo in photos) {
43 | AVFile *photoFile = [AVFile fileWithData:UIImageJPEGRepresentation(photo, 0.6)];
44 | [photoFile save:&theError];
45 | if (theError) {
46 | *error = theError;
47 | return;
48 | }
49 | [photoFiles addObject:photoFile];
50 | }
51 | AVUser *user = [AVUser currentUser];
52 | LCAlbum *album = [LCAlbum object];
53 | album.creator = user;
54 | album.albumContent = text;
55 | album.albumPhotos = photoFiles;
56 | album.isDel = NO;
57 | album.digUsers = [NSArray array];
58 | album.comments = [NSArray array];
59 | [album save:&theError];
60 | *error = theError;
61 | }
62 |
63 | /**
64 | * @discussion 因为不同朋友圈里的评论或者点赞的人很有可能重复,这里我们遍历所有的 User,然后统一缓存起来。原先这里的逻辑是很简单的,这里为了更好的性能优化了。见这个Commit:https://github.com/lzwjava/LZAlbum/commit/afa731608ecdbbd9e38ae864f04a37cd518cdbb0#diff-7d87db85844b7a3956c139f06e3e1dfbR37
65 | */
66 | - (void)findAlbumWithBlock:(AVArrayResultBlock)block {
67 | AVQuery *q = [LCAlbum query];
68 | [q orderByDescending:KEY_CREATED_AT];
69 | [q includeKey:KEY_ALBUM_PHOTOS];
70 | [q includeKey:KEY_COMMENTS];
71 | [q setLimit:100];
72 | [q whereKey:KEY_IS_DEL equalTo:@(NO)];
73 | [q setCachePolicy:kAVCachePolicyNetworkElseCache];
74 | [q findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
75 | if (error) {
76 | block(nil, error);
77 | } else {
78 | NSMutableSet *userIds = [NSMutableSet set];
79 | [self iterateUsersInAlbums:objects block:^(AVUser *user) {
80 | [userIds addObject:user.objectId];
81 | }];
82 | [self cacheUsersByIds:userIds block:^(BOOL succeeded, NSError *error) {
83 | if (error) {
84 | block(objects, error);
85 | } else {
86 | [self iterateUsersInAlbums:objects block:^(AVUser *user) {
87 | [self fillPointerUser:user];
88 | }];
89 | block(objects, nil);
90 | }
91 | }];
92 | }
93 | }];
94 | }
95 |
96 | typedef void (^AVUserHandleBlock)(AVUser *user);
97 |
98 | /*!
99 | * 找出 Album 里相关的所有 User,这些 User只有 objectId,没有 username 等数据
100 | */
101 | - (void)iterateUsersInAlbums:(NSArray *)albums block:(AVUserHandleBlock)block {
102 | for (LCAlbum *album in albums) {
103 | if (album.creator) {
104 | block(album.creator);
105 | }
106 | for (AVUser *digUser in album.digUsers) {
107 | block(digUser);
108 | }
109 | for (LZComment *comment in album.comments) {
110 | if (comment != nil && ![comment isEqual:[NSNull null]]) {
111 | if (comment.commentUser) {
112 | block(comment.commentUser);
113 | }
114 | if (comment.toUser) {
115 | block(comment.toUser);
116 | }
117 | }
118 | }
119 | }
120 | }
121 |
122 | /*!
123 | * 填充 username,createdAt 等数据
124 | */
125 | - (void)fillPointerUser:(AVUser *)pointerUser {
126 | AVUser *fullUser = [self lookUpUserById:pointerUser.objectId];
127 | [pointerUser objectFromDictionary:[fullUser dictionaryForObject]];
128 | }
129 |
130 | #pragma mark - User Cache
131 |
132 | - (AVUser *)lookUpUserById:(NSString *)objectId {
133 | return self.cachedUsers[objectId];
134 | }
135 |
136 | - (void)addUserToCache:(AVUser *)user {
137 | self.cachedUsers[user.objectId] = user;
138 | }
139 |
140 | - (void)cacheUsersByIds:(NSMutableSet *)userIds block:(AVBooleanResultBlock)block {
141 | NSMutableSet *uncached = [NSMutableSet set];
142 | for (NSString *userId in userIds) {
143 | if ([self lookUpUserById:userId] == nil) {
144 | [uncached addObject:userId];
145 | }
146 | }
147 | if (uncached.count > 0) {
148 | AVQuery *query = [AVUser query];
149 | [query whereKey:@"objectId" containedIn:[uncached allObjects]];
150 | [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
151 | if (error) {
152 | block(NO, error);
153 | } else {
154 | for (AVUser *user in objects) {
155 | [self addUserToCache:user];
156 | }
157 | block(YES, nil);
158 | }
159 | }];
160 | } else {
161 | block(YES, nil);
162 | }
163 | }
164 |
165 | - (NSArray *)getObjectIds:(NSArray *)avObjects {
166 | NSMutableArray *objectIds = [NSMutableArray array];
167 | for (AVObject *object in avObjects) {
168 | [objectIds addObject:object.objectId];
169 | }
170 | return objectIds;
171 | }
172 |
173 | - (void)digOrCancelDigOfAlbum:(LCAlbum *)album block:(AVBooleanResultBlock)block {
174 | AVUser *user = [AVUser currentUser];
175 | if ([album.digUsers containsObject:user]) {
176 | [album removeObject:user forKey:KEY_DIG_USERS];
177 | } else {
178 | [album addObject:user forKey:KEY_DIG_USERS];
179 | }
180 | [album saveInBackgroundWithBlock:block];
181 | }
182 |
183 | - (void)commentToUser:(AVUser *)toUser AtAlbum:(LCAlbum *)album content:(NSString *)content block:(AVBooleanResultBlock)block {
184 | LZComment *comment = [LZComment object];
185 | comment.commentContent = content;
186 | AVUser *user = [AVUser currentUser];
187 | comment.commentUser = user;
188 | comment.album = album;
189 | comment.toUser = toUser;
190 | [comment saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
191 | if (error) {
192 | block(NO, error);
193 | } else {
194 | [album addObject:comment forKey:KEY_COMMENTS];
195 | [album saveInBackgroundWithBlock:block];
196 | }
197 | }];
198 | }
199 |
200 | - (BOOL)file:(AVObject *)file existsInAlbums:(NSArray *)albums {
201 | for (LCAlbum *album in albums) {
202 | for (AVFile *photo in album.albumPhotos) {
203 | if ([photo.objectId isEqualToString:file.objectId]) {
204 | return YES;
205 | }
206 | }
207 | }
208 | return NO;
209 | }
210 |
211 | // 数据维护,删掉没有出现在朋友圈里的文件,这里会把头像文件也删除掉,TODO FIX
212 | - (void)deleteUnusedFiles {
213 | AVQuery *query = [LCAlbum query];
214 | [query includeKey:KEY_ALBUM_PHOTOS];
215 | query.limit = 1000;
216 | [query findObjectsInBackgroundWithBlock:^(NSArray *albums, NSError *error) {
217 | if (!error) {
218 | AVQuery *query = [AVQuery queryWithClassName:@"_File"];
219 | [query orderByAscending:@"createdAt"];
220 | query.limit = 1000;
221 | [query findObjectsInBackgroundWithBlock:^(NSArray *files, NSError *error) {
222 | if (!error) {
223 | NSMutableArray *toDeletes = [NSMutableArray array];
224 | for (AVObject *file in files) {
225 | if (![self file:file existsInAlbums:albums]) {
226 | NSLog(@"file not exists will delete");
227 | [toDeletes addObject:file];
228 | } else {
229 | NSLog(@"file exists do not delete");
230 | };
231 | }
232 | [AVObject deleteAllInBackground:toDeletes block:^(BOOL succeeded, NSError *error) {
233 | NSLog(@"deleted, error %@", error);
234 | }];
235 | }
236 | }];
237 | }
238 | }];
239 | }
240 |
241 | @end
242 |
--------------------------------------------------------------------------------
/LZAlbum/model/LZAlbum.h:
--------------------------------------------------------------------------------
1 | //
2 | // LZAlbum.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/25.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "LZAlbumComment.h"
11 | #import "LZMacros.h"
12 |
13 | #define LZLinkTextForegroundColor RGB(117, 135, 181)
14 | #define LZLinkTextHighlightColor [UIColor colorWithWhite:0.7 alpha:1]
15 |
16 | static const CGFloat kLZAlbumAvatarSpacing=15.0f;
17 | static const CGFloat kLZAlbumAvatarImageSize=45.0f;
18 |
19 | static const CGFloat kLZAlbumPhotoSize=70;
20 | static const CGFloat kLZAlbumPhotoInset=5;
21 |
22 | static const CGFloat kLZAlbumFontSize=15;
23 |
24 | @interface LZPhoto : NSObject
25 |
26 | @property (nonatomic, copy) NSString *thumbnailUrl;
27 |
28 | @property (nonatomic, copy) NSString *originUrl;
29 |
30 | + (instancetype)photoWithOriginUrl:(NSString *)originUrl thumbnailUrl:(NSString *)thumbnailUrl;
31 |
32 | - (NSString *)actualThumbnailUrl;
33 |
34 | @end
35 |
36 | //dhmark - CellModel
37 |
38 | #define k
39 |
40 | @interface LZAlbum : NSObject
41 |
42 | @property (nonatomic,copy) NSString* username;
43 |
44 | @property (nonatomic,copy) NSString* avatarUrl;
45 |
46 | @property (nonatomic,copy) NSString* albumShareContent;
47 |
48 | @property (nonatomic,strong) NSArray* albumSharePhotos;
49 |
50 | @property (nonatomic,strong) NSArray* albumShareLikes;
51 |
52 | @property (nonatomic,strong) NSArray* albumShareComments;
53 |
54 | @property (nonatomic,copy) NSDate* albumShareTimestamp;
55 |
56 | @property (nonatomic,strong) NSMutableDictionary *drawingContext;
57 | @property (nonatomic,assign) CGFloat rowHeight;
58 | @property (nonatomic,assign) CGFloat contentHeight;
59 | @property (nonatomic,assign) CGFloat collectionHeight;
60 | @property (nonatomic,assign) CGFloat commentsHeight;
61 | + (CGFloat)contentWidth;
62 |
63 | @end
64 |
--------------------------------------------------------------------------------
/LZAlbum/model/LZAlbum.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbum.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/25.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZAlbum.h"
10 |
11 | @implementation LZPhoto
12 |
13 | + (instancetype)photoWithOriginUrl:(NSString *)originUrl thumbnailUrl:(NSString *)thumbnailUrl {
14 | LZPhoto *photo = [[LZPhoto alloc] init];
15 | photo.originUrl = originUrl;
16 | photo.thumbnailUrl = thumbnailUrl;
17 | return photo;
18 | }
19 |
20 | - (NSString *)actualThumbnailUrl {
21 | if (self.thumbnailUrl) {
22 | return self.thumbnailUrl;
23 | } else {
24 | return self.originUrl;
25 | }
26 | }
27 |
28 | @end
29 |
30 | @implementation LZAlbum
31 |
32 | -(NSDictionary *)drawingContext
33 | {
34 | if (!_drawingContext) {
35 | _drawingContext = [[NSMutableDictionary alloc]initWithCapacity:2];
36 | }
37 | return _drawingContext;
38 | }
39 |
40 | + (CGFloat)contentWidth {
41 | return CGRectGetWidth([[UIScreen mainScreen] bounds])-3*kLZAlbumAvatarSpacing-kLZAlbumAvatarImageSize;
42 | }
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/LZAlbum/model/LZAlbumComment.h:
--------------------------------------------------------------------------------
1 | //
2 | // LZAlbumComment.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/8/29.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface LZAlbumComment : NSObject
12 |
13 | @property (nonatomic,copy) NSString *fromUsername;
14 | @property (nonatomic,copy) NSString *toUsername;
15 | @property (nonatomic,copy) NSString *commentContent;
16 |
17 | - (NSRange)fromUsernameRange;
18 | - (NSRange)toUsernameRange;
19 | - (NSString *)fullCommentText;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/LZAlbum/model/LZAlbumComment.m:
--------------------------------------------------------------------------------
1 | //
2 | // LZAlbumComment.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/8/29.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZAlbumComment.h"
10 |
11 | @interface LZAlbumComment()
12 |
13 | @property (nonatomic, assign) NSRange fromRange;
14 | @property (nonatomic, assign) NSRange toRange;
15 | @property (nonatomic, strong) NSString *fullText;
16 |
17 | @end
18 |
19 | @implementation LZAlbumComment
20 |
21 | - (NSRange)fromUsernameRange {
22 | [self buildCommentText];
23 | return self.fromRange;
24 | }
25 |
26 | - (NSRange)toUsernameRange {
27 | [self buildCommentText];
28 | return self.toRange;
29 | }
30 |
31 | - (NSString *)fullCommentText {
32 | [self buildCommentText];
33 | return self.fullText;
34 | }
35 |
36 | - (void)buildCommentText {
37 | NSMutableString *text = [NSMutableString string];
38 |
39 | NSRange fromRange = NSMakeRange(NSNotFound, 0);
40 | if (self.fromUsername) {
41 | [text appendString:self.fromUsername];
42 | fromRange.location = 0;
43 | fromRange.length = self.fromUsername.length;
44 | }
45 |
46 | NSRange toRange = NSMakeRange(NSNotFound, 0);
47 | if (self.toUsername) {
48 | [text appendString:@"回复"];
49 | toRange.location = text.length;
50 | toRange.length = self.toUsername.length;
51 | [text appendString:self.toUsername];
52 | }
53 | if (self.commentContent) {
54 | [text appendString:@":"];
55 | [text appendString:self.commentContent];
56 | }
57 |
58 | self.fromRange = fromRange;
59 | self.toRange= toRange;
60 | self.fullText = text;
61 | }
62 |
63 | @end
64 |
--------------------------------------------------------------------------------
/LZAlbum/model/avobject/AVUser+MCCustomUser.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCUser.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/12.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "LZCommon.h"
11 |
12 | #define KEY_USERNAME @"username"
13 | #define KEY_AVATAR @"avatar"
14 |
15 | @interface AVUser(MCCustomUser)
16 |
17 | -(AVFile*)avatar;
18 |
19 | -(void)setAvatar:(AVFile*)avatar;
20 |
21 | -(NSString*)avatarUrl;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/LZAlbum/model/avobject/AVUser+MCCustomUser.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCUser.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/12.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "AVUser+MCCustomUser.h"
10 |
11 | @implementation AVUser(MCCustomUser)
12 |
13 | -(AVFile*)avatar{
14 | return [self objectForKey:KEY_AVATAR];
15 | }
16 |
17 | -(void)setAvatar:(AVFile*)avatar{
18 | [self setObject:avatar forKey:KEY_AVATAR];
19 | }
20 |
21 | -(NSString*)avatarUrl{
22 | return [self avatar].url;
23 | }
24 |
25 | @end
--------------------------------------------------------------------------------
/LZAlbum/model/avobject/LCAlbum.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCFeed.h
3 | // LZAlbum
4 | //
5 | // Created by wangyuansong on 15/3/11.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "LZAVObjectHeader.h"
11 |
12 | #define KEY_CLS @"cls"
13 | #define KEY_ALBUM_TYPE @"albumType"
14 | #define KEY_ALBUM_CONTENT @"albumContent"
15 | #define KEY_ALBUM_PHOTOS @"albumPhotos"
16 | #define KEY_DIG_USERS @"digUsers"
17 | #define KEY_COMMENTS @"comments"
18 | #define KEY_IS_DEL @"isDel"
19 | #define KEY_CREATOR @"creator"
20 |
21 | @interface LCAlbum : AVObject
22 |
23 | @property (nonatomic,strong) AVUser* creator; // 创建者
24 | @property (nonatomic,copy) NSString* albumContent; //分享内容
25 | @property (nonatomic,assign) NSArray* albumPhotos; //分享照片 _File Array
26 | @property (nonatomic,assign) NSArray* digUsers; //赞过的人 _User Array
27 | @property (nonatomic,assign) NSArray* comments; // Comment Array
28 | @property (nonatomic,assign) BOOL isDel; //是否删除
29 |
30 | // createdAt : 发布时间
31 |
32 | @end
33 |
--------------------------------------------------------------------------------
/LZAlbum/model/avobject/LCAlbum.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCFeed.m
3 | // LZAlbum
4 | //
5 | // Created by wangyuansong on 15/3/11.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LCAlbum.h"
10 |
11 | @implementation LCAlbum
12 |
13 | @dynamic creator;
14 | @dynamic albumContent;
15 | @dynamic albumPhotos;
16 | @dynamic comments;
17 | @dynamic digUsers;
18 | @dynamic isDel;
19 |
20 | +(NSString*)parseClassName{
21 | return @"Album";
22 | }
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/LZAlbum/model/avobject/LZAVObjectHeader.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCAVObjectHeader.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/4/4.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #ifndef LZAlbum_MCAVObjectHeader_h
10 | #define LZAlbum_MCAVObjectHeader_h
11 |
12 | #define KEY_CREATED_AT @"createdAt"
13 | #define KEY_UPDATED_AT @"updatedAt"
14 | #define KEY_OBJECT_ID @"objectId"
15 |
16 | #endif
17 |
18 |
--------------------------------------------------------------------------------
/LZAlbum/model/avobject/LZComment.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCComment.h
3 | // LZAlbum
4 | //
5 | // Created by wangyuansong on 15/3/12.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZCommon.h"
10 | #import "LCAlbum.h"
11 |
12 | #define KEY_ALBUM @"album"
13 | #define KEY_COMMENT_USER @"commentUser"
14 | #define KEY_COMMENT_USERNAME @"commentUsername"
15 | #define KEY_COMMENT_CONTENT @"commentContent"
16 | #define KEY_TO_USER @"toUser"
17 |
18 | @interface LZComment : AVObject
19 |
20 | @property (nonatomic,strong) LCAlbum* album;//关联分享
21 | @property (nonatomic,strong) AVUser* commentUser;//评论用户
22 | @property (nonatomic,strong) NSString* commentContent;//评论内容
23 | @property (nonatomic,strong)AVUser* toUser;//关联用户
24 |
25 | // createdAt:评论时间
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/LZAlbum/model/avobject/LZComment.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCComment.m
3 | // LZAlbum
4 | //
5 | // Created by wangyuansong on 15/3/12.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZComment.h"
10 |
11 | @implementation LZComment
12 |
13 | @dynamic album;
14 | @dynamic commentContent;
15 | @dynamic commentUser;
16 | @dynamic toUser;
17 |
18 | +(NSString*)parseClassName{
19 | return @"Comment";
20 | }
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/LZAlbum/model/form/LZEntryForm.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCRootForm.h
3 | // MCAlbum
4 | //
5 | // Created by lzw on 15/4/29.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "LZLoginForm.h"
11 | #import "LZRegisterForm.h"
12 |
13 | @interface LZEntryForm : NSObject
14 |
15 | @property (nonatomic,strong) LZLoginForm *loginForm;
16 | @property (nonatomic,strong) LZRegisterForm *registerForm;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/LZAlbum/model/form/LZEntryForm.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCRootForm.m
3 | // MCAlbum
4 | //
5 | // Created by lzw on 15/4/29.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZEntryForm.h"
10 |
11 | @implementation LZEntryForm
12 |
13 | -(NSDictionary*)loginFormField{
14 | return @{FXFormFieldInline:@YES,FXFormFieldHeader:@"Login"};
15 | }
16 |
17 | -(NSDictionary*)registerFormField{
18 | return @{FXFormFieldHeader:@"Not Registered?",FXFormFieldTitle:@"Register"};
19 | }
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/LZAlbum/model/form/LZLoginForm.h:
--------------------------------------------------------------------------------
1 | //
2 | // LoginForm.h
3 | // MCAlbum
4 | //
5 | // Created by lzw on 15/4/29.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "LZRegisterForm.h"
11 | #import
12 |
13 | @interface LZLoginForm : NSObject
14 |
15 | @property (nonatomic,strong) NSString *username;
16 | @property (nonatomic,strong) NSString *password;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/LZAlbum/model/form/LZLoginForm.m:
--------------------------------------------------------------------------------
1 | //
2 | // LoginForm.m
3 | // MCAlbum
4 | //
5 | // Created by lzw on 15/4/29.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZLoginForm.h"
10 |
11 | @implementation LZLoginForm
12 |
13 | -(NSArray*)extraFields{
14 | return @[@{FXFormFieldHeader:@"",FXFormFieldTitle:@"Login",FXFormFieldAction:@"submitLogin:"}];
15 | }
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/LZAlbum/model/form/LZRegisterForm.h:
--------------------------------------------------------------------------------
1 | //
2 | // RegisterForm.h
3 | // MCAlbum
4 | //
5 | // Created by lzw on 15/4/29.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface LZRegisterForm : NSObject
13 |
14 | @property (nonatomic,strong) UIImage *avatar;
15 | @property (nonatomic,strong) NSString *username;
16 | @property (nonatomic,strong) NSString *password;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/LZAlbum/model/form/LZRegisterForm.m:
--------------------------------------------------------------------------------
1 | //
2 | // RegisterForm.m
3 | // MCAlbum
4 | //
5 | // Created by lzw on 15/4/29.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZRegisterForm.h"
10 |
11 | @implementation LZRegisterForm
12 |
13 | -(NSArray*)extraFields{
14 | return @[@{FXFormFieldHeader:@"",FXFormFieldTitle:@"Register",FXFormFieldAction:@"submitRegister:"}];
15 | }
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/LZAlbum/resources/AlbumAddBtn@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzwjava/LZAlbum/33838f42510be45cb9b32f903ee52e022aa33c8d/LZAlbum/resources/AlbumAddBtn@2x.png
--------------------------------------------------------------------------------
/LZAlbum/resources/AlbumAddBtnHL@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzwjava/LZAlbum/33838f42510be45cb9b32f903ee52e022aa33c8d/LZAlbum/resources/AlbumAddBtnHL@2x.png
--------------------------------------------------------------------------------
/LZAlbum/resources/AlbumFlagMark@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzwjava/LZAlbum/33838f42510be45cb9b32f903ee52e022aa33c8d/LZAlbum/resources/AlbumFlagMark@2x.png
--------------------------------------------------------------------------------
/LZAlbum/resources/AlbumHeaderBackgrounImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzwjava/LZAlbum/33838f42510be45cb9b32f903ee52e022aa33c8d/LZAlbum/resources/AlbumHeaderBackgrounImage@2x.png
--------------------------------------------------------------------------------
/LZAlbum/resources/AlbumInformationLikeHL@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzwjava/LZAlbum/33838f42510be45cb9b32f903ee52e022aa33c8d/LZAlbum/resources/AlbumInformationLikeHL@2x.png
--------------------------------------------------------------------------------
/LZAlbum/resources/AlbumInformationLikeHL@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzwjava/LZAlbum/33838f42510be45cb9b32f903ee52e022aa33c8d/LZAlbum/resources/AlbumInformationLikeHL@3x.png
--------------------------------------------------------------------------------
/LZAlbum/resources/AlbumOperateMore@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzwjava/LZAlbum/33838f42510be45cb9b32f903ee52e022aa33c8d/LZAlbum/resources/AlbumOperateMore@2x.png
--------------------------------------------------------------------------------
/LZAlbum/resources/AlbumOperateMoreHL@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzwjava/LZAlbum/33838f42510be45cb9b32f903ee52e022aa33c8d/LZAlbum/resources/AlbumOperateMoreHL@2x.png
--------------------------------------------------------------------------------
/LZAlbum/resources/Album_like_icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzwjava/LZAlbum/33838f42510be45cb9b32f903ee52e022aa33c8d/LZAlbum/resources/Album_like_icon@2x.png
--------------------------------------------------------------------------------
/LZAlbum/resources/Album_likes_comments_background@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzwjava/LZAlbum/33838f42510be45cb9b32f903ee52e022aa33c8d/LZAlbum/resources/Album_likes_comments_background@2x.png
--------------------------------------------------------------------------------
/LZAlbum/resources/album_add_photo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzwjava/LZAlbum/33838f42510be45cb9b32f903ee52e022aa33c8d/LZAlbum/resources/album_add_photo@2x.png
--------------------------------------------------------------------------------
/LZAlbum/ui/AsyncView.h:
--------------------------------------------------------------------------------
1 | //
2 | // AsyncView.h
3 | // LearnObjective-C
4 | //
5 | // Created by donghuan1 on 16/8/4.
6 | // Copyright © 2016年 Dwight. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AsyncView : UIView
12 | ///// 用于异步绘制的队列,为nil时将使用GCD的global queue进行绘制,默认为nil
13 | @property (nonatomic, assign) dispatch_queue_t dispatchDrawQueue;
14 |
15 | /// 异步绘制时global queue的优先级,默认优先级为DEFAULT。在设置了drawQueue时此参数无效。
16 | @property (nonatomic, assign) dispatch_queue_priority_t dispatchPriority;
17 |
18 | - (BOOL)drawInRect:(CGRect)rect Context:(CGContextRef)context;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/LZAlbum/ui/AsyncView.m:
--------------------------------------------------------------------------------
1 | //
2 | // AsyncView.m
3 | // LearnObjective-C
4 | //
5 | // Created by donghuan1 on 16/8/4.
6 | // Copyright © 2016年 Dwight. All rights reserved.
7 | //
8 |
9 | #import "AsyncView.h"
10 |
11 | @implementation AsyncView
12 |
13 | - (instancetype)initWithFrame:(CGRect)frame
14 | {
15 | self = [super initWithFrame:frame];
16 | if (self) {
17 | self.dispatchPriority = DISPATCH_QUEUE_PRIORITY_DEFAULT;
18 | self.opaque = NO;
19 | self.layer.contentsScale = [[UIScreen mainScreen] scale];
20 | }
21 | return self;
22 | }
23 |
24 | - (void)didMoveToWindow
25 | {
26 | [super didMoveToWindow];
27 |
28 | if (!self.window)
29 | {
30 | // 没有 Window 说明View已经没有显示在界面上,此时应该终止绘制
31 |
32 | }
33 | else if (!self.layer.contents)
34 | {
35 | [self.layer setNeedsDisplay];
36 | }
37 | }
38 |
39 | - (dispatch_queue_t)drawQueue
40 | {
41 | if (self.dispatchDrawQueue)
42 | {
43 | return self.dispatchDrawQueue;
44 | }
45 |
46 | return dispatch_get_global_queue(self.dispatchPriority, 0);
47 | }
48 |
49 | - (void)displayLayer:(CALayer *)layer
50 | {
51 |
52 | dispatch_async([self drawQueue], ^{
53 | [self displayLayer:layer Rect:layer.frame];
54 | });
55 | }
56 |
57 | - (BOOL)drawInRect:(CGRect)rect Context:(CGContextRef)context
58 | {
59 | return YES;
60 | }
61 |
62 | - (void)displayLayer:(CALayer *)layer Rect:(CGRect)rect
63 | {
64 | CGContextRef context = NULL;
65 | UIGraphicsBeginImageContextWithOptions(layer.bounds.size, layer.isOpaque, layer.contentsScale);
66 | context = UIGraphicsGetCurrentContext();
67 | CGContextSaveGState(context);
68 |
69 | if (rect.origin.x || rect.origin.y)
70 | {
71 | CGContextTranslateCTM(context, rect.origin.x, -rect.origin.y);
72 | }
73 |
74 | if (self.backgroundColor &&
75 | self.backgroundColor != [UIColor clearColor])
76 | {
77 | CGContextSetFillColorWithColor(context, self.backgroundColor.CGColor);
78 | CGContextFillRect(context, rect);
79 | }
80 | [self drawInRect:rect Context:context];
81 | CGContextRestoreGState(context);
82 |
83 | if(true)//所有绘制完成
84 | {
85 | CGImageRef CGImage = context ? CGBitmapContextCreateImage(context) : nil;
86 |
87 | UIImage *image = CGImage ? [UIImage imageWithCGImage:CGImage] : nil;
88 |
89 | dispatch_async(dispatch_get_main_queue(), ^{
90 | layer.contents = (id)image.CGImage;
91 | });
92 | }
93 |
94 | }
95 |
96 |
97 |
98 |
99 | @end
100 |
--------------------------------------------------------------------------------
/LZAlbum/ui/LZBaseTC.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCBaseTC.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/12.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "LZBaseVC.h"
11 |
12 | @interface LZBaseTC : LZBaseVC
13 |
14 | @property (nonatomic,strong) UITableView* tableView;
15 |
16 | @property (nonatomic,assign) UITableViewStyle tableViewStyle;
17 |
18 | @property (nonatomic,strong) NSMutableArray* dataSource;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/LZAlbum/ui/LZBaseTC.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCBaseTC.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/12.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZBaseTC.h"
10 |
11 | @interface LZBaseTC ()
12 |
13 | @end
14 |
15 | @implementation LZBaseTC
16 |
17 | - (void)viewDidLoad {
18 | [super viewDidLoad];
19 | [self.view addSubview:self.tableView];
20 | }
21 |
22 | -(UITableView*)tableView{
23 | if(_tableView==nil){
24 | CGRect tableViewFrame = self.view.bounds;
25 | tableViewFrame.size.height -= (self.navigationController.viewControllers.count > 1 ? 0 : (CGRectGetHeight(self.tabBarController.tabBar.bounds)));
26 | _tableView = [[UITableView alloc] initWithFrame:tableViewFrame style:self.tableViewStyle];
27 | _tableView.delegate=self;
28 | _tableView.dataSource=self;
29 | }
30 | return _tableView;
31 | }
32 |
33 | - (void)didReceiveMemoryWarning {
34 | [super didReceiveMemoryWarning];
35 | }
36 |
37 | -(void)dealloc{
38 | }
39 |
40 | -(NSMutableArray*)dataSource{
41 | if(_dataSource==nil){
42 | _dataSource=[NSMutableArray array];
43 | }
44 | return _dataSource;
45 | }
46 |
47 | -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
48 | return 1;
49 | }
50 |
51 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
52 | return self.dataSource.count;
53 | }
54 |
55 | -(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
56 | return nil;
57 | }
58 |
59 | @end
60 |
--------------------------------------------------------------------------------
/LZAlbum/ui/LZBaseVC.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCViewController.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/12.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "LZMacros.h"
11 | #import
12 |
13 | @interface LZBaseVC : UIViewController
14 |
15 | -(void)showNetworkIndicator;
16 |
17 | -(void)hideNetworkIndicator;
18 |
19 | -(void)showProgress;
20 |
21 | -(void)hideProgress;
22 |
23 | -(void)alert:(NSString*)msg;
24 |
25 | -(BOOL)alertError:(NSError*)error;
26 |
27 | -(BOOL)filterError:(NSError*)error;
28 |
29 | -(void)runInMainQueue:(void (^)())queue;
30 |
31 | -(void)runInGlobalQueue:(void (^)())queue;
32 |
33 | -(void)runAfterSecs:(float)secs block:(void (^)())block;
34 |
35 | -(void)showHUDText:(NSString*)text;
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/LZAlbum/ui/LZBaseVC.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCViewController.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/12.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZBaseVC.h"
10 |
11 | @interface LZBaseVC ()
12 |
13 | @end
14 |
15 | @implementation LZBaseVC
16 |
17 | -(void)alert:(NSString*)msg{
18 | UIAlertView *alertView=[[UIAlertView alloc]
19 | initWithTitle:nil message:msg delegate:nil
20 | cancelButtonTitle:@"确定" otherButtonTitles:nil];
21 | [alertView show];
22 | }
23 |
24 | -(BOOL)alertError:(NSError*)error{
25 | if(error){
26 | [self alert:[NSString stringWithFormat:@"%@",error]];
27 | return YES;
28 | }
29 | return NO;
30 | }
31 |
32 | -(BOOL)filterError:(NSError*)error{
33 | return [self alertError:error]==NO;
34 | }
35 |
36 | -(void)showNetworkIndicator{
37 | UIApplication* app=[UIApplication sharedApplication];
38 | app.networkActivityIndicatorVisible=YES;
39 | }
40 |
41 | -(void)hideNetworkIndicator{
42 | UIApplication* app=[UIApplication sharedApplication];
43 | app.networkActivityIndicatorVisible=NO;
44 | }
45 |
46 | -(void)showProgress{
47 | [MBProgressHUD showHUDAddedTo:self.view animated:YES];
48 | }
49 |
50 | -(void)hideProgress{
51 | [MBProgressHUD hideHUDForView:self.view animated:YES];
52 | }
53 |
54 | -(void)showHUDText:(NSString*)text{
55 | MBProgressHUD* hud=[MBProgressHUD showHUDAddedTo:self.view animated:YES];
56 | hud.labelText=text;
57 | hud.margin=10.f;
58 | hud.removeFromSuperViewOnHide=YES;
59 | hud.mode=MBProgressHUDModeText;
60 | [hud hide:YES afterDelay:2];
61 | }
62 |
63 | -(void)runInMainQueue:(void (^)())queue{
64 | dispatch_async(dispatch_get_main_queue(), queue);
65 | }
66 |
67 | -(void)runInGlobalQueue:(void (^)())queue{
68 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), queue);
69 | }
70 |
71 | -(void)runAfterSecs:(float)secs block:(void (^)())block{
72 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, secs*NSEC_PER_SEC), dispatch_get_main_queue(), block);
73 | }
74 |
75 | - (void)viewDidLoad {
76 | [super viewDidLoad];
77 | }
78 |
79 | - (void)didReceiveMemoryWarning {
80 | [super didReceiveMemoryWarning];
81 | }
82 |
83 |
84 | @end
85 |
--------------------------------------------------------------------------------
/LZAlbum/ui/LZEntryFormController.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCEntryFormController.h
3 | // MCAlbum
4 | //
5 | // Created by lzw on 15/4/29.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZBaseTC.h"
10 |
11 | @interface LZEntryFormController : LZBaseTC
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/LZAlbum/ui/LZEntryFormController.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCEntryFormController.m
3 | // MCAlbum
4 | //
5 | // Created by lzw on 15/4/29.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZEntryFormController.h"
10 | #import "LZEntryForm.h"
11 | #import
12 | #import "AVUser+MCCustomUser.h"
13 | #import "AppDelegate.h"
14 |
15 | @interface LZEntryFormController()
16 |
17 | @property (nonatomic,strong) FXFormController *formController;
18 |
19 | @end
20 |
21 | @implementation LZEntryFormController
22 |
23 | - (instancetype)init
24 | {
25 | self = [super init];
26 | if (self) {
27 | self.tableViewStyle=UITableViewStyleGrouped;
28 | self.title=@"登录";
29 | }
30 | return self;
31 | }
32 |
33 |
34 | -(void)viewDidLoad{
35 | [super viewDidLoad];
36 | self.formController=[[FXFormController alloc] init];
37 | self.formController.tableView=self.tableView;
38 | self.formController.form=[[LZEntryForm alloc] init];
39 | }
40 |
41 | -(void)submitLogin:(UITableViewCell *)cell{
42 | LZLoginForm *loginForm=cell.field.form;
43 | WEAKSELF
44 | [AVUser logInWithUsernameInBackground:loginForm.username password:loginForm.password block:^(AVUser *user, NSError *error) {
45 | if([weakSelf filterError:error]){
46 | [weakSelf toMainVC];
47 | }
48 | }];
49 | }
50 |
51 | -(void)submitRegister:(UITableViewCell *)cell{
52 | LZRegisterForm *registerForm=cell.field.form;
53 | if(registerForm.username.length>0 && registerForm.password.length>0
54 | && registerForm.avatar!=nil){
55 | UIImage *avatarImage=[[self class] roundImage:registerForm.avatar toSize:CGSizeMake(200, 200) radius:10];
56 | AVFile *avatar=[AVFile fileWithData:UIImagePNGRepresentation(avatarImage)];
57 | WEAKSELF
58 | [avatar saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
59 | if([weakSelf filterError:error]){
60 | AVUser *user=[[AVUser alloc] init];
61 | user.username=registerForm.username;
62 | user.password=registerForm.password;
63 | [user setAvatar:avatar];
64 | [user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
65 | if([weakSelf filterError:error]){
66 | [weakSelf toMainVC];
67 | }
68 | }];
69 | }
70 | }];
71 | } else {
72 | [self alert:@"请完善资料"];
73 | }
74 | }
75 |
76 | -(void)toMainVC{
77 | AppDelegate *appDelegate=[UIApplication sharedApplication].delegate;
78 | [appDelegate toNextController];
79 | }
80 |
81 |
82 | +(UIImage *)roundImage:(UIImage *) image toSize:(CGSize)size radius: (float) radius;
83 | {
84 | CGRect rect=CGRectMake(0, 0, size.width, size.height);
85 | UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
86 | [[UIBezierPath bezierPathWithRoundedRect:rect
87 | cornerRadius:radius] addClip];
88 | [image drawInRect:rect];
89 | UIImage* rounded = UIGraphicsGetImageFromCurrentImageContext();
90 | UIGraphicsEndImageContext();
91 | return rounded;
92 | }
93 |
94 | @end
95 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/AsyncRichTextView.h:
--------------------------------------------------------------------------------
1 | //
2 | // AsyncRichTextView.h
3 | // LZAlbum
4 | //
5 | // Created by liudonghuan on 16/10/27.
6 | // Copyright © 2016年 lzw. All rights reserved.
7 | //
8 |
9 | #import "AsyncView.h"
10 | #import
11 | #import "LZAlbum.h"
12 | @protocol LZAlbumRichTextViewDelegate
13 |
14 | -(void)didCommentButtonClick:(UIButton*)button;
15 |
16 | -(void)didSelectCommentAtIndexPath:(NSIndexPath*)indexPath;
17 |
18 | @end
19 |
20 | @interface AsyncRichTextView : AsyncView
21 | @property (nonatomic,strong)LZAlbum *album;
22 | @property (nonatomic,weak) id richTextViewDelegate;
23 | - (instancetype)initWithFrame:(CGRect)frame Album:(LZAlbum *)album;
24 | @end
25 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/AsyncRichTextView.m:
--------------------------------------------------------------------------------
1 | //
2 | // AsyncRichTextView.m
3 | // LZAlbum
4 | //
5 | // Created by liudonghuan on 16/10/27.
6 | // Copyright © 2016年 lzw. All rights reserved.
7 | //
8 |
9 | #import "AsyncRichTextView.h"
10 | #import "LZAlbumRichTextView.h"
11 | #import
12 | #import "LZAlbumCollectionFlowLayout.h"
13 | #import "LZAlbumPhotoCollectionViewCell.h"
14 | #import "XHImageViewer.h"
15 | #import
16 |
17 |
18 | @interface AsyncRichTextView()
19 | {
20 |
21 | }
22 | @property (nonatomic,strong) UIImageView* avatarImageView;
23 | @property (nonatomic,strong) UICollectionView* shareCollectionView;
24 | @property (nonatomic,strong) UIButton* commentButton;
25 | @property (nonatomic,strong) LZAlbumLikesCommentsView* likesCommentsView;
26 | @end
27 | static NSString* photoCollectionViewIdentifier=@"photoCell";
28 | @implementation AsyncRichTextView
29 |
30 | /*
31 | // Only override drawRect: if you perform custom drawing.
32 | // An empty implementation adversely affects performance during animation.
33 | - (void)drawRect:(CGRect)rect {
34 | // Drawing code
35 | }
36 | */
37 | - (instancetype)initWithFrame:(CGRect)frame Album:(LZAlbum *)album;
38 | {
39 | if (self = [super initWithFrame:frame]) {
40 | _album = album;
41 | NSString *text = album.albumShareContent;
42 | [self drawViews];
43 | [self setupImage];
44 | }
45 | return self;
46 | }
47 |
48 | -(LZAlbumLikesCommentsView*)likesCommentsView{
49 | if(_likesCommentsView==nil){
50 | _likesCommentsView=[[LZAlbumLikesCommentsView alloc] initWithFrame:CGRectZero];
51 | _likesCommentsView.albumLikesCommentsViewDelegate=self;
52 | }
53 | _likesCommentsView.frame = CGRectMake(kLZAlbumAvatarSpacing+kLZAlbumAvatarImageSize+kLZAlbumAvatarSpacing,kLZAlbumAvatarSpacing+kLZAlbumUsernameHeight + _album.contentHeight + _album.collectionHeight + 2*kLZAlbumContentLineSpacing*4, [LZAlbum contentWidth], self.album.commentsHeight);
54 | _likesCommentsView.album = self.album;
55 | return _likesCommentsView;
56 | }
57 | -(UIButton*)commentButton{
58 | if(_commentButton==nil){
59 | _commentButton=[[UIButton alloc] initWithFrame:CGRectZero];
60 | [_commentButton setBackgroundImage:[UIImage imageNamed:@"AlbumOperateMore"] forState:UIControlStateNormal];
61 | [_commentButton setBackgroundImage:[UIImage imageNamed:@"AlbumOperateMoreHL"] forState:UIControlStateHighlighted];
62 | [_commentButton addTarget:self action:@selector(didCommentButtonClick:) forControlEvents:UIControlEventTouchUpInside];
63 | }
64 | _commentButton.frame = CGRectMake(kLZAlbumAvatarSpacing+kLZAlbumAvatarImageSize+kLZAlbumAvatarSpacing + [LZAlbum contentWidth]-kLZAlbumCommentButtonWidth, CGRectGetMaxY(_shareCollectionView.frame)+kLZAlbumContentLineSpacing, kLZAlbumCommentButtonWidth, kLZAlbumCommentButtonHeight);
65 | return _commentButton;
66 | }
67 |
68 | -(UICollectionView*)shareCollectionView{
69 | if(_shareCollectionView==nil){
70 | _shareCollectionView=[[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:[[LZAlbumCollectionFlowLayout alloc] init]];
71 | _shareCollectionView.backgroundColor=[UIColor clearColor];
72 | [_shareCollectionView registerClass:[LZAlbumPhotoCollectionViewCell class] forCellWithReuseIdentifier:photoCollectionViewIdentifier];
73 | _shareCollectionView.delegate=self;
74 | _shareCollectionView.dataSource=self;
75 | }
76 | _shareCollectionView.frame=CGRectMake(kLZAlbumAvatarSpacing+kLZAlbumAvatarImageSize+kLZAlbumAvatarSpacing,kLZAlbumAvatarSpacing + kLZAlbumUsernameHeight + _album.contentHeight + kLZAlbumContentLineSpacing, kLZAlbumPhotoSize*3+2*kLZAlbumPhotoInset, _album.collectionHeight);
77 | return _shareCollectionView;
78 | }
79 |
80 | -(UIImageView*)avatarImageView{
81 | if(_avatarImageView==nil){
82 | _avatarImageView=[[UIImageView alloc] initWithFrame:CGRectMake(kLZAlbumAvatarSpacing,kLZAlbumAvatarSpacing, kLZAlbumAvatarImageSize, kLZAlbumAvatarImageSize)];
83 | }
84 | return _avatarImageView;
85 | }
86 |
87 | - (void)setupImage
88 | {
89 | [self.avatarImageView sd_setImageWithURL:[NSURL URLWithString:_album.avatarUrl]];
90 | }
91 |
92 | - (void)drawViews
93 | {
94 | [self addSubview:self.avatarImageView];
95 | [self addSubview:self.shareCollectionView];
96 | [self addSubview:self.commentButton];
97 | [self addSubview:self.likesCommentsView];
98 | }
99 |
100 | - (BOOL)drawInRect:(CGRect)rect Context:(CGContextRef)context
101 | {
102 | if (_album == nil) {
103 | return YES;
104 | }
105 | if (_album.username == nil) {
106 | _album.username = @"no name";
107 | }
108 | // sleep(2);
109 | //名字一般只有一行
110 | NSMutableAttributedString *nameAttributed = [[NSMutableAttributedString alloc]initWithString:_album.username];
111 | [nameAttributed addAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kLZAlbumFontSize],NSForegroundColorAttributeName:RGB(52, 164, 254)} range:NSMakeRange(0, nameAttributed.string.length)];
112 | [nameAttributed drawInRect:CGRectMake(kLZAlbumAvatarSpacing+kLZAlbumAvatarImageSize+kLZAlbumAvatarSpacing,kLZAlbumAvatarSpacing,[LZAlbum contentWidth] , kLZAlbumUsernameHeight)];
113 |
114 | //时间只有一行
115 | NSMutableAttributedString *timeAttributed = [[NSMutableAttributedString alloc]initWithString:_album.albumShareTimestamp.timeAgoSinceNow];
116 | [timeAttributed addAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12],NSForegroundColorAttributeName:RGB(180, 196, 210)} range:NSMakeRange(0, timeAttributed.string.length)];
117 | [timeAttributed drawInRect:CGRectMake(kLZAlbumAvatarSpacing+kLZAlbumAvatarImageSize+kLZAlbumAvatarSpacing,kLZAlbumAvatarSpacing+kLZAlbumUsernameHeight + _album.contentHeight + _album.collectionHeight + 2*kLZAlbumContentLineSpacing,[LZAlbum contentWidth] , kLZAlbumUsernameHeight)];
118 |
119 | NSMutableAttributedString *nameAttributed2 = [[NSMutableAttributedString alloc]initWithString:_album.albumShareContent];
120 | [nameAttributed2 addAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kLZAlbumFontSize],NSForegroundColorAttributeName:RGB(52, 164, 254)} range:NSMakeRange(0, _album.albumShareContent.length)];
121 | // [nameAttributed2 drawInRect:CGRectMake(kLZAlbumAvatarSpacing+kLZAlbumAvatarImageSize+kLZAlbumAvatarSpacing, kLZAlbumAvatarSpacing + kLZAlbumUsernameHeight , [LZAlbum contentWidth], _album.contentHeight)];
122 | //矩阵变换
123 | CGContextSetTextMatrix(context, CGAffineTransformIdentity);
124 |
125 |
126 | CGContextScaleCTM(context, 1.0, -1.0);
127 | CGContextTranslateCTM(context, 0, -rect.size.height);
128 |
129 |
130 | //正文,图文混排,短链等。需要图文混排,部分文字需要可点击等功能,因此用coretext
131 | NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:_album.albumShareContent];
132 | [attributedString addAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kLZAlbumFontSize],NSForegroundColorAttributeName:[UIColor blackColor]} range:NSMakeRange(0, _album.albumShareContent.length)];
133 |
134 |
135 | CTFramesetterRef ctFramesetter = CTFramesetterCreateWithAttributedString((CFMutableAttributedStringRef)attributedString);
136 | CGMutablePathRef path = CGPathCreateMutable();
137 | CGRect bounds = CGRectMake(kLZAlbumAvatarSpacing+kLZAlbumAvatarImageSize+kLZAlbumAvatarSpacing, kLZAlbumAvatarSpacing + kLZAlbumUsernameHeight + kLZAlbumContentLineSpacing , [LZAlbum contentWidth], rect.size.height);
138 |
139 | CGPathAddRect(path, NULL, [self changeRect:bounds ParentRect:rect]);
140 |
141 | CTFrameRef kFrameRef = CTFramesetterCreateFrame(ctFramesetter,CFRangeMake(0, 0), path, NULL);
142 | CTFrameDraw(kFrameRef, context);
143 |
144 | CFRelease(path);
145 | CFRelease(ctFramesetter);
146 | return YES;
147 | }
148 |
149 | - (CGRect)changeRect:(CGRect)rect ParentRect:(CGRect)pRect;
150 | {
151 | CGRect newRect = rect;
152 | newRect.origin.y = pRect.size.height - rect.size.height - rect.origin.y;
153 | return newRect;
154 | }
155 |
156 | #pragma mark - collection view
157 |
158 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
159 | return _album.albumSharePhotos.count;
160 | }
161 |
162 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
163 | LZAlbumPhotoCollectionViewCell* photoCell=[collectionView dequeueReusableCellWithReuseIdentifier:photoCollectionViewIdentifier forIndexPath:indexPath];
164 | if(photoCell==nil){
165 | photoCell=[[LZAlbumPhotoCollectionViewCell alloc] initWithFrame:CGRectMake(0, 0, kLZAlbumPhotoSize, kLZAlbumPhotoSize)];
166 | }
167 | LZPhoto *photo = self.album.albumSharePhotos[indexPath.row];
168 | [photoCell.photoImageView sd_setImageWithURL:[NSURL URLWithString:photo.actualThumbnailUrl]];
169 | photoCell.indexPath=indexPath;
170 | return photoCell;
171 | }
172 |
173 | -(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
174 | // self.selectedIndexPath = indexPath;
175 |
176 | LZAlbumPhotoCollectionViewCell* photoCell=(LZAlbumPhotoCollectionViewCell*)[self.shareCollectionView cellForItemAtIndexPath:indexPath];
177 |
178 | NSArray* visibleCells=self.shareCollectionView.visibleCells;
179 | NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"indexPath" ascending:YES];
180 | visibleCells = [visibleCells sortedArrayUsingDescriptors:[NSArray arrayWithObject:sort]];
181 |
182 | NSMutableArray* imageViews=[NSMutableArray array];
183 | [visibleCells enumerateObjectsUsingBlock:^(LZAlbumPhotoCollectionViewCell* cell, NSUInteger idx, BOOL *stop) {
184 | [imageViews addObject:cell.photoImageView];
185 | }];
186 | XHImageViewer* imageViewer=[[XHImageViewer alloc] init];
187 | imageViewer.delegate = self;
188 | [imageViewer showWithImageViews:imageViews selectedView:photoCell.photoImageView];
189 | }
190 |
191 | #pragma mark - XHImageViewerDelegate
192 |
193 | - (void)imageViewer:(XHImageViewer *)imageViewer didShowImageView:(UIImageView *)selectedView atIndex:(NSInteger)index {
194 | LZPhoto *photo = self.album.albumSharePhotos[index];
195 | // [self.imageLoadingIndicator startAnimating];
196 | [selectedView sd_setImageWithURL:[NSURL URLWithString:photo.originUrl] placeholderImage:selectedView.image completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
197 | // [self.imageLoadingIndicator stopAnimating];
198 | }];
199 | }
200 |
201 | - (void)imageViewer:(XHImageViewer *)imageViewer willDismissWithSelectedView:(UIImageView *)selectedView {
202 | // [self.imageLoadingIndicator stopAnimating];
203 | }
204 |
205 | #pragma mark - action
206 |
207 | -(void)didCommentButtonClick:(UIButton*)sender{
208 | if([_richTextViewDelegate respondsToSelector:@selector(didCommentButtonClick:)]){
209 | [_richTextViewDelegate didCommentButtonClick:sender];
210 | }
211 | }
212 |
213 | -(void)didSelectCommentAtIndexPath:(NSIndexPath *)indexPath{
214 | if([_richTextViewDelegate respondsToSelector:@selector(didSelectCommentAtIndexPath:)]){
215 | [_richTextViewDelegate didSelectCommentAtIndexPath:indexPath];
216 | }
217 | }
218 |
219 | @end
220 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/AsyncView.h:
--------------------------------------------------------------------------------
1 | //
2 | // AsyncView.h
3 | // LearnObjective-C
4 | //
5 | // Created by donghuan1 on 16/10/28.
6 | // Copyright © 2016年 Dwight. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AsyncView : UIView
12 | // 用于异步绘制的队列,为nil时将使用GCD的global queue进行绘制,默认为nil
13 | @property (nonatomic, assign) dispatch_queue_t dispatchDrawQueue;
14 |
15 | // 异步绘制时global queue的优先级,默认优先级为DEFAULT。在设置了drawQueue时此参数无效。
16 | @property (nonatomic, assign) dispatch_queue_priority_t dispatchPriority;
17 |
18 | - (BOOL)drawInRect:(CGRect)rect Context:(CGContextRef)context;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/AsyncView.m:
--------------------------------------------------------------------------------
1 | //
2 | // AsyncView.m
3 | // LearnObjective-C
4 | //
5 | // Created by donghuan1 on 16/10/28.
6 | // Copyright © 2016年 Dwight. All rights reserved.
7 | //
8 |
9 | #import "AsyncView.h"
10 |
11 | @implementation AsyncView
12 |
13 | - (instancetype)initWithFrame:(CGRect)frame
14 | {
15 | self = [super initWithFrame:frame];
16 | if (self) {
17 | self.dispatchPriority = DISPATCH_QUEUE_PRIORITY_DEFAULT;
18 | self.opaque = NO;
19 | self.layer.contentsScale = [[UIScreen mainScreen] scale];
20 | }
21 | return self;
22 | }
23 |
24 | - (void)didMoveToWindow
25 | {
26 | [super didMoveToWindow];
27 |
28 | if (!self.window)
29 | {
30 | // 没有 Window 说明View已经没有显示在界面上,此时应该终止绘制
31 |
32 | }
33 | else if (!self.layer.contents)
34 | {
35 | [self.layer setNeedsDisplay];
36 | }
37 | }
38 |
39 | - (dispatch_queue_t)drawQueue
40 | {
41 | if (self.dispatchDrawQueue)
42 | {
43 | return self.dispatchDrawQueue;
44 | }
45 |
46 | return dispatch_get_global_queue(self.dispatchPriority, 0);
47 | }
48 |
49 | - (void)displayLayer:(CALayer *)layer
50 | {
51 |
52 | dispatch_async([self drawQueue], ^{
53 | [self displayLayer:layer Rect:layer.frame];
54 | });
55 | }
56 |
57 | - (BOOL)drawInRect:(CGRect)rect Context:(CGContextRef)context
58 | {
59 | return YES;
60 | }
61 |
62 | - (void)displayLayer:(CALayer *)layer Rect:(CGRect)rect
63 | {
64 | CGContextRef context = NULL;
65 | UIGraphicsBeginImageContextWithOptions(layer.bounds.size, layer.isOpaque, layer.contentsScale);
66 | context = UIGraphicsGetCurrentContext();
67 | CGContextSaveGState(context);
68 |
69 | if (rect.origin.x || rect.origin.y)
70 | {
71 | CGContextTranslateCTM(context, rect.origin.x, -rect.origin.y);
72 | }
73 |
74 | if (self.backgroundColor &&
75 | self.backgroundColor != [UIColor clearColor])
76 | {
77 | CGContextSetFillColorWithColor(context, self.backgroundColor.CGColor);
78 | CGContextFillRect(context, rect);
79 | }
80 | [self drawInRect:rect Context:context];
81 | CGContextRestoreGState(context);
82 |
83 | if(true)//所有绘制完成
84 | {
85 | CGImageRef CGImage = context ? CGBitmapContextCreateImage(context) : nil;
86 |
87 | UIImage *image = CGImage ? [UIImage imageWithCGImage:CGImage] : nil;
88 |
89 | dispatch_async(dispatch_get_main_queue(), ^{
90 | layer.contents = (id)image.CGImage;
91 | });
92 | if (CGImage) {
93 | //不释放内存一下就爆
94 | CGImageRelease(CGImage);
95 | }
96 | }
97 | UIGraphicsEndImageContext();
98 |
99 | }
100 |
101 | //共用绘制方法
102 | //绘制文字
103 |
104 |
105 |
106 | @end
107 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZAlbumCollectionFlowLayout.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbumCollectionFlowLayout.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/27.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface LZAlbumCollectionFlowLayout : UICollectionViewFlowLayout
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZAlbumCollectionFlowLayout.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbumCollectionFlowLayout.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/27.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZAlbumCollectionFlowLayout.h"
10 | #import "LZAlbum.h"
11 |
12 | @implementation LZAlbumCollectionFlowLayout
13 |
14 | - (instancetype)init
15 | {
16 | self = [super init];
17 | if (self) {
18 | self.itemSize=CGSizeMake(kLZAlbumPhotoSize, kLZAlbumPhotoSize);
19 | self.minimumInteritemSpacing=kLZAlbumPhotoInset;
20 | self.minimumLineSpacing=kLZAlbumPhotoInset;
21 | }
22 | return self;
23 | }
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZAlbumCommentTableViewCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // LZAlbumCommentTableViewCell.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/8/29.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "LZAlbum.h"
11 |
12 | @interface LZAlbumCommentTableViewCell : UITableViewCell
13 |
14 | +(CGFloat)calculateCellHeightWithAlbumComment:(LZAlbumComment*)albumComment fixWidth:(CGFloat)width;
15 |
16 | -(void)setupItem:(LZAlbumComment*)item atIndexPath:(NSIndexPath*)indexPath;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZAlbumCommentTableViewCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // LZAlbumCommentTableViewCell.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/8/29.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "LZAlbumCommentTableViewCell.h"
11 |
12 | @interface LZAlbumCommentTableViewCell()
13 |
14 | @property (nonatomic,strong) LZAlbumComment* albumComment;
15 | @property (nonatomic,strong) TTTAttributedLabel* commentLabel;
16 |
17 | @end
18 |
19 | @implementation LZAlbumCommentTableViewCell
20 |
21 | - (void)awakeFromNib {
22 | }
23 |
24 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
25 | [super setSelected:selected animated:animated];
26 | }
27 |
28 | +(NSString*)textOfAlbumComment:(LZAlbumComment*)albumComment{
29 | if(albumComment==nil){
30 | return @"";
31 | }
32 | return [NSString stringWithFormat:@"%@ : %@",albumComment.fromUsername,albumComment.commentContent];
33 | }
34 |
35 | +(CGFloat)calculateCellHeightWithAlbumComment:(LZAlbumComment*)albumComment fixWidth:(CGFloat)width{
36 | if(albumComment==nil){
37 | return 0;
38 | }
39 | NSString* text=[albumComment fullCommentText];
40 | TTTAttributedLabel *mockLabel = [[TTTAttributedLabel alloc] initWithFrame:CGRectMake(0, 0, [LZAlbum contentWidth], CGFLOAT_MAX)];
41 | [[self class] customCommentLabel:mockLabel];
42 | mockLabel.text = text;
43 | [mockLabel sizeToFit];
44 | CGFloat height = mockLabel.frame.size.height;
45 | return height;
46 | }
47 |
48 | -(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
49 | self=[super initWithStyle:style reuseIdentifier:reuseIdentifier];
50 | if(self){
51 | self.backgroundColor=[UIColor clearColor];
52 | self.contentView.backgroundColor=[UIColor clearColor];
53 | self.selectionStyle = UITableViewCellSelectionStyleDefault;
54 | [self.contentView addSubview:self.commentLabel];
55 | }
56 | return self;
57 | }
58 |
59 | -(void)layoutSubviews{
60 | [super layoutSubviews];
61 | CGRect commentFrame=self.commentLabel.frame;
62 | commentFrame.size.height=[[self class] calculateCellHeightWithAlbumComment:_albumComment fixWidth:[LZAlbum contentWidth]];
63 | self.commentLabel.frame=commentFrame;
64 | }
65 |
66 | -(void)setupItem:(LZAlbumComment*)item atIndexPath:(NSIndexPath*)indexPath {
67 | _albumComment=item;
68 | NSRange fromUsernameRange = item.fromUsernameRange;
69 | NSRange toUsernameRange = item.toUsernameRange;
70 | NSString *fullCommentText = item.fullCommentText;
71 | if (fullCommentText.length > 0) {
72 | NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:fullCommentText];
73 | [attributedText setAttributes:@{NSForegroundColorAttributeName:[UIColor blueColor]} range:fromUsernameRange];
74 | [attributedText setAttributes:@{NSForegroundColorAttributeName:[UIColor blueColor]} range:toUsernameRange];
75 | [self.commentLabel setText:attributedText afterInheritingLabelAttributesAndConfiguringWithBlock:^NSMutableAttributedString *(NSMutableAttributedString *mutableAttributedString) {
76 | return mutableAttributedString;
77 | }];
78 | if (fromUsernameRange.location != NSNotFound) {
79 | [self.commentLabel addLinkToURL:[NSURL URLWithString:item.fromUsername] withRange:fromUsernameRange];
80 | }
81 | if (toUsernameRange.location != NSNotFound) {
82 | [self.commentLabel addLinkToURL:[NSURL URLWithString:item.toUsername] withRange:toUsernameRange];
83 | }
84 | } else {
85 | self.commentLabel.text = nil;
86 | }
87 | }
88 |
89 | -(TTTAttributedLabel *)commentLabel{
90 | if(_commentLabel==nil){
91 | _commentLabel=[[TTTAttributedLabel alloc] initWithFrame:CGRectMake(0, 0, [LZAlbum contentWidth], 10)];
92 | _commentLabel.textColor = [UIColor darkGrayColor];
93 | _commentLabel.linkAttributes = @{(id)NSUnderlineStyleAttributeName:@(NO), (id)kCTForegroundColorAttributeName:(id)LZLinkTextForegroundColor.CGColor};
94 | _commentLabel.activeLinkAttributes = @{(id)kTTTBackgroundFillColorAttributeName:(id)LZLinkTextHighlightColor.CGColor};
95 | _commentLabel.delegate = self;
96 | [[self class] customCommentLabel:_commentLabel];
97 | }
98 | return _commentLabel;
99 | }
100 |
101 | + (void)customCommentLabel:(TTTAttributedLabel *)label {
102 | label.font=[UIFont systemFontOfSize:kLZAlbumFontSize];
103 | label.numberOfLines = 0;
104 | label.lineBreakMode = NSLineBreakByWordWrapping;
105 | }
106 |
107 | - (void)attributedLabel:(TTTAttributedLabel *)label
108 | didSelectLinkWithURL:(NSURL *)url {
109 | DLog(@"%@ clicked", url.absoluteString);
110 | }
111 |
112 | - (void)prepareForReuse {
113 | [super prepareForReuse];
114 | self.commentLabel.text = nil;
115 | }
116 |
117 | @end
118 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZAlbumLikesCommentsView.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbumLikesCommentsView.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/28.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "LZAlbum.h"
11 | #import "AsyncView.h"
12 |
13 | static CGFloat kLZAlbumCommentCellUsernameWidth=22;
14 | static CGFloat kLZAlbumCommentIconHeight = 16;
15 |
16 | @protocol MCAlbumLikesCommentsViewDelegate
17 |
18 | -(void)didSelectCommentAtIndexPath:(NSIndexPath*)indexPath;
19 |
20 | @end
21 |
22 | @interface LZAlbumLikesCommentsView : AsyncView
23 |
24 | @property (nonatomic,strong) id albumLikesCommentsViewDelegate;
25 |
26 | @property (nonatomic, strong) LZAlbum *album;
27 |
28 | + (BOOL)shouldShowLikesCommentsViewWithAlbum:(LZAlbum *)album;
29 | + (CGFloat)caculateLikesCommentsViewHeightWithAlbum:(LZAlbum*)album;
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZAlbumLikesCommentsView.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbumLikesCommentsView.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/28.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZAlbumLikesCommentsView.h"
10 | #import "LZMacros.h"
11 | #import "LZAlbumCommentTableViewCell.h"
12 | #import
13 |
14 | static NSString* kLZAlbumCommentCellIndetifier=@"albumCommentCell";
15 |
16 | @interface LZAlbumLikesCommentsView ()
17 |
18 | @property (nonatomic,strong) UIView *likeContainerView;
19 | @property (nonatomic,strong) TTTAttributedLabel* likesLabel;
20 | @property (nonatomic,strong) UIImageView *likeIconView;
21 | @property (nonatomic,strong) UITableView *commentTableView;
22 |
23 | @end
24 |
25 | @implementation LZAlbumLikesCommentsView
26 |
27 | + (BOOL)shouldShowLikesViewWithAlbum:(LZAlbum *)album {
28 | return album.albumShareLikes.count > 0;
29 | }
30 |
31 | + (BOOL)shouldShowCommentsViewWithAlbum:(LZAlbum *)album {
32 | return album.albumShareComments.count > 0;
33 | }
34 |
35 | + (BOOL)shouldShowLikesCommentsViewWithAlbum:(LZAlbum *)album {
36 | return [self shouldShowLikesViewWithAlbum:album] | [self shouldShowCommentsViewWithAlbum:album];
37 | }
38 |
39 | + (CGFloat)caculateLikesViewHeightWithAlbum:(LZAlbum *)album {
40 | if (![self shouldShowLikesViewWithAlbum:album]) {
41 | return 0;
42 | }
43 | TTTAttributedLabel *mockLikesLabel = [[TTTAttributedLabel alloc] initWithFrame:CGRectMake(0, 0, [LZAlbum contentWidth] - kLZAlbumCommentIconHeight, CGFLOAT_MAX)];
44 | [[self class] customLikesLabel:mockLikesLabel];
45 | [[self class] reloadLikesWithAlbum:album likesLabel:mockLikesLabel];
46 | [mockLikesLabel sizeToFit];
47 | return CGRectGetHeight(mockLikesLabel.frame);
48 | }
49 |
50 | + (CGFloat)caculateCommentsViewHeightWithAlbum:(LZAlbum *)album {
51 | CGFloat fixWidth=[LZAlbum contentWidth];
52 | CGFloat commentsHeight=0;
53 | for(LZAlbumComment* albumComment in album.albumShareComments){
54 | commentsHeight+=[LZAlbumCommentTableViewCell calculateCellHeightWithAlbumComment:albumComment fixWidth:fixWidth];
55 | }
56 | return commentsHeight;
57 | }
58 |
59 | + (CGFloat)caculateLikesCommentsViewHeightWithAlbum:(LZAlbum*)album {
60 | CGFloat height=0;
61 | if ([self shouldShowLikesViewWithAlbum:album]) {
62 | height += [self caculateLikesViewHeightWithAlbum:album];
63 | }
64 | if([self shouldShowCommentsViewWithAlbum:album]){
65 | height += [self caculateCommentsViewHeightWithAlbum:album];
66 | }
67 | return height;
68 | }
69 |
70 | - (instancetype)initWithFrame:(CGRect)frame
71 | {
72 | self = [super initWithFrame:frame];
73 | if (self) {
74 | self.clipsToBounds=YES;
75 | self.backgroundColor=RGB(240, 245, 249);
76 | [self addSubview:self.likeContainerView];
77 | [self addSubview:self.commentTableView];
78 | }
79 | return self;
80 | }
81 |
82 | #pragma mark - Propertys
83 |
84 | -(UIImageView*)likeIconView{
85 | if(_likeIconView==nil){
86 | _likeIconView=[[UIImageView alloc] initWithFrame:CGRectMake(0, 2, kLZAlbumCommentIconHeight, kLZAlbumCommentIconHeight)];
87 | _likeIconView.image = [UIImage imageNamed:@"AlbumInformationLikeHL"];
88 | }
89 | return _likeIconView;
90 | }
91 |
92 | -(TTTAttributedLabel *)likesLabel{
93 | if(_likesLabel==nil){
94 | _likesLabel= [[TTTAttributedLabel alloc] initWithFrame:CGRectMake(CGRectGetMaxX(self.likeIconView.frame), 0, [LZAlbum contentWidth] - CGRectGetWidth(self.likeIconView.frame), CGFLOAT_MAX)];
95 | _likesLabel.linkAttributes = @{(id)NSUnderlineStyleAttributeName:@(NO), (id)kCTForegroundColorAttributeName:(id)LZLinkTextForegroundColor.CGColor};
96 | _likesLabel.activeLinkAttributes = @{(id)kTTTBackgroundFillColorAttributeName:(id)LZLinkTextHighlightColor.CGColor};
97 | _likesLabel.textColor = [UIColor darkGrayColor];
98 | _likesLabel.delegate = self;
99 | [[self class] customLikesLabel:_likesLabel];
100 | }
101 | return _likesLabel;
102 | }
103 |
104 | + (void)customLikesLabel:(TTTAttributedLabel *)likesLabel {
105 | likesLabel.font = [UIFont systemFontOfSize:kLZAlbumFontSize];
106 | likesLabel.numberOfLines = 0;
107 | likesLabel.lineBreakMode = NSLineBreakByWordWrapping;
108 | }
109 |
110 | -(UIView*)likeContainerView{
111 | if(_likeContainerView==nil){
112 | _likeContainerView=[[UIView alloc] initWithFrame:CGRectZero];
113 | _likeContainerView.autoresizesSubviews=YES;
114 | [_likeContainerView addSubview:self.likeIconView];
115 | [_likeContainerView addSubview:self.likesLabel];
116 | _likeContainerView.clipsToBounds = YES;
117 | }
118 | return _likeContainerView;
119 | }
120 |
121 | -(UITableView*)commentTableView{
122 | if(_commentTableView==nil){
123 | _commentTableView=[[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
124 | _commentTableView.separatorColor=[UIColor clearColor];
125 | _commentTableView.separatorStyle=UITableViewCellSeparatorStyleNone;
126 | [_commentTableView registerClass:[LZAlbumCommentTableViewCell class] forCellReuseIdentifier:kLZAlbumCommentCellIndetifier];
127 | _commentTableView.dataSource=self;
128 | _commentTableView.delegate=self;
129 | _commentTableView.scrollEnabled=NO;
130 | _commentTableView.autoresizingMask=UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
131 | _commentTableView.backgroundColor=[UIColor clearColor];
132 | }
133 | return _commentTableView;
134 | }
135 |
136 | #pragma mark -
137 |
138 | - (void)attributedLabel:(TTTAttributedLabel *)label
139 | didSelectLinkWithURL:(NSURL *)url {
140 | DLog();
141 | }
142 |
143 | - (void)setAlbum:(LZAlbum *)album {
144 | _album = album;
145 | [[self class] reloadLikesWithAlbum:album likesLabel:self.likesLabel];
146 | [self.commentTableView reloadData];
147 | [self setNeedsLayout];
148 | }
149 |
150 | + (void)reloadLikesWithAlbum:(LZAlbum *)album likesLabel:(TTTAttributedLabel *)likesLabel {
151 | NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] init];
152 | NSMutableArray *locations = [NSMutableArray array];
153 | for(int i=0;i0;
172 | BOOL shouldShowComment=self.album.albumShareComments.count>0;
173 |
174 | if(!shouldShowLike && !shouldShowComment){
175 | self.frame=CGRectZero;
176 | return;
177 | }
178 |
179 | CGFloat likesViewHeight = [[self class] caculateLikesViewHeightWithAlbum:self.album];
180 | CGRect likesLabelFrame = self.likesLabel.frame;
181 | likesLabelFrame.size.height = likesViewHeight;
182 | self.likesLabel.frame = likesLabelFrame;
183 |
184 | CGRect likeContainerFrame=self.likeContainerView.frame;
185 | likeContainerFrame.size=CGSizeMake(CGRectGetWidth(self.bounds), likesViewHeight);
186 | self.likeContainerView.frame=likeContainerFrame;
187 |
188 | CGRect commentTableFrame=self.commentTableView.frame;
189 | commentTableFrame.origin.y=CGRectGetMaxY(self.likeContainerView.frame);
190 | commentTableFrame.size.height = [[self class] caculateCommentsViewHeightWithAlbum:self.album];
191 | self.commentTableView.frame=commentTableFrame;
192 |
193 | // CGRect frame=self.frame;
194 | // frame.size.height= CGRectGetMaxY(self.commentTableView.frame);
195 | // self.frame=frame;
196 | }
197 |
198 | #pragma mark - UITablView DataSource
199 |
200 | -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
201 | return self.album.albumShareComments.count;
202 | }
203 |
204 | -(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
205 | LZAlbumCommentTableViewCell* commentCell=[tableView dequeueReusableCellWithIdentifier:kLZAlbumCommentCellIndetifier forIndexPath:indexPath];
206 | if(commentCell==nil){
207 | commentCell=[[LZAlbumCommentTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kLZAlbumCommentCellIndetifier];
208 | }
209 | LZAlbumComment* albumComment=self.album.albumShareComments[indexPath.row];
210 | [commentCell setupItem:albumComment atIndexPath:indexPath];
211 | return commentCell;
212 | }
213 |
214 | -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
215 | LZAlbumComment* albumComment=self.album.albumShareComments[indexPath.row];
216 | CGFloat cellHeight=[LZAlbumCommentTableViewCell calculateCellHeightWithAlbumComment:albumComment fixWidth:[LZAlbum contentWidth]];
217 | return cellHeight;
218 | }
219 |
220 | -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
221 | [tableView deselectRowAtIndexPath:indexPath animated:YES];
222 | if([self.albumLikesCommentsViewDelegate respondsToSelector:@selector(didSelectCommentAtIndexPath:)]){
223 | [self.albumLikesCommentsViewDelegate didSelectCommentAtIndexPath:indexPath];
224 | }
225 | }
226 |
227 | @end
228 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZAlbumOperationView.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbumOperationView.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/28.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | typedef enum : NSUInteger{
12 | MCAlbumOperationTypeLike=0,
13 | MCAlbumOperationTypeReply
14 | }MCAlbumOperationType;
15 |
16 | static CGFloat kLZAlbumOperationViewWidth=120;
17 | static CGFloat kLZAlbumOperationViewHeight=34;
18 |
19 | @class LZAlbumOperationView;
20 |
21 |
22 | @protocol MCAlbumOperationViewDelegate
23 |
24 | @optional
25 |
26 | -(void)albumOperationView:(LZAlbumOperationView*)albumOperationView didClickOfType:(MCAlbumOperationType)operationType;
27 |
28 | @end
29 |
30 | @interface LZAlbumOperationView : UIView
31 |
32 | @property (nonatomic,strong) id albumOperationViewDelegate;
33 |
34 | @property (nonatomic,assign) BOOL shouldShowed;
35 |
36 | +(instancetype)initialOperationView;
37 |
38 | -(void)showAtView:(UIView*)containerView rect:(CGRect)targetRect;
39 |
40 | -(void)dismiss;
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZAlbumOperationView.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbumOperationView.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/28.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZAlbumOperationView.h"
10 |
11 | @interface LZAlbumOperationView ()
12 |
13 | @property (nonatomic,strong) UIButton* likeButton;
14 | @property (nonatomic,strong) UIButton* replyButton;
15 | @property (nonatomic,assign) CGRect targetRect;
16 |
17 | @end
18 |
19 | @implementation LZAlbumOperationView
20 |
21 | +(instancetype)initialOperationView{
22 | LZAlbumOperationView* operationView=[[LZAlbumOperationView alloc] initWithFrame:CGRectZero];
23 | return operationView;
24 | }
25 |
26 | - (instancetype)initWithFrame:(CGRect)frame
27 | {
28 | self = [super initWithFrame:frame];
29 | if (self) {
30 | self.backgroundColor=[UIColor colorWithWhite:0.0 alpha:0.8];
31 | self.layer.masksToBounds=YES;
32 | self.layer.cornerRadius=5;
33 | [self addSubview:self.likeButton];
34 | [self addSubview:self.replyButton];
35 | }
36 | return self;
37 | }
38 |
39 | -(UIButton*)likeButton{
40 | if(_likeButton==nil){
41 | _likeButton=[[UIButton alloc] initWithFrame:CGRectMake(0, 0, kLZAlbumOperationViewWidth/2, kLZAlbumOperationViewHeight)];
42 | _likeButton.tag=MCAlbumOperationTypeLike;
43 | _likeButton.titleLabel.font=[UIFont systemFontOfSize:14];
44 | [_likeButton addTarget:self action:@selector(operationViewDidClick:) forControlEvents:UIControlEventTouchUpInside];
45 | }
46 | return _likeButton;
47 | }
48 |
49 | -(UIButton*)replyButton{
50 | if(_replyButton==nil){
51 | _replyButton=[[UIButton alloc] initWithFrame:CGRectMake(kLZAlbumOperationViewWidth/2, 0, kLZAlbumOperationViewWidth/2, kLZAlbumOperationViewHeight)];
52 | _replyButton.tag=MCAlbumOperationTypeReply;
53 | _replyButton.titleLabel.font=[UIFont systemFontOfSize:14];
54 | [_replyButton addTarget:self action:@selector(operationViewDidClick:) forControlEvents:UIControlEventTouchUpInside];
55 | }
56 | return _replyButton;
57 | }
58 |
59 | -(void)operationViewDidClick:(UIButton*)sender{
60 | if([_albumOperationViewDelegate respondsToSelector:@selector(albumOperationView:didClickOfType:)]){
61 | [_albumOperationViewDelegate albumOperationView:self didClickOfType:sender.tag];
62 | }
63 | }
64 |
65 | -(void)showAtView:(UIView*)containerView rect:(CGRect)targetRect{
66 | if(_shouldShowed){
67 | return;
68 | }
69 | _shouldShowed=YES;
70 | self.targetRect=targetRect;
71 | [containerView addSubview:self];
72 |
73 | self.frame=CGRectMake(targetRect.origin.x, targetRect.origin.y, 0, kLZAlbumOperationViewHeight);
74 |
75 | [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
76 | self.frame=CGRectMake(targetRect.origin.x-kLZAlbumOperationViewWidth, targetRect.origin.y, kLZAlbumOperationViewWidth, kLZAlbumOperationViewHeight);
77 | } completion:^(BOOL finished) {
78 | [_likeButton setTitle:@"赞" forState:UIControlStateNormal];
79 | [_replyButton setTitle:@"评论" forState:UIControlStateNormal];
80 | }];
81 | }
82 |
83 | -(void)dismiss{
84 | if(self.shouldShowed==NO){
85 | return;
86 | }
87 | self.shouldShowed=NO;
88 | [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
89 | self.frame=CGRectMake(_targetRect.origin.x, _targetRect.origin.y, 0, kLZAlbumOperationViewHeight);
90 | } completion:^(BOOL finished) {
91 | [_likeButton setTitle:nil forState:UIControlStateNormal];
92 | [_replyButton setTitle:nil forState:UIControlStateNormal];
93 | [self removeFromSuperview];
94 | }];
95 | }
96 |
97 | @end
98 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZAlbumPhotoCollectionViewCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbumPhotoCollectionViewCell.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/27.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface LZAlbumPhotoCollectionViewCell : UICollectionViewCell
12 |
13 | @property (nonatomic,strong) NSIndexPath* indexPath;
14 |
15 | @property (nonatomic,strong) UIImageView* photoImageView;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZAlbumPhotoCollectionViewCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbumPhotoCollectionViewCell.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/27.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZAlbumPhotoCollectionViewCell.h"
10 |
11 | @implementation LZAlbumPhotoCollectionViewCell
12 |
13 | -(UIImageView*)photoImageView{
14 | if(_photoImageView==nil){
15 | _photoImageView=[[UIImageView alloc] initWithFrame:self.bounds];
16 | _photoImageView.contentMode=UIViewContentModeScaleAspectFill;
17 | _photoImageView.layer.masksToBounds=YES;
18 | }
19 | return _photoImageView;
20 | }
21 |
22 | - (instancetype)initWithFrame:(CGRect)frame
23 | {
24 | self = [super initWithFrame:frame];
25 | if (self) {
26 | [self.contentView addSubview:self.photoImageView];
27 | }
28 | return self;
29 | }
30 |
31 | - (void)prepareForReuse {
32 | [super prepareForReuse];
33 | self.photoImageView.image = nil;
34 | self.indexPath = nil;
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZAlbumReplyView.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbumReplyView.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/30.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 | static CGFloat kLZAlbumReplyViewPadding=10;
11 | static CGFloat kLZAlbumReplyViewHeight=44;
12 |
13 | @class LZAlbumReplyView;
14 |
15 | @protocol MCAlbumReplyViewDelegate
16 |
17 | -(void)albumReplyView:(LZAlbumReplyView*)albumReplyView didReply:(NSString*)text;
18 |
19 | @end
20 |
21 | @interface LZAlbumReplyView : UIView
22 |
23 | @property (nonatomic,strong) id albumReplyViewDelegate;
24 |
25 | -(void)show;
26 |
27 | -(void)dismiss;
28 |
29 | -(void)finishReply;
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZAlbumReplyView.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbumReplyView.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/30.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZAlbumReplyView.h"
10 | #import "LZInputAccessoryView.h"
11 |
12 | @interface LZAlbumReplyView ()
13 |
14 | @property (nonatomic,strong) UITextField* textField;
15 |
16 | @property (nonatomic,strong) UITextField* inputTextField;
17 |
18 | @property (nonatomic,strong) LZInputAccessoryView* customInputAccessoryView;
19 |
20 | @end
21 |
22 | @implementation LZAlbumReplyView
23 |
24 | - (instancetype)initWithFrame:(CGRect)frame
25 | {
26 | self = [super initWithFrame:frame];
27 | if (self) {
28 | self.backgroundColor=[UIColor colorWithWhite:0.910 alpha:1.000];
29 | [self addSubview:self.textField];
30 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow) name:UIKeyboardDidShowNotification object:nil];
31 | }
32 | return self;
33 | }
34 |
35 | -(void)dealloc{
36 | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidShowNotification object:nil];
37 | }
38 |
39 | -(void)keyboardDidShow{
40 | [self becomeFirstResponderForInputTextField];
41 | }
42 |
43 | -(void)becomeFirstResponderForTextField{
44 | if([self.textField isFirstResponder]==NO){
45 | [self.textField becomeFirstResponder];
46 | }
47 | }
48 |
49 | -(void)becomeFirstResponderForInputTextField{
50 | if([self.inputTextField isFirstResponder]==NO){
51 | [self.inputTextField becomeFirstResponder];
52 | }
53 | }
54 |
55 | -(void)resignFirstResponderForTwoTextFields{
56 | if([self.inputTextField isFirstResponder]){
57 | [self.inputTextField resignFirstResponder];
58 | }
59 |
60 | if([self.textField isFirstResponder]){
61 | [self.textField resignFirstResponder];
62 | }
63 | CGRect frame = self.customInputAccessoryView.keyboardViewProxy.frame;
64 | CGFloat keyboardMaxH = CGRectGetHeight([UIScreen mainScreen].bounds);
65 | if (self.customInputAccessoryView.keyboardViewProxy != nil && frame.origin.y != keyboardMaxH) {
66 | frame.origin.y = keyboardMaxH;
67 | self.customInputAccessoryView.keyboardViewProxy.frame = frame;
68 | }
69 | }
70 |
71 | -(void)show{
72 | [self becomeFirstResponderForTextField];
73 | }
74 |
75 | -(void)dismiss{
76 | [self resignFirstResponderForTwoTextFields];
77 | }
78 |
79 | -(UITextField*)textField{
80 | if(_textField==nil){
81 | _textField=[[UITextField alloc] initWithFrame:CGRectZero];
82 | _textField.inputAccessoryView=self.customInputAccessoryView;
83 | _textField.returnKeyType=UIReturnKeySend;
84 | }
85 | return _textField;
86 | }
87 |
88 | -(UIView*)customInputAccessoryView{
89 | if(_customInputAccessoryView==nil){
90 | _customInputAccessoryView=[[LZInputAccessoryView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth([UIScreen mainScreen].bounds), 44)];
91 | _customInputAccessoryView.backgroundColor = [UIColor colorWithWhite:0.910 alpha:1.000];
92 | [_customInputAccessoryView addSubview:self.inputTextField];
93 | }
94 | return _customInputAccessoryView;
95 | }
96 |
97 | -(UITextField*)inputTextField{
98 | if(_inputTextField==nil){
99 | _inputTextField=[[UITextField alloc] initWithFrame:CGRectMake(kLZAlbumReplyViewPadding, kLZAlbumReplyViewPadding, CGRectGetWidth(_customInputAccessoryView.frame)-kLZAlbumReplyViewPadding*2, 44-kLZAlbumReplyViewPadding*2)];
100 | _inputTextField.delegate=self;
101 | _inputTextField.returnKeyType=UIReturnKeySend;
102 | _inputTextField.borderStyle=UITextBorderStyleRoundedRect;
103 | }
104 | return _inputTextField;
105 | }
106 |
107 | -(BOOL)textFieldShouldReturn:(UITextField *)textField{
108 | if(textField.text.length>0){
109 | if([_albumReplyViewDelegate respondsToSelector:@selector(albumReplyView:didReply:)]){
110 | [_albumReplyViewDelegate albumReplyView:self didReply:textField.text];
111 | }
112 | }
113 | return YES;
114 | }
115 |
116 | -(void)finishReply{
117 | [self resignFirstResponderForTwoTextFields];
118 | self.inputTextField.text=nil;
119 | }
120 |
121 | @end
122 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZAlbumRichTextView.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbumRichTextView.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/25.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "LZAlbum.h"
11 | #import "LZAlbumLikesCommentsView.h"
12 | #import "AsyncView.h"
13 |
14 | static const CGFloat kLZAlbumUsernameHeight=18.0f;
15 | static const CGFloat kLZAlbumContentLineSpacing=4.0f;
16 | static const CGFloat kLZAlbumCommentButtonWidth=25.0f;
17 | static const CGFloat kLZAlbumCommentButtonHeight=25.0f;
18 |
19 | @protocol LZAlbumRichTextViewDelegate
20 |
21 | -(void)didCommentButtonClick:(UIButton*)button;
22 |
23 | -(void)didSelectCommentAtIndexPath:(NSIndexPath*)indexPath;
24 |
25 | @end
26 |
27 | @interface LZAlbumRichTextView : UIView
28 |
29 | @property (nonatomic,strong) LZAlbum* album;
30 |
31 | @property (nonatomic,strong) id richTextViewDelegate;
32 |
33 | +(CGFloat)calculateRichTextHeightWithAlbum:(LZAlbum*)album;
34 |
35 | +(CGFloat)getLabelHeightWithText:(NSString*)text maxWidth:(CGFloat)maxWidth font:(NSFont*)font;
36 | +(CGFloat)getContentLabelHeightWithAlbum:(LZAlbum *)album;
37 | +(CGFloat)getPhotoCollectionViewHeightWithAlbum:(LZAlbum *)album;
38 | @end
39 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZAlbumRichTextView.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbumRichTextView.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/25.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZAlbumRichTextView.h"
10 | #import "LZAlbumCollectionFlowLayout.h"
11 | #import "LZAlbumPhotoCollectionViewCell.h"
12 | #import "LZAlbumLikesCommentsView.h"
13 | #import "LZAlbumCommentTableViewCell.h"
14 | #import "LZMacros.h"
15 | #import "XHImageViewer.h"
16 | #import
17 | #import
18 |
19 | @interface LZAlbumRichTextView()
20 |
21 | @property (nonatomic,strong) UIImageView* avatarImageView;
22 |
23 | @property (nonatomic,strong) UILabel* usernameLabel;
24 |
25 | @property (nonatomic,strong) UILabel* contentLabel;
26 |
27 | @property (nonatomic,strong) UICollectionView* shareCollectionView;
28 |
29 | @property (nonatomic,strong) UILabel* timestampLabel;
30 |
31 | @property (nonatomic,strong) UIButton* commentButton;
32 |
33 | @property (nonatomic,strong) LZAlbumLikesCommentsView* likesCommentsView;
34 |
35 | @property (nonatomic, strong) NSIndexPath *selectedIndexPath;
36 |
37 | @property (nonatomic, strong) UIActivityIndicatorView *imageLoadingIndicator;
38 |
39 | @end
40 |
41 | static NSString* photoCollectionViewIdentifier=@"photoCell";
42 |
43 | @implementation LZAlbumRichTextView
44 |
45 | +(NSFont*)contentFont{
46 | return [UIFont systemFontOfSize:kLZAlbumFontSize];
47 | }
48 |
49 | +(CGFloat)getLabelHeightWithText:(NSString*)text maxWidth:(CGFloat)maxWidth font:(NSFont*)font{
50 | return [text boundingRectWithSize:CGSizeMake(maxWidth,CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:font} context:nil].size.height;
51 | }
52 |
53 | +(CGFloat)getContentLabelHeightWithAlbum:(LZAlbum *)album{
54 | NSString *text = album.albumShareContent;
55 | if(text.length == 0){
56 | return 0;
57 | }
58 | return [self getLabelHeightWithText:text maxWidth:[LZAlbum contentWidth] font:[self contentFont]];
59 | }
60 |
61 | +(CGFloat)getPhotoCollectionViewHeightWithAlbum:(LZAlbum *)album{
62 | NSInteger photoCount = album.albumSharePhotos.count;
63 | if(photoCount==0){
64 | return 0;
65 | }
66 | NSInteger row=photoCount/3+(photoCount%3 ? 1:0);
67 | return row*kLZAlbumPhotoSize+(row-1)*kLZAlbumPhotoInset;
68 | }
69 |
70 | +(CGFloat)calculateRichTextHeightWithAlbum:(LZAlbum*)album {
71 | if(album==nil) {
72 | return 0;
73 | }
74 | CGFloat richTextHeight=kLZAlbumAvatarSpacing;
75 | richTextHeight += kLZAlbumUsernameHeight;
76 | if ([self shouldShowContentLabelWithAlbum:album]) {
77 | richTextHeight += kLZAlbumContentLineSpacing;
78 | richTextHeight += [[self class] getContentLabelHeightWithAlbum:album];
79 | }
80 | if ([self shouldShowPhotoCollectionViewWithAlbum:album]) {
81 | richTextHeight += kLZAlbumContentLineSpacing;
82 | richTextHeight += [[self class] getPhotoCollectionViewHeightWithAlbum:album];
83 | }
84 | richTextHeight+=kLZAlbumContentLineSpacing;
85 | richTextHeight+=kLZAlbumCommentButtonHeight;
86 | if([LZAlbumLikesCommentsView shouldShowLikesCommentsViewWithAlbum:album]) {
87 | richTextHeight += kLZAlbumContentLineSpacing;
88 | richTextHeight += [LZAlbumLikesCommentsView caculateLikesCommentsViewHeightWithAlbum:album];
89 | }
90 | richTextHeight+=kLZAlbumAvatarSpacing;
91 | return richTextHeight;
92 | }
93 |
94 | #pragma mark - should show
95 |
96 | + (BOOL)shouldShowContentLabelWithAlbum:(LZAlbum *)album {
97 | return album.albumShareContent.length > 0;
98 | }
99 |
100 | + (BOOL)shouldShowPhotoCollectionViewWithAlbum:(LZAlbum *)album {
101 | return album.albumSharePhotos.count > 0;
102 | }
103 |
104 | #pragma mark - View init
105 |
106 | -(UIImageView*)avatarImageView{
107 | if(_avatarImageView==nil){
108 | _avatarImageView=[[UIImageView alloc] initWithFrame:CGRectMake(kLZAlbumAvatarSpacing,kLZAlbumAvatarSpacing, kLZAlbumAvatarImageSize, kLZAlbumAvatarImageSize)];
109 | }
110 | return _avatarImageView;
111 | }
112 |
113 | -(UILabel*)usernameLabel{
114 | if(_usernameLabel==nil){
115 | _usernameLabel=[[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMaxX(_avatarImageView.frame)+kLZAlbumAvatarSpacing, kLZAlbumAvatarSpacing,[LZAlbum contentWidth] , kLZAlbumUsernameHeight)];
116 | _usernameLabel.backgroundColor=[UIColor clearColor];
117 | _usernameLabel.textColor=RGB(52, 164, 254);
118 | }
119 | return _usernameLabel;
120 | }
121 |
122 | -(UILabel*)contentLabel{
123 | if(!_contentLabel){
124 | _contentLabel=[[UILabel alloc] initWithFrame:CGRectZero];
125 | _contentLabel.font=[UIFont systemFontOfSize:kLZAlbumFontSize];
126 | _contentLabel.backgroundColor=[UIColor clearColor];
127 | _contentLabel.numberOfLines=0;
128 | }
129 | return _contentLabel;
130 | }
131 |
132 | -(UICollectionView*)shareCollectionView{
133 | if(_shareCollectionView==nil){
134 | _shareCollectionView=[[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:[[LZAlbumCollectionFlowLayout alloc] init]];
135 | _shareCollectionView.backgroundColor=[UIColor clearColor];
136 | [_shareCollectionView registerClass:[LZAlbumPhotoCollectionViewCell class] forCellWithReuseIdentifier:photoCollectionViewIdentifier];
137 | _shareCollectionView.delegate=self;
138 | _shareCollectionView.dataSource=self;
139 | }
140 | return _shareCollectionView;
141 | }
142 |
143 | -(UILabel*)timestampLabel{
144 | if(_timestampLabel==nil){
145 | _timestampLabel=[[UILabel alloc] initWithFrame:CGRectZero];
146 | _timestampLabel.font=[UIFont systemFontOfSize:12];
147 | _timestampLabel.textColor=RGB(180, 196, 210);
148 | }
149 | return _timestampLabel;
150 | }
151 |
152 | -(UIButton*)commentButton{
153 | if(_commentButton==nil){
154 | _commentButton=[[UIButton alloc] initWithFrame:CGRectZero];
155 | [_commentButton setBackgroundImage:[UIImage imageNamed:@"AlbumOperateMore"] forState:UIControlStateNormal];
156 | [_commentButton setBackgroundImage:[UIImage imageNamed:@"AlbumOperateMoreHL"] forState:UIControlStateHighlighted];
157 | [_commentButton addTarget:self action:@selector(didCommentButtonClick:) forControlEvents:UIControlEventTouchUpInside];
158 | }
159 | return _commentButton;
160 | }
161 |
162 | -(LZAlbumLikesCommentsView*)likesCommentsView{
163 | if(_likesCommentsView==nil){
164 | _likesCommentsView=[[LZAlbumLikesCommentsView alloc] initWithFrame:CGRectZero];
165 | _likesCommentsView.albumLikesCommentsViewDelegate=self;
166 | }
167 | return _likesCommentsView;
168 | }
169 |
170 | - (UIActivityIndicatorView *)imageLoadingIndicator {
171 | if (_imageLoadingIndicator == nil) {
172 | _imageLoadingIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
173 | _imageLoadingIndicator.center = self.window.center;
174 | _imageLoadingIndicator.hidesWhenStopped = YES;
175 | _imageLoadingIndicator.hidden = NO;
176 | [self.window addSubview:_imageLoadingIndicator];
177 | }
178 | [self.window bringSubviewToFront:_imageLoadingIndicator];
179 | return _imageLoadingIndicator;
180 | }
181 |
182 | -(void)setAlbum:(LZAlbum *)album{
183 | _album=album;
184 | self.usernameLabel.text=_album.username;
185 | self.contentLabel.text=album.albumShareContent;
186 | [self.avatarImageView sd_setImageWithURL:[NSURL URLWithString:album.avatarUrl]];
187 | [self.shareCollectionView reloadData];
188 | self.timestampLabel.text=_album.albumShareTimestamp.timeAgoSinceNow;
189 |
190 | self.likesCommentsView.album = album;
191 |
192 | [self setNeedsLayout];
193 | }
194 |
195 | -(void)setup{
196 | [self addSubview:self.avatarImageView];
197 | [self addSubview:self.usernameLabel];
198 | [self addSubview:self.contentLabel];
199 | [self addSubview:self.shareCollectionView];
200 | [self addSubview:self.timestampLabel];
201 | [self addSubview:self.commentButton];
202 | [self addSubview:self.likesCommentsView];
203 | }
204 |
205 | - (instancetype)initWithFrame:(CGRect)frame
206 | {
207 | self = [super initWithFrame:frame];
208 | if (self) {
209 | [self setup];
210 | }
211 | return self;
212 | }
213 |
214 | - (void)resetSubviewRects
215 | {
216 |
217 | }
218 |
219 | -(void)layoutSubviews{
220 | [super layoutSubviews];
221 |
222 | CGFloat contentLabelY = CGRectGetMaxY(_usernameLabel.frame);
223 | if ([[self class] shouldShowContentLabelWithAlbum:self.album]) {
224 | contentLabelY += kLZAlbumContentLineSpacing;
225 | }
226 | CGRect contentFrame = CGRectMake(CGRectGetMinX(_usernameLabel.frame), contentLabelY, CGRectGetWidth(_usernameLabel.frame), [[self class] getContentLabelHeightWithAlbum:_album]);
227 | _contentLabel.frame=contentFrame;
228 |
229 | CGFloat shareCollectionViewY = CGRectGetMaxY(_contentLabel.frame);
230 | if ([[self class] shouldShowPhotoCollectionViewWithAlbum:self.album]) {
231 | shareCollectionViewY += kLZAlbumContentLineSpacing;
232 | }
233 | _shareCollectionView.frame=CGRectMake(CGRectGetMinX(_usernameLabel.frame),shareCollectionViewY, kLZAlbumPhotoSize*3+2*kLZAlbumPhotoInset, [[self class] getPhotoCollectionViewHeightWithAlbum:self.album]);
234 |
235 | _commentButton.frame=CGRectMake(CGRectGetMaxX(_contentLabel.frame)-kLZAlbumCommentButtonWidth, CGRectGetMaxY(_shareCollectionView.frame)+kLZAlbumContentLineSpacing, kLZAlbumCommentButtonWidth, kLZAlbumCommentButtonHeight);
236 |
237 | _timestampLabel.frame=CGRectMake(CGRectGetMinX(_contentLabel.frame), CGRectGetMinY(_commentButton.frame), CGRectGetWidth(_contentLabel.frame)-kLZAlbumCommentButtonWidth, CGRectGetHeight(_commentButton.frame));
238 |
239 | CGFloat likesCommentsViewY = CGRectGetMaxY(_timestampLabel.frame);
240 | if ([LZAlbumLikesCommentsView shouldShowLikesCommentsViewWithAlbum:self.album]) {
241 | likesCommentsViewY += kLZAlbumContentLineSpacing;
242 | }
243 | _likesCommentsView.frame=CGRectMake(CGRectGetMinX(_timestampLabel.frame), likesCommentsViewY , CGRectGetWidth(_contentLabel.frame), [LZAlbumLikesCommentsView caculateLikesCommentsViewHeightWithAlbum:_album]);
244 |
245 | CGRect frame=self.frame;
246 | frame.size.height = CGRectGetMaxY(_likesCommentsView.frame) + kLZAlbumAvatarSpacing;
247 | self.frame=frame;
248 | }
249 |
250 | #pragma mark - collection view
251 |
252 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
253 | return _album.albumSharePhotos.count;
254 | }
255 |
256 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
257 | LZAlbumPhotoCollectionViewCell* photoCell=[collectionView dequeueReusableCellWithReuseIdentifier:photoCollectionViewIdentifier forIndexPath:indexPath];
258 | if(photoCell==nil){
259 | photoCell=[[LZAlbumPhotoCollectionViewCell alloc] initWithFrame:CGRectMake(0, 0, kLZAlbumPhotoSize, kLZAlbumPhotoSize)];
260 | }
261 | LZPhoto *photo = self.album.albumSharePhotos[indexPath.row];
262 | [photoCell.photoImageView sd_setImageWithURL:[NSURL URLWithString:photo.actualThumbnailUrl]];
263 | photoCell.indexPath=indexPath;
264 | return photoCell;
265 | }
266 |
267 | -(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
268 | self.selectedIndexPath = indexPath;
269 |
270 | LZAlbumPhotoCollectionViewCell* photoCell=(LZAlbumPhotoCollectionViewCell*)[self.shareCollectionView cellForItemAtIndexPath:indexPath];
271 |
272 | NSArray* visibleCells=self.shareCollectionView.visibleCells;
273 | NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"indexPath" ascending:YES];
274 | visibleCells = [visibleCells sortedArrayUsingDescriptors:[NSArray arrayWithObject:sort]];
275 |
276 | NSMutableArray* imageViews=[NSMutableArray array];
277 | [visibleCells enumerateObjectsUsingBlock:^(LZAlbumPhotoCollectionViewCell* cell, NSUInteger idx, BOOL *stop) {
278 | [imageViews addObject:cell.photoImageView];
279 | }];
280 | XHImageViewer* imageViewer=[[XHImageViewer alloc] init];
281 | imageViewer.delegate = self;
282 | [imageViewer showWithImageViews:imageViews selectedView:photoCell.photoImageView];
283 | }
284 |
285 | #pragma mark - XHImageViewerDelegate
286 |
287 | - (void)imageViewer:(XHImageViewer *)imageViewer didShowImageView:(UIImageView *)selectedView atIndex:(NSInteger)index {
288 | LZPhoto *photo = self.album.albumSharePhotos[index];
289 | [self.imageLoadingIndicator startAnimating];
290 | [selectedView sd_setImageWithURL:[NSURL URLWithString:photo.originUrl] placeholderImage:selectedView.image completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
291 | [self.imageLoadingIndicator stopAnimating];
292 | }];
293 | }
294 |
295 | - (void)imageViewer:(XHImageViewer *)imageViewer willDismissWithSelectedView:(UIImageView *)selectedView {
296 | [self.imageLoadingIndicator stopAnimating];
297 | }
298 |
299 | #pragma mark - action
300 |
301 | -(void)didCommentButtonClick:(UIButton*)sender{
302 | if([_richTextViewDelegate respondsToSelector:@selector(didCommentButtonClick:)]){
303 | [_richTextViewDelegate didCommentButtonClick:sender];
304 | }
305 | }
306 |
307 | -(void)didSelectCommentAtIndexPath:(NSIndexPath *)indexPath{
308 | if([_richTextViewDelegate respondsToSelector:@selector(didSelectCommentAtIndexPath:)]){
309 | [_richTextViewDelegate didSelectCommentAtIndexPath:indexPath];
310 | }
311 | }
312 |
313 | @end
314 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZAlbumTableViewCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbumTableViewCell.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/25.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "LZAlbum.h"
11 | #import "LZAlbumRichTextView.h"
12 | @protocol LZAlbumTableViewCellDelegate
13 |
14 | @optional
15 |
16 | -(void)didCommentButtonClick:(UIButton*)button indexPath:(NSIndexPath*)indexPath;
17 |
18 | -(void)didSelectCommentAtCellIndexPath:(NSIndexPath*)cellIndexPath commentIndexPath:(NSIndexPath*)commentIndexPath;
19 |
20 | @end
21 |
22 | @interface LZAlbumTableViewCell : UITableViewCell
23 |
24 | @property (nonatomic,strong) LZAlbum* currentAlbum;
25 |
26 | @property (nonatomic,strong) NSIndexPath* indexPath;
27 |
28 | @property (nonatomic,strong) id albumTableViewCellDelegate;
29 | @property (nonatomic,strong) LZAlbumRichTextView* albumRichTextView;
30 | +(CGFloat)calculateCellHeightWithAlbum:(LZAlbum*)album;
31 |
32 | @end
33 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZAlbumTableViewCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // MCAlbumTableViewCell.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/3/25.
6 | // Copyright (c) 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZAlbumTableViewCell.h"
10 |
11 |
12 | @interface LZAlbumTableViewCell ()
13 |
14 |
15 |
16 | @end
17 |
18 | @implementation LZAlbumTableViewCell
19 |
20 | +(CGFloat)calculateCellHeightWithAlbum:(LZAlbum*)album{
21 | return [LZAlbumRichTextView calculateRichTextHeightWithAlbum:album];
22 | }
23 |
24 | - (void)awakeFromNib {
25 | // Initialization code
26 | }
27 |
28 | -(LZAlbumRichTextView*)albumRichTextView{
29 | if(_albumRichTextView==nil){
30 | _albumRichTextView=[[LZAlbumRichTextView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth([[UIScreen mainScreen] bounds]), 40)];
31 | _albumRichTextView.richTextViewDelegate=self;
32 | }
33 | _albumRichTextView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
34 | return _albumRichTextView;
35 | }
36 |
37 | -(void)setCurrentAlbum:(LZAlbum *)currentAlbum{
38 | _currentAlbum=currentAlbum;
39 | _albumRichTextView.album=currentAlbum;
40 | }
41 |
42 | -(void)setup{
43 | self.selectionStyle=UITableViewCellSelectionStyleNone;
44 | [self.contentView addSubview:self.albumRichTextView];
45 | }
46 |
47 | -(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
48 | self=[super initWithStyle:style reuseIdentifier:reuseIdentifier];
49 | if(self){
50 | [self setup];
51 | }
52 | return self;
53 | }
54 |
55 | -(void)dealloc{
56 | _albumRichTextView=nil;
57 | }
58 |
59 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
60 | [super setSelected:selected animated:animated];
61 | // Configure the view for the selected state
62 | }
63 |
64 | -(void)didCommentButtonClick:(UIButton *)button{
65 | if([_albumTableViewCellDelegate respondsToSelector:@selector(didCommentButtonClick:indexPath:)]){
66 | [_albumTableViewCellDelegate didCommentButtonClick:button indexPath:self.indexPath];
67 | }
68 | }
69 |
70 | -(void)didSelectCommentAtIndexPath:(NSIndexPath *)indexPath{
71 | if([_albumTableViewCellDelegate respondsToSelector:@selector(didSelectCommentAtCellIndexPath:commentIndexPath:)]){
72 | [_albumTableViewCellDelegate didSelectCommentAtCellIndexPath:self.indexPath commentIndexPath:indexPath];
73 | }
74 | }
75 |
76 | - (void)prepareForReuse {
77 | [super prepareForReuse];
78 | self.albumRichTextView.album = nil;
79 | }
80 |
81 | @end
82 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZInputAccessoryView.h:
--------------------------------------------------------------------------------
1 | //
2 | // LZInputAccessoryView.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/10/1.
6 | // Copyright © 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface LZInputAccessoryView : UIView
12 |
13 | /* The system keyboard view used as reference. */
14 | @property (nonatomic, weak, readonly) UIView *keyboardViewProxy;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/LZInputAccessoryView.m:
--------------------------------------------------------------------------------
1 | //
2 | // LZInputAccessoryView.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/10/1.
6 | // Copyright © 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #define SLK_IS_IOS9_AND_HIGHER ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0)
10 |
11 | #import "LZInputAccessoryView.h"
12 |
13 | @implementation LZInputAccessoryView
14 |
15 |
16 | #pragma mark - Super Overrides
17 |
18 | - (void)willMoveToSuperview:(UIView *)newSuperview
19 | {
20 | if (newSuperview) {
21 | if (SLK_IS_IOS9_AND_HIGHER) {
22 |
23 | NSPredicate *windowPredicate = [NSPredicate predicateWithFormat:@"self isMemberOfClass: %@", NSClassFromString(@"UIRemoteKeyboardWindow")];
24 | UIWindow *keyboardWindow = [[[UIApplication sharedApplication].windows filteredArrayUsingPredicate:windowPredicate] firstObject];
25 |
26 | for (UIView *subview in keyboardWindow.subviews) {
27 | for (UIView *hostview in subview.subviews) {
28 | if ([hostview isMemberOfClass:NSClassFromString(@"UIInputSetHostView")]) {
29 | _keyboardViewProxy = hostview;
30 | break;
31 | }
32 | }
33 | }
34 | }
35 | else {
36 | _keyboardViewProxy = newSuperview;
37 | }
38 | }
39 | }
40 |
41 |
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/LZAlbum/ui/views/test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzwjava/LZAlbum/33838f42510be45cb9b32f903ee52e022aa33c8d/LZAlbum/ui/views/test.png
--------------------------------------------------------------------------------
/LZAlbum/vendor/PathCover/Resources/MenuBackground@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzwjava/LZAlbum/33838f42510be45cb9b32f903ee52e022aa33c8d/LZAlbum/vendor/PathCover/Resources/MenuBackground@2x.png
--------------------------------------------------------------------------------
/LZAlbum/vendor/PathCover/Resources/circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzwjava/LZAlbum/33838f42510be45cb9b32f903ee52e022aa33c8d/LZAlbum/vendor/PathCover/Resources/circle.png
--------------------------------------------------------------------------------
/LZAlbum/vendor/PathCover/Resources/circle@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzwjava/LZAlbum/33838f42510be45cb9b32f903ee52e022aa33c8d/LZAlbum/vendor/PathCover/Resources/circle@2x.png
--------------------------------------------------------------------------------
/LZAlbum/vendor/PathCover/Resources/meicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzwjava/LZAlbum/33838f42510be45cb9b32f903ee52e022aa33c8d/LZAlbum/vendor/PathCover/Resources/meicon.png
--------------------------------------------------------------------------------
/LZAlbum/vendor/PathCover/Resources/pullrefresh.aif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lzwjava/LZAlbum/33838f42510be45cb9b32f903ee52e022aa33c8d/LZAlbum/vendor/PathCover/Resources/pullrefresh.aif
--------------------------------------------------------------------------------
/LZAlbum/vendor/PathCover/XHPathCover.h:
--------------------------------------------------------------------------------
1 | //
2 | // XHPathConver.h
3 | // XHPathCover
4 | //
5 | // Created by 曾 宪华 on 14-2-7.
6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | // user info key for Dictionary
12 | extern NSString *const XHUserNameKey;
13 | extern NSString *const XHBirthdayKey;
14 |
15 | @interface XHPathCover : UIView
16 |
17 | // parallax background
18 | @property (nonatomic, strong) UIImageView *bannerImageView;
19 | @property (nonatomic, strong) UIImageView *bannerImageViewWithImageEffects;
20 |
21 | // user info
22 | @property (nonatomic, strong) UIButton *avatarButton;
23 | @property (nonatomic, strong) UILabel *userNameLabel;
24 | @property (nonatomic, strong) UILabel *birthdayLabel;
25 |
26 |
27 | //scrollView call back
28 | @property (nonatomic) BOOL touching;
29 | @property (nonatomic) CGFloat offsetY;
30 |
31 | // parallax background origin Y for parallaxHeight
32 | @property (nonatomic, assign) CGFloat parallaxHeight; // default is 170, this height was not self heigth.
33 |
34 | @property (nonatomic, assign) BOOL isZoomingEffect; // default is NO, if isZoomingEffect is YES, will be dissmiss parallax effect
35 | @property (nonatomic, assign) BOOL isLightEffect; // default is YES
36 | @property (nonatomic, assign) CGFloat lightEffectPadding; // default is 80
37 | @property (nonatomic, assign) CGFloat lightEffectAlpha; // default is 1.12 (between 1 - 2)
38 |
39 | @property (nonatomic, copy) void(^handleRefreshEvent)(void);
40 |
41 | @property (nonatomic, copy) void(^handleTapBackgroundImageEvent)(void);
42 |
43 | // stop Refresh
44 | - (void)stopRefresh;
45 |
46 | // background image
47 | - (void)setBackgroundImage:(UIImage *)backgroundImage;
48 | // custom set url for subClass, There is not work
49 | - (void)setBackgroundImageUrlString:(NSString *)backgroundImageUrlString;
50 |
51 | // avatar image
52 | - (void)setAvatarImage:(UIImage *)avatarImage;
53 | // custom set url for subClass, There is not work
54 | - (void)setAvatarUrlString:(NSString *)avatarUrlString;
55 |
56 | // set info, Example : NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:@"Jack", @"userName", @"1990-10-19", @"birthday", nil];
57 | - (void)setInfo:(NSDictionary *)info;
58 |
59 | - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
60 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView;
61 | - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
62 | - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
63 | @end
64 |
--------------------------------------------------------------------------------
/LZAlbum/vendor/PathCover/XHPathCover.m:
--------------------------------------------------------------------------------
1 | //
2 | // XHPathConver.m
3 | // XHPathCover
4 | //
5 | // Created by 曾 宪华 on 14-2-7.
6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved.
7 | //
8 |
9 | #import "XHPathCover.h"
10 | #import "XHWaterDropRefresh.h"
11 |
12 | NSString *const XHUserNameKey = @"XHUserName";
13 | NSString *const XHBirthdayKey = @"XHBirthday";
14 |
15 | #import
16 | #import
17 |
18 | @interface UIImage (ImageEffects)
19 | - (UIImage *)applyLightEffect;
20 | @end
21 |
22 | @implementation UIImage (ImageEffects)
23 |
24 | - (UIImage *)applyLightEffect {
25 | UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3];
26 | return [self applyBlurWithRadius:30 tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
27 | }
28 |
29 | - (UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage {
30 | // Check pre-conditions.
31 | if (self.size.width < 1 || self.size.height < 1) {
32 | NSLog (@"*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self);
33 | return nil;
34 | }
35 | if (!self.CGImage) {
36 | NSLog (@"*** error: image must be backed by a CGImage: %@", self);
37 | return nil;
38 | }
39 | if (maskImage && !maskImage.CGImage) {
40 | NSLog (@"*** error: maskImage must be backed by a CGImage: %@", maskImage);
41 | return nil;
42 | }
43 |
44 | CGRect imageRect = { CGPointZero, self.size };
45 | UIImage *effectImage = self;
46 |
47 | BOOL hasBlur = blurRadius > __FLT_EPSILON__;
48 | BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__;
49 | if (hasBlur || hasSaturationChange) {
50 | UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
51 | CGContextRef effectInContext = UIGraphicsGetCurrentContext();
52 | CGContextScaleCTM(effectInContext, 1.0, -1.0);
53 | CGContextTranslateCTM(effectInContext, 0, -self.size.height);
54 | CGContextDrawImage(effectInContext, imageRect, self.CGImage);
55 |
56 | vImage_Buffer effectInBuffer;
57 |
58 |
59 | effectInBuffer.data = CGBitmapContextGetData(effectInContext);
60 | effectInBuffer.width = CGBitmapContextGetWidth(effectInContext);
61 | effectInBuffer.height = CGBitmapContextGetHeight(effectInContext);
62 | effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext);
63 |
64 | UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
65 | CGContextRef effectOutContext = UIGraphicsGetCurrentContext();
66 | vImage_Buffer effectOutBuffer;
67 | effectOutBuffer.data = CGBitmapContextGetData(effectOutContext);
68 | effectOutBuffer.width = CGBitmapContextGetWidth(effectOutContext);
69 | effectOutBuffer.height = CGBitmapContextGetHeight(effectOutContext);
70 | effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext);
71 |
72 | if (hasBlur) {
73 | // A description of how to compute the box kernel width from the Gaussian
74 | // radius (aka standard deviation) appears in the SVG spec:
75 | // http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement
76 | //
77 | // For larger values of 's' (s >= 2.0), an approximation can be used: Three
78 | // successive box-blurs build a piece-wise quadratic convolution kernel, which
79 | // approximates the Gaussian kernel to within roughly 3%.
80 | //
81 | // let d = floor(s * 3*sqrt(2*pi)/4 + 0.5)
82 | //
83 | // ... if d is odd, use three box-blurs of size 'd', centered on the output pixel.
84 | //
85 | CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale];
86 | NSUInteger radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5);
87 | if (radius % 2 != 1) {
88 | radius += 1; // force radius to be odd so that the three box-blur methodology works.
89 | }
90 | vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, (unsigned int)radius, (unsigned int)radius, 0, kvImageEdgeExtend);
91 | vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, (unsigned int)radius, (unsigned int)radius, 0, kvImageEdgeExtend);
92 | vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, (unsigned int)radius, (unsigned int)radius, 0, kvImageEdgeExtend);
93 | }
94 | BOOL effectImageBuffersAreSwapped = NO;
95 | if (hasSaturationChange) {
96 | CGFloat s = saturationDeltaFactor;
97 | CGFloat floatingPointSaturationMatrix[] = {
98 | 0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0,
99 | 0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0,
100 | 0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0,
101 | 0, 0, 0, 1,
102 | };
103 | const int32_t divisor = 256;
104 | NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]);
105 | int16_t saturationMatrix[matrixSize];
106 | for (NSUInteger i = 0; i < matrixSize; ++i) {
107 | saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor);
108 | }
109 | if (hasBlur) {
110 | vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags);
111 | effectImageBuffersAreSwapped = YES;
112 | }
113 | else {
114 | vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags);
115 | }
116 | }
117 | if (!effectImageBuffersAreSwapped)
118 | effectImage = UIGraphicsGetImageFromCurrentImageContext();
119 | UIGraphicsEndImageContext();
120 |
121 | if (effectImageBuffersAreSwapped)
122 | effectImage = UIGraphicsGetImageFromCurrentImageContext();
123 | UIGraphicsEndImageContext();
124 | }
125 |
126 | // Set up output context.
127 | UIGraphicsBeginImageContextWithOptions(self.size, NO, [[UIScreen mainScreen] scale]);
128 | CGContextRef outputContext = UIGraphicsGetCurrentContext();
129 | CGContextScaleCTM(outputContext, 1.0, -1.0);
130 | CGContextTranslateCTM(outputContext, 0, -self.size.height);
131 |
132 | // Draw base image.
133 | CGContextDrawImage(outputContext, imageRect, self.CGImage);
134 |
135 | // Draw effect image.
136 | if (hasBlur) {
137 | CGContextSaveGState(outputContext);
138 | if (maskImage) {
139 | CGContextClipToMask(outputContext, imageRect, maskImage.CGImage);
140 | }
141 | CGContextDrawImage(outputContext, imageRect, effectImage.CGImage);
142 | CGContextRestoreGState(outputContext);
143 | }
144 |
145 | // Add in color tint.
146 | if (tintColor) {
147 | CGContextSaveGState(outputContext);
148 | CGContextSetFillColorWithColor(outputContext, tintColor.CGColor);
149 | CGContextFillRect(outputContext, imageRect);
150 | CGContextRestoreGState(outputContext);
151 | }
152 |
153 | // Output image is ready.
154 | UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
155 | UIGraphicsEndImageContext();
156 |
157 | return outputImage;
158 | }
159 |
160 | @end
161 |
162 | @interface XHPathCover () {
163 | BOOL normal, paste, hasStop;
164 | BOOL isrefreshed;
165 | }
166 |
167 | @property (nonatomic, strong) UIView *bannerView;
168 |
169 | @property (nonatomic, strong) UIView *showView;
170 |
171 | @property (nonatomic, strong) XHWaterDropRefresh *waterDropRefresh;
172 |
173 | @property (nonatomic, assign) CGFloat showUserInfoViewOffsetHeight;
174 |
175 | @end
176 |
177 | @implementation XHPathCover
178 |
179 | #pragma mark - Publish Api
180 |
181 | - (void)stopRefresh {
182 | [_waterDropRefresh stopRefresh];
183 | if(_touching == NO) {
184 | [self resetTouch];
185 | } else {
186 | hasStop = YES;
187 | }
188 | }
189 |
190 | // background
191 | - (void)setBackgroundImage:(UIImage *)backgroundImage {
192 | if (backgroundImage) {
193 | _bannerImageView.image = backgroundImage;
194 | _bannerImageViewWithImageEffects.image = [backgroundImage applyLightEffect];
195 | }
196 | }
197 |
198 | - (void)setBackgroundImageUrlString:(NSString *)backgroundImageUrlString {
199 | if (backgroundImageUrlString) {
200 |
201 | }
202 | }
203 |
204 | // avatar
205 | - (void)setAvatarImage:(UIImage *)avatarImage {
206 | if (avatarImage) {
207 | [_avatarButton setImage:avatarImage forState:UIControlStateNormal];
208 | }
209 | }
210 |
211 | - (void)setAvatarUrlString:(NSString *)avatarUrlString {
212 | if (avatarUrlString) {
213 |
214 | }
215 | }
216 |
217 | // set info
218 | - (void)setInfo:(NSDictionary *)info {
219 | NSString *userName = [info valueForKey:XHUserNameKey];
220 | if (userName) {
221 | self.userNameLabel.text = userName;
222 | }
223 |
224 | NSString *birthday = [info valueForKey:XHBirthdayKey];
225 | if (birthday) {
226 | self.birthdayLabel.text = birthday;
227 | }
228 | }
229 |
230 | - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
231 | self.touching = YES;
232 | }
233 |
234 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
235 | self.offsetY = scrollView.contentOffset.y;
236 | }
237 |
238 | - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
239 | if(decelerate == NO) {
240 | self.touching = NO;
241 | }
242 | }
243 | - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
244 | self.touching = NO;
245 | }
246 |
247 | #pragma mark - Propertys
248 |
249 | - (void)setTouching:(BOOL)touching {
250 | if(touching) {
251 | if(hasStop) {
252 | [self resetTouch];
253 | }
254 |
255 | if(normal) {
256 | paste = YES;
257 | } else if (paste == NO && _waterDropRefresh.isRefreshing == NO) {
258 | normal = YES;
259 | }
260 | } else if(_waterDropRefresh.isRefreshing == NO) {
261 | [self resetTouch];
262 | }
263 | _touching = touching;
264 | }
265 |
266 | - (void)setOffsetY:(CGFloat)y {
267 | CGFloat fixAdaptorPadding = 0;
268 | if ([[[UIDevice currentDevice] systemVersion] integerValue] >= 7.0) {
269 | fixAdaptorPadding = 64;
270 | }
271 | y += fixAdaptorPadding;
272 | _offsetY = y;
273 | CGRect frame = _showView.frame;
274 | if(y < 0) {
275 | if((_waterDropRefresh.isRefreshing) || hasStop) {
276 | if(normal && paste == NO) {
277 | frame.origin.y = self.showUserInfoViewOffsetHeight + y;
278 | _showView.frame = frame;
279 | } else {
280 | if(frame.origin.y != self.showUserInfoViewOffsetHeight) {
281 | frame.origin.y = self.showUserInfoViewOffsetHeight;
282 | _showView.frame = frame;
283 | }
284 | }
285 | } else {
286 | frame.origin.y = self.showUserInfoViewOffsetHeight + y;
287 | _showView.frame = frame;
288 | }
289 | } else {
290 | if(normal && _touching && isrefreshed) {
291 | paste = YES;
292 | }
293 | if(frame.origin.y != self.showUserInfoViewOffsetHeight) {
294 | frame.origin.y = self.showUserInfoViewOffsetHeight;
295 | _showView.frame = frame;
296 | }
297 | }
298 | if (hasStop == NO) {
299 | _waterDropRefresh.currentOffset = y;
300 | }
301 |
302 | UIView *bannerSuper = _bannerImageView.superview;
303 | CGRect bframe = bannerSuper.frame;
304 | if(y < 0) {
305 | bframe.origin.y = y;
306 | bframe.size.height = -y + bannerSuper.superview.frame.size.height;
307 | bannerSuper.frame = bframe;
308 |
309 | CGPoint center = _bannerImageView.center;
310 | center.y = bannerSuper.frame.size.height / 2;
311 | _bannerImageView.center = center;
312 |
313 | if (self.isZoomingEffect) {
314 | _bannerImageView.center = center;
315 | CGFloat scale = fabsf(y) / self.parallaxHeight;
316 | _bannerImageView.transform = CGAffineTransformMakeScale(1+scale, 1+scale);
317 | }
318 | } else {
319 | if(bframe.origin.y != 0) {
320 | bframe.origin.y = 0;
321 | bframe.size.height = bannerSuper.superview.frame.size.height;
322 | bannerSuper.frame = bframe;
323 | }
324 | if(y < bframe.size.height) {
325 | CGPoint center = _bannerImageView.center;
326 | center.y = bannerSuper.frame.size.height/2 + 0.5 * y;
327 | _bannerImageView.center = center;
328 | }
329 | }
330 |
331 | if (self.isLightEffect) {
332 | if(y < 0 && y >= -self.lightEffectPadding) {
333 | float percent = (-y / (self.lightEffectPadding * self.lightEffectAlpha));
334 | self.bannerImageViewWithImageEffects.alpha = percent;
335 |
336 | } else if (y <= -self.lightEffectPadding) {
337 | self.bannerImageViewWithImageEffects.alpha = self.lightEffectPadding / (self.lightEffectPadding * self.lightEffectAlpha);
338 | } else if (y > self.lightEffectPadding) {
339 | self.bannerImageViewWithImageEffects.alpha = 0;
340 | }
341 | }
342 | }
343 |
344 | #pragma mark - Life cycle
345 |
346 | - (id)initWithFrame:(CGRect)frame {
347 | self = [super initWithFrame:frame];
348 | if (self) {
349 | // Initialization code
350 | [self _setup];
351 | }
352 | return self;
353 | }
354 |
355 | - (id)initWithCoder:(NSCoder *)aDecoder {
356 | self = [super initWithCoder:aDecoder];
357 | if(self)
358 | {
359 | [self _setup];
360 | }
361 | return self;
362 | }
363 |
364 | - (void)_setup {
365 | self.parallaxHeight = 170;
366 | self.isLightEffect = YES;
367 | self.lightEffectPadding = 80;
368 | self.lightEffectAlpha = 1.15;
369 |
370 | _bannerView = [[UIView alloc] initWithFrame:self.bounds];
371 | _bannerView.clipsToBounds = YES;
372 | UITapGestureRecognizer *tapGestureRecongnizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureRecongnizerHandle:)];
373 | [_bannerView addGestureRecognizer:tapGestureRecongnizer];
374 |
375 | _bannerImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, -self.parallaxHeight, CGRectGetWidth(_bannerView.frame), CGRectGetHeight(_bannerView.frame) + self.parallaxHeight * 2)];
376 | _bannerImageView.contentMode = UIViewContentModeScaleToFill;
377 | [_bannerView addSubview:self.bannerImageView];
378 |
379 | _bannerImageViewWithImageEffects = [[UIImageView alloc] initWithFrame:_bannerImageView.frame];
380 | _bannerImageViewWithImageEffects.alpha = 0.;
381 | [_bannerView addSubview:self.bannerImageViewWithImageEffects];
382 |
383 | [self addSubview:self.bannerView];
384 |
385 | CGFloat waterDropRefreshHeight = 100;
386 | CGFloat waterDropRefreshWidth = 20;
387 | _waterDropRefresh = [[XHWaterDropRefresh alloc] initWithFrame:CGRectMake(33, CGRectGetHeight(self.bounds) - waterDropRefreshHeight, waterDropRefreshWidth, waterDropRefreshHeight)];
388 | _waterDropRefresh.refreshCircleImage = [UIImage imageNamed:@"circle"];
389 | _waterDropRefresh.offsetHeight = 20; // 线条的长度
390 | [self addSubview:self.waterDropRefresh];
391 |
392 | CGFloat avatarButtonHeight = 66;
393 | self.showUserInfoViewOffsetHeight = CGRectGetHeight(self.frame) - waterDropRefreshHeight / 3 - avatarButtonHeight;
394 | _showView = [[UIView alloc] initWithFrame:CGRectMake(0, self.showUserInfoViewOffsetHeight, CGRectGetWidth(self.bounds), waterDropRefreshHeight)];
395 | _showView.backgroundColor = [UIColor clearColor];
396 |
397 | _avatarButton = [[UIButton alloc] initWithFrame:CGRectMake(15, 0, avatarButtonHeight, avatarButtonHeight)];
398 |
399 | _userNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(93, 0, 207, 34)];
400 | _userNameLabel.textColor = [UIColor whiteColor];
401 | _userNameLabel.backgroundColor = [UIColor clearColor];
402 | _userNameLabel.shadowColor = [UIColor blackColor];
403 | _userNameLabel.shadowOffset = CGSizeMake(0, 2);
404 | _userNameLabel.font = [UIFont boldSystemFontOfSize:28.0f];
405 |
406 |
407 | _birthdayLabel = [[UILabel alloc] initWithFrame:CGRectMake(93, 42, 207, 24)];
408 | _birthdayLabel.textColor = [UIColor whiteColor];
409 | _birthdayLabel.backgroundColor = [UIColor clearColor];
410 | _birthdayLabel.shadowColor = [UIColor blackColor];
411 | _birthdayLabel.shadowOffset = CGSizeMake(0, 2);
412 | _birthdayLabel.font = [UIFont systemFontOfSize:14.0f];
413 |
414 | [_showView addSubview:self.avatarButton];
415 | [_showView addSubview:self.userNameLabel];
416 | [_showView addSubview:self.birthdayLabel];
417 |
418 | [self addSubview:self.showView];
419 | }
420 |
421 | - (void)dealloc {
422 | self.bannerImageView = nil;
423 | self.bannerImageViewWithImageEffects = nil;
424 |
425 | self.avatarButton = nil;
426 | self.userNameLabel = nil;
427 | self.birthdayLabel = nil;
428 |
429 | self.bannerView = nil;
430 | self.showView = nil;
431 |
432 | self.waterDropRefresh = nil;
433 | }
434 |
435 | - (void)willMoveToSuperview:(UIView *)newSuperview {
436 | [super willMoveToSuperview:newSuperview];
437 | if(newSuperview) {
438 | [self initWaterView];
439 | }
440 | }
441 |
442 | - (void)initWaterView {
443 | __weak XHPathCover *wself =self;
444 | [_waterDropRefresh setHandleRefreshEvent:^{
445 | [wself setIsRefreshed:YES];
446 | if(wself.handleRefreshEvent) {
447 | wself.handleRefreshEvent();
448 | }
449 | }];
450 | }
451 |
452 | #pragma mark - previte method
453 |
454 | - (void)tapGestureRecongnizerHandle:(UITapGestureRecognizer *)tapGestureRecongnizer {
455 | if (self.handleTapBackgroundImageEvent) {
456 | self.handleTapBackgroundImageEvent();
457 | }
458 | }
459 |
460 | - (void)setIsRefreshed:(BOOL)b {
461 | isrefreshed = b;
462 | }
463 |
464 | - (void)refresh {
465 | if(_waterDropRefresh.isRefreshing) {
466 | [_waterDropRefresh startRefreshAnimation];
467 | }
468 | }
469 |
470 | - (void)resetTouch {
471 | normal = NO;
472 | paste = NO;
473 | hasStop = NO;
474 | isrefreshed = NO;
475 | }
476 |
477 | @end
478 |
--------------------------------------------------------------------------------
/LZAlbum/vendor/PathCover/XHSoundManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // XHSoundManager.h
3 | // XHPathCover
4 | //
5 | // Created by 曾 宪华 on 14-2-7.
6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface XHSoundManager : NSObject
12 |
13 | + (instancetype)sharedInstance;
14 |
15 | - (void)playRefreshSound;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/LZAlbum/vendor/PathCover/XHSoundManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // XHSoundManager.m
3 | // XHPathCover
4 | //
5 | // Created by 曾 宪华 on 14-2-7.
6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved.
7 | //
8 |
9 | #import "XHSoundManager.h"
10 | #import
11 |
12 | @interface XHSoundManager () {
13 | SystemSoundID refreshSound;
14 | }
15 |
16 | @end
17 |
18 | @implementation XHSoundManager
19 |
20 | + (instancetype)sharedInstance {
21 | static XHSoundManager *instance;
22 | static dispatch_once_t onceToken;
23 | dispatch_once(&onceToken, ^{
24 | instance = [[XHSoundManager alloc] init];
25 | });
26 | return instance;
27 | }
28 |
29 | - (id)init {
30 | self = [super init];
31 | if (self) {
32 | NSURL *url = [[NSBundle mainBundle] URLForResource:@"pullrefresh" withExtension:@"aif"];
33 | AudioServicesCreateSystemSoundID((__bridge CFURLRef)(url) , &refreshSound);
34 | }
35 | return self;
36 | }
37 |
38 | - (void)playRefreshSound {
39 | AudioServicesPlaySystemSound(refreshSound);
40 | }
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/LZAlbum/vendor/PathCover/XHWaterDropRefresh.h:
--------------------------------------------------------------------------------
1 | //
2 | // XHWaterDropRefresh.h
3 | // XHPathCover
4 | //
5 | // Created by 曾 宪华 on 14-2-7.
6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface XHWaterDropRefresh : UIView
12 |
13 | @property (nonatomic, assign) CGFloat radius; // default is 5.
14 | @property (nonatomic, assign) CGFloat maxOffset; // default is 70
15 | @property (nonatomic, assign) CGFloat deformationLength; // default is 0.4 (between 0.1 -- 0.9)
16 | @property (nonatomic, assign) CGFloat offsetHeight;
17 | @property (nonatomic, strong) UIImage *refreshCircleImage;
18 | @property (nonatomic, readonly) BOOL isRefreshing;
19 |
20 | - (void)stopRefresh;
21 | - (void)startRefreshAnimation;
22 |
23 | @property (nonatomic, copy) void(^handleRefreshEvent)(void) ;
24 | @property (nonatomic) float currentOffset;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/LZAlbum/vendor/PathCover/XHWaterDropRefresh.m:
--------------------------------------------------------------------------------
1 | //
2 | // XHWaterDropRefresh.m
3 | // XHPathCover
4 | //
5 | // Created by 曾 宪华 on 14-2-7.
6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved.
7 | //
8 |
9 | #import "XHWaterDropRefresh.h"
10 | #import "XHSoundManager.h"
11 |
12 | @interface XHWaterDropRefresh () {
13 | BOOL _isRefresh;
14 | }
15 |
16 | @property (nonatomic, strong) CAShapeLayer *shapeLayer;
17 | @property (nonatomic, strong) CAShapeLayer *lineLayer;
18 | @property (nonatomic, strong) UIImageView *refreshView;
19 |
20 |
21 | @property (nonatomic, strong) NSTimer *timer;
22 |
23 | @end
24 |
25 | @implementation XHWaterDropRefresh
26 |
27 | #pragma mark - Propertys
28 |
29 | - (BOOL)isRefreshing {
30 | return _isRefresh;
31 | }
32 |
33 |
34 | #pragma mark - Life cycle
35 |
36 | - (id)initWithFrame:(CGRect)frame
37 | {
38 | self = [super initWithFrame:frame];
39 | if (self) {
40 | // Initialization code
41 | [self _setup];
42 | }
43 | return self;
44 | }
45 |
46 | - (id)initWithCoder:(NSCoder *)aDecoder
47 | {
48 | self = [super initWithCoder:aDecoder];
49 | if(self)
50 | {
51 | [self _setup];
52 | }
53 | return self;
54 | }
55 |
56 | - (void)dealloc {
57 | self.refreshCircleImage = nil;
58 |
59 | self.shapeLayer = nil;
60 | self.lineLayer = nil;
61 | self.refreshView = nil;
62 | }
63 |
64 | - (void)_setup {
65 | self.deformationLength = 0.4;
66 | self.maxOffset = 70; // 改变最大拉断距离
67 | self.radius = 5.; // 改变圆圈的半径
68 | self.offsetHeight = 20; // 改变线条的长度
69 |
70 | CGRect frame = self.frame;
71 | frame.size = CGSizeMake(30, 100); //固定 30 * 100 为什么要固定本身的大小呢?
72 | self.frame = frame;
73 |
74 | _lineLayer = [CAShapeLayer layer];
75 | _lineLayer.fillColor = [UIColor colorWithRed:222./255. green:216./255. blue:211./255. alpha:0.5].CGColor;
76 | [self.layer addSublayer:_lineLayer];
77 |
78 |
79 | _shapeLayer = [CAShapeLayer layer];
80 | _shapeLayer.fillColor = [UIColor colorWithRed:222./255. green:216./255. blue:211./255. alpha:1].CGColor;
81 | _shapeLayer.strokeColor = [[UIColor whiteColor] CGColor];
82 | _shapeLayer.lineWidth = 2;
83 | [self.layer addSublayer:_shapeLayer];
84 |
85 | self.currentOffset = 0;
86 | }
87 |
88 | #pragma mark - Publish Api
89 |
90 | - (void)stopRefresh {
91 | _isRefresh = NO;
92 |
93 | CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"opacity"];
94 | anim.fromValue = @(1);
95 | anim.toValue = @(0);
96 | anim.duration = 0.2;
97 | anim.delegate = self;
98 | [_refreshView.layer addAnimation:anim forKey:nil];
99 | _refreshView.layer.opacity = 0;
100 |
101 |
102 | anim = [CABasicAnimation animationWithKeyPath:@"opacity"];
103 | anim.fromValue = @(0);
104 | anim.toValue = @(1);
105 | anim.beginTime = 0.2;
106 | anim.duration = 0.2;
107 | anim.delegate = self;
108 | [_shapeLayer addAnimation:anim forKey:nil];
109 | _shapeLayer.opacity = 0;
110 | }
111 |
112 |
113 | - (void)startRefreshAnimation {
114 | if(self.refreshView == nil) {
115 | _refreshView = [[UIImageView alloc] initWithImage:self.refreshCircleImage];
116 | CGRect refreshViewFrame = _refreshView.frame;
117 | refreshViewFrame.size = CGSizeMake(18, 18);
118 | [self addSubview:_refreshView];
119 | }
120 | _shapeLayer.opacity = 0;
121 |
122 | _refreshView.center = CGPointMake(15,self.frame.size.height - 20 - _radius);
123 | [_refreshView.layer removeAllAnimations];
124 | _refreshView.layer.opacity = 1;
125 |
126 | CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
127 | animation.duration = 1;
128 | animation.fromValue = @0;
129 | animation.toValue = @(M_PI*2);
130 | animation.repeatCount = INT_MAX;
131 |
132 | [_refreshView.layer addAnimation:animation forKey:@"rotation"];
133 | }
134 |
135 | #pragma mark - CGMutablePathRef Help Method
136 |
137 | - (CGMutablePathRef)createPathWithOffset:(float)currentOffset {
138 | CGMutablePathRef path = CGPathCreateMutable();
139 | float top = self.frame.size.height - 20 - _radius*2 - currentOffset;
140 | float wdiff = currentOffset * self.deformationLength; // 改变拉断之前,水滴的长度
141 |
142 | if(currentOffset == 0) {
143 | CGPathAddEllipseInRect(path, NULL, CGRectMake(15-_radius, top, _radius*2, _radius*2));
144 | } else {
145 | CGPathAddArc(path, NULL, 15, top+_radius, _radius, 0, M_PI, YES);
146 | float bottom = top + wdiff+_radius*2;
147 | if(currentOffset < 10) {
148 | CGPathAddCurveToPoint(path, NULL,15-_radius,bottom,15,bottom, 15,bottom);
149 | CGPathAddCurveToPoint(path, NULL, 15,bottom,15+_radius,bottom, 15+_radius, top+_radius);
150 | } else {
151 | CGPathAddCurveToPoint(path, NULL,15-_radius ,top +_radius, 15 - _radius ,bottom - _radius, 15, bottom);
152 | CGPathAddCurveToPoint(path,NULL, 15 + _radius, bottom - _radius, 15+_radius,top +_radius , 15+_radius, top+_radius);
153 | }
154 | }
155 | CGPathCloseSubpath(path);
156 |
157 | return path;
158 | }
159 |
160 | - (void)setCurrentOffset:(float)currentOffset {
161 | if(_isRefresh)
162 | return;
163 |
164 | [self privateSetCurrentOffset:currentOffset];
165 | }
166 |
167 | - (void)privateSetCurrentOffset:(float)currentOffset {
168 | currentOffset = currentOffset>0?0:currentOffset;
169 | currentOffset = -currentOffset;
170 | _currentOffset = currentOffset;
171 | if(currentOffset < _maxOffset) {
172 | float wdiff = currentOffset* 0.2;
173 | float top = self.frame.size.height - 20 - _radius*2 - currentOffset;
174 |
175 | CGMutablePathRef path = [self createPathWithOffset:currentOffset];
176 | _shapeLayer.path = path;
177 | CGPathRelease(path);
178 |
179 |
180 | CGMutablePathRef line = CGPathCreateMutable();
181 | float w = ((_maxOffset - currentOffset)/_maxOffset) + 1;
182 | CGPathAddRect(line, NULL, CGRectMake(15-w/2, top + wdiff + _radius*2,w, currentOffset-wdiff + self.offsetHeight)); // 最好的+20就是线条的长度
183 | _lineLayer.path = line;
184 |
185 | self.transform = CGAffineTransformMakeScale(0.8+0.2*(w-1), 1);
186 | } else {
187 | if(self.timer == nil)
188 | {
189 | _isRefresh = YES;
190 | self.transform = CGAffineTransformIdentity;
191 | self.timer = [NSTimer timerWithTimeInterval:0.02 target:self selector:@selector(resetWater) userInfo:nil repeats:YES];
192 | [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
193 | [_timer fire];
194 | }
195 | }
196 | }
197 |
198 | - (void)resetWater {
199 | [self privateSetCurrentOffset:-(_currentOffset-(_maxOffset/8))];
200 | if(_currentOffset == 0) {
201 | [self.timer invalidate];
202 | self.timer = nil;
203 |
204 | // play refresh stop sound
205 | [[XHSoundManager sharedInstance] playRefreshSound];
206 |
207 | if(self.handleRefreshEvent != nil) {
208 | self.handleRefreshEvent();
209 | }
210 | [self startRefreshAnimation];
211 | }
212 | }
213 |
214 |
215 | - (void)animationDidStop:(CABasicAnimation *)anim finished:(BOOL)flag {
216 | if(anim.beginTime > 0) {
217 | _shapeLayer.opacity = 1;
218 | } else {
219 | [_refreshView.layer removeAllAnimations];
220 | }
221 | }
222 |
223 | /*
224 | // Only override drawRect: if you perform custom drawing.
225 | // An empty implementation adversely affects performance during animation.
226 | - (void)drawRect:(CGRect)rect
227 | {
228 | // Drawing code
229 | }
230 | */
231 |
232 | @end
233 |
--------------------------------------------------------------------------------
/LZAlbum/vendor/XHImageViewer/XHImageViewer.h:
--------------------------------------------------------------------------------
1 | //
2 | // XHImageViewer.h
3 | // XHImageViewer
4 | //
5 | // Created by 曾 宪华 on 14-2-17.
6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved.
7 | //
8 |
9 | #import
10 | @class XHImageViewer;
11 | @protocol XHImageViewerDelegate
12 |
13 | @optional
14 |
15 | - (void)imageViewer:(XHImageViewer *)imageViewer didShowImageView:(UIImageView*)selectedView atIndex:(NSInteger)index;
16 | - (void)imageViewer:(XHImageViewer *)imageViewer willDismissWithSelectedView:(UIImageView*)selectedView;
17 |
18 | @end
19 |
20 | @interface XHImageViewer : UIView
21 |
22 | @property (nonatomic, weak) id delegate;
23 | @property (nonatomic, assign) CGFloat backgroundScale;
24 |
25 | - (void)showWithImageViews:(NSArray*)views selectedView:(UIImageView*)selectedView;
26 | @end
27 |
--------------------------------------------------------------------------------
/LZAlbum/vendor/XHImageViewer/XHImageViewer.m:
--------------------------------------------------------------------------------
1 | //
2 | // XHImageViewer.m
3 | // XHImageViewer
4 | //
5 | // Created by 曾 宪华 on 14-2-17.
6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved.
7 | //
8 |
9 | #import "XHImageViewer.h"
10 | #import "XHViewState.h"
11 | #import "XHZoomingImageView.h"
12 |
13 | @interface XHImageViewer ()
14 |
15 | @property (nonatomic, strong) UIScrollView *scrollView;
16 | @property (nonatomic, strong) NSArray *imgViews;
17 |
18 | @end
19 |
20 | @implementation XHImageViewer
21 |
22 | - (id)init {
23 | self = [self initWithFrame:CGRectZero];
24 | if (self) {
25 | [self _setup];
26 | }
27 | return self;
28 | }
29 |
30 | - (void)_setup {
31 | self.backgroundColor = [UIColor colorWithWhite:0.1 alpha:1];
32 | self.backgroundScale = 0.95;
33 |
34 | UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(didPan:)];
35 | pan.maximumNumberOfTouches = 1;
36 | [self addGestureRecognizer:pan];
37 | }
38 |
39 | - (id)initWithFrame:(CGRect)frame {
40 | self = [super initWithFrame:[[UIScreen mainScreen] bounds]];
41 | if (self) {
42 | [self _setup];
43 | }
44 | return self;
45 | }
46 |
47 | - (void)setImageViewsFromArray:(NSArray*)views {
48 | NSMutableArray *imgViews = [NSMutableArray array];
49 | for(id obj in views) {
50 | if([obj isKindOfClass:[UIImageView class]]) {
51 | [imgViews addObject:obj];
52 |
53 | UIImageView *view = obj;
54 |
55 | XHViewState *state = [XHViewState viewStateForView:view];
56 | [state setStateWithView:view];
57 |
58 | view.userInteractionEnabled = NO;
59 | }
60 | }
61 | _imgViews = [imgViews copy];
62 | }
63 |
64 | - (void)showWithImageViews:(NSArray*)views selectedView:(UIImageView*)selectedView {
65 | [self setImageViewsFromArray:views];
66 |
67 | if(_imgViews.count > 0) {
68 | if(![selectedView isKindOfClass:[UIImageView class]] || ![_imgViews containsObject:selectedView]){
69 | selectedView = _imgViews[0];
70 | }
71 | [self showWithSelectedView:selectedView];
72 | }
73 | }
74 |
75 | #pragma mark- Properties
76 |
77 | - (void)setBackgroundColor:(UIColor *)backgroundColor {
78 | [super setBackgroundColor:[backgroundColor colorWithAlphaComponent:0]];
79 | }
80 |
81 | - (NSInteger)pageIndex {
82 | return (_scrollView.contentOffset.x / _scrollView.frame.size.width + 0.5);
83 | }
84 |
85 | #pragma mark- View management
86 |
87 | - (UIImageView *)currentView {
88 | return [_imgViews objectAtIndex:self.pageIndex];
89 | }
90 |
91 | - (void)showWithSelectedView:(UIImageView *)selectedView {
92 |
93 | [self.scrollView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
94 |
95 | const NSInteger currentPage = [_imgViews indexOfObject:selectedView];
96 |
97 | UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
98 |
99 | if(_scrollView == nil) {
100 | _scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
101 | _scrollView.pagingEnabled = YES;
102 | _scrollView.showsHorizontalScrollIndicator = NO;
103 | _scrollView.showsVerticalScrollIndicator = NO;
104 | _scrollView.backgroundColor = [self.backgroundColor colorWithAlphaComponent:1];
105 | _scrollView.alpha = 0;
106 | _scrollView.delegate = self;
107 | }
108 |
109 | [self addSubview:_scrollView];
110 | [window addSubview:self];
111 |
112 | const CGFloat fullW = window.frame.size.width;
113 | const CGFloat fullH = window.frame.size.height;
114 |
115 | selectedView.frame = [window convertRect:selectedView.frame fromView:selectedView.superview];
116 | [window addSubview:selectedView];
117 |
118 | [UIView animateWithDuration:0.3
119 | animations:^{
120 | _scrollView.alpha = 1;
121 | window.rootViewController.view.transform = CGAffineTransformMakeScale(self.backgroundScale, self.backgroundScale);
122 |
123 | selectedView.transform = CGAffineTransformIdentity;
124 |
125 | CGSize size = (selectedView.image) ? selectedView.image.size : selectedView.frame.size;
126 | CGFloat ratio = MIN(fullW / size.width, fullH / size.height);
127 | CGFloat W = ratio * size.width;
128 | CGFloat H = ratio * size.height;
129 | selectedView.frame = CGRectMake((fullW-W)/2, (fullH-H)/2, W, H);
130 | }
131 | completion:^(BOOL finished) {
132 | _scrollView.contentSize = CGSizeMake(_imgViews.count * fullW, 0);
133 | _scrollView.contentOffset = CGPointMake(currentPage * fullW, 0);
134 |
135 | UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tappedScrollView:)];
136 | [_scrollView addGestureRecognizer:gesture];
137 |
138 | for(UIImageView *view in _imgViews){
139 | view.transform = CGAffineTransformIdentity;
140 |
141 | CGSize size = (view.image) ? view.image.size : view.frame.size;
142 | CGFloat ratio = MIN(fullW / size.width, fullH / size.height);
143 | CGFloat W = ratio * size.width;
144 | CGFloat H = ratio * size.height;
145 | view.frame = CGRectMake((fullW-W)/2, (fullH-H)/2, W, H);
146 |
147 | XHZoomingImageView *tmp = [[XHZoomingImageView alloc] initWithFrame:CGRectMake([_imgViews indexOfObject:view] * fullW, 0, fullW, fullH)];
148 | tmp.imageView = view;
149 |
150 | [_scrollView addSubview:tmp];
151 | }
152 | if ([self.delegate respondsToSelector:@selector(imageViewer:didShowImageView:atIndex:)]) {
153 | [self.delegate imageViewer:self didShowImageView:selectedView atIndex:currentPage];
154 | }
155 | }
156 | ];
157 | }
158 |
159 | - (void)prepareToDismiss {
160 | UIImageView *currentView = [self currentView];
161 |
162 | if([self.delegate respondsToSelector:@selector(imageViewer:willDismissWithSelectedView:)]) {
163 | [self.delegate imageViewer:self willDismissWithSelectedView:currentView];
164 | }
165 |
166 | for(UIImageView *view in _imgViews) {
167 | if(view != currentView) {
168 | XHViewState *state = [XHViewState viewStateForView:view];
169 | view.transform = CGAffineTransformIdentity;
170 | view.frame = state.frame;
171 | view.transform = state.transform;
172 | [state.superview addSubview:view];
173 | }
174 | }
175 | }
176 |
177 | - (void)dismissWithAnimate {
178 | UIView *currentView = [self currentView];
179 | UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
180 |
181 | CGRect rct = currentView.frame;
182 | currentView.transform = CGAffineTransformIdentity;
183 | currentView.frame = [window convertRect:rct fromView:currentView.superview];
184 | [window addSubview:currentView];
185 |
186 | [UIView animateWithDuration:0.3
187 | animations:^{
188 | _scrollView.alpha = 0;
189 | window.rootViewController.view.transform = CGAffineTransformIdentity;
190 |
191 | XHViewState *state = [XHViewState viewStateForView:currentView];
192 | currentView.frame = [window convertRect:state.frame fromView:state.superview];
193 | currentView.transform = state.transform;
194 | }
195 | completion:^(BOOL finished) {
196 | XHViewState *state = [XHViewState viewStateForView:currentView];
197 | currentView.transform = CGAffineTransformIdentity;
198 | currentView.frame = state.frame;
199 | currentView.transform = state.transform;
200 | [state.superview addSubview:currentView];
201 |
202 | for (UIView *view in _imgViews) {
203 | XHViewState *_state = [XHViewState viewStateForView:view];
204 | view.userInteractionEnabled = _state.userInteratctionEnabled;
205 | }
206 |
207 | [self removeFromSuperview];
208 | }
209 | ];
210 | }
211 |
212 | #pragma mark - UIScrollViewDelegate
213 |
214 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
215 | static NSInteger previousPage = 0;
216 | NSInteger page = [self pageIndex];
217 | if (previousPage != page) {
218 | if ([self.delegate respondsToSelector:@selector(imageViewer:didShowImageView:atIndex:)]) {
219 | [self.delegate imageViewer:self didShowImageView:[self currentView] atIndex:page];
220 | }
221 | previousPage = page;
222 | }
223 | }
224 |
225 | #pragma mark- Gesture events
226 |
227 | - (void)tappedScrollView:(UITapGestureRecognizer *)sender {
228 | [self prepareToDismiss];
229 | [self dismissWithAnimate];
230 | }
231 |
232 | - (void)didPan:(UIPanGestureRecognizer *)sender {
233 | static UIImageView *currentView = nil;
234 |
235 | if(sender.state == UIGestureRecognizerStateBegan) {
236 | currentView = [self currentView];
237 |
238 | UIView *targetView = currentView.superview;
239 | while(![targetView isKindOfClass:[XHZoomingImageView class]]) {
240 | targetView = targetView.superview;
241 | }
242 |
243 | if (((XHZoomingImageView *)targetView).isViewing) {
244 | currentView = nil;
245 | } else {
246 | UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
247 | currentView.frame = [window convertRect:currentView.frame fromView:currentView.superview];
248 | [window addSubview:currentView];
249 |
250 | [self prepareToDismiss];
251 | }
252 | }
253 |
254 | if(currentView) {
255 | if(sender.state == UIGestureRecognizerStateEnded) {
256 | if(_scrollView.alpha>0.5) {
257 | [self showWithSelectedView:currentView];
258 | } else {
259 | [self dismissWithAnimate];
260 | }
261 | currentView = nil;
262 | } else {
263 | CGPoint p = [sender translationInView:self];
264 |
265 | CGAffineTransform transform = CGAffineTransformMakeTranslation(0, p.y);
266 | transform = CGAffineTransformScale(transform, 1 - fabs(p.y)/1000, 1 - fabs(p.y)/1000);
267 | currentView.transform = transform;
268 |
269 | CGFloat r = 1-fabs(p.y)/200;
270 | _scrollView.alpha = MAX(0, MIN(1, r));
271 | }
272 | }
273 | }
274 |
275 | @end
276 |
--------------------------------------------------------------------------------
/LZAlbum/vendor/XHImageViewer/XHViewState.h:
--------------------------------------------------------------------------------
1 | //
2 | // XHViewState.h
3 | // XHImageViewer
4 | //
5 | // Created by 曾 宪华 on 14-2-17.
6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface XHViewState : UIView
12 |
13 | @property (nonatomic, strong) UIView *superview;
14 | @property (nonatomic, assign) CGRect frame;
15 | @property (nonatomic, assign) BOOL userInteratctionEnabled;
16 | @property (nonatomic, assign) CGAffineTransform transform;
17 |
18 | + (XHViewState *)viewStateForView:(UIView *)view;
19 | - (void)setStateWithView:(UIView *)view;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/LZAlbum/vendor/XHImageViewer/XHViewState.m:
--------------------------------------------------------------------------------
1 | //
2 | // XHViewState.m
3 | // XHImageViewer
4 | //
5 | // Created by 曾 宪华 on 14-2-17.
6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved.
7 | //
8 |
9 | #import "XHViewState.h"
10 |
11 | @implementation XHViewState
12 |
13 | + (XHViewState *)viewStateForView:(UIView *)view {
14 | static NSMutableDictionary *dict = nil;
15 | if(dict == nil) {
16 | dict = [NSMutableDictionary dictionary];
17 | }
18 |
19 | XHViewState *state = dict[@(view.hash)];
20 | if(state == nil) {
21 | state = [[self alloc] init];
22 | dict[@(view.hash)] = state;
23 | }
24 | return state;
25 | }
26 |
27 | - (void)setStateWithView:(UIView *)view {
28 | CGAffineTransform trans = view.transform;
29 | view.transform = CGAffineTransformIdentity;
30 |
31 | self.superview = view.superview;
32 | self.frame = view.frame;
33 | self.transform = trans;
34 | self.userInteratctionEnabled = view.userInteractionEnabled;
35 |
36 | view.transform = trans;
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/LZAlbum/vendor/XHImageViewer/XHZoomingImageView.h:
--------------------------------------------------------------------------------
1 | //
2 | // XHZoomingImageView.h
3 | // XHImageViewer
4 | //
5 | // Created by 曾 宪华 on 14-2-17.
6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface XHZoomingImageView : UIView
12 |
13 | @property (nonatomic, readonly) UIScrollView *scrollView;
14 | @property (nonatomic, strong) UIImageView *imageView;
15 | @property (nonatomic, strong) UIImage *image;
16 | @property (nonatomic, readonly) BOOL isViewing;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/LZAlbum/vendor/XHImageViewer/XHZoomingImageView.m:
--------------------------------------------------------------------------------
1 | //
2 | // XHZoomingImageView.m
3 | // XHImageViewer
4 | //
5 | // Created by 曾 宪华 on 14-2-17.
6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved.
7 | //
8 |
9 | #import "XHZoomingImageView.h"
10 |
11 | @interface XHZoomingImageView ()
12 |
13 | @property (nonatomic, readwrite, strong) UIScrollView *scrollView;
14 | @property (nonatomic, strong) UIView *containerView;
15 |
16 | @end
17 |
18 | @implementation XHZoomingImageView
19 |
20 | - (void)_setup {
21 | self.clipsToBounds = YES;
22 | self.contentMode = UIViewContentModeScaleAspectFill;
23 |
24 | _scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
25 | _scrollView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
26 | _scrollView.showsHorizontalScrollIndicator = NO;
27 | _scrollView.showsVerticalScrollIndicator = NO;
28 | _scrollView.delegate = self;
29 |
30 | _containerView = [[UIView alloc] initWithFrame:self.bounds];
31 | [_scrollView addSubview:_containerView];
32 |
33 | [self addSubview:_scrollView];
34 | }
35 |
36 | - (void)awakeFromNib {
37 | [self _setup];
38 | }
39 |
40 | - (id)initWithFrame:(CGRect)frame
41 | {
42 | self = [super initWithFrame:frame];
43 | if (self) {
44 | // Initialization code
45 | [self _setup];
46 | }
47 | return self;
48 | }
49 |
50 | - (void)dealloc {
51 | [self.imageView removeObserver:self forKeyPath:@"image"];
52 | }
53 |
54 | #pragma mark- Properties
55 |
56 | - (UIImage *)image {
57 | return _imageView.image;
58 | }
59 |
60 | - (void)setImage:(UIImage *)image {
61 | if(self.imageView == nil){
62 | self.imageView = [UIImageView new];
63 | self.imageView.clipsToBounds = YES;
64 | }
65 | self.imageView.image = image;
66 | }
67 |
68 | - (void)setImageView:(UIImageView *)imageView {
69 | if(imageView != _imageView) {
70 | [_imageView removeObserver:self forKeyPath:@"image"];
71 | [_imageView removeFromSuperview];
72 |
73 | _imageView = imageView;
74 | _imageView.frame = _imageView.bounds;
75 |
76 | [_imageView addObserver:self forKeyPath:@"image" options:0 context:nil];
77 |
78 | [_containerView addSubview:_imageView];
79 |
80 | _scrollView.zoomScale = 1;
81 | _scrollView.contentOffset = CGPointZero;
82 | _containerView.bounds = _imageView.bounds;
83 |
84 | [self resetZoomScale];
85 | _scrollView.zoomScale = _scrollView.minimumZoomScale;
86 | [self scrollViewDidZoom:_scrollView];
87 | }
88 | }
89 |
90 | - (BOOL)isViewing {
91 | return (_scrollView.zoomScale != _scrollView.minimumZoomScale);
92 | }
93 |
94 | #pragma mark- observe
95 |
96 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
97 | if(object == self.imageView) {
98 | [self imageDidChange];
99 | }
100 | }
101 |
102 | - (void)imageDidChange {
103 | CGSize size = (self.imageView.image) ? self.imageView.image.size : self.bounds.size;
104 | CGFloat ratio = MIN(_scrollView.frame.size.width / size.width, _scrollView.frame.size.height / size.height);
105 | CGFloat W = ratio * size.width;
106 | CGFloat H = ratio * size.height;
107 | self.imageView.frame = CGRectMake(0, 0, W, H);
108 |
109 | _scrollView.zoomScale = 1;
110 | _scrollView.contentOffset = CGPointZero;
111 | _containerView.bounds = _imageView.bounds;
112 |
113 | [self resetZoomScale];
114 | _scrollView.zoomScale = _scrollView.minimumZoomScale;
115 | [self scrollViewDidZoom:_scrollView];
116 | }
117 |
118 | #pragma mark- Scrollview delegate
119 |
120 | - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
121 | return _containerView;
122 | }
123 |
124 | - (void)scrollViewDidZoom:(UIScrollView *)scrollView {
125 | CGFloat Ws = _scrollView.frame.size.width - _scrollView.contentInset.left - _scrollView.contentInset.right;
126 | CGFloat Hs = _scrollView.frame.size.height - _scrollView.contentInset.top - _scrollView.contentInset.bottom;
127 | CGFloat W = _containerView.frame.size.width;
128 | CGFloat H = _containerView.frame.size.height;
129 |
130 | CGRect rct = _containerView.frame;
131 | rct.origin.x = MAX((Ws-W)/2, 0);
132 | rct.origin.y = MAX((Hs-H)/2, 0);
133 | _containerView.frame = rct;
134 | }
135 |
136 | - (void)resetZoomScale {
137 | CGFloat Rw = _scrollView.frame.size.width / self.imageView.frame.size.width;
138 | CGFloat Rh = _scrollView.frame.size.height / self.imageView.frame.size.height;
139 |
140 | CGFloat scale = 1;
141 | Rw = MAX(Rw, _imageView.image.size.width / (scale * _scrollView.frame.size.width));
142 | Rh = MAX(Rh, _imageView.image.size.height / (scale * _scrollView.frame.size.height));
143 |
144 | _scrollView.contentSize = _imageView.frame.size;
145 | _scrollView.minimumZoomScale = 1;
146 | _scrollView.maximumZoomScale = MAX(MAX(Rw, Rh), 1);
147 | }
148 |
149 | @end
150 |
--------------------------------------------------------------------------------
/LZAlbum/vendor/XHPhotographyHelper/XHPhotographyHelper.h:
--------------------------------------------------------------------------------
1 | //
2 | // XHPhotographyHelper.h
3 | // MessageDisplayExample
4 | //
5 | // Created by HUAJIE-1 on 14-5-3.
6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | typedef void(^DidFinishTakeMediaCompledBlock)(UIImage *image, NSDictionary *editingInfo);
12 |
13 | @interface XHPhotographyHelper : NSObject
14 |
15 | - (void)showOnPickerViewControllerSourceType:(UIImagePickerControllerSourceType)sourceType onViewController:(UIViewController *)viewController compled:(DidFinishTakeMediaCompledBlock)compled;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/LZAlbum/vendor/XHPhotographyHelper/XHPhotographyHelper.m:
--------------------------------------------------------------------------------
1 | //
2 | // XHPhotographyHelper.m
3 | // MessageDisplayExample
4 | //
5 | // Created by HUAJIE-1 on 14-5-3.
6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved.
7 | //
8 |
9 | #import "XHPhotographyHelper.h"
10 |
11 | @interface XHPhotographyHelper ()
12 |
13 | @property (nonatomic, copy) DidFinishTakeMediaCompledBlock didFinishTakeMediaCompled;
14 |
15 | @end
16 |
17 | @implementation XHPhotographyHelper
18 |
19 | - (instancetype)init {
20 | self = [super init];
21 | if (self) {
22 | }
23 | return self;
24 | }
25 |
26 | - (void)dealloc {
27 | self.didFinishTakeMediaCompled = nil;
28 | }
29 |
30 | - (void)showOnPickerViewControllerSourceType:(UIImagePickerControllerSourceType)sourceType onViewController:(UIViewController *)viewController compled:(DidFinishTakeMediaCompledBlock)compled {
31 | if (![UIImagePickerController isSourceTypeAvailable:sourceType]) {
32 | compled(nil, nil);
33 | return;
34 | }
35 | self.didFinishTakeMediaCompled = [compled copy];
36 | UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
37 | imagePickerController.editing = YES;
38 | imagePickerController.delegate = self;
39 | imagePickerController.sourceType = sourceType;
40 | if (sourceType == UIImagePickerControllerSourceTypeCamera) {
41 | imagePickerController.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera];
42 | }
43 | [viewController presentViewController:imagePickerController animated:YES completion:NULL];
44 | }
45 |
46 | - (void)dismissPickerViewController:(UIImagePickerController *)picker {
47 | typeof(self) __weak weakSelf=self;
48 | [picker dismissViewControllerAnimated:YES completion:^{
49 | weakSelf.didFinishTakeMediaCompled = nil;
50 | }];
51 | }
52 |
53 | - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo {
54 | if (self.didFinishTakeMediaCompled) {
55 | self.didFinishTakeMediaCompled(image, editingInfo);
56 | }
57 | [self dismissPickerViewController:picker];
58 | }
59 |
60 | - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
61 | if (self.didFinishTakeMediaCompled) {
62 | self.didFinishTakeMediaCompled(nil, info);
63 | }
64 | [self dismissPickerViewController:picker];
65 | }
66 |
67 | - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
68 | [self dismissPickerViewController:picker];
69 | }
70 |
71 | @end
72 |
--------------------------------------------------------------------------------
/LZAlbumTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LZAlbumTests/LZAlbumManagerTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // LZAlbumManagerTest.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/12/20.
6 | // Copyright © 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "LZBaseTest.h"
11 |
12 | @interface LZAlbumManagerTest : LZBaseTest
13 |
14 | @end
15 |
16 | @implementation LZAlbumManagerTest
17 |
18 | - (void)setUp {
19 | [super setUp];
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 | }
22 |
23 | - (void)tearDown {
24 | // Put teardown code here. This method is called after the invocation of each test method in the class.
25 | [super tearDown];
26 | }
27 |
28 | - (void)testExample {
29 | // This is an example of a functional test case.
30 | // Use XCTAssert and related functions to verify your tests produce the correct results.
31 | }
32 |
33 | - (void)testPerformanceExample {
34 | // This is an example of a performance test case.
35 | [self measureBlock:^{
36 | // Put the code you want to measure the time of here.
37 | }];
38 | }
39 |
40 | - (void)testCommentAlbum {
41 |
42 | }
43 |
44 |
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/LZAlbumTests/LZAlbumTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // LZAlbumTests.m
3 | // LZAlbumTests
4 | //
5 | // Created by lzw on 15/11/16.
6 | // Copyright © 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZBaseTest.h"
10 | #import "LZAlbumManager.h"
11 | #import "LZAlbum.h"
12 |
13 | @interface LZAlbumTest : LZBaseTest
14 |
15 | @end
16 |
17 | @implementation LZAlbumTest
18 |
19 | - (void)setUp {
20 | [super setUp];
21 | }
22 |
23 | - (void)tearDown {
24 | [super tearDown];
25 | }
26 |
27 | - (void)testFindAlbums {
28 | [[LZAlbumManager manager] findAlbumWithBlock:^(NSArray *objects, NSError *error) {
29 | assertNil(error);
30 | assertTrue(objects.count > 0);
31 | NOTIFY
32 | }];
33 | WAIT
34 | }
35 |
36 | // 因为以下测试会污染线上数据,先注释了
37 |
38 | //- (void)testCreateAlbum {
39 | // NSError *error;
40 | // [[LZAlbumManager manager] createAlbumWithText:@"hi everyone!!!!" photos:@[] error:&error];
41 | // assertNil(error);
42 | //}
43 | //
44 | //- (void)testCreateAndFindAlbum {
45 | // NSError *error;
46 | // [[LZAlbumManager manager] createAlbumWithText:@"Hi!!!" photos:@[] error:&error];
47 | // assertNil(error);
48 | // [[LZAlbumManager manager] findAlbumWithBlock:^(NSArray *objects, NSError *error) {
49 | // assertNil(error);
50 | // assertTrue(objects.count > 0);
51 | // LCAlbum *album = objects[0];
52 | // assertEqualObjects(album.albumContent, @"Hi!!!");
53 | // NOTIFY
54 | // }];
55 | // WAIT
56 | //}
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/LZAlbumTests/LZBaseTest.h:
--------------------------------------------------------------------------------
1 | //
2 | // LZBaseTest.h
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/12/15.
6 | // Copyright © 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #define assertTrue(expr) XCTAssertTrue((expr), @"")
12 | #define assertFalse(expr) XCTAssertFalse((expr), @"")
13 | #define assertNil(a1) XCTAssertNil((a1), @"")
14 | #define assertNotNil(a1) XCTAssertNotNil((a1), @"")
15 | #define assertEqual(a1, a2) XCTAssertEqual((a1), (a2), @"")
16 | #define assertEqualObjects(a1, a2) XCTAssertEqualObjects((a1), (a2), @"")
17 | #define assertNotEqual(a1, a2) XCTAssertNotEqual((a1), (a2), @"")
18 | #define assertNotEqualObjects(a1, a2) XCTAssertNotEqualObjects((a1), (a2), @"")
19 | #define assertAccuracy(a1, a2, acc) XCTAssertEqualWithAccuracy((a1),(a2),(acc))
20 |
21 | #define WAIT \
22 | do { \
23 | [self expectationForNotification:@"LCUnitTest" object:nil handler:nil]; \
24 | [self waitForExpectationsWithTimeout:60 handler:nil]; \
25 | } while(0);
26 |
27 | #define NOTIFY \
28 | do { \
29 | [[NSNotificationCenter defaultCenter] postNotificationName:@"LCUnitTest" object:nil]; \
30 | } while(0);
31 |
32 | @interface LZBaseTest : XCTestCase
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/LZAlbumTests/LZBaseTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // LZBaseTest.m
3 | // LZAlbum
4 | //
5 | // Created by lzw on 15/12/15.
6 | // Copyright © 2015年 lzw. All rights reserved.
7 | //
8 |
9 | #import "LZBaseTest.h"
10 |
11 | @implementation LZBaseTest
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '6.0'
3 |
4 | target 'LZAlbum' do
5 | pod 'AVOSCloud', '3.1.6.2'
6 | pod 'MBProgressHUD', '0.9.1'
7 | pod 'SDWebImage', '3.7.2'
8 | pod 'DateTools', '1.5.0'
9 | pod 'FXForms', '1.2.13'
10 | pod 'TTTAttributedLabel', '1.13.4'
11 | pod 'JDStatusBarNotification'
12 | end
13 |
14 |
--------------------------------------------------------------------------------
/README-cn.md:
--------------------------------------------------------------------------------
1 | # LZAlbum
2 | 基于 LeanCloud 的朋友圈,展示了如何在 LeanCloud 上实现一对一和一对多的关系建模。
3 |
4 | 
5 |
6 |
7 | # Support
8 |
9 | 如果在使用过程中有任何问题,请提 [issue](https://github.com/lzwjava/LZAlbum/issues) ,我会在 Github 上给予帮助。
10 |
11 | # Run
12 | ```
13 | pod install --no-repo-update --verbose (报错说库找不到的话,去掉 --no-repo-update)
14 | open LZAlbum.xcworkspace
15 | ```
16 |
17 | # Credit
18 |
19 | UI 界面大量借鉴了 [MessageDisplayKit](https://github.com/xhzengAIB/MessageDisplayKit),数据放在了 LeanCloud 上,一并表示感谢。
20 |
21 | # Backend
22 |
23 | 
24 |
25 | 用公共账号登录 https://leancloud.cn ,账号/密码:leancloud@163.com/Public123 ,选择应用 LCAlbum 即可查看表结构。
26 | **注意 请不要更改后台数据,查看就好了。否则可能造成客户端崩溃**
27 | **注意 上面的账号密码不是这个应用登录的账号,而是 LeanCloud 后台的账号。应用登录的账号,先在注册界面注册一个即可。**
28 |
29 | # Document
30 |
31 | [相关文档](https://leancloud.cn/docs/ios_os_x_guide.html)
32 |
33 | # License
34 | MIT
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LZAlbum
2 |
3 | Based on LeanCloud's Moments feature, it demonstrates how to model one-to-one and one-to-many relationships on LeanCloud.
4 |
5 | 
6 |
7 | # Support
8 |
9 | If you encounter any issues during usage, please raise an [issue](https://github.com/lzwjava/LZAlbum/issues), and I will provide assistance on GitHub.
10 |
11 | # Run
12 | ```
13 | pod install --no-repo-update --verbose (If you encounter errors regarding missing libraries, remove --no-repo-update)
14 | open LZAlbum.xcworkspace
15 | ```
16 |
17 | # Credit
18 |
19 | The UI design drew heavily from [MessageDisplayKit](https://github.com/xhzengAIB/MessageDisplayKit), and the data is stored on LeanCloud. Gratitude is extended to both.
20 |
21 | # Backend
22 |
23 | 
24 |
25 | Login with the public account on https://leancloud.cn, credentials: leancloud@163.com/Public123, then select the LCAlbum app to view the table structure.
26 | **Note: Please refrain from modifying backend data, just view it. Otherwise, it may lead to client crashes.**
27 | **Note: The above-mentioned credentials are not for logging into this app but for the LeanCloud backend. For the app login, simply register a new account on the registration page.**
28 |
29 | # Document
30 |
31 | [Related documentation](https://leancloud.cn/docs/ios_os_x_guide.html)
32 |
33 | # License
34 | MIT
--------------------------------------------------------------------------------
/package.sh:
--------------------------------------------------------------------------------
1 | pod install --verbose --no-repo-update && \
2 | xcodebuild -workspace LZAlbum.xcworkspace -scheme LZAlbum archive -archivePath ./build/LZAlbum.xcarchive && \
3 | rm -rf ./build/LZAlbum.ipa && \
4 | xcodebuild -exportArchive -exportFormat ipa -archivePath build/LZAlbum.xcarchive -exportPath build/LZAlbum.ipa && \
5 | fir p build/LZAlbum.ipa -T eeca39297cfda6e31a67c9b66e1edd07
6 |
--------------------------------------------------------------------------------
/test.sh:
--------------------------------------------------------------------------------
1 | xcodebuild -workspace LZAlbum.xcworkspace -scheme LZAlbumTests -sdk iphonesimulator clean test
2 |
--------------------------------------------------------------------------------