Commit 8101e577 authored by tanzhen's avatar tanzhen

配置项目

parent f43d2e48
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
900E65811C2BB8D5003D9A9E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 900E65801C2BB8D5003D9A9E /* main.m */; };
900E65841C2BB8D5003D9A9E /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 900E65831C2BB8D5003D9A9E /* AppDelegate.m */; };
900E65871C2BB8D5003D9A9E /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 900E65861C2BB8D5003D9A9E /* ViewController.m */; };
900E658A1C2BB8D5003D9A9E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 900E65881C2BB8D5003D9A9E /* Main.storyboard */; };
900E658C1C2BB8D5003D9A9E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 900E658B1C2BB8D5003D9A9E /* Assets.xcassets */; };
900E658F1C2BB8D5003D9A9E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 900E658D1C2BB8D5003D9A9E /* LaunchScreen.storyboard */; };
900E659A1C2BB8D5003D9A9E /* TZImagePickerControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 900E65991C2BB8D5003D9A9E /* TZImagePickerControllerTests.m */; };
900E65A51C2BB8D5003D9A9E /* TZImagePickerControllerUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 900E65A41C2BB8D5003D9A9E /* TZImagePickerControllerUITests.m */; };
900EEFF81C2BBF9500EA709B /* TZImagePickerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 900EEFF71C2BBF9500EA709B /* TZImagePickerController.m */; };
900EEFFE1C2BD58B00EA709B /* TZPhotoPickerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 900EEFFD1C2BD58B00EA709B /* TZPhotoPickerController.m */; };
900EF0021C2BD7E400EA709B /* TZAssetCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 900EF0001C2BD7E400EA709B /* TZAssetCell.m */; };
900EF0031C2BD7E400EA709B /* TZAssetCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 900EF0011C2BD7E400EA709B /* TZAssetCell.xib */; };
900EF00F1C2C0B1100EA709B /* TZAssetModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 900EF00E1C2C0B1100EA709B /* TZAssetModel.m */; };
900EF0121C2C107400EA709B /* TZPhotoPreviewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 900EF0111C2C107400EA709B /* TZPhotoPreviewController.m */; };
900EF0161C2C134900EA709B /* TZPhotoPreviewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 900EF0141C2C134900EA709B /* TZPhotoPreviewCell.m */; };
900F4C4E1C382C0100C62EE2 /* navi_back@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 900F4C451C382C0100C62EE2 /* navi_back@2x.png */; };
900F4C4F1C382C0100C62EE2 /* photo_def_photoPickerVc@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 900F4C461C382C0100C62EE2 /* photo_def_photoPickerVc@2x.png */; };
900F4C501C382C0100C62EE2 /* photo_def_previewVc@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 900F4C471C382C0100C62EE2 /* photo_def_previewVc@2x.png */; };
900F4C511C382C0100C62EE2 /* photo_number_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 900F4C481C382C0100C62EE2 /* photo_number_icon@2x.png */; };
900F4C521C382C0100C62EE2 /* photo_sel_photoPickerVc@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 900F4C491C382C0100C62EE2 /* photo_sel_photoPickerVc@2x.png */; };
900F4C531C382C0100C62EE2 /* photo_sel_previewVc@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 900F4C4A1C382C0100C62EE2 /* photo_sel_previewVc@2x.png */; };
900F4C541C382C0100C62EE2 /* preview_number_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 900F4C4B1C382C0100C62EE2 /* preview_number_icon@2x.png */; };
900F4C551C382C0100C62EE2 /* TableViewArrow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 900F4C4C1C382C0100C62EE2 /* TableViewArrow@2x.png */; };
9038D58D1C38B9D4007DE549 /* photo_original_def@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 9038D58B1C38B9D4007DE549 /* photo_original_def@2x.png */; };
9038D58E1C38B9D4007DE549 /* photo_original_sel@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 9038D58C1C38B9D4007DE549 /* photo_original_sel@2x.png */; };
9038D5911C3974F0007DE549 /* TZTestCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 9038D5901C3974F0007DE549 /* TZTestCell.m */; };
90CE84AB1C3A76E5003D0779 /* preview_original_def@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 90CE84AA1C3A76E5003D0779 /* preview_original_def@2x.png */; };
90CE84AE1C3A89EF003D0779 /* TZImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 90CE84AD1C3A89EF003D0779 /* TZImageManager.m */; };
90CE84B41C3B7D39003D0779 /* VideoSendIcon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 90CE84B31C3B7D39003D0779 /* VideoSendIcon@2x.png */; };
90CE84B71C3BABB6003D0779 /* TZVideoPlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 90CE84B61C3BABB6003D0779 /* TZVideoPlayerController.m */; };
90CE84B91C3BDC8A003D0779 /* MMVideoPreviewPlay@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 90CE84B81C3BDC8A003D0779 /* MMVideoPreviewPlay@2x.png */; };
90CE84BB1C3BDCC1003D0779 /* MMVideoPreviewPlayHL@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 90CE84BA1C3BDCC1003D0779 /* MMVideoPreviewPlayHL@2x.png */; };
90EBF5D61C2E298000CB9BCC /* UIView+Layout.m in Sources */ = {isa = PBXBuildFile; fileRef = 90EBF5D51C2E298000CB9BCC /* UIView+Layout.m */; };
90EBF5E81C30273C00CB9BCC /* TZAlbumCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 90EBF5E71C30273C00CB9BCC /* TZAlbumCell.xib */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
900E65961C2BB8D5003D9A9E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 900E65741C2BB8D5003D9A9E /* Project object */;
proxyType = 1;
remoteGlobalIDString = 900E657B1C2BB8D5003D9A9E;
remoteInfo = TZImagePickerController;
};
900E65A11C2BB8D5003D9A9E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 900E65741C2BB8D5003D9A9E /* Project object */;
proxyType = 1;
remoteGlobalIDString = 900E657B1C2BB8D5003D9A9E;
remoteInfo = TZImagePickerController;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
900E657C1C2BB8D5003D9A9E /* TZImagePickerController.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TZImagePickerController.app; sourceTree = BUILT_PRODUCTS_DIR; };
900E65801C2BB8D5003D9A9E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
900E65821C2BB8D5003D9A9E /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
900E65831C2BB8D5003D9A9E /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
900E65851C2BB8D5003D9A9E /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
900E65861C2BB8D5003D9A9E /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
900E65891C2BB8D5003D9A9E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
900E658B1C2BB8D5003D9A9E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
900E658E1C2BB8D5003D9A9E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
900E65901C2BB8D5003D9A9E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
900E65951C2BB8D5003D9A9E /* TZImagePickerControllerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TZImagePickerControllerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
900E65991C2BB8D5003D9A9E /* TZImagePickerControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TZImagePickerControllerTests.m; sourceTree = "<group>"; };
900E659B1C2BB8D5003D9A9E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
900E65A01C2BB8D5003D9A9E /* TZImagePickerControllerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TZImagePickerControllerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
900E65A41C2BB8D5003D9A9E /* TZImagePickerControllerUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TZImagePickerControllerUITests.m; sourceTree = "<group>"; };
900E65A61C2BB8D5003D9A9E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
900EEFF61C2BBF9500EA709B /* TZImagePickerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZImagePickerController.h; sourceTree = "<group>"; };
900EEFF71C2BBF9500EA709B /* TZImagePickerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZImagePickerController.m; sourceTree = "<group>"; };
900EEFFC1C2BD58B00EA709B /* TZPhotoPickerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZPhotoPickerController.h; sourceTree = "<group>"; };
900EEFFD1C2BD58B00EA709B /* TZPhotoPickerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZPhotoPickerController.m; sourceTree = "<group>"; };
900EEFFF1C2BD7E400EA709B /* TZAssetCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZAssetCell.h; sourceTree = "<group>"; };
900EF0001C2BD7E400EA709B /* TZAssetCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZAssetCell.m; sourceTree = "<group>"; };
900EF0011C2BD7E400EA709B /* TZAssetCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TZAssetCell.xib; sourceTree = "<group>"; };
900EF00D1C2C0B1100EA709B /* TZAssetModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZAssetModel.h; sourceTree = "<group>"; };
900EF00E1C2C0B1100EA709B /* TZAssetModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZAssetModel.m; sourceTree = "<group>"; };
900EF0101C2C107400EA709B /* TZPhotoPreviewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZPhotoPreviewController.h; sourceTree = "<group>"; };
900EF0111C2C107400EA709B /* TZPhotoPreviewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZPhotoPreviewController.m; sourceTree = "<group>"; };
900EF0131C2C134800EA709B /* TZPhotoPreviewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZPhotoPreviewCell.h; sourceTree = "<group>"; };
900EF0141C2C134900EA709B /* TZPhotoPreviewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZPhotoPreviewCell.m; sourceTree = "<group>"; };
900F4C451C382C0100C62EE2 /* navi_back@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "navi_back@2x.png"; sourceTree = "<group>"; };
900F4C461C382C0100C62EE2 /* photo_def_photoPickerVc@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "photo_def_photoPickerVc@2x.png"; sourceTree = "<group>"; };
900F4C471C382C0100C62EE2 /* photo_def_previewVc@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "photo_def_previewVc@2x.png"; sourceTree = "<group>"; };
900F4C481C382C0100C62EE2 /* photo_number_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "photo_number_icon@2x.png"; sourceTree = "<group>"; };
900F4C491C382C0100C62EE2 /* photo_sel_photoPickerVc@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "photo_sel_photoPickerVc@2x.png"; sourceTree = "<group>"; };
900F4C4A1C382C0100C62EE2 /* photo_sel_previewVc@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "photo_sel_previewVc@2x.png"; sourceTree = "<group>"; };
900F4C4B1C382C0100C62EE2 /* preview_number_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "preview_number_icon@2x.png"; sourceTree = "<group>"; };
900F4C4C1C382C0100C62EE2 /* TableViewArrow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "TableViewArrow@2x.png"; sourceTree = "<group>"; };
9038D58B1C38B9D4007DE549 /* photo_original_def@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "photo_original_def@2x.png"; sourceTree = "<group>"; };
9038D58C1C38B9D4007DE549 /* photo_original_sel@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "photo_original_sel@2x.png"; sourceTree = "<group>"; };
9038D58F1C3974F0007DE549 /* TZTestCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZTestCell.h; sourceTree = "<group>"; };
9038D5901C3974F0007DE549 /* TZTestCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZTestCell.m; sourceTree = "<group>"; };
90CE84AA1C3A76E5003D0779 /* preview_original_def@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "preview_original_def@2x.png"; sourceTree = "<group>"; };
90CE84AC1C3A89EF003D0779 /* TZImageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZImageManager.h; sourceTree = "<group>"; };
90CE84AD1C3A89EF003D0779 /* TZImageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZImageManager.m; sourceTree = "<group>"; };
90CE84B31C3B7D39003D0779 /* VideoSendIcon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "VideoSendIcon@2x.png"; sourceTree = "<group>"; };
90CE84B51C3BABB6003D0779 /* TZVideoPlayerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZVideoPlayerController.h; sourceTree = "<group>"; };
90CE84B61C3BABB6003D0779 /* TZVideoPlayerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZVideoPlayerController.m; sourceTree = "<group>"; };
90CE84B81C3BDC8A003D0779 /* MMVideoPreviewPlay@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MMVideoPreviewPlay@2x.png"; sourceTree = "<group>"; };
90CE84BA1C3BDCC1003D0779 /* MMVideoPreviewPlayHL@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "MMVideoPreviewPlayHL@2x.png"; sourceTree = "<group>"; };
90EBF5D41C2E298000CB9BCC /* UIView+Layout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Layout.h"; sourceTree = "<group>"; };
90EBF5D51C2E298000CB9BCC /* UIView+Layout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Layout.m"; sourceTree = "<group>"; };
90EBF5E71C30273C00CB9BCC /* TZAlbumCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TZAlbumCell.xib; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
900E65791C2BB8D5003D9A9E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
900E65921C2BB8D5003D9A9E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
900E659D1C2BB8D5003D9A9E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
900E65731C2BB8D5003D9A9E = {
isa = PBXGroup;
children = (
900E657E1C2BB8D5003D9A9E /* TZImagePickerController */,
900E65981C2BB8D5003D9A9E /* TZImagePickerControllerTests */,
900E65A31C2BB8D5003D9A9E /* TZImagePickerControllerUITests */,
900E657D1C2BB8D5003D9A9E /* Products */,
);
sourceTree = "<group>";
};
900E657D1C2BB8D5003D9A9E /* Products */ = {
isa = PBXGroup;
children = (
900E657C1C2BB8D5003D9A9E /* TZImagePickerController.app */,
900E65951C2BB8D5003D9A9E /* TZImagePickerControllerTests.xctest */,
900E65A01C2BB8D5003D9A9E /* TZImagePickerControllerUITests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
900E657E1C2BB8D5003D9A9E /* TZImagePickerController */ = {
isa = PBXGroup;
children = (
900EEFF51C2BBF7600EA709B /* TZImagePickerController */,
900E65821C2BB8D5003D9A9E /* AppDelegate.h */,
900E65831C2BB8D5003D9A9E /* AppDelegate.m */,
900E65851C2BB8D5003D9A9E /* ViewController.h */,
900E65861C2BB8D5003D9A9E /* ViewController.m */,
9038D58F1C3974F0007DE549 /* TZTestCell.h */,
9038D5901C3974F0007DE549 /* TZTestCell.m */,
900E65881C2BB8D5003D9A9E /* Main.storyboard */,
900E658B1C2BB8D5003D9A9E /* Assets.xcassets */,
900E658D1C2BB8D5003D9A9E /* LaunchScreen.storyboard */,
900E65901C2BB8D5003D9A9E /* Info.plist */,
900E657F1C2BB8D5003D9A9E /* Supporting Files */,
);
path = TZImagePickerController;
sourceTree = "<group>";
};
900E657F1C2BB8D5003D9A9E /* Supporting Files */ = {
isa = PBXGroup;
children = (
900E65801C2BB8D5003D9A9E /* main.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
900E65981C2BB8D5003D9A9E /* TZImagePickerControllerTests */ = {
isa = PBXGroup;
children = (
900E65991C2BB8D5003D9A9E /* TZImagePickerControllerTests.m */,
900E659B1C2BB8D5003D9A9E /* Info.plist */,
);
path = TZImagePickerControllerTests;
sourceTree = "<group>";
};
900E65A31C2BB8D5003D9A9E /* TZImagePickerControllerUITests */ = {
isa = PBXGroup;
children = (
900E65A41C2BB8D5003D9A9E /* TZImagePickerControllerUITests.m */,
900E65A61C2BB8D5003D9A9E /* Info.plist */,
);
path = TZImagePickerControllerUITests;
sourceTree = "<group>";
};
900EEFF51C2BBF7600EA709B /* TZImagePickerController */ = {
isa = PBXGroup;
children = (
90CE84AC1C3A89EF003D0779 /* TZImageManager.h */,
90CE84AD1C3A89EF003D0779 /* TZImageManager.m */,
900EEFF61C2BBF9500EA709B /* TZImagePickerController.h */,
900EEFF71C2BBF9500EA709B /* TZImagePickerController.m */,
900EEFFC1C2BD58B00EA709B /* TZPhotoPickerController.h */,
900EEFFD1C2BD58B00EA709B /* TZPhotoPickerController.m */,
900EEFFF1C2BD7E400EA709B /* TZAssetCell.h */,
900EF0001C2BD7E400EA709B /* TZAssetCell.m */,
900EF0011C2BD7E400EA709B /* TZAssetCell.xib */,
90EBF5E71C30273C00CB9BCC /* TZAlbumCell.xib */,
900EF00D1C2C0B1100EA709B /* TZAssetModel.h */,
900EF00E1C2C0B1100EA709B /* TZAssetModel.m */,
900EF0101C2C107400EA709B /* TZPhotoPreviewController.h */,
900EF0111C2C107400EA709B /* TZPhotoPreviewController.m */,
900EF0131C2C134800EA709B /* TZPhotoPreviewCell.h */,
900EF0141C2C134900EA709B /* TZPhotoPreviewCell.m */,
90CE84B51C3BABB6003D0779 /* TZVideoPlayerController.h */,
90CE84B61C3BABB6003D0779 /* TZVideoPlayerController.m */,
90EBF5D41C2E298000CB9BCC /* UIView+Layout.h */,
90EBF5D51C2E298000CB9BCC /* UIView+Layout.m */,
900EF0041C2C055600EA709B /* Resource */,
);
path = TZImagePickerController;
sourceTree = "<group>";
};
900EF0041C2C055600EA709B /* Resource */ = {
isa = PBXGroup;
children = (
90CE84BA1C3BDCC1003D0779 /* MMVideoPreviewPlayHL@2x.png */,
90CE84B81C3BDC8A003D0779 /* MMVideoPreviewPlay@2x.png */,
90CE84B31C3B7D39003D0779 /* VideoSendIcon@2x.png */,
90CE84AA1C3A76E5003D0779 /* preview_original_def@2x.png */,
9038D58B1C38B9D4007DE549 /* photo_original_def@2x.png */,
9038D58C1C38B9D4007DE549 /* photo_original_sel@2x.png */,
900F4C451C382C0100C62EE2 /* navi_back@2x.png */,
900F4C461C382C0100C62EE2 /* photo_def_photoPickerVc@2x.png */,
900F4C471C382C0100C62EE2 /* photo_def_previewVc@2x.png */,
900F4C481C382C0100C62EE2 /* photo_number_icon@2x.png */,
900F4C491C382C0100C62EE2 /* photo_sel_photoPickerVc@2x.png */,
900F4C4A1C382C0100C62EE2 /* photo_sel_previewVc@2x.png */,
900F4C4B1C382C0100C62EE2 /* preview_number_icon@2x.png */,
900F4C4C1C382C0100C62EE2 /* TableViewArrow@2x.png */,
);
name = Resource;
path = Resourse;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
900E657B1C2BB8D5003D9A9E /* TZImagePickerController */ = {
isa = PBXNativeTarget;
buildConfigurationList = 900E65A91C2BB8D5003D9A9E /* Build configuration list for PBXNativeTarget "TZImagePickerController" */;
buildPhases = (
900E65781C2BB8D5003D9A9E /* Sources */,
900E65791C2BB8D5003D9A9E /* Frameworks */,
900E657A1C2BB8D5003D9A9E /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = TZImagePickerController;
productName = TZImagePickerController;
productReference = 900E657C1C2BB8D5003D9A9E /* TZImagePickerController.app */;
productType = "com.apple.product-type.application";
};
900E65941C2BB8D5003D9A9E /* TZImagePickerControllerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 900E65AC1C2BB8D5003D9A9E /* Build configuration list for PBXNativeTarget "TZImagePickerControllerTests" */;
buildPhases = (
900E65911C2BB8D5003D9A9E /* Sources */,
900E65921C2BB8D5003D9A9E /* Frameworks */,
900E65931C2BB8D5003D9A9E /* Resources */,
);
buildRules = (
);
dependencies = (
900E65971C2BB8D5003D9A9E /* PBXTargetDependency */,
);
name = TZImagePickerControllerTests;
productName = TZImagePickerControllerTests;
productReference = 900E65951C2BB8D5003D9A9E /* TZImagePickerControllerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
900E659F1C2BB8D5003D9A9E /* TZImagePickerControllerUITests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 900E65AF1C2BB8D5003D9A9E /* Build configuration list for PBXNativeTarget "TZImagePickerControllerUITests" */;
buildPhases = (
900E659C1C2BB8D5003D9A9E /* Sources */,
900E659D1C2BB8D5003D9A9E /* Frameworks */,
900E659E1C2BB8D5003D9A9E /* Resources */,
);
buildRules = (
);
dependencies = (
900E65A21C2BB8D5003D9A9E /* PBXTargetDependency */,
);
name = TZImagePickerControllerUITests;
productName = TZImagePickerControllerUITests;
productReference = 900E65A01C2BB8D5003D9A9E /* TZImagePickerControllerUITests.xctest */;
productType = "com.apple.product-type.bundle.ui-testing";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
900E65741C2BB8D5003D9A9E /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0720;
ORGANIZATIONNAME = "谭真";
TargetAttributes = {
900E657B1C2BB8D5003D9A9E = {
CreatedOnToolsVersion = 7.2;
};
900E65941C2BB8D5003D9A9E = {
CreatedOnToolsVersion = 7.2;
TestTargetID = 900E657B1C2BB8D5003D9A9E;
};
900E659F1C2BB8D5003D9A9E = {
CreatedOnToolsVersion = 7.2;
TestTargetID = 900E657B1C2BB8D5003D9A9E;
};
};
};
buildConfigurationList = 900E65771C2BB8D5003D9A9E /* Build configuration list for PBXProject "TZImagePickerController" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 900E65731C2BB8D5003D9A9E;
productRefGroup = 900E657D1C2BB8D5003D9A9E /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
900E657B1C2BB8D5003D9A9E /* TZImagePickerController */,
900E65941C2BB8D5003D9A9E /* TZImagePickerControllerTests */,
900E659F1C2BB8D5003D9A9E /* TZImagePickerControllerUITests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
900E657A1C2BB8D5003D9A9E /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
900F4C4E1C382C0100C62EE2 /* navi_back@2x.png in Resources */,
900E658F1C2BB8D5003D9A9E /* LaunchScreen.storyboard in Resources */,
900F4C4F1C382C0100C62EE2 /* photo_def_photoPickerVc@2x.png in Resources */,
900F4C551C382C0100C62EE2 /* TableViewArrow@2x.png in Resources */,
900F4C541C382C0100C62EE2 /* preview_number_icon@2x.png in Resources */,
900E658C1C2BB8D5003D9A9E /* Assets.xcassets in Resources */,
900F4C511C382C0100C62EE2 /* photo_number_icon@2x.png in Resources */,
900F4C531C382C0100C62EE2 /* photo_sel_previewVc@2x.png in Resources */,
900EF0031C2BD7E400EA709B /* TZAssetCell.xib in Resources */,
900F4C521C382C0100C62EE2 /* photo_sel_photoPickerVc@2x.png in Resources */,
900E658A1C2BB8D5003D9A9E /* Main.storyboard in Resources */,
900F4C501C382C0100C62EE2 /* photo_def_previewVc@2x.png in Resources */,
90CE84AB1C3A76E5003D0779 /* preview_original_def@2x.png in Resources */,
9038D58D1C38B9D4007DE549 /* photo_original_def@2x.png in Resources */,
90CE84BB1C3BDCC1003D0779 /* MMVideoPreviewPlayHL@2x.png in Resources */,
9038D58E1C38B9D4007DE549 /* photo_original_sel@2x.png in Resources */,
90EBF5E81C30273C00CB9BCC /* TZAlbumCell.xib in Resources */,
90CE84B41C3B7D39003D0779 /* VideoSendIcon@2x.png in Resources */,
90CE84B91C3BDC8A003D0779 /* MMVideoPreviewPlay@2x.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
900E65931C2BB8D5003D9A9E /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
900E659E1C2BB8D5003D9A9E /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
900E65781C2BB8D5003D9A9E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9038D5911C3974F0007DE549 /* TZTestCell.m in Sources */,
900EF00F1C2C0B1100EA709B /* TZAssetModel.m in Sources */,
900EEFFE1C2BD58B00EA709B /* TZPhotoPickerController.m in Sources */,
90EBF5D61C2E298000CB9BCC /* UIView+Layout.m in Sources */,
90CE84B71C3BABB6003D0779 /* TZVideoPlayerController.m in Sources */,
900EF0021C2BD7E400EA709B /* TZAssetCell.m in Sources */,
900EF0161C2C134900EA709B /* TZPhotoPreviewCell.m in Sources */,
900E65871C2BB8D5003D9A9E /* ViewController.m in Sources */,
90CE84AE1C3A89EF003D0779 /* TZImageManager.m in Sources */,
900E65841C2BB8D5003D9A9E /* AppDelegate.m in Sources */,
900E65811C2BB8D5003D9A9E /* main.m in Sources */,
900EF0121C2C107400EA709B /* TZPhotoPreviewController.m in Sources */,
900EEFF81C2BBF9500EA709B /* TZImagePickerController.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
900E65911C2BB8D5003D9A9E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
900E659A1C2BB8D5003D9A9E /* TZImagePickerControllerTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
900E659C1C2BB8D5003D9A9E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
900E65A51C2BB8D5003D9A9E /* TZImagePickerControllerUITests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
900E65971C2BB8D5003D9A9E /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 900E657B1C2BB8D5003D9A9E /* TZImagePickerController */;
targetProxy = 900E65961C2BB8D5003D9A9E /* PBXContainerItemProxy */;
};
900E65A21C2BB8D5003D9A9E /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 900E657B1C2BB8D5003D9A9E /* TZImagePickerController */;
targetProxy = 900E65A11C2BB8D5003D9A9E /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
900E65881C2BB8D5003D9A9E /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
900E65891C2BB8D5003D9A9E /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
900E658D1C2BB8D5003D9A9E /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
900E658E1C2BB8D5003D9A9E /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
900E65A71C2BB8D5003D9A9E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.2;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
900E65A81C2BB8D5003D9A9E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.2;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
900E65AA1C2BB8D5003D9A9E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
INFOPLIST_FILE = TZImagePickerController/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = tanzhen.TZImagePickerController;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
900E65AB1C2BB8D5003D9A9E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
INFOPLIST_FILE = TZImagePickerController/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = tanzhen.TZImagePickerController;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
900E65AD1C2BB8D5003D9A9E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
INFOPLIST_FILE = TZImagePickerControllerTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = tanzhen.TZImagePickerControllerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TZImagePickerController.app/TZImagePickerController";
};
name = Debug;
};
900E65AE1C2BB8D5003D9A9E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
INFOPLIST_FILE = TZImagePickerControllerTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = tanzhen.TZImagePickerControllerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TZImagePickerController.app/TZImagePickerController";
};
name = Release;
};
900E65B01C2BB8D5003D9A9E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
INFOPLIST_FILE = TZImagePickerControllerUITests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = tanzhen.TZImagePickerControllerUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_TARGET_NAME = TZImagePickerController;
USES_XCTRUNNER = YES;
};
name = Debug;
};
900E65B11C2BB8D5003D9A9E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
INFOPLIST_FILE = TZImagePickerControllerUITests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = tanzhen.TZImagePickerControllerUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_TARGET_NAME = TZImagePickerController;
USES_XCTRUNNER = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
900E65771C2BB8D5003D9A9E /* Build configuration list for PBXProject "TZImagePickerController" */ = {
isa = XCConfigurationList;
buildConfigurations = (
900E65A71C2BB8D5003D9A9E /* Debug */,
900E65A81C2BB8D5003D9A9E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
900E65A91C2BB8D5003D9A9E /* Build configuration list for PBXNativeTarget "TZImagePickerController" */ = {
isa = XCConfigurationList;
buildConfigurations = (
900E65AA1C2BB8D5003D9A9E /* Debug */,
900E65AB1C2BB8D5003D9A9E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
900E65AC1C2BB8D5003D9A9E /* Build configuration list for PBXNativeTarget "TZImagePickerControllerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
900E65AD1C2BB8D5003D9A9E /* Debug */,
900E65AE1C2BB8D5003D9A9E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
900E65AF1C2BB8D5003D9A9E /* Build configuration list for PBXNativeTarget "TZImagePickerControllerUITests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
900E65B01C2BB8D5003D9A9E /* Debug */,
900E65B11C2BB8D5003D9A9E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 900E65741C2BB8D5003D9A9E /* Project object */;
}
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:TZImagePickerController.xcodeproj">
</FileRef>
</Workspace>
//
// AppDelegate.h
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
//
// AppDelegate.m
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import "AppDelegate.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "AlbumAddBtn@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9531" systemVersion="14F1509" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9531" systemVersion="14F1509" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4Ae-5T-gEc" userLabel="TopContentView">
<rect key="frame" x="0.0" y="0.0" width="320" height="120"/>
<subviews>
<button opaque="NO" tag="2" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="r81-gA-Wag">
<rect key="frame" x="20" y="55" width="280" height="30"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="30" id="B5p-sB-c5y"/>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="127" id="KAp-UH-6ZM"/>
<constraint firstAttribute="height" constant="30" id="kdh-Nr-oix"/>
</constraints>
<state key="normal" title="pick multi-photos"/>
<variation key="default">
<mask key="constraints">
<exclude reference="B5p-sB-c5y"/>
<exclude reference="KAp-UH-6ZM"/>
</mask>
</variation>
<connections>
<action selector="pickPhotoButtonClick:" destination="BYZ-38-t0r" eventType="touchUpInside" id="Y3s-qn-oVG"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" red="0.1715644113149847" green="0.94983992737003053" blue="0.50998662079510704" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="r81-gA-Wag" firstAttribute="top" secondItem="4Ae-5T-gEc" secondAttribute="top" constant="55" id="8mQ-5b-cnI"/>
<constraint firstAttribute="trailing" secondItem="r81-gA-Wag" secondAttribute="trailing" constant="20" id="QBT-qQ-Z2n"/>
<constraint firstItem="r81-gA-Wag" firstAttribute="leading" secondItem="4Ae-5T-gEc" secondAttribute="leading" constant="20" id="o2q-G0-PT5"/>
<constraint firstAttribute="height" constant="120" id="oAh-GJ-wLO"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="4Ae-5T-gEc" firstAttribute="top" secondItem="8bC-Xf-vdC" secondAttribute="top" id="61m-nK-szh"/>
<constraint firstAttribute="trailing" secondItem="4Ae-5T-gEc" secondAttribute="trailing" id="cCX-fJ-tja"/>
<constraint firstItem="4Ae-5T-gEc" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="g2m-EG-Cux"/>
</constraints>
</view>
<simulatedScreenMetrics key="simulatedDestinationMetrics" type="retina4"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="14F1509" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="grQ-4c-o22" customClass="TZAlbumCell">
<rect key="frame" x="0.0" y="0.0" width="320" height="70"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="MN9-Rx-foD">
<rect key="frame" x="0.0" y="0.0" width="70" height="70"/>
<constraints>
<constraint firstAttribute="width" constant="70" id="9QL-fc-DfO"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Mrv-sA-Nuw">
<rect key="frame" x="80" y="0.0" width="190" height="70"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="TableViewArrow" translatesAutoresizingMaskIntoConstraints="NO" id="Nj8-PM-Kqf">
<rect key="frame" x="293" y="28" width="15" height="15"/>
<constraints>
<constraint firstAttribute="width" constant="15" id="HiN-sC-FNK"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="Mrv-sA-Nuw" firstAttribute="leading" secondItem="MN9-Rx-foD" secondAttribute="trailing" constant="10" id="1QF-Ux-8Eq"/>
<constraint firstAttribute="trailing" secondItem="Mrv-sA-Nuw" secondAttribute="trailing" constant="50" id="Hdc-BO-uDe"/>
<constraint firstAttribute="trailing" secondItem="Nj8-PM-Kqf" secondAttribute="trailing" constant="12" id="NDX-ya-7lu"/>
<constraint firstItem="MN9-Rx-foD" firstAttribute="leading" secondItem="grQ-4c-o22" secondAttribute="leading" id="Qgb-hx-Zng"/>
<constraint firstItem="MN9-Rx-foD" firstAttribute="top" secondItem="grQ-4c-o22" secondAttribute="top" id="ZZm-Sk-o83"/>
<constraint firstAttribute="bottom" secondItem="Mrv-sA-Nuw" secondAttribute="bottom" id="ca9-ki-vgD"/>
<constraint firstAttribute="bottom" secondItem="Nj8-PM-Kqf" secondAttribute="bottom" constant="27" id="cry-id-f46"/>
<constraint firstItem="Mrv-sA-Nuw" firstAttribute="top" secondItem="grQ-4c-o22" secondAttribute="top" id="gZb-1z-CPx"/>
<constraint firstItem="Nj8-PM-Kqf" firstAttribute="top" secondItem="grQ-4c-o22" secondAttribute="top" constant="28" id="rdB-Pt-8ly"/>
<constraint firstAttribute="bottom" secondItem="MN9-Rx-foD" secondAttribute="bottom" id="vxW-5h-txe"/>
</constraints>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="posterImageView" destination="MN9-Rx-foD" id="tOI-0s-GLe"/>
<outlet property="titleLable" destination="Mrv-sA-Nuw" id="Khi-UM-B6w"/>
</connections>
<point key="canvasLocation" x="584" y="432"/>
</view>
</objects>
<resources>
<image name="TableViewArrow" width="27" height="27"/>
</resources>
</document>
//
// TZAssetCell.h
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
typedef enum : NSUInteger {
TZAssetCellTypePhoto = 0,
TZAssetCellTypeLivePhoto,
TZAssetCellTypeVideo,
TZAssetCellTypeAudio,
} TZAssetCellType;
@class TZAssetModel;
@interface TZAssetCell : UICollectionViewCell
@property (weak, nonatomic) IBOutlet UIButton *selectPhotoButton;
@property (nonatomic, strong) TZAssetModel *model;
@property (nonatomic, copy) void (^didSelectPhotoBlock)(BOOL);
@property (nonatomic, assign) TZAssetCellType type;
@end
@class TZAlbumModel;
@interface TZAlbumCell : UITableViewCell
@property (nonatomic, strong) TZAlbumModel *model;
@end
//
// TZAssetCell.m
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import "TZAssetCell.h"
#import "TZAssetModel.h"
#import "UIView+Layout.h"
#import "TZImageManager.h"
#import "TZImagePickerController.h"
@interface TZAssetCell ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView; // The photo / 照片
@property (weak, nonatomic) IBOutlet UIImageView *selectImageView;
@property (weak, nonatomic) IBOutlet UIView *bottomView;
@property (weak, nonatomic) IBOutlet UILabel *timeLength;
@end
@implementation TZAssetCell
- (void)awakeFromNib {
self.timeLength.font = [UIFont boldSystemFontOfSize:11];
}
- (void)setModel:(TZAssetModel *)model {
_model = model;
[[TZImageManager manager] getPhotoWithAsset:model.asset photoWidth:self.width completion:^(UIImage *photo, NSDictionary *info) {
self.imageView.image = photo;
}];
self.selectPhotoButton.selected = model.isSelected;
self.selectImageView.image = self.selectPhotoButton.isSelected ? [UIImage imageNamed:@"photo_sel_photoPickerVc"] : [UIImage imageNamed:@"photo_def_photoPickerVc"];
self.type = TZAssetCellTypePhoto;
if (model.type == TZAssetModelMediaTypeLivePhoto) self.type = TZAssetCellTypeLivePhoto;
else if (model.type == TZAssetModelMediaTypeAudio) self.type = TZAssetCellTypeAudio;
else if (model.type == TZAssetModelMediaTypeVideo) {
self.type = TZAssetCellTypeVideo;
self.timeLength.text = model.timeLength;
}
}
- (void)setType:(TZAssetCellType)type {
_type = type;
if (type == TZAssetCellTypePhoto || type == TZAssetCellTypeLivePhoto) {
_selectImageView.hidden = NO;
_selectPhotoButton.hidden = NO;
_bottomView.hidden = YES;
} else {
_selectImageView.hidden = YES;
_selectPhotoButton.hidden = YES;
_bottomView.hidden = NO;
}
}
- (IBAction)selectPhotoButtonClick:(UIButton *)sender {
if (self.didSelectPhotoBlock) {
self.didSelectPhotoBlock(sender.isSelected);
}
self.selectImageView.image = sender.isSelected ? [UIImage imageNamed:@"photo_sel_photoPickerVc"] : [UIImage imageNamed:@"photo_def_photoPickerVc"];
if (sender.isSelected) {
[UIView showOscillatoryAnimationWithLayer:_selectImageView.layer type:TZOscillatoryAnimationToBigger];
}
}
@end
@interface TZAlbumCell ()
@property (weak, nonatomic) IBOutlet UIImageView *posterImageView;
@property (weak, nonatomic) IBOutlet UILabel *titleLable;
@end
@implementation TZAlbumCell
- (void)awakeFromNib {
self.posterImageView.clipsToBounds = YES;
}
- (void)setModel:(TZAlbumModel *)model {
_model = model;
NSMutableAttributedString *nameString = [[NSMutableAttributedString alloc] initWithString:model.name attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor blackColor]}];
NSAttributedString *countString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@" (%zd)",model.count] attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor lightGrayColor]}];
[nameString appendAttributedString:countString];
self.titleLable.attributedText = nameString;
[[TZImageManager manager] getPostImageWithAlbumModel:model completion:^(UIImage *postImage) {
self.posterImageView.image = postImage;
}];
}
/// For fitting iOS6
- (void)layoutSubviews {
if (iOS7Later) [super layoutSubviews];
}
- (void)layoutSublayersOfLayer:(CALayer *)layer {
if (iOS7Later) [super layoutSublayersOfLayer:layer];
}
@end
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="14F1509" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="gTV-IL-0wX" customClass="TZAssetCell">
<rect key="frame" x="0.0" y="0.0" width="80" height="80"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="80" height="80"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Yy8-bS-MRb">
<rect key="frame" x="0.0" y="0.0" width="80" height="80"/>
</imageView>
<button opaque="NO" contentMode="topRight" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="dNW-bU-KEf">
<rect key="frame" x="36" y="0.0" width="44" height="44"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="35a-xB-9kD"/>
<constraint firstAttribute="width" constant="44" id="c1d-za-0ro"/>
</constraints>
<connections>
<action selector="selectPhotoButtonClick:" destination="gTV-IL-0wX" eventType="touchUpInside" id="XWB-QX-A3P"/>
</connections>
</button>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="photo_def_photoPickerVc@2x" translatesAutoresizingMaskIntoConstraints="NO" id="ova-UI-tV1">
<rect key="frame" x="53" y="0.0" width="27" height="27"/>
<constraints>
<constraint firstAttribute="height" constant="27" id="QwD-vG-feB"/>
<constraint firstAttribute="width" constant="27" id="nLi-1g-3Sr"/>
</constraints>
</imageView>
<view alpha="0.80000000000000004" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="a4Q-ox-UyB" userLabel="VideoView">
<rect key="frame" x="0.0" y="63" width="80" height="17"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="VideoSendIcon" translatesAutoresizingMaskIntoConstraints="NO" id="N0z-qh-hcG">
<rect key="frame" x="8" y="0.0" width="17" height="17"/>
<constraints>
<constraint firstAttribute="width" constant="17" id="1p5-vb-QAu"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="00:12" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BXd-4T-A1o">
<rect key="frame" x="25" y="0.0" width="49" height="17"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="height" constant="17" id="C2G-yW-u1e"/>
<constraint firstAttribute="trailing" secondItem="BXd-4T-A1o" secondAttribute="trailing" constant="6" id="ET8-ta-Vkb"/>
<constraint firstItem="BXd-4T-A1o" firstAttribute="top" secondItem="a4Q-ox-UyB" secondAttribute="top" id="Uks-Bh-Vdg"/>
<constraint firstAttribute="bottom" secondItem="BXd-4T-A1o" secondAttribute="bottom" id="Uvh-dT-9bi"/>
<constraint firstItem="BXd-4T-A1o" firstAttribute="leading" secondItem="N0z-qh-hcG" secondAttribute="trailing" id="cHE-ea-FX4"/>
<constraint firstItem="N0z-qh-hcG" firstAttribute="top" secondItem="a4Q-ox-UyB" secondAttribute="top" id="dHJ-vE-Lsl"/>
<constraint firstItem="N0z-qh-hcG" firstAttribute="leading" secondItem="a4Q-ox-UyB" secondAttribute="leading" constant="8" id="iq8-Yc-XwI"/>
<constraint firstAttribute="bottom" secondItem="N0z-qh-hcG" secondAttribute="bottom" id="nr0-UX-ihC"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<constraints>
<constraint firstAttribute="trailing" secondItem="a4Q-ox-UyB" secondAttribute="trailing" id="4hT-aw-TYf"/>
<constraint firstAttribute="trailing" secondItem="Yy8-bS-MRb" secondAttribute="trailing" id="5Gq-So-iWs"/>
<constraint firstAttribute="trailing" secondItem="ova-UI-tV1" secondAttribute="trailing" id="GRy-ue-4Qr"/>
<constraint firstItem="ova-UI-tV1" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="Glw-Yv-tQT"/>
<constraint firstAttribute="bottom" secondItem="Yy8-bS-MRb" secondAttribute="bottom" id="Gsd-C1-gkC"/>
<constraint firstItem="Yy8-bS-MRb" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="Iv6-lu-ZGo"/>
<constraint firstItem="a4Q-ox-UyB" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="OZ3-n0-vkk"/>
<constraint firstAttribute="trailing" secondItem="dNW-bU-KEf" secondAttribute="trailing" id="Ofl-9X-gij"/>
<constraint firstAttribute="bottom" secondItem="a4Q-ox-UyB" secondAttribute="bottom" id="X3A-bD-wef"/>
<constraint firstItem="dNW-bU-KEf" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" id="epf-0O-UJg"/>
<constraint firstItem="Yy8-bS-MRb" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" id="s7f-8d-u0B"/>
</constraints>
<connections>
<outlet property="bottomView" destination="a4Q-ox-UyB" id="3k1-bw-ZPW"/>
<outlet property="imageView" destination="Yy8-bS-MRb" id="q1a-cl-0zn"/>
<outlet property="selectImageView" destination="ova-UI-tV1" id="xXa-XQ-rUc"/>
<outlet property="selectPhotoButton" destination="dNW-bU-KEf" id="vDo-uv-cp6"/>
<outlet property="timeLength" destination="BXd-4T-A1o" id="dbx-Cf-g5W"/>
</connections>
</collectionViewCell>
</objects>
<resources>
<image name="VideoSendIcon" width="27" height="27"/>
<image name="photo_def_photoPickerVc@2x" width="27" height="27"/>
</resources>
</document>
//
// TZAssetModel.h
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
typedef enum : NSUInteger {
TZAssetModelMediaTypePhoto = 0,
TZAssetModelMediaTypeLivePhoto,
TZAssetModelMediaTypeVideo,
TZAssetModelMediaTypeAudio
} TZAssetModelMediaType;
@class PHAsset;
@interface TZAssetModel : NSObject
@property (nonatomic, strong) id asset; ///< PHAsset or ALAsset
@property (nonatomic, assign) BOOL isSelected; ///< The select status of a photo, default is No
@property (nonatomic, assign) TZAssetModelMediaType type;
@property (nonatomic, copy) NSString *timeLength;
/// Init a photo dataModel With a asset
/// 用一个PHAsset/ALAsset实例,初始化一个照片模型
+ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type;
+ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type timeLength:(NSString *)timeLength;
@end
@class PHFetchResult;
@interface TZAlbumModel : NSObject
@property (nonatomic, strong) NSString *name; ///< The album name
@property (nonatomic, assign) NSInteger count; ///< Count of photos the album contain
@property (nonatomic, strong) id result; ///< PHFetchResult<PHAsset> or ALAssetsGroup<ALAsset>
@end
\ No newline at end of file
//
// TZAssetModel.m
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import "TZAssetModel.h"
@implementation TZAssetModel
+ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type{
TZAssetModel *model = [[TZAssetModel alloc] init];
model.asset = asset;
model.isSelected = NO;
model.type = type;
return model;
}
+ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type timeLength:(NSString *)timeLength {
TZAssetModel *model = [self modelWithAsset:asset type:type];
model.timeLength = timeLength;
return model;
}
@end
@implementation TZAlbumModel
//+ (instancetype)modelWithPHFetchResult:(id)result count:(NSInteger)count name:(NSString *)name {
// TZAlbumModel *model = [[TZAlbumModel alloc] init];
// model.result = result;
// model.count = count;
// model.name = name;
// return model;
//}
@end
\ No newline at end of file
//
// TZImageManager.h
// TZImagePickerController
//
// Created by 谭真 on 16/1/4.
// Copyright © 2016年 谭真. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
@class TZAlbumModel,TZAssetModel;
@interface TZImageManager : NSObject
+ (instancetype)manager;
/// Return YES if Authorized 返回YES如果得到了授权
- (BOOL)authorizationStatusAuthorized;
/// Get Album 获得相册/相册数组
- (void)getCameraRollAlbum:(BOOL)allowPickingVideo completion:(void (^)(TZAlbumModel *model))completion;
- (void)getAllAlbums:(BOOL)allowPickingVideo completion:(void (^)(NSArray<TZAlbumModel *> *models))completion;
/// Get Asset 获得Asset数组
- (void)getAssetsFromFetchResult:(id)result allowPickingVideo:(BOOL)allowPickingVideo completion:(void (^)(NSArray<TZAssetModel *> *models))completion;
/// Get photo 获得照片
- (void)getPostImageWithAlbumModel:(TZAlbumModel *)model completion:(void (^)(UIImage *postImage))completion;
- (void)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info))completion;
- (void)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info))completion;
/// Get video 获得视频
- (void)getVideoWithAsset:(id)asset completion:(void (^)(AVPlayerItem * playerItem, NSDictionary * info))completion;
/// Get photo bytes 获得一组照片的大小
- (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString *totalBytes))completion;
@end
//
// TZImageManager.m
// TZImagePickerController
//
// Created by 谭真 on 16/1/4.
// Copyright © 2016年 谭真. All rights reserved.
//
#import "TZImageManager.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import <Photos/Photos.h>
#import "TZAssetModel.h"
#import "TZImagePickerController.h"
@interface TZImageManager ()
@property (nonatomic, strong) ALAssetsLibrary *assetLibrary;
@end
@implementation TZImageManager
+ (instancetype)manager {
static TZImageManager *manager;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[self alloc] init];
});
return manager;
}
- (ALAssetsLibrary *)assetLibrary {
if (_assetLibrary == nil) _assetLibrary = [[ALAssetsLibrary alloc] init];
return _assetLibrary;
}
/// Return YES if Authorized 返回YES如果得到了授权
- (BOOL)authorizationStatusAuthorized {
if (iOS8Later) {
if ([PHPhotoLibrary authorizationStatus] == PHAuthorizationStatusAuthorized) return YES;
} else {
if ([ALAssetsLibrary authorizationStatus] == ALAuthorizationStatusAuthorized) return YES;
}
return NO;
}
#pragma mark - Get Album
/// Get Album 获得相册/相册数组
- (void)getCameraRollAlbum:(BOOL)allowPickingVideo completion:(void (^)(TZAlbumModel *))completion{
__block TZAlbumModel *model;
if (iOS8Later) {
PHFetchOptions *option = [[PHFetchOptions alloc] init];
if (!allowPickingVideo) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage];
option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil];
for (PHAssetCollection *collection in smartAlbums) {
if ([collection.localizedTitle isEqualToString:@"Camera Roll"]) {
PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option];
model = [self modelWithResult:fetchResult name:collection.localizedTitle];
if (completion) completion(model);
break;
}
}
} else {
[self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if ([group numberOfAssets] < 1) return;
NSString *name = [group valueForProperty:ALAssetsGroupPropertyName];
if ([name isEqualToString:@"Camera Roll"] || [name isEqualToString:@"相机胶卷"]) {
model = [self modelWithResult:group name:name];
if (completion) completion(model);
*stop = YES;
}
} failureBlock:nil];
}
}
- (void)getAllAlbums:(BOOL)allowPickingVideo completion:(void (^)(NSArray<TZAlbumModel *> *))completion{
NSMutableArray *albumArr = [NSMutableArray array];
if (iOS8Later) {
PHFetchOptions *option = [[PHFetchOptions alloc] init];
if (!allowPickingVideo) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage];
option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
PHAssetCollectionSubtype smartAlbumSubtype = PHAssetCollectionSubtypeSmartAlbumUserLibrary | PHAssetCollectionSubtypeSmartAlbumRecentlyAdded | PHAssetCollectionSubtypeSmartAlbumVideos;
// For iOS 9, We need to show ScreenShots Album && SelfPortraits Album
if (iOS9Later) {
smartAlbumSubtype = PHAssetCollectionSubtypeSmartAlbumUserLibrary | PHAssetCollectionSubtypeSmartAlbumRecentlyAdded | PHAssetCollectionSubtypeSmartAlbumScreenshots | PHAssetCollectionSubtypeSmartAlbumSelfPortraits | PHAssetCollectionSubtypeSmartAlbumVideos;
}
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:smartAlbumSubtype options:nil];
for (PHAssetCollection *collection in smartAlbums) {
PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option];
if (fetchResult.count < 1) continue;
if ([collection.localizedTitle containsString:@"Deleted"]) continue;
if ([collection.localizedTitle isEqualToString:@"Camera Roll"]) {
[albumArr insertObject:[self modelWithResult:fetchResult name:collection.localizedTitle] atIndex:0];
} else {
[albumArr addObject:[self modelWithResult:fetchResult name:collection.localizedTitle]];
}
}
PHFetchResult *albums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular | PHAssetCollectionSubtypeAlbumSyncedAlbum options:nil];
for (PHAssetCollection *collection in albums) {
PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option];
if (fetchResult.count < 1) continue;
if ([collection.localizedTitle isEqualToString:@"My Photo Stream"]) {
[albumArr insertObject:[self modelWithResult:fetchResult name:collection.localizedTitle] atIndex:1];
} else {
[albumArr addObject:[self modelWithResult:fetchResult name:collection.localizedTitle]];
}
}
if (completion) completion(albumArr);
} else {
[self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if (group == nil) {
if (completion) completion(albumArr);
}
if ([group numberOfAssets] < 1) return;
NSString *name = [group valueForProperty:ALAssetsGroupPropertyName];
if ([name isEqualToString:@"Camera Roll"] || [name isEqualToString:@"相机胶卷"]) {
[albumArr insertObject:[self modelWithResult:group name:name] atIndex:0];
} else if ([name isEqualToString:@"My Photo Stream"] || [name isEqualToString:@"我的照片流"]) {
[albumArr insertObject:[self modelWithResult:group name:name] atIndex:1];
} else {
[albumArr addObject:[self modelWithResult:group name:name]];
}
} failureBlock:nil];
}
}
#pragma mark - Get Asset
/// Get Asset 获得照片数组
- (void)getAssetsFromFetchResult:(id)result allowPickingVideo:(BOOL)allowPickingVideo completion:(void (^)(NSArray<TZAssetModel *> *))completion {
NSMutableArray *photoArr = [NSMutableArray array];
if ([result isKindOfClass:[PHFetchResult class]]) {
for (PHAsset *asset in result) {
TZAssetModelMediaType type = TZAssetModelMediaTypePhoto;
if (asset.mediaType == PHAssetMediaTypeVideo) type = TZAssetModelMediaTypeVideo;
else if (asset.mediaType == PHAssetMediaTypeAudio) type = TZAssetModelMediaTypeAudio;
else if (asset.mediaType == PHAssetMediaTypeImage) {
if (asset.mediaSubtypes == PHAssetMediaSubtypePhotoLive) type = TZAssetModelMediaTypeLivePhoto;
}
NSString *timeLength = type == TZAssetModelMediaTypeVideo ? [NSString stringWithFormat:@"%0.0f",asset.duration] : @"";
timeLength = [self getNewTimeFromDurationSecond:timeLength.integerValue];
[photoArr addObject:[TZAssetModel modelWithAsset:asset type:type timeLength:timeLength]];
}
if (completion) completion(photoArr);
} else if ([result isKindOfClass:[ALAssetsGroup class]]) {
ALAssetsGroup *gruop = (ALAssetsGroup *)result;
if (!allowPickingVideo) [gruop setAssetsFilter:[ALAssetsFilter allPhotos]];
[gruop enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result == nil) {
if (completion) completion(photoArr);
}
TZAssetModelMediaType type = TZAssetModelMediaTypePhoto;
if (!allowPickingVideo){
[photoArr addObject:[TZAssetModel modelWithAsset:result type:type]];
return;
}
/// Allow picking video
if ([[result valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypeVideo]) {
type = TZAssetModelMediaTypeVideo;
NSTimeInterval duration = [[result valueForProperty:ALAssetPropertyDuration] integerValue];
NSString *timeLength = [NSString stringWithFormat:@"%0.0f",duration];
timeLength = [self getNewTimeFromDurationSecond:timeLength.integerValue];
[photoArr addObject:[TZAssetModel modelWithAsset:result type:type timeLength:timeLength]];
} else {
[photoArr addObject:[TZAssetModel modelWithAsset:result type:type]];
}
}];
}
}
- (NSString *)getNewTimeFromDurationSecond:(NSInteger)duration {
NSString *newTime;
if (duration < 10) {
newTime = [NSString stringWithFormat:@"0:0%zd",duration];
} else if (duration < 60) {
newTime = [NSString stringWithFormat:@"0:%zd",duration];
} else {
NSInteger min = duration / 60;
NSInteger sec = duration - (min * 60);
if (sec < 10) {
newTime = [NSString stringWithFormat:@"%zd:0%zd",min,sec];
} else {
newTime = [NSString stringWithFormat:@"%zd:%zd",min,sec];
}
}
return newTime;
}
/// Get photo bytes 获得一组照片的大小
- (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString *totalBytes))completion {
__block NSInteger dataLength = 0;
for (NSInteger i = 0; i < photos.count; i++) {
TZAssetModel *model = photos[i];
if ([model.asset isKindOfClass:[PHAsset class]]) {
[[PHImageManager defaultManager] requestImageDataForAsset:model.asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
if (model.type != TZAssetModelMediaTypeVideo) dataLength += imageData.length;
if (i >= photos.count - 1) {
NSString *bytes = [self getBytesFromDataLength:dataLength];
if (completion) completion(bytes);
}
}];
} else if ([model.asset isKindOfClass:[ALAsset class]]) {
ALAssetRepresentation *representation = [model.asset defaultRepresentation];
if (model.type != TZAssetModelMediaTypeVideo) dataLength += (NSInteger)representation.size;
if (i >= photos.count - 1) {
NSString *bytes = [self getBytesFromDataLength:dataLength];
if (completion) completion(bytes);
}
}
}
}
- (NSString *)getBytesFromDataLength:(NSInteger)dataLength {
NSString *bytes;
if (dataLength >= 0.1 * (1024 * 1024)) {
bytes = [NSString stringWithFormat:@"%0.1fM",dataLength/1024/1024.0];
} else if (dataLength >= 1024) {
bytes = [NSString stringWithFormat:@"%0.0fK",dataLength/1024.0];
} else {
bytes = [NSString stringWithFormat:@"%zdB",dataLength];
}
return bytes;
}
#pragma mark - Get Photo
/// Get photo 获得照片本身
- (void)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *, NSDictionary *))completion {
[self getPhotoWithAsset:asset photoWidth:[UIScreen mainScreen].bounds.size.width completion:completion];
}
- (void)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *, NSDictionary *))completion {
if ([asset isKindOfClass:[PHAsset class]]) {
PHAsset *phAsset = (PHAsset *)asset;
CGFloat aspectRatio = phAsset.pixelWidth / (CGFloat)phAsset.pixelHeight;
CGFloat multiple = [UIScreen mainScreen].scale;
CGFloat pixelWidth = photoWidth * multiple;
CGFloat pixelHeight = pixelWidth / aspectRatio;
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:CGSizeMake(pixelWidth, pixelHeight) contentMode:PHImageContentModeAspectFit options:nil resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue]);
if (downloadFinined) {
if (completion) completion(result,info);
}
}];
} else if ([asset isKindOfClass:[ALAsset class]]) {
ALAsset *alAsset = (ALAsset *)asset;
ALAssetRepresentation *assetRep = [alAsset defaultRepresentation];
CGImageRef imageRef;
if (photoWidth == [UIScreen mainScreen].bounds.size.width) {
imageRef = [assetRep fullScreenImage];
} else {
imageRef = alAsset.thumbnail;
}
UIImage *image = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:(UIImageOrientation)[assetRep orientation]];
if (completion) completion(image,nil);
}
}
- (void)getPostImageWithAlbumModel:(TZAlbumModel *)model completion:(void (^)(UIImage *))completion {
if (iOS8Later) {
[[TZImageManager manager] getPhotoWithAsset:[model.result lastObject] photoWidth:80 completion:^(UIImage *photo, NSDictionary *info) {
if (completion) completion(photo);
}];
} else {
ALAssetsGroup *gruop = model.result;
UIImage *postImage = [UIImage imageWithCGImage:gruop.posterImage];
if (completion) completion(postImage);
}
}
#pragma mark - Get Video
- (void)getVideoWithAsset:(id)asset completion:(void (^)(AVPlayerItem * _Nullable, NSDictionary * _Nullable))completion {
if ([asset isKindOfClass:[PHAsset class]]) {
[[PHImageManager defaultManager] requestPlayerItemForVideo:asset options:nil resultHandler:^(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info) {
if (completion) completion(playerItem,info);
}];
} else if ([asset isKindOfClass:[ALAsset class]]) {
ALAsset *alAsset = (ALAsset *)asset;
ALAssetRepresentation *defaultRepresentation = [alAsset defaultRepresentation];
NSString *uti = [defaultRepresentation UTI];
NSURL *videoURL = [[asset valueForProperty:ALAssetPropertyURLs] valueForKey:uti];
AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:videoURL];
if (completion && playerItem) completion(playerItem,nil);
}
}
#pragma mark - Private Method
- (TZAlbumModel *)modelWithResult:(id)result name:(NSString *)name{
TZAlbumModel *model = [[TZAlbumModel alloc] init];
model.result = result;
model.name = [self getNewAlbumName:name];
if ([result isKindOfClass:[PHFetchResult class]]) {
PHFetchResult *fetchResult = (PHFetchResult *)result;
model.count = fetchResult.count;
} else if ([result isKindOfClass:[ALAssetsGroup class]]) {
ALAssetsGroup *gruop = (ALAssetsGroup *)result;
model.count = [gruop numberOfAssets];
}
return model;
}
- (NSString *)getNewAlbumName:(NSString *)name {
if (iOS8Later) {
NSString *newName;
if ([name containsString:@"Roll"]) newName = @"相机胶卷";
else if ([name containsString:@"Stream"]) newName = @"我的照片流";
else if ([name containsString:@"Added"]) newName = @"最近添加";
else if ([name containsString:@"Selfies"]) newName = @"自拍";
else if ([name containsString:@"shots"]) newName = @"截屏";
else if ([name containsString:@"Videos"]) newName = @"视频";
else newName = name;
return newName;
} else {
return name;
}
}
@end
//
// TZImagePickerController.h
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
#define kNaviBarAndBottonBarBgColor ([UIColor colorWithRed:(34/255.0) green:(34/255.0) blue:(34/255.0) alpha:1.0])
#define kOKButtonTitleColorNormal ([UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0])
#define kOKButtonTitleColorDisabled ([UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:0.5])
#define iOS7Later ([UIDevice currentDevice].systemVersion.floatValue >= 7.0f)
#define iOS8Later ([UIDevice currentDevice].systemVersion.floatValue >= 8.0f)
#define iOS9Later ([UIDevice currentDevice].systemVersion.floatValue >= 9.0f)
@protocol TZImagePickerControllerDelegate;
@interface TZImagePickerController : UINavigationController
/// Use this init method / 用这个初始化方法
- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount delegate:(id<TZImagePickerControllerDelegate>)delegate;
/// Default is 9 / 默认最大可选9张图片
@property (nonatomic, assign) NSInteger maxImagesCount;
/// Default is YES.if set NO, the original photo button will hide. user can't picking original photo.
/// 默认为YES,如果设置为NO,原图按钮将隐藏,用户不能选择发送原图
@property (nonatomic, assign) BOOL allowPickingOriginalPhoto;
/// Default is YES.if set NO, user can't picking video.
/// 默认为YES,如果设置为NO,用户将不能选择发送视频
@property (nonatomic, assign) BOOL allowPickingVideo;
- (void)showAlertWithTitle:(NSString *)title;
- (void)showProgressHUD;
- (void)hideProgressHUD;
// The picker does not dismiss itself; when client dismisses it these handle will be called.
// The second array will be a empty array if user not picking original photo.
// 这个照片选择器不会自己dismiss,用户dismiss这个选择器的时候,会执行下面的handle
// 如果用户没有选择发送原图,第二个数组将是空数组
@property (nonatomic, copy) void (^didFinishPickingPhotosHandle)(NSArray<UIImage *> *photos,NSArray *assets);
@property (nonatomic, copy) void (^didFinishPickingPhotosWithInfosHandle)(NSArray<UIImage *> *photos,NSArray *assets,NSArray<NSDictionary *> *infos);
@property (nonatomic, copy) void (^imagePickerControllerDidCancelHandle)();
// If user picking a video, this handle will be called.
// If system version > iOS8,asset is kind of PHAsset class, else is ALAsset class.
// 如果用户选择了一个视频,下面的handle会被执行
// 如果系统版本大于iOS8,asset是PHAsset类的对象,否则是ALAsset类的对象
@property (nonatomic, copy) void (^didFinishPickingVideoHandle)(UIImage *coverImage,id asset);
@property (nonatomic, weak) id<TZImagePickerControllerDelegate> pickerDelegate;
@end
@protocol TZImagePickerControllerDelegate <NSObject>
@optional
// The picker does not dismiss itself; the client dismisses it in these callbacks.
// Assets will be a empty array if user not picking original photo.
// 这个照片选择器不会自己dismiss,用户dismiss这个选择器的时候,会走下面的回调
// 如果用户没有选择发送原图,Assets将是空数组
- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray<UIImage *> *)photos sourceAssets:(NSArray *)assets;
- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray<UIImage *> *)photos sourceAssets:(NSArray *)assets infos:(NSArray<NSDictionary *> *)infos;
- (void)imagePickerControllerDidCancel:(TZImagePickerController *)picker;
// If user picking a video, this callback will be called.
// If system version > iOS8,asset is kind of PHAsset class, else is ALAsset class.
// 如果用户选择了一个视频,下面的handle会被执行
// 如果系统版本大于iOS8,asset是PHAsset类的对象,否则是ALAsset类的对象
- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingVideo:(UIImage *)coverImage sourceAssets:(id)asset;
@end
@interface TZAlbumPickerController : UIViewController
@end
//
// TZImagePickerController.m
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import "TZImagePickerController.h"
#import "TZPhotoPickerController.h"
#import "TZPhotoPreviewController.h"
#import "TZAssetModel.h"
#import "TZAssetCell.h"
#import "UIView+Layout.h"
#import "TZImageManager.h"
@interface TZImagePickerController () {
BOOL _pushToPhotoPickerVc;
UIButton *_progressHUD;
UIView *_HUDContainer;
UIActivityIndicatorView *_HUDIndicatorView;
UILabel *_HUDLable;
}
@end
@implementation TZImagePickerController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationBar.barStyle = UIBarStyleBlack;
self.navigationBar.translucent = YES;
[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
[UIApplication sharedApplication].statusBarHidden = NO;
if (iOS7Later) {
self.navigationBar.barTintColor = kNaviBarAndBottonBarBgColor;
self.navigationBar.tintColor = [UIColor whiteColor];
self.automaticallyAdjustsScrollViewInsets = NO;
UIBarButtonItem *barItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[TZImagePickerController class]]];
NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
textAttrs[NSForegroundColorAttributeName] = [UIColor whiteColor];
textAttrs[NSFontAttributeName] = [UIFont systemFontOfSize:15];
[barItem setTitleTextAttributes:textAttrs forState:UIControlStateNormal];
}
}
- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount delegate:(id<TZImagePickerControllerDelegate>)delegate {
TZAlbumPickerController *albumPickerVc = [[TZAlbumPickerController alloc] init];
self = [super initWithRootViewController:albumPickerVc];
if (self) {
self.maxImagesCount = maxImagesCount > 0 ? maxImagesCount : 9; // Default is 9 / 默认最大可选9张图片
self.pickerDelegate = delegate;
// Allow user picking original photo and video, you also can set No after this method
// 默认准许用户选择原图和视频, 你也可以在这个方法后置为NO
_allowPickingOriginalPhoto = YES;
_allowPickingVideo = YES;
if (![[TZImageManager manager] authorizationStatusAuthorized]) {
UILabel *tipLable = [[UILabel alloc] init];
tipLable.frame = CGRectMake(8, 0, self.view.width - 16, 300);
tipLable.textAlignment = NSTextAlignmentCenter;
tipLable.numberOfLines = 0;
tipLable.font = [UIFont systemFontOfSize:16];
tipLable.textColor = [UIColor blackColor];
NSString *appName = [[NSBundle mainBundle].infoDictionary valueForKey:@"CFBundleDisplayName"];
if (!appName) appName = [[NSBundle mainBundle].infoDictionary valueForKey:@"CFBundleName"];
tipLable.text = [NSString stringWithFormat:@"请在%@的\"设置-隐私-照片\"选项中,\r允许%@访问你的手机相册。",[UIDevice currentDevice].model,appName];
[self.view addSubview:tipLable];
} else {
_pushToPhotoPickerVc = YES;
if (_pushToPhotoPickerVc) {
TZPhotoPickerController *photoPickerVc = [[TZPhotoPickerController alloc] init];
[[TZImageManager manager] getCameraRollAlbum:self.allowPickingVideo completion:^(TZAlbumModel *model) {
photoPickerVc.model = model;
[self pushViewController:photoPickerVc animated:YES];
_pushToPhotoPickerVc = NO;
}];
}
}
}
return self;
}
- (void)showAlertWithTitle:(NSString *)title {
if (iOS8Later) {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"我知道了" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alertController animated:YES completion:nil];
} else {
[[[UIAlertView alloc] initWithTitle:title message:nil delegate:nil cancelButtonTitle:@"我知道了" otherButtonTitles:nil, nil] show];
}
}
- (void)showProgressHUD {
if (!_progressHUD) {
_progressHUD = [UIButton buttonWithType:UIButtonTypeCustom];
[_progressHUD setBackgroundColor:[UIColor clearColor]];
_HUDContainer = [[UIView alloc] init];
_HUDContainer.frame = CGRectMake((self.view.width - 120) / 2, (self.view.height - 90) / 2, 120, 90);
_HUDContainer.layer.cornerRadius = 8;
_HUDContainer.clipsToBounds = YES;
_HUDContainer.backgroundColor = [UIColor darkGrayColor];
_HUDContainer.alpha = 0.7;
_HUDIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
_HUDIndicatorView.frame = CGRectMake(45, 15, 30, 30);
_HUDLable = [[UILabel alloc] init];
_HUDLable.frame = CGRectMake(0,40, 120, 50);
_HUDLable.textAlignment = NSTextAlignmentCenter;
_HUDLable.text = @"正在处理...";
_HUDLable.font = [UIFont systemFontOfSize:15];
_HUDLable.textColor = [UIColor whiteColor];
[_HUDContainer addSubview:_HUDLable];
[_HUDContainer addSubview:_HUDIndicatorView];
[_progressHUD addSubview:_HUDContainer];
}
[_HUDIndicatorView startAnimating];
[[UIApplication sharedApplication].keyWindow addSubview:_progressHUD];
}
- (void)hideProgressHUD {
if (_progressHUD) {
[_HUDIndicatorView stopAnimating];
[_progressHUD removeFromSuperview];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
if (iOS7Later) viewController.automaticallyAdjustsScrollViewInsets = NO;
if (self.childViewControllers.count > 0) {
UIButton *backButton = [[UIButton alloc] initWithFrame:CGRectMake(3, 0, 44, 44)];
[backButton setImage:[UIImage imageNamed:@"navi_back"] forState:UIControlStateNormal];
backButton.imageEdgeInsets = UIEdgeInsetsMake(0, -5, 0, 0);
[backButton setTitle:@"返回" forState:UIControlStateNormal];
backButton.titleLabel.font = [UIFont systemFontOfSize:15];
[backButton addTarget:self action:@selector(popViewControllerAnimated:) forControlEvents:UIControlEventTouchUpInside];
viewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
}
[super pushViewController:viewController animated:animated];
}
@end
@interface TZAlbumPickerController ()<UITableViewDataSource,UITableViewDelegate> {
UITableView *_tableView;
NSMutableArray *_albumArr;
}
@end
@implementation TZAlbumPickerController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"照片";
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStylePlain target:self action:@selector(cancel)];
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
[[TZImageManager manager] getAllAlbums:imagePickerVc.allowPickingVideo completion:^(NSArray<TZAlbumModel *> *models) {
_albumArr = [NSMutableArray arrayWithArray:models];
[self configTableView];
}];
}
- (void)configTableView {
CGFloat top = 44;
if (iOS7Later) top += 20;
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, top, self.view.width, self.view.height - top) style:UITableViewStylePlain];
_tableView.rowHeight = 70;
_tableView.tableFooterView = [[UIView alloc] init];
_tableView.dataSource = self;
_tableView.delegate = self;
[_tableView registerNib:[UINib nibWithNibName:@"TZAlbumCell" bundle:nil] forCellReuseIdentifier:@"TZAlbumCell"];
[self.view addSubview:_tableView];
}
#pragma mark - Click Event
- (void)cancel {
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerControllerDidCancel:)]) {
[imagePickerVc.pickerDelegate imagePickerControllerDidCancel:imagePickerVc];
}
if (imagePickerVc.imagePickerControllerDidCancelHandle) {
imagePickerVc.imagePickerControllerDidCancelHandle();
}
}
#pragma mark - UITableViewDataSource && Delegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _albumArr.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TZAlbumCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TZAlbumCell"];
cell.model = _albumArr[indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
TZPhotoPickerController *photoPickerVc = [[TZPhotoPickerController alloc] init];
photoPickerVc.model = _albumArr[indexPath.row];
[self.navigationController pushViewController:photoPickerVc animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
@end
//
// TZPhotoPickerController.h
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
@class TZAlbumModel;
@interface TZPhotoPickerController : UIViewController
@property (nonatomic, strong) TZAlbumModel *model;
@end
//
// TZPhotoPickerController.m
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import "TZPhotoPickerController.h"
#import "TZImagePickerController.h"
#import "TZPhotoPreviewController.h"
#import "TZAssetCell.h"
#import "TZAssetModel.h"
#import "UIView+Layout.h"
#import "TZImageManager.h"
#import "TZVideoPlayerController.h"
@interface TZPhotoPickerController ()<UICollectionViewDataSource,UICollectionViewDelegate> {
UICollectionView *_collectionView;
NSMutableArray *_photoArr;
UIButton *_previewButton;
UIButton *_okButton;
UIImageView *_numberImageView;
UILabel *_numberLable;
UIButton *_originalPhotoButton;
UILabel *_originalPhotoLable;
BOOL _isSelectOriginalPhoto;
BOOL _shouldScrollToBottom;
}
@property (nonatomic, strong) NSMutableArray *selectedPhotoArr;
@end
@implementation TZPhotoPickerController
- (NSMutableArray *)selectedPhotoArr {
if (_selectedPhotoArr == nil) _selectedPhotoArr = [NSMutableArray array];
return _selectedPhotoArr;
}
- (void)viewDidLoad {
[super viewDidLoad];
_shouldScrollToBottom = YES;
self.view.backgroundColor = [UIColor whiteColor];
self.navigationItem.title = _model.name;
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStylePlain target:self action:@selector(cancel)];
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
[[TZImageManager manager] getAssetsFromFetchResult:_model.result allowPickingVideo:imagePickerVc.allowPickingVideo completion:^(NSArray<TZAssetModel *> *models) {
_photoArr = [NSMutableArray arrayWithArray:models];
[self configCollectionView];
[self configBottomToolBar];
}];
}
- (void)configCollectionView {
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
CGFloat margin = 4;
CGFloat itemWH = (self.view.width - 2 * margin - 4) / 4 - margin;
layout.itemSize = CGSizeMake(itemWH, itemWH);
layout.minimumInteritemSpacing = margin;
layout.minimumLineSpacing = margin;
CGFloat top = margin + 44;
if (iOS7Later) top += 20;
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(margin, top, self.view.width - 2 * margin, self.view.height - 50 - top) collectionViewLayout:layout];
_collectionView.backgroundColor = [UIColor whiteColor];
_collectionView.dataSource = self;
_collectionView.delegate = self;
_collectionView.alwaysBounceHorizontal = NO;
if (iOS7Later) _collectionView.contentInset = UIEdgeInsetsMake(0, 0, 0, 2);
_collectionView.scrollIndicatorInsets = UIEdgeInsetsMake(0, 0, 0, -2);
_collectionView.contentSize = CGSizeMake(self.view.width, ((_model.count + 3) / 4) * self.view.width);
[self.view addSubview:_collectionView];
[_collectionView registerNib:[UINib nibWithNibName:@"TZAssetCell" bundle:nil] forCellWithReuseIdentifier:@"TZAssetCell"];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (_shouldScrollToBottom && _photoArr.count > 0) {
[_collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:(_photoArr.count - 1) inSection:0] atScrollPosition:UICollectionViewScrollPositionBottom animated:NO];
_shouldScrollToBottom = NO;
}
}
- (void)configBottomToolBar {
UIView *bottomToolBar = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.height - 50, self.view.width, 50)];
CGFloat rgb = 253 / 255.0;
bottomToolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:1.0];
_previewButton = [UIButton buttonWithType:UIButtonTypeCustom];
_previewButton.frame = CGRectMake(10, 3, 44, 44);
[_previewButton addTarget:self action:@selector(previewButtonClick) forControlEvents:UIControlEventTouchUpInside];
_previewButton.titleLabel.font = [UIFont systemFontOfSize:16];
[_previewButton setTitle:@"预览" forState:UIControlStateNormal];
[_previewButton setTitle:@"预览" forState:UIControlStateDisabled];
[_previewButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_previewButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled];
_previewButton.enabled = NO;
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
if (imagePickerVc.allowPickingOriginalPhoto) {
_originalPhotoButton = [UIButton buttonWithType:UIButtonTypeCustom];
_originalPhotoButton.frame = CGRectMake(50, self.view.height - 50, 130, 50);
_originalPhotoButton.imageEdgeInsets = UIEdgeInsetsMake(0, -8, 0, 0);
_originalPhotoButton.contentEdgeInsets = UIEdgeInsetsMake(0, -45, 0, 0);
[_originalPhotoButton addTarget:self action:@selector(originalPhotoButtonClick) forControlEvents:UIControlEventTouchUpInside];
_originalPhotoButton.titleLabel.font = [UIFont systemFontOfSize:16];
[_originalPhotoButton setTitle:@"原图" forState:UIControlStateNormal];
[_originalPhotoButton setTitle:@"原图" forState:UIControlStateSelected];
[_originalPhotoButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
[_originalPhotoButton setTitleColor:[UIColor blackColor] forState:UIControlStateSelected];
[_originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_def"] forState:UIControlStateNormal];
[_originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_sel"] forState:UIControlStateSelected];
_originalPhotoButton.enabled = _selectedPhotoArr.count > 0;
_originalPhotoLable = [[UILabel alloc] init];
_originalPhotoLable.frame = CGRectMake(70, 0, 60, 50);
_originalPhotoLable.textAlignment = NSTextAlignmentLeft;
_originalPhotoLable.font = [UIFont systemFontOfSize:16];
_originalPhotoLable.textColor = [UIColor blackColor];
if (_isSelectOriginalPhoto) [self getSelectedPhotoBytes];
}
_okButton = [UIButton buttonWithType:UIButtonTypeCustom];
_okButton.frame = CGRectMake(self.view.width - 44 - 12, 3, 44, 44);
_okButton.titleLabel.font = [UIFont systemFontOfSize:16];
[_okButton addTarget:self action:@selector(okButtonClick) forControlEvents:UIControlEventTouchUpInside];
[_okButton setTitle:@"确定" forState:UIControlStateNormal];
[_okButton setTitle:@"确定" forState:UIControlStateDisabled];
[_okButton setTitleColor:kOKButtonTitleColorNormal forState:UIControlStateNormal];
[_okButton setTitleColor:kOKButtonTitleColorDisabled forState:UIControlStateDisabled];
_okButton.enabled = NO;
_numberImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"photo_number_icon"]];
_numberImageView.frame = CGRectMake(self.view.width - 56 - 24, 12, 26, 26);
_numberImageView.hidden = _selectedPhotoArr.count <= 0;
_numberImageView.backgroundColor = [UIColor clearColor];
_numberLable = [[UILabel alloc] init];
_numberLable.frame = _numberImageView.frame;
_numberLable.font = [UIFont systemFontOfSize:16];
_numberLable.textColor = [UIColor whiteColor];
_numberLable.textAlignment = NSTextAlignmentCenter;
_numberLable.text = [NSString stringWithFormat:@"%zd",_selectedPhotoArr.count];
_numberLable.hidden = _selectedPhotoArr.count <= 0;
_numberLable.backgroundColor = [UIColor clearColor];
UIView *divide = [[UIView alloc] init];
CGFloat rgb2 = 222 / 255.0;
divide.backgroundColor = [UIColor colorWithRed:rgb2 green:rgb2 blue:rgb2 alpha:1.0];
divide.frame = CGRectMake(0, 0, self.view.width, 1);
[bottomToolBar addSubview:divide];
[bottomToolBar addSubview:_previewButton];
[bottomToolBar addSubview:_okButton];
[bottomToolBar addSubview:_numberImageView];
[bottomToolBar addSubview:_numberLable];
[self.view addSubview:bottomToolBar];
[self.view addSubview:_originalPhotoButton];
[_originalPhotoButton addSubview:_originalPhotoLable];
}
#pragma mark - Click Event
- (void)cancel {
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerControllerDidCancel:)]) {
[imagePickerVc.pickerDelegate imagePickerControllerDidCancel:imagePickerVc];
}
if (imagePickerVc.imagePickerControllerDidCancelHandle) {
imagePickerVc.imagePickerControllerDidCancelHandle();
}
}
- (void)previewButtonClick {
TZPhotoPreviewController *photoPreviewVc = [[TZPhotoPreviewController alloc] init];
photoPreviewVc.photoArr = [NSArray arrayWithArray:self.selectedPhotoArr];
[self pushPhotoPrevireViewController:photoPreviewVc];
}
- (void)originalPhotoButtonClick {
_originalPhotoButton.selected = !_originalPhotoButton.isSelected;
_isSelectOriginalPhoto = _originalPhotoButton.isSelected;
_originalPhotoLable.hidden = !_originalPhotoButton.isSelected;
if (_isSelectOriginalPhoto) [self getSelectedPhotoBytes];
}
- (void)okButtonClick {
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
[imagePickerVc showProgressHUD];
NSMutableArray *photos = [NSMutableArray array];
NSMutableArray *assets = [NSMutableArray array];
NSMutableArray *infoArr = [NSMutableArray array];
for (NSInteger i = 0; i < _selectedPhotoArr.count; i++) {
TZAssetModel *model = _selectedPhotoArr[i];
[[TZImageManager manager] getPhotoWithAsset:model.asset completion:^(UIImage *photo, NSDictionary *info) {
if (photo) [photos addObject:photo];
if (info) [infoArr addObject:info];
if (_isSelectOriginalPhoto) [assets addObject:model.asset];
if (photos.count < _selectedPhotoArr.count) return;
if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingPhotos:sourceAssets:)]) {
[imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingPhotos:photos sourceAssets:assets];
}
if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingPhotos:sourceAssets:infos:)]) {
[imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingPhotos:photos sourceAssets:assets infos:infoArr];
}
if (imagePickerVc.didFinishPickingPhotosHandle) {
imagePickerVc.didFinishPickingPhotosHandle(photos,assets);
}
if (imagePickerVc.didFinishPickingPhotosWithInfosHandle) {
imagePickerVc.didFinishPickingPhotosWithInfosHandle(photos,assets,infoArr);
}
[imagePickerVc hideProgressHUD];
}];
}
}
#pragma mark - UICollectionViewDataSource && Delegate
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return _photoArr.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
TZAssetCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZAssetCell" forIndexPath:indexPath];
TZAssetModel *model = _photoArr[indexPath.row];
cell.model = model;
typeof(cell) weakCell = cell;
cell.didSelectPhotoBlock = ^(BOOL isSelected) {
// 1. cancel select / 取消选择
if (isSelected) {
weakCell.selectPhotoButton.selected = NO;
model.isSelected = NO;
[self.selectedPhotoArr removeObject:model];
[self refreshBottomToolBarStatus];
} else {
// 2. select:check if over the maxImagesCount / 选择照片,检查是否超过了最大个数的限制
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
if (self.selectedPhotoArr.count < imagePickerVc.maxImagesCount) {
weakCell.selectPhotoButton.selected = YES;
model.isSelected = YES;
[self.selectedPhotoArr addObject:model];
[self refreshBottomToolBarStatus];
} else {
[imagePickerVc showAlertWithTitle:[NSString stringWithFormat:@"你最多只能选择%zd张照片",imagePickerVc.maxImagesCount]];
}
}
[UIView showOscillatoryAnimationWithLayer:_numberImageView.layer type:TZOscillatoryAnimationToSmaller];
};
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
TZAssetModel *model = _photoArr[indexPath.row];
if (model.type == TZAssetModelMediaTypeVideo) {
if (_selectedPhotoArr.count > 0) {
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
[imagePickerVc showAlertWithTitle:@"选择照片时不能选择视频"];
} else {
TZVideoPlayerController *videoPlayerVc = [[TZVideoPlayerController alloc] init];
videoPlayerVc.model = model;
[self.navigationController pushViewController:videoPlayerVc animated:YES];
}
} else {
TZPhotoPreviewController *photoPreviewVc = [[TZPhotoPreviewController alloc] init];
photoPreviewVc.photoArr = _photoArr;
photoPreviewVc.currentIndex = indexPath.row;
[self pushPhotoPrevireViewController:photoPreviewVc];
}
}
#pragma mark - Private Method
- (void)refreshBottomToolBarStatus {
_previewButton.enabled = self.selectedPhotoArr.count > 0;
_okButton.enabled = self.selectedPhotoArr.count > 0;
_numberImageView.hidden = _selectedPhotoArr.count <= 0;
_numberLable.hidden = _selectedPhotoArr.count <= 0;
_numberLable.text = [NSString stringWithFormat:@"%zd",_selectedPhotoArr.count];
_originalPhotoButton.enabled = _selectedPhotoArr.count > 0;
_originalPhotoButton.selected = (_isSelectOriginalPhoto && _originalPhotoButton.enabled);
_originalPhotoLable.hidden = (!_originalPhotoButton.isSelected);
if (_isSelectOriginalPhoto) [self getSelectedPhotoBytes];
}
- (void)pushPhotoPrevireViewController:(TZPhotoPreviewController *)photoPreviewVc {
photoPreviewVc.isSelectOriginalPhoto = _isSelectOriginalPhoto;
photoPreviewVc.selectedPhotoArr = self.selectedPhotoArr;
photoPreviewVc.returnNewSelectedPhotoArrBlock = ^(NSMutableArray *newSelectedPhotoArr,BOOL isSelectOriginalPhoto) {
_selectedPhotoArr = newSelectedPhotoArr;
_isSelectOriginalPhoto = isSelectOriginalPhoto;
[_collectionView reloadData];
[self refreshBottomToolBarStatus];
};
photoPreviewVc.okButtonClickBlock = ^(NSMutableArray *newSelectedPhotoArr,BOOL isSelectOriginalPhoto){
_selectedPhotoArr = newSelectedPhotoArr;
_isSelectOriginalPhoto = isSelectOriginalPhoto;
[self okButtonClick];
};
[self.navigationController pushViewController:photoPreviewVc animated:YES];
}
- (void)getSelectedPhotoBytes {
[[TZImageManager manager] getPhotosBytesWithArray:_selectedPhotoArr completion:^(NSString *totalBytes) {
_originalPhotoLable.text = [NSString stringWithFormat:@"(%@)",totalBytes];
}];
}
@end
//
// TZPhotoPreviewCell.h
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
@class TZAssetModel;
@interface TZPhotoPreviewCell : UICollectionViewCell
@property (nonatomic, strong) TZAssetModel *model;
@property (nonatomic, copy) void (^singleTapGestureBlock)();
@end
//
// TZPhotoPreviewCell.m
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import "TZPhotoPreviewCell.h"
#import "TZAssetModel.h"
#import "UIView+Layout.h"
#import "TZImageManager.h"
@interface TZPhotoPreviewCell ()<UIGestureRecognizerDelegate,UIScrollViewDelegate> {
CGFloat _aspectRatio;
}
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) UIView *imageContainerView;
@end
@implementation TZPhotoPreviewCell
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor blackColor];
_scrollView = [[UIScrollView alloc] init];
_scrollView.frame = CGRectMake(0, 0, self.width, self.height);
_scrollView.bouncesZoom = YES;
_scrollView.maximumZoomScale = 2.5;
_scrollView.minimumZoomScale = 1.0;
_scrollView.multipleTouchEnabled = YES;
_scrollView.delegate = self;
_scrollView.scrollsToTop = NO;
_scrollView.showsHorizontalScrollIndicator = NO;
_scrollView.showsVerticalScrollIndicator = NO;
_scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_scrollView.delaysContentTouches = NO;
_scrollView.canCancelContentTouches = YES;
_scrollView.alwaysBounceVertical = NO;
[self addSubview:_scrollView];
_imageContainerView = [[UIView alloc] init];
_imageContainerView.clipsToBounds = YES;
[_scrollView addSubview:_imageContainerView];
_imageView = [[UIImageView alloc] init];
_imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500];
_imageView.clipsToBounds = YES;
[_imageContainerView addSubview:_imageView];
UITapGestureRecognizer *tap1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap:)];
[self addGestureRecognizer:tap1];
UITapGestureRecognizer *tap2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap:)];
tap2.numberOfTapsRequired = 2;
[tap1 requireGestureRecognizerToFail:tap2];
[self addGestureRecognizer:tap2];
}
return self;
}
- (void)setModel:(TZAssetModel *)model {
_model = model;
[_scrollView setZoomScale:1.0 animated:NO];
[[TZImageManager manager] getPhotoWithAsset:model.asset completion:^(UIImage *photo, NSDictionary *info) {
self.imageView.image = photo;
[self resizeSubviews];
}];
}
- (void)resizeSubviews {
_imageContainerView.origin = CGPointZero;
_imageContainerView.width = self.width;
UIImage *image = _imageView.image;
if (image.size.height / image.size.width > self.height / self.width) {
_imageContainerView.height = floor(image.size.height / (image.size.width / self.width));
} else {
CGFloat height = image.size.height / image.size.width * self.width;
if (height < 1 || isnan(height)) height = self.height;
height = floor(height);
_imageContainerView.height = height;
_imageContainerView.centerY = self.height / 2;
}
if (_imageContainerView.height > self.height && _imageContainerView.height - self.height <= 1) {
_imageContainerView.height = self.height;
}
_scrollView.contentSize = CGSizeMake(self.width, MAX(_imageContainerView.height, self.height));
[_scrollView scrollRectToVisible:self.bounds animated:NO];
_scrollView.alwaysBounceVertical = _imageContainerView.height <= self.height ? NO : YES;
_imageView.frame = _imageContainerView.bounds;
}
#pragma mark - UITapGestureRecognizer Event
- (void)doubleTap:(UITapGestureRecognizer *)tap {
if (_scrollView.zoomScale > 1.0) {
[_scrollView setZoomScale:1.0 animated:YES];
} else {
CGPoint touchPoint = [tap locationInView:self.imageView];
CGFloat newZoomScale = _scrollView.maximumZoomScale;
CGFloat xsize = self.frame.size.width / newZoomScale;
CGFloat ysize = self.frame.size.height / newZoomScale;
[_scrollView zoomToRect:CGRectMake(touchPoint.x - xsize/2, touchPoint.y - ysize/2, xsize, ysize) animated:YES];
}
}
- (void)singleTap:(UITapGestureRecognizer *)tap {
if (self.singleTapGestureBlock) {
self.singleTapGestureBlock();
}
}
#pragma mark - UIScrollViewDelegate
- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return _imageContainerView;
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
CGFloat offsetX = (scrollView.width > scrollView.contentSize.width) ? (scrollView.width - scrollView.contentSize.width) * 0.5 : 0.0;
CGFloat offsetY = (scrollView.height > scrollView.contentSize.height) ? (scrollView.height - scrollView.contentSize.height) * 0.5 : 0.0;
self.imageContainerView.center = CGPointMake(scrollView.contentSize.width * 0.5 + offsetX, scrollView.contentSize.height * 0.5 + offsetY);
}
@end
//
// TZPhotoPreviewController.h
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface TZPhotoPreviewController : UIViewController
@property (nonatomic, strong) NSArray *photoArr; ///< All photos / 所有图片的数组
@property (nonatomic, strong) NSMutableArray *selectedPhotoArr; ///< Current selected photos / 当前选中的图片数组
@property (nonatomic, assign) NSInteger currentIndex; ///< Index of the photo user click / 用户点击的图片的索引
@property (nonatomic, assign) BOOL isSelectOriginalPhoto; ///< If YES,return original photo / 是否返回原图
/// Return the new selected photos / 返回最新的选中图片数组
@property (nonatomic, copy) void (^returnNewSelectedPhotoArrBlock)(NSMutableArray *newSeletedPhotoArr, BOOL isSelectOriginalPhoto);
@property (nonatomic, copy) void (^okButtonClickBlock)(NSMutableArray *newSeletedPhotoArr, BOOL isSelectOriginalPhoto);
@end
//
// TZPhotoPreviewController.m
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import "TZPhotoPreviewController.h"
#import "TZPhotoPreviewCell.h"
#import "TZAssetModel.h"
#import "UIView+Layout.h"
#import "TZImagePickerController.h"
#import "TZImageManager.h"
@interface TZPhotoPreviewController ()<UICollectionViewDataSource,UICollectionViewDelegate,UIScrollViewDelegate> {
UICollectionView *_collectionView;
BOOL _isHideNaviBar;
UIView *_naviBar;
UIButton *_backButton;
UIButton *_selectButton;
UIView *_toolBar;
UIButton *_okButton;
UIImageView *_numberImageView;
UILabel *_numberLable;
UIButton *_originalPhotoButton;
UILabel *_originalPhotoLable;
}
@end
@implementation TZPhotoPreviewController
- (NSMutableArray *)selectedPhotoArr {
if (_selectedPhotoArr == nil) _selectedPhotoArr = [[NSMutableArray alloc] init];
return _selectedPhotoArr;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self configCollectionView];
[self configCustomNaviBar];
[self configBottomToolBar];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES];
if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES;
if (_currentIndex) [_collectionView setContentOffset:CGPointMake((self.view.width) * _currentIndex, 0) animated:NO];
[self refreshNaviBarAndBottomBarState];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:NO];
if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = NO;
}
- (void)configCustomNaviBar {
_naviBar = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.width, 64)];
_naviBar.backgroundColor = kNaviBarAndBottonBarBgColor;
_naviBar.alpha = 0.7;
_backButton = [[UIButton alloc] initWithFrame:CGRectMake(10, 10, 44, 44)];
[_backButton setImage:[UIImage imageNamed:@"navi_back"] forState:UIControlStateNormal];
[_backButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[_backButton addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
_selectButton = [[UIButton alloc] initWithFrame:CGRectMake(self.view.width - 54, 10, 42, 42)];
[_selectButton setImage:[UIImage imageNamed:@"photo_def_photoPickerVc"] forState:UIControlStateNormal];
[_selectButton setImage:[UIImage imageNamed:@"photo_sel_photoPickerVc"] forState:UIControlStateSelected];
[_selectButton addTarget:self action:@selector(select:) forControlEvents:UIControlEventTouchUpInside];
[_naviBar addSubview:_selectButton];
[_naviBar addSubview:_backButton];
[self.view addSubview:_naviBar];
}
- (void)configBottomToolBar {
_toolBar = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.height - 44, self.view.width, 44)];
CGFloat rgb = 34 / 255.0;
_toolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:1.0];
_toolBar.alpha = 0.7;
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
if (imagePickerVc.allowPickingOriginalPhoto) {
_originalPhotoButton = [UIButton buttonWithType:UIButtonTypeCustom];
_originalPhotoButton.frame = CGRectMake(5, 0, 120, 44);
_originalPhotoButton.imageEdgeInsets = UIEdgeInsetsMake(0, -8, 0, 0);
_originalPhotoButton.contentEdgeInsets = UIEdgeInsetsMake(0, -50, 0, 0);
_originalPhotoButton.backgroundColor = [UIColor clearColor];
[_originalPhotoButton addTarget:self action:@selector(originalPhotoButtonClick) forControlEvents:UIControlEventTouchUpInside];
_originalPhotoButton.titleLabel.font = [UIFont systemFontOfSize:13];
[_originalPhotoButton setTitle:@"原图" forState:UIControlStateNormal];
[_originalPhotoButton setTitle:@"原图" forState:UIControlStateSelected];
[_originalPhotoButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
[_originalPhotoButton setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected];
[_originalPhotoButton setImage:[UIImage imageNamed:@"preview_original_def"] forState:UIControlStateNormal];
[_originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_sel"] forState:UIControlStateSelected];
_originalPhotoLable = [[UILabel alloc] init];
_originalPhotoLable.frame = CGRectMake(60, 0, 70, 44);
_originalPhotoLable.textAlignment = NSTextAlignmentLeft;
_originalPhotoLable.font = [UIFont systemFontOfSize:13];
_originalPhotoLable.textColor = [UIColor whiteColor];
_originalPhotoLable.backgroundColor = [UIColor clearColor];
if (_isSelectOriginalPhoto) [self showPhotoBytes];
}
_okButton = [UIButton buttonWithType:UIButtonTypeCustom];
_okButton.frame = CGRectMake(self.view.width - 44 - 12, 0, 44, 44);
_okButton.titleLabel.font = [UIFont systemFontOfSize:16];
[_okButton addTarget:self action:@selector(okButtonClick) forControlEvents:UIControlEventTouchUpInside];
[_okButton setTitle:@"确定" forState:UIControlStateNormal];
[_okButton setTitleColor:kOKButtonTitleColorNormal forState:UIControlStateNormal];
_numberImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"photo_number_icon"]];
_numberImageView.backgroundColor = [UIColor clearColor];
_numberImageView.frame = CGRectMake(self.view.width - 56 - 24, 9, 26, 26);
_numberImageView.hidden = _selectedPhotoArr.count <= 0;
_numberLable = [[UILabel alloc] init];
_numberLable.frame = _numberImageView.frame;
_numberLable.font = [UIFont systemFontOfSize:16];
_numberLable.textColor = [UIColor whiteColor];
_numberLable.textAlignment = NSTextAlignmentCenter;
_numberLable.text = [NSString stringWithFormat:@"%zd",_selectedPhotoArr.count];
_numberLable.hidden = _selectedPhotoArr.count <= 0;
_numberLable.backgroundColor = [UIColor clearColor];
[_originalPhotoButton addSubview:_originalPhotoLable];
[_toolBar addSubview:_okButton];
[_toolBar addSubview:_originalPhotoButton];
[_toolBar addSubview:_numberImageView];
[_toolBar addSubview:_numberLable];
[self.view addSubview:_toolBar];
}
- (void)configCollectionView {
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
layout.itemSize = CGSizeMake(self.view.width, self.view.height);
layout.minimumInteritemSpacing = 0;
layout.minimumLineSpacing = 0;
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, self.view.width , self.view.height) collectionViewLayout:layout];
_collectionView.backgroundColor = [UIColor blackColor];
_collectionView.dataSource = self;
_collectionView.delegate = self;
_collectionView.pagingEnabled = YES;
_collectionView.scrollsToTop = NO;
_collectionView.showsHorizontalScrollIndicator = NO;
_collectionView.contentOffset = CGPointMake(0, 0);
_collectionView.contentSize = CGSizeMake(self.view.width * _photoArr.count, self.view.height);
[self.view addSubview:_collectionView];
[_collectionView registerClass:[TZPhotoPreviewCell class] forCellWithReuseIdentifier:@"TZPhotoPreviewCell"];
}
#pragma mark - Click Event
- (void)select:(UIButton *)selectButton {
TZAssetModel *model = _photoArr[_currentIndex];
if (!selectButton.isSelected) {
// 1. select:check if over the maxImagesCount / 选择照片,检查是否超过了最大个数的限制
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
if (self.selectedPhotoArr.count >= imagePickerVc.maxImagesCount) {
[imagePickerVc showAlertWithTitle:[NSString stringWithFormat:@"你最多只能选择%zd张照片",imagePickerVc.maxImagesCount]];
return;
// 2. if not over the maxImagesCount / 如果没有超过最大个数限制
} else {
[self.selectedPhotoArr addObject:model];
if (model.type == TZAssetModelMediaTypeVideo) {
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
[imagePickerVc showAlertWithTitle:@"多选状态下选择视频,默认将视频当图片发送"];
}
}
} else {
[self.selectedPhotoArr removeObject:model];
}
model.isSelected = !selectButton.isSelected;
[self refreshNaviBarAndBottomBarState];
if (model.isSelected) {
[UIView showOscillatoryAnimationWithLayer:selectButton.imageView.layer type:TZOscillatoryAnimationToBigger];
}
[UIView showOscillatoryAnimationWithLayer:_numberImageView.layer type:TZOscillatoryAnimationToSmaller];
}
- (void)back {
[self.navigationController popViewControllerAnimated:YES];
if (self.returnNewSelectedPhotoArrBlock) {
self.returnNewSelectedPhotoArrBlock(self.selectedPhotoArr,_isSelectOriginalPhoto);
}
}
- (void)okButtonClick {
if (_selectedPhotoArr.count == 0) {
TZAssetModel *model = _photoArr[_currentIndex];
[_selectedPhotoArr addObject:model];
}
if (self.okButtonClickBlock) {
self.okButtonClickBlock(self.selectedPhotoArr,_isSelectOriginalPhoto);
}
}
- (void)originalPhotoButtonClick {
_originalPhotoButton.selected = !_originalPhotoButton.isSelected;
_isSelectOriginalPhoto = _originalPhotoButton.isSelected;
_originalPhotoLable.hidden = !_originalPhotoButton.isSelected;
if (_isSelectOriginalPhoto) {
[self showPhotoBytes];
if (!_selectButton.isSelected) [self select:_selectButton];
}
}
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint offSet = scrollView.contentOffset;
_currentIndex = offSet.x / self.view.width;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
[self refreshNaviBarAndBottomBarState];
}
#pragma mark - UICollectionViewDataSource && Delegate
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return _photoArr.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
TZPhotoPreviewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZPhotoPreviewCell" forIndexPath:indexPath];
cell.model = _photoArr[indexPath.row];
if (!cell.singleTapGestureBlock) {
cell.singleTapGestureBlock = ^(){
// show or hide naviBar / 显示或隐藏导航栏
_isHideNaviBar = !_isHideNaviBar;
_naviBar.hidden = _isHideNaviBar;
_toolBar.hidden = _isHideNaviBar;
};
}
return cell;
}
#pragma mark - Private Method
- (void)refreshNaviBarAndBottomBarState {
TZAssetModel *model = _photoArr[_currentIndex];
_selectButton.selected = model.isSelected;
_numberLable.text = [NSString stringWithFormat:@"%zd",_selectedPhotoArr.count];
_numberImageView.hidden = (_selectedPhotoArr.count <= 0 || _isHideNaviBar);
_numberLable.hidden = (_selectedPhotoArr.count <= 0 || _isHideNaviBar);
_originalPhotoButton.selected = _isSelectOriginalPhoto;
_originalPhotoLable.hidden = !_originalPhotoButton.isSelected;
if (_isSelectOriginalPhoto) [self showPhotoBytes];
// If is previewing video, hide original photo button
// 如果正在预览的是视频,隐藏原图按钮
if (_isHideNaviBar) return;
if (model.type == TZAssetModelMediaTypeVideo) {
_originalPhotoButton.hidden = YES;
_originalPhotoLable.hidden = YES;
} else {
_originalPhotoButton.hidden = NO;
if (_isSelectOriginalPhoto) _originalPhotoLable.hidden = NO;
}
}
- (void)showPhotoBytes {
[[TZImageManager manager] getPhotosBytesWithArray:@[_photoArr[_currentIndex]] completion:^(NSString *totalBytes) {
_originalPhotoLable.text = [NSString stringWithFormat:@"(%@)",totalBytes];
}];
}
@end
//
// TZVideoPlayerController.h
// TZImagePickerController
//
// Created by 谭真 on 16/1/5.
// Copyright © 2016年 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
@class TZAssetModel;
@interface TZVideoPlayerController : UIViewController
@property (nonatomic, strong) TZAssetModel *model;
@end
\ No newline at end of file
//
// TZVideoPlayerController.m
// TZImagePickerController
//
// Created by 谭真 on 16/1/5.
// Copyright © 2016年 谭真. All rights reserved.
//
#import "TZVideoPlayerController.h"
#import <MediaPlayer/MediaPlayer.h>
#import "UIView+Layout.h"
#import "TZImageManager.h"
#import "TZAssetModel.h"
#import "TZImagePickerController.h"
#import "TZPhotoPreviewController.h"
@interface TZVideoPlayerController () {
AVPlayer *_player;
UIButton *_playButton;
UIImage *_cover;
UIView *_toolBar;
UIButton *_okButton;
UIProgressView *_progress;
}
@end
@implementation TZVideoPlayerController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
self.navigationItem.title = @"视频预览";
[self configMoviePlayer];
}
- (void)configMoviePlayer {
[[TZImageManager manager] getPhotoWithAsset:_model.asset completion:^(UIImage *photo, NSDictionary *info) {
_cover = photo;
}];
[[TZImageManager manager] getVideoWithAsset:_model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) {
dispatch_async(dispatch_get_main_queue(), ^{
_player = [AVPlayer playerWithPlayerItem:playerItem];
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
playerLayer.frame = self.view.bounds;
[self.view.layer addSublayer:playerLayer];
[self addProgressObserver];
[self configPlayButton];
[self configBottomToolBar];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem];
});
}];
}
/// Show progress,do it next time / 给播放器添加进度更新,下次加上
-(void)addProgressObserver{
AVPlayerItem *playerItem = _player.currentItem;
UIProgressView *progress = _progress;
[_player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
float current = CMTimeGetSeconds(time);
float total = CMTimeGetSeconds([playerItem duration]);
if (current) {
[progress setProgress:(current/total) animated:YES];
}
}];
}
- (void)configPlayButton {
_playButton = [UIButton buttonWithType:UIButtonTypeCustom];
_playButton.frame = CGRectMake(0, 64, self.view.width, self.view.height - 64 - 44);
[_playButton setImage:[UIImage imageNamed:@"MMVideoPreviewPlay"] forState:UIControlStateNormal];
[_playButton setImage:[UIImage imageNamed:@"MMVideoPreviewPlayHL"] forState:UIControlStateHighlighted];
[_playButton addTarget:self action:@selector(playButtonClick) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_playButton];
}
- (void)configBottomToolBar {
_toolBar = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.height - 44, self.view.width, 44)];
CGFloat rgb = 34 / 255.0;
_toolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:1.0];
_toolBar.alpha = 0.7;
_okButton = [UIButton buttonWithType:UIButtonTypeCustom];
_okButton.frame = CGRectMake(self.view.width - 44 - 12, 0, 44, 44);
_okButton.titleLabel.font = [UIFont systemFontOfSize:16];
[_okButton addTarget:self action:@selector(okButtonClick) forControlEvents:UIControlEventTouchUpInside];
[_okButton setTitle:@"确定" forState:UIControlStateNormal];
[_okButton setTitleColor:kOKButtonTitleColorNormal forState:UIControlStateNormal];
[_toolBar addSubview:_okButton];
[self.view addSubview:_toolBar];
}
#pragma mark - Click Event
- (void)playButtonClick {
CMTime currentTime = _player.currentItem.currentTime;
CMTime durationTime = _player.currentItem.duration;
if (_player.rate == 0.0f) {
if (currentTime.value == durationTime.value) [_player.currentItem seekToTime:CMTimeMake(0, 1)];
[_player play];
[self.navigationController setNavigationBarHidden:YES];
_toolBar.hidden = YES;
[_playButton setImage:nil forState:UIControlStateNormal];
if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES;
} else {
[self pausePlayerAndShowNaviBar];
}
}
- (void)okButtonClick {
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingVideo:sourceAssets:)]) {
[imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingVideo:_cover sourceAssets:_model.asset];
}
if (imagePickerVc.didFinishPickingVideoHandle) {
imagePickerVc.didFinishPickingVideoHandle(_cover,_model.asset);
}
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - Notification Method
- (void)pausePlayerAndShowNaviBar {
[_player pause];
_toolBar.hidden = NO;
[self.navigationController setNavigationBarHidden:NO];
[_playButton setImage:[UIImage imageNamed:@"MMVideoPreviewPlay"] forState:UIControlStateNormal];
if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = NO;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end
//
// UIView+Layout.h
//
// Created by 谭真 on 15/2/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
typedef enum : NSUInteger {
TZOscillatoryAnimationToBigger,
TZOscillatoryAnimationToSmaller,
} TZOscillatoryAnimationType;
@interface UIView (Layout)
@property (nonatomic) CGFloat left; ///< Shortcut for frame.origin.x.
@property (nonatomic) CGFloat top; ///< Shortcut for frame.origin.y
@property (nonatomic) CGFloat right; ///< Shortcut for frame.origin.x + frame.size.width
@property (nonatomic) CGFloat bottom; ///< Shortcut for frame.origin.y + frame.size.height
@property (nonatomic) CGFloat width; ///< Shortcut for frame.size.width.
@property (nonatomic) CGFloat height; ///< Shortcut for frame.size.height.
@property (nonatomic) CGFloat centerX; ///< Shortcut for center.x
@property (nonatomic) CGFloat centerY; ///< Shortcut for center.y
@property (nonatomic) CGPoint origin; ///< Shortcut for frame.origin.
@property (nonatomic) CGSize size; ///< Shortcut for frame.size.
+ (void)showOscillatoryAnimationWithLayer:(CALayer *)layer type:(TZOscillatoryAnimationType)type;
@end
//
// UIView+Layout.m
//
// Created by 谭真 on 15/2/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import "UIView+Layout.h"
@implementation UIView (Layout)
- (CGFloat)left {
return self.frame.origin.x;
}
- (void)setLeft:(CGFloat)x {
CGRect frame = self.frame;
frame.origin.x = x;
self.frame = frame;
}
- (CGFloat)top {
return self.frame.origin.y;
}
- (void)setTop:(CGFloat)y {
CGRect frame = self.frame;
frame.origin.y = y;
self.frame = frame;
}
- (CGFloat)right {
return self.frame.origin.x + self.frame.size.width;
}
- (void)setRight:(CGFloat)right {
CGRect frame = self.frame;
frame.origin.x = right - frame.size.width;
self.frame = frame;
}
- (CGFloat)bottom {
return self.frame.origin.y + self.frame.size.height;
}
- (void)setBottom:(CGFloat)bottom {
CGRect frame = self.frame;
frame.origin.y = bottom - frame.size.height;
self.frame = frame;
}
- (CGFloat)width {
return self.frame.size.width;
}
- (void)setWidth:(CGFloat)width {
CGRect frame = self.frame;
frame.size.width = width;
self.frame = frame;
}
- (CGFloat)height {
return self.frame.size.height;
}
- (void)setHeight:(CGFloat)height {
CGRect frame = self.frame;
frame.size.height = height;
self.frame = frame;
}
- (CGFloat)centerX {
return self.center.x;
}
- (void)setCenterX:(CGFloat)centerX {
self.center = CGPointMake(centerX, self.center.y);
}
- (CGFloat)centerY {
return self.center.y;
}
- (void)setCenterY:(CGFloat)centerY {
self.center = CGPointMake(self.center.x, centerY);
}
- (CGPoint)origin {
return self.frame.origin;
}
- (void)setOrigin:(CGPoint)origin {
CGRect frame = self.frame;
frame.origin = origin;
self.frame = frame;
}
- (CGSize)size {
return self.frame.size;
}
- (void)setSize:(CGSize)size {
CGRect frame = self.frame;
frame.size = size;
self.frame = frame;
}
+ (void)showOscillatoryAnimationWithLayer:(CALayer *)layer type:(TZOscillatoryAnimationType)type{
NSNumber *animationScale1 = type == TZOscillatoryAnimationToBigger ? @(1.15) : @(0.5);
NSNumber *animationScale2 = type == TZOscillatoryAnimationToBigger ? @(0.92) : @(1.15);
[UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut animations:^{
[layer setValue:animationScale1 forKeyPath:@"transform.scale"];
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut animations:^{
[layer setValue:animationScale2 forKeyPath:@"transform.scale"];
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut animations:^{
[layer setValue:@(1.0) forKeyPath:@"transform.scale"];
} completion:nil];
}];
}];
}
@end
//
// TZTestCell.h
// TZImagePickerController
//
// Created by 谭真 on 16/1/3.
// Copyright © 2016年 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface TZTestCell : UICollectionViewCell
@property (nonatomic, strong) UIImageView *imageView;
@end
//
// TZTestCell.m
// TZImagePickerController
//
// Created by 谭真 on 16/1/3.
// Copyright © 2016年 谭真. All rights reserved.
//
#import "TZTestCell.h"
@implementation TZTestCell
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor whiteColor];
_imageView = [[UIImageView alloc] init];
_imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500];
_imageView.contentMode = UIViewContentModeScaleAspectFill;
[self addSubview:_imageView];
self.clipsToBounds = YES;
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
_imageView.frame = self.bounds;
}
@end
//
// ViewController.h
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
//
// ViewController.m
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import "ViewController.h"
#import "TZImagePickerController.h"
#import "UIView+Layout.h"
#import "TZTestCell.h"
@interface ViewController ()<TZImagePickerControllerDelegate,UICollectionViewDataSource,UICollectionViewDelegate> {
UICollectionView *_collectionView;
NSMutableArray *_selectedPhotos;
NSMutableArray *_selectedAssets;
CGFloat _itemWH;
CGFloat _margin;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
_selectedPhotos = [NSMutableArray array];
_selectedAssets = [NSMutableArray array];
[self configCollectionView];
}
- (void)configCollectionView {
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
_margin = 4;
_itemWH = (self.view.width - 2 * _margin - 4) / 3 - _margin;
layout.itemSize = CGSizeMake(_itemWH, _itemWH);
layout.minimumInteritemSpacing = _margin;
layout.minimumLineSpacing = _margin;
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(_margin, 120, self.view.width - 2 * _margin, 400) collectionViewLayout:layout];
CGFloat rgb = 244 / 255.0;
_collectionView.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:1.0];
_collectionView.contentInset = UIEdgeInsetsMake(4, 0, 0, 2);
_collectionView.scrollIndicatorInsets = UIEdgeInsetsMake(0, 0, 0, -2);
_collectionView.dataSource = self;
_collectionView.delegate = self;
[self.view addSubview:_collectionView];
[_collectionView registerClass:[TZTestCell class] forCellWithReuseIdentifier:@"TZTestCell"];
}
#pragma mark UICollectionView
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return _selectedPhotos.count + 1;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
TZTestCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZTestCell" forIndexPath:indexPath];
if (indexPath.row == _selectedPhotos.count) {
cell.imageView.image = [UIImage imageNamed:@"AlbumAddBtn"];
} else {
cell.imageView.image = _selectedPhotos[indexPath.row];
}
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == _selectedPhotos.count) [self pickPhotoButtonClick:nil];
}
#pragma mark Click Event
- (IBAction)pickPhotoButtonClick:(UIButton *)sender {
TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:9 delegate:self];
// You can get the photos by block, the same as by delegate.
// 你可以通过block或者代理,来得到用户选择的照片.
[imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray<UIImage *> *photos, NSArray *assets) {
}];
[self presentViewController:imagePickerVc animated:YES completion:nil];
}
#pragma mark TZImagePickerControllerDelegate
/// User click cancel button
/// 用户点击了取消
- (void)imagePickerControllerDidCancel:(TZImagePickerController *)picker {
NSLog(@"cancel");
}
/// User finish picking photo,if assets are not empty, user picking original photo.
/// 用户选择好了图片,如果assets非空,则用户选择了原图。
- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray *)photos sourceAssets:(NSArray *)assets{
[_selectedPhotos addObjectsFromArray:photos];
[_collectionView reloadData];
_collectionView.contentSize = CGSizeMake(0, ((_selectedPhotos.count + 2) / 3 ) * (_margin + _itemWH));
}
/// User finish picking video,
/// 用户选择好了视频
- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingVideo:(UIImage *)coverImage sourceAssets:(id)asset {
[_selectedPhotos addObjectsFromArray:@[coverImage]];
[_collectionView reloadData];
_collectionView.contentSize = CGSizeMake(0, ((_selectedPhotos.count + 2) / 3 ) * (_margin + _itemWH));
}
@end
//
// main.m
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
//
// TZImagePickerControllerTests.m
// TZImagePickerControllerTests
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import <XCTest/XCTest.h>
@interface TZImagePickerControllerTests : XCTestCase
@end
@implementation TZImagePickerControllerTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testExample {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
- (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
}];
}
@end
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
//
// TZImagePickerControllerUITests.m
// TZImagePickerControllerUITests
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import <XCTest/XCTest.h>
@interface TZImagePickerControllerUITests : XCTestCase
@end
@implementation TZImagePickerControllerUITests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
// In UI tests it is usually best to stop immediately when a failure occurs.
self.continueAfterFailure = NO;
// UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
[[[XCUIApplication alloc] init] launch];
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void)testExample {
// Use recording to get started writing UI tests.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
@end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment