Захват полного снимка экрана со строкой состояния в iOS программно
Я использую этот код для захвата снимка экрана и сохранения его в фотоальбоме.
-(void)TakeScreenshotAndSaveToPhotoAlbum
{
UIWindow *window = [UIApplication sharedApplication].keyWindow;
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)])
UIGraphicsBeginImageContextWithOptions(window.bounds.size, NO, [UIScreen mainScreen].scale);
else
UIGraphicsBeginImageContext(window.bounds.size);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}
Но проблема в том, что всякий раз, когда снимок экрана сохраняется, я вижу, что строка состояния iPhone не записана. Вместо этого появляется пустое пространство внизу. Как и следующее изображение:
![enter image description here]()
Что я делаю неправильно?
Ответы
Ответ 1
Строка состояния фактически находится в собственном UIWindow, в вашем коде вы только визуализируете представление своего диспетчера взглядов, который не включает это.
"Официальный" способ скриншотов был здесь, но теперь, похоже, был удален Apple, вероятно, из-за его устаревания.
В iOS 7 теперь есть новый метод для UIScreen
для получения представления, содержащего содержимое всего экрана:
- (UIView *)snapshotViewAfterScreenUpdates:(BOOL)afterUpdates
Это даст вам представление, которое затем можно манипулировать на экране для различных визуальных эффектов.
Если вы хотите нарисовать иерархию представлений в контексте, вам необходимо выполнить итерацию через окна приложения ([[UIApplication sharedApplication] windows]
) и вызвать этот метод для каждого из них:
- (BOOL)drawViewHierarchyInRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates
Вы можете комбинировать два вышеупомянутых подхода и отобразить снимок, а затем использовать приведенный выше метод для моментального снимка для его рисования.
Ответ 2
Предлагаемый "официальный" способ скриншотов не отображает строку состояния (она не находится в списке окон приложения). Как проверено на iOS 5.
Я считаю, что это по соображениям безопасности, но об этом не упоминается в документах.
Я предлагаю два варианта:
- нарисуйте изображение строки состояния заглушки из ресурсов вашего приложения (необязательно обновите индикатор времени);
- захватить только ваше представление, без строки состояния или обрезать изображение (размер изображения будет отличаться от стандартного разрешения устройства); Кадр состояния-строки известен из соответствующего свойства объекта приложения.
Ответ 3
Вот мой код, чтобы сделать снимок экрана и сохранить его как NSData (внутри IBAction). С помощью sotred NSData вы можете делиться или отправлять по электронной почте или что угодно делать
CGSize imageSize = [[UIScreen mainScreen] bounds].size;
if (NULL != UIGraphicsBeginImageContextWithOptions)
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
else
UIGraphicsBeginImageContext(imageSize);
CGContextRef context = UIGraphicsGetCurrentContext();
// Iterate over every window from back to front
for (UIWindow *window in [[UIApplication sharedApplication] windows])
{
if (![window respondsToSelector:@selector(screen)] || [window screen] == [UIScreen mainScreen])
{
// -renderInContext: renders in the coordinate space of the layer,
// so we must first apply the layer geometry to the graphics context
CGContextSaveGState(context);
// Center the context around the window anchor point
CGContextTranslateCTM(context, [window center].x, [window center].y);
// Apply the window transform about the anchor point
CGContextConcatCTM(context, [window transform]);
// Offset by the portion of the bounds left of and above the anchor point
CGContextTranslateCTM(context,
-[window bounds].size.width * [[window layer] anchorPoint].x,
-[window bounds].size.height * [[window layer] anchorPoint].y);
// Render the layer hierarchy to the current context
[[window layer] renderInContext:context];
// Restore the context
CGContextRestoreGState(context);
}
}
// Retrieve the screenshot image
UIImage *imageForEmail = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *imageDataForEmail = UIImageJPEGRepresentation(imageForEmail, 1.0);
Ответ 4
Ответ на поставленный выше вопрос для Objective-C
уже записан, вот вариант ответа Swift
на поставленный выше вопрос.
Для Свифта 3+
Сделайте снимок экрана, а затем используйте его для отображения где-либо или для отправки через Интернет.
extension UIImage {
class var screenShot: UIImage? {
let imageSize = UIScreen.main.bounds.size as CGSize;
UIGraphicsBeginImageContextWithOptions(imageSize, false, 0)
guard let context = UIGraphicsGetCurrentContext() else {return nil}
for obj : AnyObject in UIApplication.shared.windows {
if let window = obj as? UIWindow {
if window.responds(to: #selector(getter: UIWindow.screen)) || window.screen == UIScreen.main {
// so we must first apply the layer geometry to the graphics context
context.saveGState();
// Center the context around the window anchor point
context.translateBy(x: window.center.x, y: window.center
.y);
// Apply the window transform about the anchor point
context.concatenate(window.transform);
// Offset by the portion of the bounds left of and above the anchor point
context.translateBy(x: -window.bounds.size.width * window.layer.anchorPoint.x,
y: -window.bounds.size.height * window.layer.anchorPoint.y);
// Render the layer hierarchy to the current context
window.layer.render(in: context)
// Restore the context
context.restoreGState();
}
}
}
guard let image = UIGraphicsGetImageFromCurrentImageContext() else {return nil}
return image
}
}
Использование приведенного выше снимка экрана
Позволяет отображать снимок экрана выше на UIImageView
yourImageView = UIImage.screenShot
Получить данные изображения для сохранения/отправки через Интернет
if let img = UIImage.screenShot {
if let data = UIImagePNGRepresentation(img) {
//send this data over web or store it anywhere
}
}
Ответ 5
Swift, iOS 13:
Приведенный ниже код (и другие способы доступа) теперь приводят к падению приложения с сообщением:
Приложение называется -statusBar или -statusBar Window на UIApplication: этот код необходимо изменить, так как больше нет строки состояния или окна строки состояния. Вместо этого используйте объект statusBarManager на сцене окна.
Сцены окон и statusBarManager действительно дают нам доступ к кадру - если это все еще возможно, я не знаю, как.
Swift, iOS 10-12:
Следующее работает для меня, и после профилирования всех методов для захвата программных скриншотов - это самый быстрый и рекомендуемый путь от Apple после iOS 10
let screenshotSize = CGSize(width: UIScreen.main.bounds.width * 0.6, height: UIScreen.main.bounds.height * 0.6)
let renderer = UIGraphicsImageRenderer(size: screenshotSize)
let statusBar = UIApplication.shared.value(forKey: "statusBarWindow") as? UIWindow
let screenshot = renderer.image { _ in
UIApplication.shared.keyWindow?.drawHierarchy(in: CGRect(origin: .zero, size: screenshotSize), afterScreenUpdates: true)
statusBar?.drawHierarchy(in: CGRect(origin: .zero, size: screenshotSize), afterScreenUpdates: true)
}
Вам не нужно уменьшать размер скриншота (вы можете использовать UIScreen.main.bounds
напрямую, если хотите)
Ответ 6
Захватите весь экран iPhone, получите строку состояния с помощью KVC:
if let snapView = window.snapshotView(afterScreenUpdates: false) {
if let statusBarSnapView = (UIApplication.shared.value(forKey: "statusBar") as? UIView)?.snapshotView(afterScreenUpdates: false) {
snapView.addSubview(statusBarSnapView)
}
UIGraphicsBeginImageContextWithOptions(snapView.bounds.size, true, 0)
snapView.drawHierarchy(in: snapView.bounds, afterScreenUpdates: true)
let snapImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
Ответ 7
Для меня работает следующее: запись строки состояния (iOS 9, Swift)
let screen = UIScreen.mainScreen()
let snapshotView = screen.snapshotViewAfterScreenUpdates(true)
UIGraphicsBeginImageContextWithOptions(snapshotView.bounds.size, true, 0)
snapshotView.drawViewHierarchyInRect(snapshotView.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()