Commit 15ad81c9 authored by Syan's avatar Syan

Initial commit

parents
*.pbxproj -text
\ No newline at end of file
# OSX
#
.DS_Store
# node.js
#
node_modules/
npm-debug.log
yarn-error.log
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
project.xcworkspace
# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
# BUCK
buck-out/
\.buckd/
*.keystore
\ No newline at end of file
# react-native-syan-image-picker
## Getting started
`$ npm install react-native-syan-image-picker --save`
### Mostly automatic installation
`$ react-native link react-native-syan-image-picker`
### Manual installation
#### iOS
1. In XCode, in the project navigator, right click `Libraries``Add Files to [your project's name]`
2. Go to `node_modules``react-native-syan-image-picker` and add `RNSyanImagePicker.xcodeproj`
3. In XCode, in the project navigator, select your project. Add `libRNSyanImagePicker.a` to your project's `Build Phases``Link Binary With Libraries`
4. Run your project (`Cmd+R`)<
#### Android
1. Open up `android/app/src/main/java/[...]/MainActivity.java`
- Add `import com.reactlibrary.RNSyanImagePickerPackage;` to the imports at the top of the file
- Add `new RNSyanImagePickerPackage()` to the list returned by the `getPackages()` method
2. Append the following lines to `android/settings.gradle`:
```
include ':react-native-syan-image-picker'
project(':react-native-syan-image-picker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-syan-image-picker/android')
```
3. Insert the following lines inside the dependencies block in `android/app/build.gradle`:
```
compile project(':react-native-syan-image-picker')
```
#### Windows
[Read it! :D](https://github.com/ReactWindows/react-native)
1. In Visual Studio add the `RNSyanImagePicker.sln` in `node_modules/react-native-syan-image-picker/windows/RNSyanImagePicker.sln` folder to their solution, reference from their app.
2. Open up your `MainPage.cs` app
- Add `using Com.Reactlibrary.RNSyanImagePicker;` to the usings at the top of the file
- Add `new RNSyanImagePickerPackage()` to the `List<IReactPackage>` returned by the `Packages` method
## Usage
```javascript
import RNSyanImagePicker from 'react-native-syan-image-picker';
// TODO: What to do with the module?
RNSyanImagePicker;
```
\ No newline at end of file
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.1'
}
}
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
minSdkVersion 16
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
lintOptions {
abortOnError false
}
}
repositories {
mavenCentral()
}
dependencies {
compile 'com.facebook.react:react-native:+'
compile 'com.github.LuckSiege.PictureSelector:picture_library:v2.1.1'
}
\ No newline at end of file
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.reactlibrary">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</manifest>
\ No newline at end of file
package com.reactlibrary;
import android.app.Activity;
import android.content.Intent;
import android.graphics.BitmapFactory;
import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.BaseActivityEventListener;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;
import com.luck.picture.lib.PictureSelector;
import com.luck.picture.lib.compress.Luban;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.config.PictureMimeType;
import com.luck.picture.lib.entity.LocalMedia;
import java.util.ArrayList;
import java.util.List;
public class RNSyanImagePickerModule extends ReactContextBaseJavaModule {
private final ReactApplicationContext reactContext;
private List<LocalMedia> selectList = new ArrayList<>();
private Callback mPickerCallback;
public RNSyanImagePickerModule(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
reactContext.addActivityEventListener(mActivityEventListener);
}
@Override
public String getName() {
return "RNSyanImagePicker";
}
@ReactMethod
public void showImagePicker(ReadableMap options, Callback callback) {
int imageCount = options.getInt("imageCount");
boolean isCamera = options.getBoolean("isCamera");
boolean isCrop = options.getBoolean("isCrop");
int CropW = options.getInt("CropW");
int CropH = options.getInt("CropH");
boolean isGif = options.getBoolean("isGif");
boolean showCropCircle = options.getBoolean("showCropCircle");
boolean showCropFrame = options.getBoolean("showCropFrame");
boolean showCropGrid = options.getBoolean("showCropGrid");
int modeValue;
if (imageCount == 1) {
modeValue = 1;
} else {
modeValue = 2;
}
this.mPickerCallback = callback;
Activity currentActivity = getCurrentActivity();
PictureSelector.create(currentActivity)
.openGallery(PictureMimeType.ofImage())// 全部.PictureMimeType.ofAll()、图片.ofImage()、视频.ofVideo()、音频.ofAudio()
.maxSelectNum(imageCount)// 最大图片选择数量
.minSelectNum(1)// 最小选择数量
.imageSpanCount(4)// 每行显示个数
.selectionMode(modeValue)// 多选 or 单选
.previewImage(true)// 是否可预览图片
.previewVideo(false)// 是否可预览视频
.compressGrade(Luban.THIRD_GEAR)// luban压缩档次,默认3档 Luban.FIRST_GEAR、Luban.CUSTOM_GEAR
.isCamera(isCamera)// 是否显示拍照按钮
.enableCrop(isCrop)// 是否裁剪
.compress(true)// 是否压缩
.compressMode(PictureConfig.SYSTEM_COMPRESS_MODE)//系统自带 or 鲁班压缩 PictureConfig.SYSTEM_COMPRESS_MODE or LUBAN_COMPRESS_MODE
.glideOverride(160, 160)// glide 加载宽高,越小图片列表越流畅,但会影响列表图片浏览的清晰度
.withAspectRatio(CropW, CropH)// 裁剪比例 如16:9 3:2 3:4 1:1 可自定义 裁剪比例自定义
.hideBottomControls(isCrop)// 是否显示uCrop工具栏,默认不显示
.isGif(isGif)// 是否显示gif图片
.freeStyleCropEnabled(true)// 裁剪框是否可拖拽
.circleDimmedLayer(showCropCircle)// 是否圆形裁剪
.showCropFrame(showCropFrame)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false
.showCropGrid(showCropGrid)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false
.openClickSound(false)// 是否开启点击声音
.cropCompressQuality(90)// 裁剪压缩质量 默认100
.scaleEnabled(true)// 裁剪是否可放大缩小图片
.forResult(PictureConfig.CHOOSE_REQUEST);//结果回调onActivityResult code
}
private final ActivityEventListener mActivityEventListener = new BaseActivityEventListener() {
@Override
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case PictureConfig.CHOOSE_REQUEST:
selectList = PictureSelector.obtainMultipleResult(data);
WritableArray imageList = new WritableNativeArray();
for (LocalMedia media : selectList) {
WritableMap aImage = new WritableNativeMap();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
if (!media.isCompressed()) {
BitmapFactory.decodeFile(media.getPath(), options);
aImage.putDouble("width", options.outWidth);
aImage.putDouble("height", options.outHeight);
aImage.putString("type", "image");
aImage.putString("uri", "file://" + media.getPath());
} else {
// 压缩过,取 media.getCompressPath();
BitmapFactory.decodeFile(media.getCompressPath(), options);
aImage.putDouble("width", options.outWidth);
aImage.putDouble("height", options.outHeight);
aImage.putString("type", "image");
aImage.putString("uri", "file://" + media.getCompressPath());
}
if (media.isCut()) {
aImage.putString("original_uri", "file://" + media.getCutPath());
} else {
aImage.putString("original_uri", "file://" + media.getPath());
}
imageList.pushMap(aImage);
}
if (selectList.isEmpty()) {
mPickerCallback.invoke("取消");
} else {
mPickerCallback.invoke(null, imageList);
}
}
}
};
}
\ No newline at end of file
package com.reactlibrary;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class RNSyanImagePickerPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(new RNSyanImagePickerModule(reactContext));
}
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
\ No newline at end of file
import {
NativeModules,
Platform,
Dimensions,
} from 'react-native';
const {RNSyanImagePicker} = NativeModules;
const {width, height} = Dimensions.get('window');
export default {
showImagePicker(options, bc) {
const optionObj = {
imageCount: 1,
isCamera: true,
isCrop: false,
CropW: ~~(width*0.6),
CropH: ~~(width*0.6),
isGif: false,
showCropCircle: false,
showCropFrame: true,
showCropGrid: false,
...options
}
return RNSyanImagePicker.showImagePicker(optionObj, bc)
// if (Platform.OS == 'android') {
//
// const optionObj = {
// imageCount: 1,
// isCamera: true,
// isCrop: false,
// CropW: 100,
// CropH: 100,
// isGif: false,
// showCropCircle: false,
// showCropFrame: true,
// showCropGrid: false,
// ...options
// }
//
// return RNSyanImagePicker.showImagePicker(optionObj)
//
// } else {
// let x = (width - CropWidth) / 2;
// let y = (height - CropHeight) / 2;
// return RNSyanImagePicker.show(count, Crop, x, y, CropWidth, CropHeight, SelectVideo).then((result) => {
// return result;
// });
// }
}
};
#if __has_include("RCTBridgeModule.h")
#import "RCTBridgeModule.h"
#else
#import <React/RCTBridgeModule.h>
#endif
@interface RNSyanImagePicker : NSObject <RCTBridgeModule>
@end
\ No newline at end of file
#import "RNSyanImagePicker.h"
#import "TZImagePickerController.h"
@implementation RNSyanImagePicker
RCT_EXPORT_MODULE()
RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options
callback:(RCTResponseSenderBlock)callback) {
//照片最大可选张数
NSInteger imageCount = [options[@"imageCount"] integerValue];
//显示内部拍照按钮
BOOL isCamera = [options[@"isCamera"] boolValue];
BOOL isCrop = [options[@"isCrop"] boolValue];
NSInteger CropW = [options[@"CropW"] integerValue];
NSInteger CropH = [options[@"CropH"] integerValue];
BOOL isGif = [options[@"isGif"] boolValue];
BOOL showCropCircle = [options[@"showCropCircle"] boolValue];
TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:imageCount delegate:nil];
imagePickerVc.maxImagesCount = imageCount;
imagePickerVc.allowPickingGif = isGif; // 允许GIF
imagePickerVc.allowTakePicture = isCamera; // 允许用户在内部拍照
imagePickerVc.allowPickingVideo = NO; // 不允许视频
imagePickerVc.allowPickingOriginalPhoto = NO; // 允许原图
imagePickerVc.allowCrop = isCrop; // 裁剪
if (imageCount == 1) {
// 单选模式
imagePickerVc.showSelectBtn = NO;
imagePickerVc.allowPreview = NO;
if(isCrop){
if(showCropCircle) {
imagePickerVc.needCircleCrop = showCropCircle; //圆形裁剪
} else {
CGFloat x = ([[UIScreen mainScreen] bounds].size.width - CropW) / 2;
CGFloat y = ([[UIScreen mainScreen] bounds].size.height - CropH) / 2;
imagePickerVc.cropRect = imagePickerVc.cropRect = CGRectMake(x,y,CropW,CropH);
}
}
}
__block TZImagePickerController *weakPicker = imagePickerVc;
[imagePickerVc setDidFinishPickingPhotosWithInfosHandle:^(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto,NSArray<NSDictionary *> *infos) {
NSMutableArray *selectedPhotos = [NSMutableArray array];
[weakPicker showProgressHUD];
if (imageCount == 1 && isCrop) {
NSMutableDictionary *photo = [NSMutableDictionary dictionary];
// 剪切图片并放在tmp中
photo[@"width"] = @(photos[0].size.width);
photo[@"height"] = @(photos[0].size.height);
NSString *fileName = [NSString stringWithFormat:@"%d.jpg", arc4random() % 10000000];
NSString *filePath = [NSString stringWithFormat:@"%@/tmp/%@", NSHomeDirectory(), fileName];
if ([UIImageJPEGRepresentation(photos[0], 0.9) writeToFile:filePath atomically:YES]) {
photo[@"uri"] = filePath;
} else {
NSLog(@"保存压缩图片失败");
}
[selectedPhotos addObject:photo];
} else {
[infos enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSMutableDictionary *photo = [NSMutableDictionary dictionary];
photo[@"width"] = @(photos[idx].size.width);
photo[@"height"] = @(photos[idx].size.height);
photo[@"original_uri"] = [(NSURL *)obj[@"PHImageFileURLKey"] absoluteString];
NSString *fileName = [NSString stringWithFormat:@"%d.jpg", arc4random() % 10000000];
NSString *filePath = [NSString stringWithFormat:@"%@/tmp/%@", NSHomeDirectory(), fileName];
if ([UIImageJPEGRepresentation(photos[idx], 0.9) writeToFile:filePath atomically:YES]) {
photo[@"uri"] = filePath;
} else {
NSLog(@"保存压缩图片失败");
}
[selectedPhotos addObject:photo];
}];
}
callback(@[[NSNull null],[NSArray arrayWithArray:selectedPhotos]]);
[weakPicker hideProgressHUD];
}];
[imagePickerVc setImagePickerControllerDidCancelHandle:^{
callback(@[@"取消"]);
}];
[[[[UIApplication sharedApplication] keyWindow] rootViewController] presentViewController:imagePickerVc animated:YES completion:nil];
}
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
@end
Pod::Spec.new do |s|
s.name = "RNSyanImagePicker"
s.version = "1.0.0"
s.summary = "RNSyanImagePicker"
s.description = <<-DESC
RNSyanImagePicker
DESC
s.homepage = ""
s.license = "MIT"
# s.license = { :type => "MIT", :file => "FILE_LICENSE" }
s.author = { "author" => "author@domain.cn" }
s.platform = :ios, "7.0"
s.source = { :git => "https://github.com/author/RNSyanImagePicker.git", :tag => "master" }
s.source_files = "RNSyanImagePicker/**/*.{h,m}"
s.requires_arc = true
s.dependency "React"
#s.dependency "others"
end
\ No newline at end of file
This diff is collapsed.
//
// NSBundle+TZImagePicker.h
// TZImagePickerController
//
// Created by 谭真 on 16/08/18.
// Copyright © 2016年 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface NSBundle (TZImagePicker)
+ (NSBundle *)tz_imagePickerBundle;
+ (NSString *)tz_localizedStringForKey:(NSString *)key value:(NSString *)value;
+ (NSString *)tz_localizedStringForKey:(NSString *)key;
@end
//
// NSBundle+TZImagePicker.m
// TZImagePickerController
//
// Created by 谭真 on 16/08/18.
// Copyright © 2016年 谭真. All rights reserved.
//
#import "NSBundle+TZImagePicker.h"
#import "TZImagePickerController.h"
@implementation NSBundle (TZImagePicker)
+ (NSBundle *)tz_imagePickerBundle {
NSBundle *bundle = [NSBundle bundleForClass:[TZImagePickerController class]];
NSURL *url = [bundle URLForResource:@"TZImagePickerController" withExtension:@"bundle"];
bundle = [NSBundle bundleWithURL:url];
return bundle;
}
+ (NSString *)tz_localizedStringForKey:(NSString *)key {
return [self tz_localizedStringForKey:key value:@""];
}
+ (NSString *)tz_localizedStringForKey:(NSString *)key value:(NSString *)value {
static NSBundle *bundle = nil;
if (bundle == nil) {
NSString *language = [NSLocale preferredLanguages].firstObject;
if ([language rangeOfString:@"zh-Hans"].location != NSNotFound) {
language = @"zh-Hans";
} else {
language = @"en";
}
bundle = [NSBundle bundleWithPath:[[NSBundle tz_imagePickerBundle] pathForResource:language ofType:@"lproj"]];
}
NSString *value1 = [bundle localizedStringForKey:key value:value table:nil];
return value1;
}
@end
//
// TZAssetCell.h
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <Photos/Photos.h>
typedef enum : NSUInteger {
TZAssetCellTypePhoto = 0,
TZAssetCellTypeLivePhoto,
TZAssetCellTypePhotoGif,
TZAssetCellTypeVideo,
TZAssetCellTypeAudio,
} TZAssetCellType;
@class TZAssetModel;
@interface TZAssetCell : UICollectionViewCell
@property (weak, nonatomic) UIButton *selectPhotoButton;
@property (nonatomic, strong) TZAssetModel *model;
@property (nonatomic, copy) void (^didSelectPhotoBlock)(BOOL);
@property (nonatomic, assign) TZAssetCellType type;
@property (nonatomic, assign) BOOL allowPickingGif;
@property (nonatomic, assign) BOOL allowPickingMultipleVideo;
@property (nonatomic, copy) NSString *representedAssetIdentifier;
@property (nonatomic, assign) int32_t imageRequestID;
@property (nonatomic, copy) NSString *photoSelImageName;
@property (nonatomic, copy) NSString *photoDefImageName;
@property (nonatomic, assign) BOOL showSelectBtn;
@property (assign, nonatomic) BOOL allowPreview;
@end
@class TZAlbumModel;
@interface TZAlbumCell : UITableViewCell
@property (nonatomic, strong) TZAlbumModel *model;
@property (weak, nonatomic) UIButton *selectedCountButton;
@end
@interface TZAssetCameraCell : UICollectionViewCell
@property (nonatomic, strong) UIImageView *imageView;
@end
This diff is collapsed.
//
// 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,
TZAssetModelMediaTypePhotoGif,
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>
@property (nonatomic, strong) NSArray *models;
@property (nonatomic, strong) NSArray *selectedModels;
@property (nonatomic, assign) NSUInteger selectedCount;
@property (nonatomic, assign) BOOL isCameraRoll;
@end
//
// TZAssetModel.m
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import "TZAssetModel.h"
#import "TZImageManager.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
- (void)setResult:(id)result {
_result = result;
BOOL allowPickingImage = [[[NSUserDefaults standardUserDefaults] objectForKey:@"tz_allowPickingImage"] isEqualToString:@"1"];
BOOL allowPickingVideo = [[[NSUserDefaults standardUserDefaults] objectForKey:@"tz_allowPickingVideo"] isEqualToString:@"1"];
[[TZImageManager manager] getAssetsFromFetchResult:result allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage completion:^(NSArray<TZAssetModel *> *models) {
_models = models;
if (_selectedModels) {
[self checkSelectedModels];
}
}];
}
- (void)setSelectedModels:(NSArray *)selectedModels {
_selectedModels = selectedModels;
if (_models) {
[self checkSelectedModels];
}
}
- (void)checkSelectedModels {
self.selectedCount = 0;
NSMutableArray *selectedAssets = [NSMutableArray array];
for (TZAssetModel *model in _selectedModels) {
[selectedAssets addObject:model.asset];
}
for (TZAssetModel *model in _models) {
if ([[TZImageManager manager] isAssetsArray:selectedAssets containAsset:model.asset]) {
self.selectedCount ++;
}
}
}
- (NSString *)name {
if (_name) {
return _name;
}
return @"";
}
@end
//
// TZGifPhotoPreviewController.h
// TZImagePickerController
//
// Created by ttouch on 2016/12/13.
// Copyright © 2016年 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
@class TZAssetModel;
@interface TZGifPhotoPreviewController : UIViewController
@property (nonatomic, strong) TZAssetModel *model;
@end
//
// TZGifPhotoPreviewController.m
// TZImagePickerController
//
// Created by ttouch on 2016/12/13.
// Copyright © 2016年 谭真. All rights reserved.
//
#import "TZGifPhotoPreviewController.h"
#import "TZImagePickerController.h"
#import "TZAssetModel.h"
#import "UIView+Layout.h"
#import "TZPhotoPreviewCell.h"
#import "TZImageManager.h"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
@interface TZGifPhotoPreviewController () {
UIView *_toolBar;
UIButton *_doneButton;
UIProgressView *_progress;
TZPhotoPreviewView *_previewView;
UIStatusBarStyle _originStatusBarStyle;
}
@end
@implementation TZGifPhotoPreviewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
if (tzImagePickerVc) {
self.navigationItem.title = [NSString stringWithFormat:@"GIF %@",tzImagePickerVc.previewBtnTitleStr];
}
[self configPreviewView];
[self configBottomToolBar];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
_originStatusBarStyle = [UIApplication sharedApplication].statusBarStyle;
[UIApplication sharedApplication].statusBarStyle = iOS7Later ? UIStatusBarStyleLightContent : UIStatusBarStyleBlackOpaque;
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[UIApplication sharedApplication].statusBarStyle = _originStatusBarStyle;
}
- (void)configPreviewView {
_previewView = [[TZPhotoPreviewView alloc] initWithFrame:CGRectZero];
_previewView.model = self.model;
__weak typeof(self) weakSelf = self;
[_previewView setSingleTapGestureBlock:^{
[weakSelf signleTapAction];
}];
[self.view addSubview:_previewView];
}
- (void)configBottomToolBar {
_toolBar = [[UIView alloc] initWithFrame:CGRectZero];
CGFloat rgb = 34 / 255.0;
_toolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.7];
_doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
_doneButton.titleLabel.font = [UIFont systemFontOfSize:16];
[_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside];
TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
if (tzImagePickerVc) {
[_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal];
[_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal];
} else {
[_doneButton setTitle:[NSBundle tz_localizedStringForKey:@"Done"] forState:UIControlStateNormal];
[_doneButton setTitleColor:[UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0] forState:UIControlStateNormal];
}
[_toolBar addSubview:_doneButton];
UILabel *byteLabel = [[UILabel alloc] init];
byteLabel.textColor = [UIColor whiteColor];
byteLabel.font = [UIFont systemFontOfSize:13];
byteLabel.frame = CGRectMake(10, 0, 100, 44);
[[TZImageManager manager] getPhotosBytesWithArray:@[_model] completion:^(NSString *totalBytes) {
byteLabel.text = totalBytes;
}];
[_toolBar addSubview:byteLabel];
[self.view addSubview:_toolBar];
}
#pragma mark - Layout
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
_previewView.frame = self.view.bounds;
_previewView.scrollView.frame = self.view.bounds;
_doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44);
_toolBar.frame = CGRectMake(0, self.view.tz_height - 44, self.view.tz_width, 44);
}
#pragma mark - Click Event
- (void)signleTapAction {
_toolBar.hidden = !_toolBar.isHidden;
[self.navigationController setNavigationBarHidden:_toolBar.isHidden];
if (!TZ_isGlobalHideStatusBar) {
if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = _toolBar.isHidden;
}
}
- (void)doneButtonClick {
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
if (self.navigationController) {
if (imagePickerVc.autoDismiss) {
[self.navigationController dismissViewControllerAnimated:YES completion:^{
[self callDelegateMethod];
}];
}
} else {
[self dismissViewControllerAnimated:YES completion:^{
[self callDelegateMethod];
}];
}
}
- (void)callDelegateMethod {
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
UIImage *animatedImage = _previewView.imageView.image;
if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingGifImage:sourceAssets:)]) {
[imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingGifImage:animatedImage sourceAssets:_model.asset];
}
if (imagePickerVc.didFinishPickingGifImageHandle) {
imagePickerVc.didFinishPickingGifImageHandle(animatedImage,_model.asset);
}
}
#pragma clang diagnostic pop
@end
//
// TZImageCropManager.h
// TZImagePickerController
//
// Created by 谭真 on 2016/12/5.
// Copyright © 2016年 谭真. All rights reserved.
// 图片裁剪管理类
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface TZImageCropManager : NSObject
/// 裁剪框背景的处理
+ (void)overlayClippingWithView:(UIView *)view cropRect:(CGRect)cropRect containerView:(UIView *)containerView needCircleCrop:(BOOL)needCircleCrop;
/*
1.7.2 为了解决多位同学对于图片裁剪的需求,我这两天有空便在研究图片裁剪
幸好有tuyou的PhotoTweaks库做参考,裁剪的功能实现起来简单许多
该方法和其内部引用的方法基本来自于tuyou的PhotoTweaks库,我做了稍许删减和修改
感谢tuyou同学在github开源了优秀的裁剪库PhotoTweaks,表示感谢
PhotoTweaks库的github链接:https://github.com/itouch2/PhotoTweaks
*/
/// 获得裁剪后的图片
+ (UIImage *)cropImageView:(UIImageView *)imageView toRect:(CGRect)rect zoomScale:(double)zoomScale containerView:(UIView *)containerView;
/// 获取圆形图片
+ (UIImage *)circularClipImage:(UIImage *)image;
@end
/// 该分类的代码来自SDWebImage:https://github.com/rs/SDWebImage
/// 为了防止冲突,我将分类名字和方法名字做了修改
@interface UIImage (TZGif)
+ (UIImage *)sd_tz_animatedGIFWithData:(NSData *)data;
@end
//
// TZImageCropManager.m
// TZImagePickerController
//
// Created by 谭真 on 2016/12/5.
// Copyright © 2016年 谭真. All rights reserved.
//
#import "TZImageCropManager.h"
#import "UIView+Layout.h"
#import <ImageIO/ImageIO.h>
#import "TZImageManager.h"
@implementation TZImageCropManager
/// 裁剪框背景的处理
+ (void)overlayClippingWithView:(UIView *)view cropRect:(CGRect)cropRect containerView:(UIView *)containerView needCircleCrop:(BOOL)needCircleCrop {
UIBezierPath *path= [UIBezierPath bezierPathWithRect:[UIScreen mainScreen].bounds];
CAShapeLayer *layer = [CAShapeLayer layer];
if (needCircleCrop) { // 圆形裁剪框
[path appendPath:[UIBezierPath bezierPathWithArcCenter:containerView.center radius:cropRect.size.width / 2 startAngle:0 endAngle: 2 * M_PI clockwise:NO]];
} else { // 矩形裁剪框
[path appendPath:[UIBezierPath bezierPathWithRect:cropRect]];
}
layer.path = path.CGPath;
layer.fillRule = kCAFillRuleEvenOdd;
layer.fillColor = [[UIColor blackColor] CGColor];
layer.opacity = 0.5;
[view.layer addSublayer:layer];
}
/// 获得裁剪后的图片
+ (UIImage *)cropImageView:(UIImageView *)imageView toRect:(CGRect)rect zoomScale:(double)zoomScale containerView:(UIView *)containerView {
CGAffineTransform transform = CGAffineTransformIdentity;
// 平移的处理
CGRect imageViewRect = [imageView convertRect:imageView.bounds toView:containerView];
CGPoint point = CGPointMake(imageViewRect.origin.x + imageViewRect.size.width / 2, imageViewRect.origin.y + imageViewRect.size.height / 2);
CGFloat xMargin = containerView.tz_width - CGRectGetMaxX(rect) - rect.origin.x;
CGPoint zeroPoint = CGPointMake((CGRectGetWidth(containerView.frame) - xMargin) / 2, containerView.center.y);
CGPoint translation = CGPointMake(point.x - zeroPoint.x, point.y - zeroPoint.y);
transform = CGAffineTransformTranslate(transform, translation.x, translation.y);
// 缩放的处理
transform = CGAffineTransformScale(transform, zoomScale, zoomScale);
CGImageRef imageRef = [self newTransformedImage:transform
sourceImage:imageView.image.CGImage
sourceSize:imageView.image.size
outputWidth:rect.size.width * [UIScreen mainScreen].scale
cropSize:rect.size
imageViewSize:imageView.frame.size];
UIImage *cropedImage = [UIImage imageWithCGImage:imageRef];
cropedImage = [[TZImageManager manager] fixOrientation:cropedImage];
CGImageRelease(imageRef);
return cropedImage;
}
+ (CGImageRef)newTransformedImage:(CGAffineTransform)transform sourceImage:(CGImageRef)sourceImage sourceSize:(CGSize)sourceSize outputWidth:(CGFloat)outputWidth cropSize:(CGSize)cropSize imageViewSize:(CGSize)imageViewSize {
CGImageRef source = [self newScaledImage:sourceImage toSize:sourceSize];
CGFloat aspect = cropSize.height/cropSize.width;
CGSize outputSize = CGSizeMake(outputWidth, outputWidth*aspect);
CGContextRef context = CGBitmapContextCreate(NULL, outputSize.width, outputSize.height, CGImageGetBitsPerComponent(source), 0, CGImageGetColorSpace(source), CGImageGetBitmapInfo(source));
CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
CGContextFillRect(context, CGRectMake(0, 0, outputSize.width, outputSize.height));
CGAffineTransform uiCoords = CGAffineTransformMakeScale(outputSize.width / cropSize.width, outputSize.height / cropSize.height);
uiCoords = CGAffineTransformTranslate(uiCoords, cropSize.width/2.0, cropSize.height / 2.0);
uiCoords = CGAffineTransformScale(uiCoords, 1.0, -1.0);
CGContextConcatCTM(context, uiCoords);
CGContextConcatCTM(context, transform);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGRectMake(-imageViewSize.width/2, -imageViewSize.height/2.0, imageViewSize.width, imageViewSize.height), source);
CGImageRef resultRef = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGImageRelease(source);
return resultRef;
}
+ (CGImageRef)newScaledImage:(CGImageRef)source toSize:(CGSize)size {
CGSize srcSize = size;
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 8, 0, rgbColorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(rgbColorSpace);
CGContextSetInterpolationQuality(context, kCGInterpolationNone);
CGContextTranslateCTM(context, size.width/2, size.height/2);
CGContextDrawImage(context, CGRectMake(-srcSize.width/2, -srcSize.height/2, srcSize.width, srcSize.height), source);
CGImageRef resultRef = CGBitmapContextCreateImage(context);
CGContextRelease(context);
return resultRef;
}
/// 获取圆形图片
+ (UIImage *)circularClipImage:(UIImage *)image {
UIGraphicsBeginImageContextWithOptions(image.size, NO, [UIScreen mainScreen].scale);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
CGContextAddEllipseInRect(ctx, rect);
CGContextClip(ctx);
[image drawInRect:rect];
UIImage *circleImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return circleImage;
}
@end
@implementation UIImage (TZGif)
+ (UIImage *)sd_tz_animatedGIFWithData:(NSData *)data {
if (!data) {
return nil;
}
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
size_t count = CGImageSourceGetCount(source);
UIImage *animatedImage;
if (count <= 1) {
animatedImage = [[UIImage alloc] initWithData:data];
}
else {
NSMutableArray *images = [NSMutableArray array];
NSTimeInterval duration = 0.0f;
for (size_t i = 0; i < count; i++) {
CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
if (!image) {
continue;
}
duration += [self sd_frameDurationAtIndex:i source:source];
[images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
CGImageRelease(image);
}
if (!duration) {
duration = (1.0f / 10.0f) * count;
}
animatedImage = [UIImage animatedImageWithImages:images duration:duration];
}
CFRelease(source);
return animatedImage;
}
+ (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source {
float frameDuration = 0.1f;
CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
if (delayTimeUnclampedProp) {
frameDuration = [delayTimeUnclampedProp floatValue];
}
else {
NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
if (delayTimeProp) {
frameDuration = [delayTimeProp floatValue];
}
}
// Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
// We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
// a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
// for more information.
if (frameDuration < 0.011f) {
frameDuration = 0.100f;
}
CFRelease(cfFrameProperties);
return frameDuration;
}
@end
//
// 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>
#import <Photos/Photos.h>
#import "TZAssetModel.h"
@class TZAlbumModel,TZAssetModel;
@protocol TZImagePickerControllerDelegate;
@interface TZImageManager : NSObject
@property (nonatomic, strong) PHCachingImageManager *cachingImageManager;
+ (instancetype)manager NS_SWIFT_NAME(default());
+ (void)deallocManager;
@property (assign, nonatomic) id<TZImagePickerControllerDelegate> pickerDelegate;
@property (nonatomic, assign) BOOL shouldFixOrientation;
/// Default is 600px / 默认600像素宽
@property (nonatomic, assign) CGFloat photoPreviewMaxWidth;
/// The pixel width of output image, Default is 828px / 导出图片的宽度,默认828像素宽
@property (nonatomic, assign) CGFloat photoWidth;
/// Default is 4, Use in photos collectionView in TZPhotoPickerController
/// 默认4列, TZPhotoPickerController中的照片collectionView
@property (nonatomic, assign) NSInteger columnNumber;
/// Sort photos ascending by modificationDate,Default is YES
/// 对照片排序,按修改时间升序,默认是YES。如果设置为NO,最新的照片会显示在最前面,内部的拍照按钮会排在第一个
@property (nonatomic, assign) BOOL sortAscendingByModificationDate;
/// Minimum selectable photo width, Default is 0
/// 最小可选中的图片宽度,默认是0,小于这个宽度的图片不可选中
@property (nonatomic, assign) NSInteger minPhotoWidthSelectable;
@property (nonatomic, assign) NSInteger minPhotoHeightSelectable;
@property (nonatomic, assign) BOOL hideWhenCanNotSelect;
/// Return YES if Authorized 返回YES如果得到了授权
- (BOOL)authorizationStatusAuthorized;
+ (NSInteger)authorizationStatus;
- (void)requestAuthorizationWithCompletion:(void (^)())completion;
/// Get Album 获得相册/相册数组
- (void)getCameraRollAlbum:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAlbumModel *model))completion;
- (void)getAllAlbums:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray<TZAlbumModel *> *models))completion;
/// Get Assets 获得Asset数组
- (void)getAssetsFromFetchResult:(id)result allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray<TZAssetModel *> *models))completion;
- (void)getAssetFromFetchResult:(id)result atIndex:(NSInteger)index allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAssetModel *model))completion;
/// Get photo 获得照片
- (void)getPostImageWithAlbumModel:(TZAlbumModel *)model completion:(void (^)(UIImage *postImage))completion;
- (int32_t)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion;
- (int32_t)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion;
- (int32_t)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed;
- (int32_t)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed;
/// Get full Image 获取原图
/// 如下两个方法completion一般会调多次,一般会先返回缩略图,再返回原图(详见方法内部使用的系统API的说明),如果info[PHImageResultIsDegradedKey] 为 YES,则表明当前返回的是缩略图,否则是原图。
- (void)getOriginalPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info))completion;
- (void)getOriginalPhotoWithAsset:(id)asset newCompletion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion;
// 该方法中,completion只会走一次
- (void)getOriginalPhotoDataWithAsset:(id)asset completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion;
/// Save photo 保存照片
- (void)savePhotoWithImage:(UIImage *)image completion:(void (^)(NSError *error))completion;
- (void)savePhotoWithImage:(UIImage *)image location:(CLLocation *)location completion:(void (^)(NSError *error))completion;
/// Get video 获得视频
- (void)getVideoWithAsset:(id)asset completion:(void (^)(AVPlayerItem * playerItem, NSDictionary * info))completion;
- (void)getVideoWithAsset:(id)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(AVPlayerItem *, NSDictionary *))completion;
/// Export video 导出视频
- (void)getVideoOutputPathWithAsset:(id)asset completion:(void (^)(NSString *outputPath))completion;
/// Get photo bytes 获得一组照片的大小
- (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString *totalBytes))completion;
/// Judge is a assets array contain the asset 判断一个assets数组是否包含这个asset
- (BOOL)isAssetsArray:(NSArray *)assets containAsset:(id)asset;
- (NSString *)getAssetIdentifier:(id)asset;
- (BOOL)isCameraRollAlbum:(id)metadata;
/// 检查照片大小是否满足最小要求
- (BOOL)isPhotoSelectableWithAsset:(id)asset;
- (CGSize)photoSizeWithAsset:(id)asset;
/// 修正图片转向
- (UIImage *)fixOrientation:(UIImage *)aImage;
/// 获取asset的资源类型
- (TZAssetModelMediaType)getAssetType:(id)asset;
@end
//@interface TZSortDescriptor : NSSortDescriptor
//
//@end
This diff is collapsed.
<?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>StringsTable</key>
<string>Root</string>
<key>PreferenceSpecifiers</key>
<array>
<dict>
<key>Type</key>
<string>PSGroupSpecifier</string>
<key>Title</key>
<string>Group</string>
</dict>
<dict>
<key>Type</key>
<string>PSTextFieldSpecifier</string>
<key>Title</key>
<string>Name</string>
<key>Key</key>
<string>name_preference</string>
<key>DefaultValue</key>
<string></string>
<key>IsSecure</key>
<false/>
<key>KeyboardType</key>
<string>Alphabet</string>
<key>AutocapitalizationType</key>
<string>None</string>
<key>AutocorrectionType</key>
<string>No</string>
</dict>
<dict>
<key>Type</key>
<string>PSToggleSwitchSpecifier</string>
<key>Title</key>
<string>Enabled</string>
<key>Key</key>
<string>enabled_preference</string>
<key>DefaultValue</key>
<true/>
</dict>
<dict>
<key>Type</key>
<string>PSSliderSpecifier</string>
<key>Key</key>
<string>slider_preference</string>
<key>DefaultValue</key>
<real>0.5</real>
<key>MinimumValue</key>
<integer>0</integer>
<key>MaximumValue</key>
<integer>1</integer>
<key>MinimumValueImage</key>
<string></string>
<key>MaximumValueImage</key>
<string></string>
</dict>
</array>
</dict>
</plist>
This diff is collapsed.
This diff is collapsed.
//
// TZLocationManager.h
// TZImagePickerController
//
// Created by 谭真 on 2017/06/03.
// Copyright © 2017年 谭真. All rights reserved.
// 定位管理类
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
@interface TZLocationManager : NSObject
+ (instancetype)manager;
/// 开始定位
- (void)startLocation;
- (void)startLocationWithSuccessBlock:(void (^)(CLLocation *location,CLLocation *oldLocation))successBlock failureBlock:(void (^)(NSError *error))failureBlock;
- (void)startLocationWithGeocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock;
- (void)startLocationWithSuccessBlock:(void (^)(CLLocation *location,CLLocation *oldLocation))successBlock failureBlock:(void (^)(NSError *error))failureBlock geocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock;
@end
//
// TZLocationManager.m
// TZImagePickerController
//
// Created by 谭真 on 2017/06/03.
// Copyright © 2017年 谭真. All rights reserved.
// 定位管理类
#import "TZLocationManager.h"
#import "TZImagePickerController.h"
@interface TZLocationManager ()<CLLocationManagerDelegate>
@property (nonatomic, strong) CLLocationManager *locationManager;
/// 定位成功的回调block
@property (nonatomic, copy) void (^successBlock)(CLLocation *location,CLLocation *oldLocation);
/// 编码成功的回调block
@property (nonatomic, copy) void (^geocodeBlock)(NSArray *geocodeArray);
/// 定位失败的回调block
@property (nonatomic, copy) void (^failureBlock)(NSError *error);
@end
@implementation TZLocationManager
+ (instancetype)manager {
static TZLocationManager *manager;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[self alloc] init];
manager.locationManager = [[CLLocationManager alloc] init];
manager.locationManager.delegate = manager;
if (iOS8Later) {
[manager.locationManager requestWhenInUseAuthorization];
}
});
return manager;
}
- (void)startLocation {
[self startLocationWithSuccessBlock:nil failureBlock:nil geocoderBlock:nil];
}
- (void)startLocationWithSuccessBlock:(void (^)(CLLocation *location,CLLocation *oldLocation))successBlock failureBlock:(void (^)(NSError *error))failureBlock {
[self startLocationWithSuccessBlock:successBlock failureBlock:failureBlock geocoderBlock:nil];
}
- (void)startLocationWithGeocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock {
[self startLocationWithSuccessBlock:nil failureBlock:nil geocoderBlock:geocoderBlock];
}
- (void)startLocationWithSuccessBlock:(void (^)(CLLocation *location,CLLocation *oldLocation))successBlock failureBlock:(void (^)(NSError *error))failureBlock geocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock {
[self.locationManager startUpdatingLocation];
_successBlock = successBlock;
_geocodeBlock = geocoderBlock;
_failureBlock = failureBlock;
}
#pragma mark - CLLocationManagerDelegate
/// 地理位置发生改变时触发
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
[manager stopUpdatingLocation];
if (_successBlock) {
_successBlock(newLocation,oldLocation);
}
if (_geocodeBlock) {
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *array, NSError *error) {
_geocodeBlock(array);
}];
}
}
/// 定位失败回调方法
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(@"定位失败, 错误: %@",error);
switch([error code]) {
case kCLErrorDenied: { // 用户禁止了定位权限
} break;
default: break;
}
if (_failureBlock) {
_failureBlock(error);
}
}
@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, assign) BOOL isFirstAppear;
@property (nonatomic, assign) NSInteger columnNumber;
@property (nonatomic, strong) TZAlbumModel *model;
@end
@interface TZCollectionView : UICollectionView
@end
This diff is collapsed.
//
// TZPhotoPreviewCell.h
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
@class TZAssetModel;
@interface TZAssetPreviewCell : UICollectionViewCell
@property (nonatomic, strong) TZAssetModel *model;
@property (nonatomic, copy) void (^singleTapGestureBlock)();
- (void)configSubviews;
- (void)photoPreviewCollectionViewDidScroll;
@end
@class TZAssetModel,TZProgressView,TZPhotoPreviewView;
@interface TZPhotoPreviewCell : TZAssetPreviewCell
@property (nonatomic, copy) void (^imageProgressUpdateBlock)(double progress);
@property (nonatomic, strong) TZPhotoPreviewView *previewView;
@property (nonatomic, assign) BOOL allowCrop;
@property (nonatomic, assign) CGRect cropRect;
- (void)recoverSubviews;
@end
@interface TZPhotoPreviewView : UIView
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIView *imageContainerView;
@property (nonatomic, strong) TZProgressView *progressView;
@property (nonatomic, assign) BOOL allowCrop;
@property (nonatomic, assign) CGRect cropRect;
@property (nonatomic, strong) TZAssetModel *model;
@property (nonatomic, strong) id asset;
@property (nonatomic, copy) void (^singleTapGestureBlock)();
@property (nonatomic, copy) void (^imageProgressUpdateBlock)(double progress);
@property (nonatomic, assign) int32_t imageRequestID;
- (void)recoverSubviews;
@end
@class AVPlayer, AVPlayerLayer;
@interface TZVideoPreviewCell : TZAssetPreviewCell
@property (strong, nonatomic) AVPlayer *player;
@property (strong, nonatomic) AVPlayerLayer *playerLayer;
@property (strong, nonatomic) UIButton *playButton;
@property (strong, nonatomic) UIImage *cover;
- (void)pausePlayerAndShowNaviBar;
@end
@interface TZGifPreviewCell : TZAssetPreviewCell
@property (strong, nonatomic) TZPhotoPreviewView *previewView;
@end
This diff is collapsed.
//
// TZPhotoPreviewController.h
// TZImagePickerController
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface TZPhotoPreviewController : UIViewController
@property (nonatomic, strong) NSMutableArray *models; ///< All photo models / 所有图片模型数组
@property (nonatomic, strong) NSMutableArray *photos; ///< All photos / 所有图片数组
@property (nonatomic, assign) NSInteger currentIndex; ///< Index of the photo user click / 用户点击的图片的索引
@property (nonatomic, assign) BOOL isSelectOriginalPhoto; ///< If YES,return original photo / 是否返回原图
@property (nonatomic, assign) BOOL isCropImage;
/// Return the new selected photos / 返回最新的选中图片数组
@property (nonatomic, copy) void (^backButtonClickBlock)(BOOL isSelectOriginalPhoto);
@property (nonatomic, copy) void (^doneButtonClickBlock)(BOOL isSelectOriginalPhoto);
@property (nonatomic, copy) void (^doneButtonClickBlockCropMode)(UIImage *cropedImage,id asset);
@property (nonatomic, copy) void (^doneButtonClickBlockWithPreviewType)(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto);
@end
This diff is collapsed.
//
// TZProgressView.h
// TZImagePickerController
//
// Created by ttouch on 2016/12/6.
// Copyright © 2016年 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface TZProgressView : UIView
@property (nonatomic, assign) double progress;
@end
//
// TZProgressView.m
// TZImagePickerController
//
// Created by ttouch on 2016/12/6.
// Copyright © 2016年 谭真. All rights reserved.
//
#import "TZProgressView.h"
@interface TZProgressView ()
@property (nonatomic, strong) CAShapeLayer *progressLayer;
@end
@implementation TZProgressView
- (instancetype)init {
self = [super init];
if (self) {
self.backgroundColor = [UIColor clearColor];
_progressLayer = [CAShapeLayer layer];
_progressLayer.fillColor = [[UIColor clearColor] CGColor];
_progressLayer.strokeColor = [[UIColor whiteColor] CGColor];
_progressLayer.opacity = 1;
_progressLayer.lineCap = kCALineCapRound;
_progressLayer.lineWidth = 5;
[_progressLayer setShadowColor:[UIColor blackColor].CGColor];
[_progressLayer setShadowOffset:CGSizeMake(1, 1)];
[_progressLayer setShadowOpacity:0.5];
[_progressLayer setShadowRadius:2];
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGPoint center = CGPointMake(rect.size.width / 2, rect.size.height / 2);
CGFloat radius = rect.size.width / 2;
CGFloat startA = - M_PI_2;
CGFloat endA = - M_PI_2 + M_PI * 2 * _progress;
_progressLayer.frame = self.bounds;
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
_progressLayer.path =[path CGPath];
[_progressLayer removeFromSuperlayer];
[self.layer addSublayer:_progressLayer];
}
- (void)setProgress:(double)progress {
_progress = progress;
[self setNeedsDisplay];
}
@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;
AVPlayerLayer *_playerLayer;
UIButton *_playButton;
UIImage *_cover;
UIView *_toolBar;
UIButton *_doneButton;
UIProgressView *_progress;
UIStatusBarStyle _originStatusBarStyle;
}
@end
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
@implementation TZVideoPlayerController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
if (tzImagePickerVc) {
self.navigationItem.title = tzImagePickerVc.previewBtnTitleStr;
}
[self configMoviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:UIApplicationWillResignActiveNotification object:nil];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
_originStatusBarStyle = [UIApplication sharedApplication].statusBarStyle;
[UIApplication sharedApplication].statusBarStyle = iOS7Later ? UIStatusBarStyleLightContent : UIStatusBarStyleBlackOpaque;
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[UIApplication sharedApplication].statusBarStyle = _originStatusBarStyle;
}
- (void)configMoviePlayer {
[[TZImageManager manager] getPhotoWithAsset:_model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
_cover = photo;
}];
[[TZImageManager manager] getVideoWithAsset:_model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) {
dispatch_async(dispatch_get_main_queue(), ^{
_player = [AVPlayer playerWithPlayerItem:playerItem];
_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 setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal];
[_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlayHL"] forState:UIControlStateHighlighted];
[_playButton addTarget:self action:@selector(playButtonClick) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_playButton];
}
- (void)configBottomToolBar {
_toolBar = [[UIView alloc] initWithFrame:CGRectZero];
CGFloat rgb = 34 / 255.0;
_toolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.7];
_doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
_doneButton.titleLabel.font = [UIFont systemFontOfSize:16];
[_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside];
TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
if (tzImagePickerVc) {
[_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal];
[_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal];
} else {
[_doneButton setTitle:[NSBundle tz_localizedStringForKey:@"Done"] forState:UIControlStateNormal];
[_doneButton setTitleColor:[UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0] forState:UIControlStateNormal];
}
[_toolBar addSubview:_doneButton];
[self.view addSubview:_toolBar];
}
#pragma mark - Layout
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
_playerLayer.frame = self.view.bounds;
_playButton.frame = CGRectMake(0, 64, self.view.tz_width, self.view.tz_height - 64 - 44);
_doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44);
_toolBar.frame = CGRectMake(0, self.view.tz_height - 44, self.view.tz_width, 44);
}
#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 (!TZ_isGlobalHideStatusBar) {
if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES;
}
} else {
[self pausePlayerAndShowNaviBar];
}
}
- (void)doneButtonClick {
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
if (self.navigationController) {
if (imagePickerVc.autoDismiss) {
[self.navigationController dismissViewControllerAnimated:YES completion:^{
[self callDelegateMethod];
}];
} else {
[self callDelegateMethod];
}
} else {
[self dismissViewControllerAnimated:YES completion:^{
[self callDelegateMethod];
}];
}
}
- (void)callDelegateMethod {
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);
}
}
#pragma mark - Notification Method
- (void)pausePlayerAndShowNaviBar {
[_player pause];
_toolBar.hidden = NO;
[self.navigationController setNavigationBarHidden:NO];
[_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal];
if (!TZ_isGlobalHideStatusBar) {
if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = NO;
}
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma clang diagnostic pop
@end
This diff is collapsed.
This diff is collapsed.
{
"name": "react-native-syan-image-picker",
"version": "0.0.1",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"react-native"
],
"author": "",
"license": ""
}
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