UITableViewCell

时间:2016-02-02 16:11:19

标签: ios objective-c uitableview uiview drawrect

我面临的有点复杂(至少看起来对我来说)问题与我制作的自定义 UIView (称为 EventBadge )。< / p>

这是我的自定义类的代码:

EventBadge.h

@interface EventBadge : UIView

- (void)setBadgeFillColor:(UIColor *) color;
- (void)setBadgeBorderColor:(UIColor *) color;
- (void)setBadgeIcon:(MyCustomIcons) icon;

@end

EventBadge.m

@implementation EventBadge

UIColor *badgeFillColor;
UIColor *badgeBorderColor;
MyCustomIcons badgeIcon;

- (void)drawRect:(CGRect)rect {

    // Gets graphic context
    CGContextRef context = UIGraphicsGetCurrentContext();

    // Sets fill and border colors for cirlce
    CGContextSetFillColor(context, CGColorGetComponents([badgeFillColor CGColor]));
    CGContextSetStrokeColor(context, CGColorGetComponents([badgeBorderColor CGColor]));

    // Set border line width
    CGContextSetLineWidth(context, 2.0);

    // Set rect containing circle as inset of rect
    CGRect circle = CGRectInset(rect, 1, 1);

    // Draw fill and stroke into rect
    CGContextFillEllipseInRect(context, circle);
    CGContextStrokeEllipseInRect(context, circle);

    // Draws icon
    [self drawBadgeIconInside:circle];

    // Fill graphic context with path
    CGContextFillPath(context);
}

/**
 * Sets the background color for the badge and forces refresh
 */
- (void)setBadgeFillColor:(UIColor *) color{
    badgeFillColor = color;
    [self setNeedsDisplay];
}

/**
 * Sets the background color for the badge and forces refresh
 */
- (void)setBadgeBorderColor:(UIColor *) color{
    badgeBorderColor = color;
    [self setNeedsDisplay];
}

/**
 * Sets the icon for the badge and forces refresh
 */
- (void)setBadgeIcon:(MyCustomIcons) icon{
    badgeIcon = icon;
    [self setNeedsDisplay];
}

/**
 * Draws the badge icon inside a rectangle
 */
- (void)drawBadgeIconInside:(CGRect) rect {

    // Creates the inner rectangle from the original one (20x20)
    CGRect iconContainer = CGRectInset(rect, 5, 5);

    // Switch on badgeIcon: many different supported types
    switch (badgeIcon) {
        case EventLocation:
            [StyleKit drawIconLocationWithFrame:iconContainer colorBase:[StyleKit blackMP]];
            break;
        case EventCar:
            [StyleKit drawIconCarWithFrame:iconContainer colorBase:[StyleKit blackMP]];
            break;
        default:
            MyLog(MyLogLevelError, @"INVALID MyCustomIcon");
            break;
    }
}

@end

我有一个 UITableView ,可以填充三种不同类型的 UITableViewCell ,让我们说 TypeA TypeB TypeC

TypeA TypeB 里面有不同的元素( UILabels UIViews 等等),他们都有我的 EventBadge TypeC 仅由标准元素组成。

这里是所有细胞类型的代码:

TypeA.h

@interface TypeACell : UITableViewCell

@property (strong, nonatomic) IBOutlet UIView *prevRouteView;
@property (strong, nonatomic) IBOutlet UIView *nextRouteView;
@property (strong, nonatomic) IBOutlet UILabel *addressLabel;
@property (strong, nonatomic) IBOutlet EventBadge *eventBadgeView;

@end

TypeB.h

@interface TypeBCell : UITableViewCell

