2012-12-06 11 views
5

A UIImageVIew (imageView) viene aggiunto al self.view, catturando la vista con l'album funziona perfettamente:renderInContext non cattura subviews ruotati

CGSize size = CGSizeMake(self.view.frame.size.height, self.view.frame.size.width); 
UIGraphicsBeginImageContext(size); 
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()]; 
UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 
UIGraphicsEndImageContext(); 
UIImageWriteToSavedPhotosAlbum(image, self, nil, nil); 

Tuttavia, se il imageView visualizzazione secondaria viene ruotata di:

[CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; 

La cattura di self.view non riflette ancora la rotazione. La sottoview imageView è come se non fosse ruotata.

Come rendere renderInContext funziona con le visualizzazioni secondarie ruotate da CABasicAnimation?

UPDATE:

Attenzione: L'CALayer/-renderInContext: metodo non implementare il modello completo composizione Core Animation. Il codice fornito di seguito sarà in grado di risolvere la maggior parte delle situazioni, ma ci sono alcune cose che il metodo CALayer/-renderInContext: non esegue correttamente il rendering, quindi è possibile contattare l'Assistenza tecnica degli sviluppatori per le soluzioni alternative al .

ufficiale di Apple tecnico Q & Un QA1703 suggerito di contattare l'Assistenza tecnica sviluppatori per le richieste di soluzione.

Esiste già una soluzione?

risposta

5

Utilizzare layer.presentationLayer anziché layer quando renderInContext.

Ecco un categoria per prendere screenshot di UIView, UIView + Screenshot.h:

// 
// UIView+Screenshot.h 
// 
// Created by Horace Ho on 2012/12/11. 
// Copyright (c) 2012 Horace Ho. All rights reserved. 
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy 
// of this software and associated documentation files (the "Software"), to deal 
// in the Software without restriction, including without limitation the rights 
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
// copies of the Software, and to permit persons to whom the Software is 
// furnished to do so, subject to the following conditions: 
// 
// The above copyright notice and this permission notice shall be included in 
// all copies or substantial portions of the Software. 
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
// THE SOFTWARE. 

@interface UIView (HHScreenShot) 
- (UIImage *)screenshot:(UIDeviceOrientation)orientation isOpaque:(BOOL)isOpaque usePresentationLayer:(BOOL)usePresentationLayer; 
@end 

@implementation UIView (HHScreenShot) 

- (UIImage *)screenshot:(UIDeviceOrientation)orientation isOpaque:(BOOL)isOpaque usePresentationLayer:(BOOL)usePresentationLayer 
{ 
    CGSize size; 

    if (orientation == UIDeviceOrientationPortrait || orientation == UIDeviceOrientationPortraitUpsideDown) { 
     size = CGSizeMake(self.frame.size.width, self.frame.size.height); 
    } else { 
     size = CGSizeMake(self.frame.size.height, self.frame.size.width); 
    } 

    UIGraphicsBeginImageContextWithOptions(size, isOpaque, 0.0); 

    if (usePresentationLayer) { 
     [self.layer.presentationLayer renderInContext:UIGraphicsGetCurrentContext()]; 
    } else { 
     [self.layer renderInContext:UIGraphicsGetCurrentContext()]; 
    } 

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 

    UIGraphicsEndImageContext(); 

    return image; 
} 

@end 

Per utilizzare:

UIImage *image = [self.view screenshot:UIDeviceOrientationPortrait 
           isOpaque:YES 
        usePresentationLayer:YES]; 
1

Dalla documentazione:

Questo metodo rende direttamente dall'albero strato, ignorando eventuali animazioni aggiunti all'albero rendering.

Dovresti leggere la rotazione dal livello di presentazione e ruotare il contesto grafico.

+0

Come _rotate il context_ grafica che può essere riconosciuto di 'renderInContext'? – ohho

+0

'CGContextRotateCTM (context, angle)' –

+0

Sto cercando un'acquisizione dello schermo di livello superiore (come la cattura dello schermo combo tasto di accensione/spegnimento). Dato che ci sono molte sottoview all'interno di subviews che sono ruotate da 'CABasicAnimation' ... – ohho

0

Come ha detto David, le animazioni non vengono renderizzate da renderInContext. Le animazioni vengono applicate al livello di presentazione, che è solo la visualizzazione.

La cosa più semplice da fare sarebbe applicare la rotazione al livello all'interno di una CATransaction che disabilita le animazioni implicite, quindi acquisisce il livello.

Credo che funzionerebbe. (Tuttavia non ho provato quella cosa specifica, quindi non sono positivo.)

In alternativa, è possibile impostare le animazioni in modo che non siano impostate per rimanere in vigore una volta completata l'animazione, ma invece modificare la proprietà sottostante subito prima dell'inizio dell'animazione. Quindi, quando esegui il rendering del livello, i sottolivelli dovrebbero disegnare nelle loro posizioni finali.

Il rendering di un'animazione "in volo" sarebbe molto più complicato. Per questo è necessario camminare sull'albero dei livelli, interrogare il livello di presentazione di ogni livello e trasferire le impostazioni che si stanno animando al livello di base. Ciò rovinerebbe i tuoi livelli una volta che l'animazione è completa, quindi dovresti salvare il valore di ogni proprietà in qualche modo, impostarlo sul suo valore "in volo" dal livello di presentazione, catturare la tua immagine, quindi impostare la proprietà/proprietà di ogni livello indietro, tutte all'interno di una CATransaction che disabilita l'animazione.

+0

Ho provato' CATransaction' ma senza fortuna. Dal documento 'CATransaction', la mia comprensione è che le animazioni sono già _intributamente_funzionate (dal punto di vista dell'utente, le sottoview vengono ruotate, ma sono già rimaste sullo schermo per un po '). – ohho

1

Dovresti essere in grado di utilizzare renderInContext con il livello di presentazione. Anche se questo potrebbe non seguire la gerarchia dei livelli per te. Così probabilmente sarebbe più facile se hai fatto una di queste cose:

  • applicare la rotazione a tutti i sub-strati colpite e rendere lo strato radice
  • scrivere un metodo ricorsivo per comporre manualmente i livelli di presentazione da soli