2012-10-05 24 views
8

Estoy intentando implementar una actividad personalizada para las actividades estándar (Imprimir, Correo, FaceBook, etc.) pero por ahora solo quiero la Impresión estándar (para AirPrint) y mi propia impresión personalizada por un método directo. Obviamente me falta algo fundamental ya que ninguno de los métodos de mi clase personalizada se llama. Por ahora, solo tengo una declaración NSLog para descubrir la secuencia de llamadas y para que funcione el framework.Problemas al agregar actividad personalizada a UIActivityController

La siguiente es mi código de prueba para la clase de actividad personalizada:

// PrintActivity.h 

#import <UIKit/UIKit.h> 

@interface PrintActivity : UIActivity 

@end 

Y el .m

#import "PrintActivity.h" 

@interface PrintActivity() 
@property (nonatomic, strong) UIWebView *dummyWebView; 
@end 

@implementation PrintActivity 

- (NSString *)activityType { 
    NSLog(@"activityType"); 
    return @"MetriScan Print"; 
} 

- (NSString *)activityTitle { 
    NSLog(@"activityTitle"); 
    return @"MetriScan\nPrint"; 
} 

- (UIImage *)activityImage { 
    NSLog(@"activityImage"); 
    UIImage *icon = [UIImage imageNamed:@"metriscan_57_c2a_3.png"]; 
    return icon; 
} 

- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems { 
    NSLog(@"canPerformWithActivityItems"); 
    return YES; 
} 

- (void)prepareWithActivityItems:(NSArray *)activityItems { 
    NSLog(@"prepareWithActivityItems"); 
} 

- (void)performActivity { 
    NSLog(@"Do the actual printing here"); 
// My custom code here 

} 

Y esta es la invocación de la rutina principal:

- (IBAction)printReport:(UIBarButtonItem *)sender { 
    NSLog(@"Print Report"); 

    PrintActivity *metriscanPrint = [[PrintActivity alloc] init]; 

    UIViewPrintFormatter *printFormatter = [self.webView viewPrintFormatter]; 

    NSArray *activityItems = [NSArray arrayWithObjects:printFormatter, nil]; 
    NSArray *appActivities = [NSArray arrayWithObjects:metriscanPrint, nil]; 
    UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:appActivities]; 
    //activityController.excludedActivityTypes = [NSArray arrayWithObjects:UIActivityTypePostToFacebook, UIActivityTypePostToTwitter, UIActivityTypePostToWeibo, UIActivityTypeMail, UIActivityTypeMessage, nil]; 
    activityController.completionHandler = ^(NSString *activityType, BOOL completed) { 
     sender.enabled = YES; 
    }; 

    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { 
     [self presentViewController:activityController animated:YES completion:nil]; 
    } else { 
     sender.enabled = NO; 
     self.printPop = [[UIPopoverController alloc] initWithContentViewController:activityController]; 
     [self.printPop presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES]; 
    } 

Como dije, no se llama a ninguno de los métodos de la clase personalizada, pero los iconos de Correo, Mensaje y Copia del sistema se muestran en el hoja de actividad y no el icono Imprimir. Esperaba solo el icono Imprimir del sistema (y el mío).

Si elimino el comentario del bloque superior de instrucciones (y comente NSArray * activityItems ...........) más abajo, los iconos de sistema Correo, Mensaje, Imprimir y Copiar. En este experimento, creo que estoy mezclando diferentes métodos mediante la creación de mi propio formateador, ¿pero esa parecía ser la sugerencia en la WWDC 2012?

Si elimino el comentario de la línea con 'excludeActivityTypes', solo obtengo el icono de Imprimir del sistema.

Me agradaría cualquier entrada para ayudarme a resolver esto.

Y si alguien sabe de algún código de ejemplo para hacer lo que quiero, sería fantástico.

Edit: Código actualizado a mi código de trabajo.

Respuesta

7

También me estaba tirando de los pelos por encima de UIActivity esta última semana, Apple realmente tiene que explicar mejor y tener más funciones añadidas; Prueba esto:

PrintActivity.h

#import <UIKit/UIKit.h> 
@interface PrintActivity : UIActivity 
@end 

PrintActivity.m

#import "PrintActivity.h" 

@implementation PrintActivity 

- (NSString *)activityType 
{ 
    return @"MetriScan.Print"; 
} 

- (NSString *)activityTitle 
{ 
    return @"Print MtriScan"; 
} 

- (UIImage *)activityImage 
{ 
    //***** Note: I recommend using two sizes, as the iPad's UIActivity image size differs from 
    //***** the iPhone's. Also, create @2x sizes for Retina compatible devices. So you will  
    //***** have a total of 4 images. 
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) 
{ 
    return [UIImage imageNamed:@"test_72.png"]; 
} 

    return [UIImage imageNamed:@"test_57.png"]; 
} 

- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems 
{ 
    NSLog(@"%s", __FUNCTION__); 
    return YES; 
} 

- (void)prepareWithActivityItems:(NSArray *)activityItems 
{ 
    NSLog(@"%s",__FUNCTION__); 
} 

