Обратные вызовы делегатов CALayer в UITableViewCell - рабочий процесс - PullRequest
0 голосов
/ 29 сентября 2011

Я использую несколько CALayers для рисования своего контента в подклассе UITableViewCell. Предполагается, что фактическое рисование вызывается методом делегата CALayer drawLayer: inContext :. Однако методы делегата никогда не вызываются.

Вот моя структура:

  • CustomCell: UITalbeViewCell
    • создает CustomCellContentView: UIView
      • создает CABackgroundLayer: CALayer
      • создает CATextLayer: CALayer
    • создает CALayerDelegate: NSObject

Каждый customCell имеет customContentView, который содержит все CALayers для рисования. Каждый customCell создает caLayerDelegate для вызова CALayers. CaLayerDelegate отправляет отчет в customCell.

CustomCell:

#define CALAYER_TEXTLAYER_NAME              @"CATextLayer"
#define CALAYER_BGLAYER_NAME                @"CABackgroundLayer"

...

- (id) customContentViewForCurrentCell
{
    CGRect contentViewFrame = CGRectMake(-CC_LEFTRIGHT_PADDING, 0., self.contentView.bounds.size.width, self.contentView.bounds.size.height);

    CustomCellContentView *cellContentView = [[[CustomCellContentView alloc] initWithFrame: contentViewFrame] autorelease];

    CALayerDelegate *layerDelegate = [[CALayerDelegate alloc] initWithView: self];
    cellContentView.layerDelegate = layerDelegate;
    [cellContentView setupSubLayers];

    [layerDelegate release];

    return cellContentView;
}

#pragma mark - Initialisation

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];

    if (!self) 
        return nil;

    self.customContentView = (CustomCellContentView *)[self customContentViewForCurrentCell];
    self.customContentView.opaque = TRUE;

    self.backgroundColor = [UIColor clearColor];
    self.selectionStyle = UITableViewCellSelectionStyleNone;
    [self.contentView addSubview: self.customContentView];

    return self;
}

#pragma mark - Cell Update

- (void) refreshLayout
{
    [self setNeedsDisplay];
    [self.customContentView setNeedsDisplay];
}

...

#pragma mark - CALayer Delegate Methods

-(void) drawLayer: (CALayer*) layer inContext: (CGContextRef) context 
{

}

-(void) drawCABackgroundLayer: (CALayer*) layer inContext: (CGContextRef) context
{
    UIGraphicsPushContext(context);

    CGRect contentRect = [layer bounds];
    UIImage *bgImage = [[ImageCacheController sharedImageCache] imageFromCache: GENERIC_BGIMAGE_FILENAME];

    [bgImage drawInRect: CGRectMake(contentRect.origin.x, contentRect.origin.y, contentRect.size.width, contentRect.size.height)];

    UIGraphicsPopContext();
}

-(void) drawCATextLayer: (CALayer*) layer inContext: (CGContextRef) context
{
    UIGraphicsPushContext(context);

    CGContextSetShadowWithColor(context, CGSizeMake(0.f, 2.0f), 0.0f, [UIColor mainLabelShadowColor].CGColor);

    [[UIColor mainLabelColor] set];
    UIFont *mainFont = [UIFont fontWithName: FONT_INFOS size: CC_MAINLABEL_FONTSIZE_MAX];

    [@"ArthurDent" drawAtPoint: [self mainViewPosition] 
                           forWidth: CC_MAINLABEL_WIDTH 
                           withFont: mainFont 
                        minFontSize: CC_MAINLABEL_FONTSIZE_MAX 
                     actualFontSize: NULL 
                      lineBreakMode: UILineBreakModeTailTruncation 
                 baselineAdjustment: UIBaselineAdjustmentAlignBaselines];

    UIGraphicsPopContext();
}

CustomCellContentView:

@interface CustomCellContentView : UIView 
{
    CALayerDelegate *layerDelegate;

    CALayer *backgroundLayer;
    CALayer *textLayer;
}