@property (strong, nonatomic) IBOutlet EventBadge *eventBadgeView;
@property (strong, nonatomic) IBOutlet UIView *prevRouteView;
@property (strong, nonatomic) IBOutlet UIView *nextRouteView;
@property (strong, nonatomic) IBOutlet UILabel *titleLabel;
@property (strong, nonatomic) IBOutlet UILabel *addressLabel;
@property (strong, nonatomic) IBOutlet UILabel *startTime;
@property (strong, nonatomic) IBOutlet UILabel *endTime;
@property (strong, nonatomic) IBOutlet CalendarColorView *calendarColor;

@end

TypeC.h

@interface TypeCCell : UITableViewCell

@property (strong, nonatomic) IBOutlet UIView *routeView;
@property (strong, nonatomic) IBOutlet UILabel *duration;
@property (strong, nonatomic) IBOutlet UILabel *startTime;
@property (strong, nonatomic) IBOutlet UILabel *endTime;
@property (strong, nonatomic) IBOutlet CalendarColorView *calendarColor;
@property (strong, nonatomic) IBOutlet TransportTypeIconView *transportTypeView;

@end

我在ViewController的 cellForRowAtIndexPath 方法中选择单元格类型,查看_tableviewData中存储的对象类型(用于填充tableView的数组)。代码如下所示:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    if([_tableviewData[indexPath.row] isKindOfClass:[EventTypeA class]]){
        EventTypeA *event = (EventTypeA *)_tableviewData[indexPath.row];
        return [self tableView:tableView createTypeACell:event atIndexPath:indexPath];
    } 

    else if([_tableviewData[indexPath.row] isKindOfClass:[EventTypeB class]]) {
        EventTypeB *event = (EventTypeB *)_tableviewData[indexPath.row];
        return [self tableView:tableView createTypeBCell:event atIndexPath:indexPath];
    } 

    else {
        EventTypeC *event = (EventTypeC *)_tableviewData[indexPath.row];
        return [self tableView:tableView createTypeCCell:event atIndexPath:indexPath];
    } 
}

在每个方法createTypeXCell中,我直接处理元素并设置它们的属性。一切都按预期工作除了属性在我的自定义视图上设置。所以 TypeC 效果很好, TypeA TypeB 中的所有内容都按预期工作我的颜色和图标的设置除外的 eventBadgeView

我得到的行为是,无论 UITableViewCell 属于哪个 eventBadgeView ,都会使用上一个 eventBadgeView 的属性进行绘制正在工作(阵列的最后一项)。

如果我在 UITableView 上向上或向下滚动一点,足以呈现一个项目,那么该项目会很好地更新,具有我之前设置的属性。 但如果我滚动太多,一切都会再次搞砸了。

我注意到drawRect总是在setNeedsDisplay之后被调用很多,而且我已经知道这就是这样的。

我已经阅读了很多SO帖子(我没有在这里链接所有这些帖子)并且基于那些我试图做的事情(没有运气)是:

  1. 在方法中调用[cell.eventBadgeView setNeedsDisplay] 设置属性后创建单元格
  2. 将设置单元格属性和[cell.eventBadgeView setNeedsDisplay]的所有部分放在dispatch_async
  3. 使用CALayer来强迫&#34;强迫&#34; drawRect是同步执行的
  4. 也许正如我对ObjectiveC的新手一样,我错过了一些基本的东西,而且我对自定义的EventBadge有很大的疑虑:UIView类因为其他一切正常。

    提前感谢您的帮助! :)

1 个答案:

答案 0 :(得分:1)

您应该将这些变量声明为实现主体,否则它们将像.m文件中的gloabal变量一样被威胁(有关此here的更多信息)

UIColor *badgeFillColor;
UIColor *badgeBorderColor;
MyCustomIcons badgeIcon;

将它们放在接口中(在.m文件中或直接在.h中)并将它们声明为@property

@interface MPEventBadge ()

@property (strong, nonatomic) UIColor *badgeFillColor;
@property (strong, nonatomic) UIColor *badgeBorderColor;
@property (nonatomic) MPInsertEventIcons badgeIcon;

@end

然后您可以访问变量,如

_badgeFillColor = color;