- (UIViewController *)activityViewController 
{ 
    NSLog(@"%s",__FUNCTION__); 
    return nil; 
} 

- (void)performActivity 
{ 
    // This is where your custom print code should go 

} 

@end 

No se olvide de hacer que estos dos archivos, así:

PrintProvider.h

#import <UIKit/UIKit.h> 

@interface PrintProvider : UIActivityItemProvider <UIActivityItemSource> 

@end 

PrintProvi der.m

#import "PrintProvider.h" 

@implementation PrintProvider 

#pragma mark - UIActivityItemSource 

- (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType 
{ 
    NSLog(@"%s",__FUNCTION__); 
    NSLog(@"%@", activityType); 
    return [super activityViewController:activityViewController itemForActivityType:activityType]; 
} 

@end 

Ahora por fin podemos llamarlo:

- (IBAction)printReport:(UIBarButtonItem *)sender { 


CustomProvider *customProvider = 
       [[CustomProvider alloc]init]; 
       NSArray *items = [NSArray arrayWithObjects:customProvider,nil]; 

       CustomActivity *ca = [[CustomActivity alloc]init]; 

       UIActivityViewController *activityVC = 
       [[UIActivityViewController alloc] initWithActivityItems:items 
                applicationActivities:[NSArray arrayWithObject:ca]]; 

       activityVC.excludedActivityTypes = @[UIActivityTypePostToWeibo, 
       UIActivityTypeAssignToContact,UIActivityTypeCopyToPasteboard, 
       UIActivityTypeSaveToCameraRoll,UIActivityTypeMail,UIActivityTypePostToTwitter, 
       UIActivityTypePostToFacebook,UIActivityTypeMessage]; 

       activityVC.completionHandler = ^(NSString *activityType, BOOL completed) 
       { 
        NSLog(@" activityType: %@", activityType); 
        NSLog(@" completed: %i", completed); 
       }; 

        self.popoverController = [[UIPopoverController alloc] initWithContentViewController:activityVC]; 

        CGRect rect = [[UIScreen mainScreen] bounds]; 

        [self.popoverController 
        presentPopoverFromRect:rect inView:self.view 
        permittedArrowDirections:0 
        animated:YES]; 
} 
+2

troop231 Gracias por responder la pregunta. Resultó que te había solucionado el problema de forma casi idéntica. Mi confusión original fue qué poner en activityItems y applicationActivities, respectivamente. Para completar, he actualizado el código en mi pregunta original. – bjarne

+0

De nada :) Creo que el potencial de UIActivity es enorme. – klcjr89

+0

Gracias, realmente funciona. ¿Pero este enfoque no se contradice con la advertencia de Apple sobre no anular los servicios del sistema? 'Debería subclase UIActivity solo si desea proporcionar servicios personalizados para el usuario. El sistema ya proporciona soporte para muchos servicios estándar y los hace disponibles a través del objeto UIActivityViewController. Por ejemplo, el controlador de vista de actividad estándar admite datos de correo electrónico, publica elementos en una de las cuentas de redes sociales del usuario y varias otras opciones. No es necesario que proporcione servicios personalizados para ninguno de los tipos incorporados. – Anastasia

-1

gracias por su ayuda, chicos!Y, la imagen actividad para, parece que tenemos para proporcionar una imagen después de esto mediante la documentación de Apple:

El canal alfa de la imagen se utiliza como una máscara para generar el última imagen que se presenta al usuario. Se ignora cualquier dato de color en la imagen . Los píxeles opacos tienen un degradado aplicado y . Este degradado se coloca encima de un fondo estándar. Por lo tanto, una imagen completamente opaca produciría un rectángulo lleno de degradado. Para iPhone y iPod touch, las imágenes no deben ser mayores de 43 por 43 puntos (que equivalen a 86 por 86 píxeles para dispositivos con pantallas Retina). Para iPad, las imágenes no deben ser mayores de 55 x 55 puntos (que equivale a 110 por 110 píxeles para iPads con pantallas Retina.)

3

@ troop231 - excelente respuesta y muy útil.

Lo único que agregaría es asegurarse de indicar que se ha completado la operación o no se ejecutará la rutina de finalización y el popover no se cerrará. Algo como:

- (void)performActivity { 
    NSLog(@"Do the actual activity here"); 
    // My custom code here 

    [self activityDidFinish:YES]; // indicate completion here!! 
} 
+0

Gracias por agregar esto. Me he estado preguntando sobre la forma correcta. Esto hará que active activityController.completionHandler, donde debe descartar avc. – VaporwareWolf

+0

Acabo de pensarlo, pero no he tenido tiempo de probarlo. PODRÍA ser cierto que no es necesario llamar explícitamente al controlador de finalización (como mostré anteriormente) si uno (en su lugar) llamó '[super performActivity]' antes de regresar. ¿Es posible que el método de superclase invoque al controlador de finalización? Avísame si tienes tiempo para probarlo. – jbbenni

Cuestiones relacionadas