滚动到该区域时,TiledScrollView不显示某些图块

时间:2012-01-11 21:21:01

标签: ios objective-c uiscrollview

我在使用Apple的TiledScrollView3_Tiling/​Classes/​TiledScrollView.m)时遇到了一些问题,有时瓷砖在我滚动时没有显示,有时则会显示。为了澄清,我看到的问题类似于拥有100行的tableview列表,一次只显示10行。当您滚动列表时,有时一行或多行是空白的并保持空白,因为一旦它们显示在屏幕上,就不会重新加载以确保内容存在。但是,一旦这些空白行离开屏幕并说你回滚到它们,它们就会显示内容。

它的行为似乎是完全随机的,没有明显的模式。我知道委托方法((UIView *)tiledScrollView:(TiledScrollView *)tiledScrollView tileForRow:(int)row column:(int)column resolution:(int)resolution)正在通过NSLog执行。

我的问题是:
你有没有遇到这种现象,你是如何解决的?或
我的调试技巧非常简陋。如果我想通过查看tile或子视图是否存在来隔离问题,或者imageView无法获取图像或者是否存在渲染问题......我将如何进行调试?

注意 - 下面显示的委托方法是上面的tilesScrollView委托方法的精简版本,其中我删除了代码的行和分辨率部分,因为如果我只是水平滚动则不需要它。

- (UIView *)tiledScrollView:(HorizontalTiledScrollView *)tiledScrollView column:(int)column {
NSLog(@"+++ %s +++", __PRETTY_FUNCTION__);

// re-use a tile rather than creating a new one, if possible
UIView *tile = [tiledScrollView dequeueReusableTile];

if (!tile) {
    // the scroll view will handle setting the tile's frame, so we don't have to worry about it
    if (tiledScrollView == self.timeHour) {
        tile = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, TIMEHOUR_COLUMN_WIDTH, TIMEHOUR_COLUMN_HEIGHT)] autorelease]; 
    } else if (tiledScrollView == self.timeMinute) {
        tile = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, TIMEMINUTE_COLUMN_WIDTH, TIMEMINUTE_COLUMN_HEIGHT)] autorelease];
    }

    // Some of the tiles won't be completely filled, because they're on the right or bottom edge.
    // By default, the image would be stretched to fill the frame of the image view, but we don't
    // want this. Setting the content mode to "top left" ensures that the images around the edge are
    // positioned properly in their tiles. 
    [tile setContentMode:UIViewContentModeTopLeft]; 
}

for(UIView *subview in [tile subviews]) {
    if (subview.tag != 3) {
        [subview removeFromSuperview]; //remove all previous subviews in tile except tile annotation if present
    }
}
UIImageView *imgView = [[UIImageView alloc] init];
UILabel *digitLabel;

// Add blank UIImageView as filler or UIImageView with PNG or UILabel if no PNG sized correctly and offsetted from tile's origin as subviews in the tile
if (tiledScrollView == self.timeHour) {
    if (column < 1) {
        imgView.frame = CGRectZero;
        [tile addSubview:imgView];
        [tile bringSubviewToFront:imgView];
    } else {
        int digitH = ((column - 1) % 12 + 1);
        imgView.frame = CGRectMake(9, 0, 17, 21);
        [imgView setContentMode:UIViewContentModeScaleToFill]; 
        if ((imgView.image = [UIImage imageNamed:[NSString stringWithFormat:@"TimeHour_%02d.png", digitH]])) {
            [tile addSubview:imgView];
            [tile bringSubviewToFront:imgView];
        } else {
//                NSLog(@"No TimeHour_%02d.png", digitH);
            digitLabel = [self makeDigitLabel:digitH frame:imgView.frame fontSize:14.0];
            [tile addSubview:digitLabel];
            [tile bringSubviewToFront:digitLabel];
        }
    }
} else if (tiledScrollView == self.timeMinute) {
//        if (column % 2) {
//            tile.backgroundColor = [UIColor redColor];
//        } else {
//            tile.backgroundColor = [UIColor blueColor];
//        }
    if (column < 1) {
        imgView.frame = CGRectZero;
        [tile addSubview:imgView];
        [tile bringSubviewToFront:imgView];
    } else {
        int digitM = ((column - 1) % 60);
        imgView.frame = CGRectMake(9, 0, 16, 15);
        [imgView setContentMode:UIViewContentModeScaleToFill]; 
        if ((imgView.image = [UIImage imageNamed:[NSString stringWithFormat:@"TimeMinute_%02d.png", digitM]])) {
            [tile addSubview:imgView];
            [tile bringSubviewToFront:imgView];
        } else {
            NSLog(@"No TimeMinute_%02d.png", digitM);
            digitLabel = [self makeDigitLabel:digitM frame:imgView.frame fontSize:12.0];
            [tile addSubview:digitLabel];
            [tile bringSubviewToFront:digitLabel];
        }
    }
}
}
[imgView release];
NSLog(@"Tile: %d",[tile.subviews count]);
return tile;
}

希望它很清楚。 谢谢你的帮助,
西仁

1 个答案:

答案 0 :(得分:1)

我终于解决了这个问题!

问题不在上面发布的代码中。它位于Apple的TiledScrollView的layoutSubviews方法中。有一行代码可以计算下面显示的最大列(最大行有类似的计算)

int lastNeededCol  = MIN(maxCol, floorf(CGRectGetMaxX(visibleBounds) / scaledTileWidth));

在我的情况下,这个公式会计算一个额外的列而不是需要的列,这个列块最终会在屏幕外停留。当你没有滚动并将动画设置为NO时,这很好。但是当您在scrollview setContentOffset方法调用中滚动和/或将动画设置为YES时,由于动画导致的延迟或者滚动速度非常慢,有时会导致缺少切片。动画或移动非常慢,导致滚动视图检测到有移动,因此调用layoutSubviews方法,其中一行代码检查以查看哪些切片可见并丢弃不可见的切片。现在,如果你做得恰到好处,那么之前创建的额外图块会被删除,因为它仍然在屏幕外,并且永远不会再创建,直到图块移动到远离屏幕触发重新加载该图块为止。

我所做的修正是将上面的行更改为:

int lastNeededCol  = MIN(maxCol, floorf((CGRectGetMaxX(visibleBounds)-0.1) / scaledTileWidth));

这个新的公式计算出需要在屏幕上显示的正确的图块列数,从而消除了掉落在屏幕外的额外图块的全部内容。

我在github上创建了一个示例代码,有助于演示这一点。 https://github.com/hmistry/TiledScrollViewDebug