Question

In my efforts to upgrade my application to support IOS7 I found out that UIPageControl doesn't support the UIImageView. They have changed it.

I'm subclassing the UIPageControl in order to put custom circles instead the regular ones (attached an example)

My class is:

- (id)initWithFrame:(CGRect)frame 
{
    // if the super init was successfull the overide begins.
    if ((self = [super initWithFrame:frame])) 
    { 
        // allocate two bakground images, one as the active page and the other as the inactive
        activeImage = [UIImage imageNamed:@"active_page_image.png"];
        inactiveImage = [UIImage imageNamed:@"inactive_page_image.png"];
    }
    return self;
}

// Update the background images to be placed at the right position
-(void) updateDots
{
    for (int i = 0; i < [self.subviews count]; i++)
    {
        UIImageView* dot = [self.subviews objectAtIndex:i];
        if (i == self.currentPage) dot.image = activeImage;
        else dot.image = inactiveImage;
    }
}

// overide the setCurrentPage
-(void) setCurrentPage:(NSInteger)page
{
    [super setCurrentPage:page];
    [self updateDots];
}

PageControl (the blue is the current page)

Now in the IOS7 I got the following error:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIView setImage:]: unrecognized selector sent to instance 0xe02ef00'

and after investigating I understood that the following code cause the error:

UIImageView* dot = [self.subviews objectAtIndex:i];
if (i == self.currentPage) dot.image = activeImage;
    else dot.image = inactiveImage;

I checked the subviews and saw that it is UIView instead of UIImageView. probably Apple changed something.

Any idea how to fix it?

Was it helpful?

Solution

It looks like they changed the subviews to standard UIViews. I managed to work around it by doing this:

for (int i = 0; i < [self.subviews count]; i++)
{
    UIView* dotView = [self.subviews objectAtIndex:i];
    UIImageView* dot = nil;

    for (UIView* subview in dotView.subviews)
    {
        if ([subview isKindOfClass:[UIImageView class]])
        {
            dot = (UIImageView*)subview;
            break;
        }
    }

    if (dot == nil)
    {
        dot = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, dotView.frame.size.width, dotView.frame.size.height)];
        [dotView addSubview:dot];
    }

    if (i == self.currentPage)
    {
        if(self.activeImage)
            dot.image = activeImage;
    }
    else
    {
         if (self.inactiveImage)
             dot.image = inactiveImage;
    }
}

OTHER TIPS

maybe dot isn't kind of UIImageView, so try like this

UIImageView* dot = [self.subviews objectAtIndex:i];
if ([dot isKindOfClass:[UIImageView class]]) {
    if (i == self.currentPage) 
        dot.image = activeImage;
    else 
        dot.image = inactiveImage;
}

I've got a bit cleaner solution:

for (int i = 0; i < [self.subviews count]; i++) {
    UIView *dotView = [self.subviews objectAtIndex:i];
    if ([dotView isKindOfClass:[UIImageView class]]) {
        UIImageView* dot = (UIImageView*)dotView;
        dot.frame = CGRectMake(dot.frame.origin.x, dot.frame.origin.y, _activeImage.size.width, _activeImage.size.height);
        if (i == self.currentPage)
            dot.image = _activeImage;
        else
            dot.image = _inactiveImage;
    }
    else {
        dotView.frame = CGRectMake(dotView.frame.origin.x, dotView.frame.origin.y, _activeImage.size.width, _activeImage.size.height);
        if (i == self.currentPage)
            [dotView setBackgroundColor:[UIColor colorWithPatternImage:_activeImage]];
        else
            [dotView setBackgroundColor:[UIColor colorWithPatternImage:_inactiveImage]];
    }
}

The idea is instead of adding subview to UIView for iOS7 just set UIView background image.

Just a little refactor for devgeek's solution to make it a bit more compact

for (int i = 0; i < [self.subviews count]; i++) {
    UIImage *customDotImage = (i == self.currentPage) ? _activeDot : _inactiveDot;
    UIView *dotView = [self.subviews objectAtIndex:i];
    dotView.frame = CGRectMake(dotView.frame.origin.x, dotView.frame.origin.y, customDotImage.size.width, customDotImage.size.height);
    if ([dotView isKindOfClass:[UIImageView class]]) { // in iOS 6, UIPageControl contains UIImageViews
        ((UIImageView *)dotView).image = customDotImage;
    }
    else { // in iOS 7, UIPageControl contains normal UIViews
        dotView.backgroundColor = [UIColor colorWithPatternImage:customDotImage];
    }
}

Just override layoutSubviews in your subclass of UIPageControl

- (void) layoutSubviews
{
    [super layoutSubviews];
    for (UIView* dot in self.subviews)
    {
        CGRect f = dot.frame;
        //sets all the dots to be 5x5
        f.size = CGSizeMake(5, 5);
        //need to reposition vertically as the dots get repositioned when selected
        f.origin.y = CGRectGetMidY(self.bounds) - CGRectGetHeight(f)/2;
        dot.frame = f;
        //update the cornerRadius to be sure that they are perfect circles
        dot.layer.cornerRadius = CGRectGetWidth(f)/2;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top