@property (nonatomic, retain) CALayerDelegate *layerDelegate;

@property (nonatomic, retain) CALayer *backgroundLayer;
@property (nonatomic, retain) CALayer *textLayer;

- (void) setupSubLayers;

@end



@implementation CustomCellContentView

@synthesize textLayer, backgroundLayer, layerDelegate;

#pragma mark - Initialisation

- (id) initWithFrame:(CGRect)frame
{
    self = [super initWithFrame: frame];

    if(!self)
        return nil;

    return self;
}

- (void) setupSubLayers
{    
    self.textLayer = [CALayer layer];
    self.textLayer.name = CALAYER_TEXTLAYER_NAME;
    self.textLayer.shadowColor = [UIColor mainLabelShadowColor].CGColor;
    self.textLayer.shadowOffset = CGSizeMake(0.0f, 2.0f);
    self.textLayer.shadowOpacity = 1.f;
    self.textLayer.shadowRadius = 0.f;
    self.textLayer.needsDisplayOnBoundsChange = TRUE;
    self.textLayer.delegate = self.layerDelegate;

    self.backgroundLayer = [CALayer layer];
    self.backgroundLayer.name = CALAYER_BGLAYER_NAME;
    self.backgroundLayer.needsDisplayOnBoundsChange = TRUE;
    self.backgroundLayer.delegate = self.layerDelegate;

    [self.layer addSublayer: self.textLayer];
    [self.layer addSublayer: self.backgroundLayer];

    [self.textLayer setNeedsDisplay];
    [self.backgroundLayer setNeedsDisplay];
}

#pragma mark - SetNeedsDisplay Overwritten

- (void) setNeedsDisplay
{
    [super setNeedsDisplay];

    [self.layer setNeedsDisplay];    
    [self.textLayer setNeedsDisplay];
    [self.backgroundLayer setNeedsDisplay];
}

...

CALayerDelegate:

@implementation CALayerDelegate

#pragma mark - Initialisation

-(id) initWithView: (UIView *) view 
{
    self = [super init];

    if (!self) 
        return nil;

    _view = view;

    return self;
}

#pragma mark - CALayer Delegate Methods

-(void) drawLayer: (CALayer*) layer inContext: (CGContextRef) context 
{
    NSString* methodName = [NSString stringWithFormat: @"draw%@:inContext:", [layer name]];

    SEL selector = NSSelectorFromString(methodName);

    if (![_view respondsToSelector: selector])
        selector = @selector(drawLayer:inContext:);

    [_view performSelector: selector 
                withObject: layer 
                withObject: (id)context];
}

@end

Я читал для UIViewController, лучше создавать под-CALayers в awakeFromNib:, а не в initWithFrame:, потому что есть некоторая форма поддержки слоя, происходящая после initWithFrame:, которая отбрасывает создание подслоев. Итак, вы должны добавлять подслои только после загрузки представления?

Я использую отдельные CALayerDelegate - объекты, поэтому CustomCell и его представление отвечают только за customContentView.layer.

Кто-нибудь знает, что я делаю не так?

Заранее спасибо !!

Ответы [ 2 ]

0 голосов
/ 27 ноября 2012

Убедитесь, что ваш кадр не CGRectZero.

У меня была проблема, похожая на то, что вы описываете. Если для фрейма используется CGRectZero, это предотвратит вызов drawLayer: inContext.

0 голосов
/ 29 сентября 2011

Из документации для CALayer, описывающей свойство «делегат»: «В iOS, если слой связан с объектом UIView, это свойство должно быть установлено на представление, которому принадлежит слой».

Если я правильно прочитал, вам нужно установить CustomCellContentView в качестве делегата слоя. Переместите функциональность из CALayerDelegate прямо в ваш пользовательский класс представления и посмотрите, работает ли он. В любом случае, это будет стандартный способ сделать это, вместо того, чтобы создавать отдельный класс, который будет действовать как делегат.

...