Как сделать так, чтобы пользовательский оверлей камеры UIImagePicker был полноэкранным в iOS 7?
Я заинтересован в использовании пользовательского наложения для UIImagePickerController
для элементов управления камерой, занимающих весь экран, очень похоже на то, что делает приложение камеры по умолчанию при переключении на функцию видео.
Я упомянул несколько вопросов здесь на SO по этой теме, в частности, этот, а также пример Apple о том, как использовать пользовательское наложение для UIImagePickerController, но ни один из них не смог привести к успешному полноэкранному результату с IOS 7.
Итак, вот как выглядит пользовательский интерфейс камеры с пользовательским оверлеем (без каких-либо кнопок):
Обратите внимание, что в нижней части экрана есть черная полоса. Я заметил, что я могу удалить черную полосу, если я изменю cameraAspectRatio
в 1, но это искажает масштаб камеры, так как он имеет очень увеличенное изображение. Есть ли способ получить полноэкранный режим без чрезмерного искажения увеличения (я понимаю, что нужно немного), а также убрать черную полосу?
Вот мой код, который настраивает пользовательское наложение:
{
self.imagePickerController.showsCameraControls = NO;
[[NSBundle mainBundle] loadNibNamed:@"overlayView" owner:self options:nil];
self.overlayView.frame = self.imagePickerController.cameraOverlayView.frame;
self.imagePickerController.cameraOverlayView = self.overlayView;
self.overlayView = nil;
// Device's screen size (ignoring rotation intentionally):
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
float cameraAspectRatio = 4.0 / 3.0; //! Note: 4.0 and 4.0 works
float imageWidth = floorf(screenSize.width * cameraAspectRatio);
float scale = ceilf((screenSize.height / imageWidth) * 10.0) / 10.0;
self.imagePickerController.cameraViewTransform = CGAffineTransformMakeScale(scale, scale);
}
Обновить:
Еще одна проблема, которую я заметил, заключается в том, что изображение, отображаемое в режиме предварительного просмотра камеры, всегда меньше и содержит меньше деталей, чем изображение, которое сохраняется при использовании метода. [self.imagePickerController takePicture]
, Проиллюстрировать:
Вот как выглядит клавиатура в окне предварительного просмотра камеры с черной полосой ниже (извините, она немного шаткая):
Тем не менее, обратите внимание, что фактическое захваченное изображение на панели предварительного просмотра имеет гораздо больше деталей, как показано здесь, особенно в направлении сверху, а также слева и справа.
Мой вопрос заключается в том, как можно настроить предварительный просмотр моей камеры таким образом, чтобы пользователь видел в предварительном просмотре именно то изображение, которое он будет захватывать и которое могло быть показано ему впоследствии? Спасибо!
Обновление 2
Вот весь код в viewDidLoad
который устанавливает элементы управления камерой.
- (void)viewDidLoad
{
[super viewDidLoad];
//Appearance configuration
self.navigationItem.hidesBackButton = YES;
//UIImagePickerController initialization and setup
self.imagePickerController = [[UIImagePickerController alloc] init];
self.imagePickerController.delegate = self;
self.imagePickerController.allowsEditing = NO;
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]){
self.imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera; //if there is a camera avaliable
} else {
self.imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;//otherwise go to the folder
}
self.imagePickerController.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeImage, nil];
if (self.imagePickerController.sourceType == UIImagePickerControllerSourceTypeCamera)
{
self.imagePickerController.showsCameraControls = NO;
[[NSBundle mainBundle] loadNibNamed:@"overlayView" owner:self options:nil];
self.overlayView.frame = self.imagePickerController.cameraOverlayView.frame;
self.imagePickerController.cameraOverlayView = self.overlayView;
self.overlayView = nil;
// Device's screen size (ignoring rotation intentionally):
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
int heightOffset = 0;
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"))
{
heightOffset = 120; //whole screen :)
}
float cameraAspectRatio = 4.0 / 3.0; //! Note: 4.0 and 4.0 works
float imageWidth = floorf(screenSize.width * cameraAspectRatio);
float scale = ceilf(((screenSize.height + heightOffset) / imageWidth) * 10.0) / 10.0;
self.imagePickerController.cameraViewTransform = CGAffineTransformMakeScale(scale, scale);
}
}
И в viewWillAppear
Я называю вид средства выбора изображений:
BOOL modalPresent = (BOOL)(self.presentedViewController);
//Present the Camera UIImagePicker if no image is taken
if (!appDelegate.imageStorageDictionary[@"picture1"]){
if (modalPresent == NO){ //checks if the UIImagePickerController is modally active
[self presentViewController:self.imagePickerController animated:NO completion:nil];
}
}
9 ответов
После многих попыток это то, что сработало для меня, благодаря огромному количеству предложений других людей. Следующие факты очень помогли узнать и запомнить:
Разрешение точек камеры составляет 426 * 320. Чтобы высота предварительного просмотра камеры была растянута до высоты экрана телефона 568, ее необходимо умножить на коэффициент 1,3333 при использовании CGAffineTransformScale
,
Обратите внимание, что ниже жестко запрограммированы различные числа в зависимости от разрешения экрана iPhone 5 в пунктах. Их можно улучшить, используя такие объекты, как screen.height, screen.width и другие переменные, чтобы сделать его применимым к размерам iPhone 4/4s.
self.imagePickerController.showsCameraControls = NO;
[[NSBundle mainBundle] loadNibNamed:@"overlayView" owner:self options:nil];
self.overlayView.frame = self.imagePickerController.cameraOverlayView.frame;
self.imagePickerController.cameraOverlayView = self.overlayView;
self.overlayView = nil;
//For iphone 5+
//Camera is 426 * 320. Screen height is 568. Multiply by 1.333 in 5 inch to fill vertical
CGAffineTransform translate = CGAffineTransformMakeTranslation(0.0, 71.0); //This slots the preview exactly in the middle of the screen by moving it down 71 points
self.imagePickerController.cameraViewTransform = translate;
CGAffineTransform scale = CGAffineTransformScale(translate, 1.333333, 1.333333);
self.imagePickerController.cameraViewTransform = scale;
В Свифте
var picker: UIImagePickerController = UIImagePickerController();
picker.sourceType = UIImagePickerControllerSourceType.Camera;
picker.showsCameraControls = false;
var screenBounds: CGSize = UIScreen.mainScreen().bounds.size;
var scale = screenBounds.height / screenBounds.width;
picker.cameraViewTransform = CGAffineTransformScale(picker.cameraViewTransform, scale, scale);
Убедитесь, что вы учитываете изменение строки состояния 20px в iOS7. Если вы столкнулись с черным экраном 20px в нижней части экрана, то это будет вашей проблемой. Вы можете проверить, работает ли приложение в ios7 или нет одним из этих препроцессоров.
#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
И вы можете внести следующие изменения в свой код и посмотреть, работает ли он
{
self.imagePickerController.showsCameraControls = NO;
[[NSBundle mainBundle] loadNibNamed:@"overlayView" owner:self options:nil];
self.overlayView.frame = self.imagePickerController.cameraOverlayView.frame;
self.imagePickerController.cameraOverlayView = self.overlayView;
self.overlayView = nil;
// Device's screen size (ignoring rotation intentionally):
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
int heightOffset = 0;
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"))
{
heightOffset = 20;
}
float cameraAspectRatio = 4.0 / 3.0; //! Note: 4.0 and 4.0 works
float imageWidth = floorf(screenSize.width * cameraAspectRatio);
float scale = ceilf(((screenSize.height + heightOffset) / imageWidth) * 10.0) / 10.0;
self.imagePickerController.cameraViewTransform = CGAffineTransformMakeScale(scale, scale);
}
Пожалуйста, дайте мне знать, если это работает. Я не закодировал это, чтобы проверить.
Существует более простой способ получить полноэкранный оверлей, по крайней мере, протестированный в iOS 9.
let view = ... your overlayView
let bounds = UIScreen.mainScreen().bounds
view.center = CGPoint(x: bounds.midX, y: bounds.midY)
view.bounds = bounds
self.imagePicker.cameraOverlayView = view
Поскольку соотношение сторон экрана отличается от соотношения 4/3 самой камеры, необходимо (как вы упомянули) слегка обрезать края, чтобы изображение доходило до дна.
Чтобы сделать это, вам нужно, чтобы ширина была достаточно широкой, чтобы высота могла быть на весь экран. Итак, ширина и высота вашего изображения должны быть:
float cameraAspectRatio = 4.0 / 3.0; //! Note: 4.0 and 4.0 works
float imageWidth = screenSize.height / cameraAspectRatio;
Вы также, вероятно, захотите, чтобы представление, представляющее изображение с камеры, имело ту ширину, которая простирается с обеих сторон экрана.
Попробуй этот код, он у меня нормально работает
UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;
cameraUI.showsCameraControls = NO;
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
float cameraAspectRatio = 4.0 / 3.0;
float imageHeight = floorf(screenSize.width * cameraAspectRatio);
float scale = screenSize.height / imageHeight;
float trans = (screenSize.height - imageHeight)/2;
CGAffineTransform translate = CGAffineTransformMakeTranslation(0.0, trans);
CGAffineTransform final = CGAffineTransformScale(translate, scale, scale);
cameraUI.cameraViewTransform = final
;
cameraUI.delegate = self;
[self presentViewController:cameraUI animated:YES completion:nil];
Этот код предполагает, что аспект исходной области предварительного просмотра камеры - 4:3.
Я не знаю, почему вы используете размер экрана. Просто попробуйте этот простой код:
if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera])
{
UIImagePickerController *controller = [[UIImagePickerController alloc] init];
controller.sourceType = UIImagePickerControllerSourceTypeCamera;
controller.allowsEditing = NO;
controller.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:
UIImagePickerControllerSourceTypeCamera];
controller.delegate = self;
[self presentViewController:controller animated:NO completion:^{}];
}
Чтобы решить аналогичную проблему, я создал экземпляр ViewController из раскадровки и использовал вид контроллера в качестве наложения камеры. Я не знаю, если это то, что вы ищете, но я использовал следующий код:
UIImagePickerController *globalPicker = [[UIImagePickerController alloc] init];
globalPicker.delegate = self;
globalPicker.sourceType = UIImagePickerControllerSourceTypeCamera;controller=[self.storyboard instantiateViewControllerWithIdentifier:@"myVC"];
overlayView = controller.view;
UIView *cameraView=[[UIView alloc] initWithFrame:self.view.bounds];
[cameraView addSubview:overlayView];
[globalPicker setCameraOverlayView:cameraView];
Попробуйте этот код, чтобы сохранить результирующее изображение в произвольном размере. Я получил результат с помощью пользовательского метода для получения результирующего изображения в качестве нестандартного размера.
Сначала создать IBOutlet
за UIImageview
,
-(void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString *mediaType = info[UIImagePickerControllerMediaType];
[self dismissViewControllerAnimated:YES completion:nil];
if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
OriginalImage=info[UIImagePickerControllerOriginalImage];
image = info[UIImagePickerControllerOriginalImage];
//----------------------------------------
imageview.image = image; //------------- additional method for custom image size
self resizeImage];
//-----------------------------------------
if (_newMedia)
UIImageWriteToSavedPhotosAlbum(image,self,@selector(image:finishedSavingWithError:contextInfo:),nil);
}
else if ([mediaType isEqualToString:(NSString *)kUTTypeMovie])
{
// Code here to support video if enabled
}
}
//---- Изменение размера исходного изображения с помощью пользовательского метода ----------------------
-(void)resizeImage
{
UIImage *resizeImage = imageview.image;
float width = 320;
float height = 320;
CGSize newSize = CGSizeMake(320,320);
UIGraphicsBeginImageContextWithOptions(newSize,NO,0.0);
CGRect rect = CGRectMake(0, 0, width, height);
float widthRatio = resizeImage.size.width / width;
float heightRatio = resizeImage.size.height / height;
float divisor = widthRatio > heightRatio ? widthRatio : heightRatio;
width = resizeImage.size.width / divisor;
height = resizeImage.size.height / divisor;
rect.size.width = width;
rect.size.height = height;
//indent in case of width or height difference
float offset = (width - height) / 2;
if (offset > 0) {
rect.origin.y = offset;
}
else {
rect.origin.x = -offset;
}
[resizeImage drawInRect: rect];
UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
imageview.image = smallImage;
imageview.contentMode = UIViewContentModeScaleAspectFit;
}