UIScrollView setNeedsDisplay 不工作,还是别的啥?
Posted
技术标签:
【中文标题】UIScrollView setNeedsDisplay 不工作,还是别的啥?【英文标题】:UIScrollView setNeedsDisplay not working, or something else?UIScrollView setNeedsDisplay 不工作,还是别的什么? 【发布时间】:2012-02-07 18:17:07 【问题描述】:问题下方给出了这个问题的最终解决方案
我的目标是创建一个图像选择器,它最初在滚动视图内创建每个图像视图,然后将该图像视图的引用传递给一个方法,该方法将使用适当的图像异步更新 imageview.image .
这很好用。
我遇到的问题是滚动视图只显示图像视图在方法结束时批量显示,而我希望它们按原样逐个打印已创建(图像可用与否)。
如果我触摸滚动视图进行滚动,它会按照我想要的方式工作,但如果我完全不触摸,屏幕会保持白色,直到所有图像,而不仅仅是图像视图,已完成加载。
我尝试将 setNeedsDisplay 放置在任何地方,适用于每个视图,包括 self.view、scrollview 和每个单独的 imageview。怎么回事?
- (void)viewDidLoad
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^
[self setGridView];
);
- (void)setGridView
// begin loading images
NSString * retina = ([[MVProject sharedInstance] settings_retina]) ? @"2" : @"";
CGRect scrollframe = CGRectMake(0, 0, 300, 275);
UIScrollView * newscrollview;
newscrollview = [[UIScrollView alloc] initWithFrame:scrollframe];
newscrollview.scrollEnabled = YES;
newscrollview.delegate = self;
[newscrollview setContentSize:CGSizeMake(300, (((ceilf([[NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:@"Flickr_Dictionary"]] count]/4)) * (58+15)) + 15 + 58 + 15))];
[picsMVContentCell.contentView addSubview:newscrollview];
float currentx = 11;
float currenty = 17;
NSInteger index = 0;
for (NSDictionary * d in [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:@"Flickr_Dictionary"]])
// create button
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(currentx, currenty, 58, 58);
button.imageView.backgroundColor = [UIColor colorWithRed:(241/255.0) green:(241/255.0) blue:(241/255.0) alpha:1];
button.imageView.contentMode = UIViewContentModeScaleAspectFit;
button.imageView.layer.cornerRadius = 6;
button.imageView.layer.masksToBounds = YES;
button.imageView.accessibilityLabel = [d objectForKey:@"id"];
button.imageView.accessibilityValue = [d objectForKey:@"full"];
button.imageView.tag = index++;
[button addTarget:self action:@selector(imageClick:) forControlEvents:UIControlEventTouchUpInside];
UIImage * image = [MVImage imageWithImage:[UIImage imageNamed:@""] covertToWidth:58.0f covertToHeight:58.0f];
[button setImage:image forState:UIControlStateNormal];
[newscrollview addSubview:button];
[newscrollview bringSubviewToFront:button];
[newscrollview setNeedsDisplay];
// calculate next image view position
currentx += (button.imageView.frame.size.width+15);
if (currentx >= 289)
currentx = 11;
currenty += (button.imageView.frame.size.height+15);
// set image
NSString * nsuserdefault = [NSString stringWithFormat:@"Settings_SFThumbs%@_%@", retina, [d objectForKey:@"id"]];
if ([NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]])
MVImage * thumb = [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]];
[button setImage:[MVImage imageWithImage:[[UIImage alloc] initWithData:thumb.data] covertToWidth:58.0f covertToHeight:58.0f] forState:UIControlStateNormal];
else
[MVProject asynchronousImageLoad:button.imageView urlpath:[d objectForKey:@"thumb"] nsuserdefaultpath:nsuserdefault];
于 2012 年 2 月 7 日下午 3:26 编辑
这些更改修复了与问题中给出的代码相关的所有问题
感谢@Eugene 为我指明了正确的方向
/* ---------- ---------- ---------- ---------- ---------- */
- (void)viewDidLoad
[super viewDidLoad];
[[MVProject sharedInstance] syncLoadSF:0];
self.newscrollview = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 300, 275)];
self.newscrollview.scrollEnabled = YES;
self.newscrollview.delegate = self;
[self.newscrollview setContentSize:CGSizeMake(300, (((ceilf(([[NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:@"Flickr_Dictionary"]] count]-1)/4)) * (58+15)) + 15 + 58 + 15))];
[picsMVContentCell.contentView addSubview:self.newscrollview];
[self setGridView];
/* ---------- ---------- ---------- ---------- ---------- */
- (void)setGridView
NSString * retina = ([[MVProject sharedInstance] settings_retina]) ? @"2" : @"";
[self.newscrollview setNeedsDisplay];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^
NSInteger index = 0;
for (NSDictionary * d in [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:@"Flickr_Dictionary"]])
// create button
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake((11 + ((index%4)*(58+15))), (17 + ((floorf(index/4))*(58+15))), 58, 58);
button.imageView.backgroundColor = [UIColor colorWithRed:(241/255.0) green:(241/255.0) blue:(241/255.0) alpha:1];
button.imageView.contentMode = UIViewContentModeScaleAspectFit;
button.imageView.layer.cornerRadius = 3;
button.imageView.layer.masksToBounds = YES;
button.imageView.accessibilityLabel = [d objectForKey:@"id"];
button.imageView.accessibilityValue = [d objectForKey:@"full"];
button.imageView.tag = index++;
[button addTarget:self action:@selector(imageClick:) forControlEvents:UIControlEventTouchUpInside];
dispatch_sync(dispatch_get_main_queue(), ^
[button setImage:[MVImage imageWithImage:[UIImage imageNamed:@""] covertToWidth:58.0f covertToHeight:58.0f] forState:UIControlStateNormal];
[self.newscrollview addSubview:button];
[self.newscrollview bringSubviewToFront:button];
[self.newscrollview setNeedsDisplay];
// set image
NSString * nsuserdefault = [NSString stringWithFormat:@"Settings_SFThumbs%@_%@", retina, [d objectForKey:@"id"]];
if ([NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]])
MVImage * thumb = [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]];
[button setImage:[MVImage imageWithImage:[[UIImage alloc] initWithData:thumb.data] covertToWidth:58.0f covertToHeight:58.0f] forState:UIControlStateNormal];
else
[MVProject asynchronousImageLoad:button.imageView urlpath:[d objectForKey:@"thumb"] nsuserdefaultpath:nsuserdefault];
);
);
[self.newscrollview setNeedsDisplay];
【问题讨论】:
【参考方案1】:您不能在后台线程上进行绘图。每次添加子视图时,都应该在主线程中执行此操作。所以你的救命之恩是在同步块中使用你的绘图代码,它在主队列上运行
dispatch_sync(dispatch_get_main_queue(), ^
[newscrollview addSubview:button];
[newscrollview bringSubviewToFront:button];
[newscrollview setNeedsDisplay];
// calculate next image view position
currentx += (button.imageView.frame.size.width+15);
if (currentx >= 289)
currentx = 11;
currenty += (button.imageView.frame.size.height+15);
// set image
NSString * nsuserdefault = [NSString stringWithFormat:@"Settings_SFThumbs%@_%@", retina, [d objectForKey:@"id"]];
if ([NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]])
MVImage * thumb = [NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:nsuserdefault]];
[button setImage:[MVImage imageWithImage:[[UIImage alloc] initWithData:thumb.data] covertToWidth:58.0f covertToHeight:58.0f] forState:UIControlStateNormal];
else
[MVProject asynchronousImageLoad:button.imageView urlpath:[d objectForKey:@"thumb"] nsuserdefaultpath:nsuserdefault];
);
【讨论】:
【参考方案2】:您遇到的问题是设置图像。您尝试做的是将所有图像容器添加到滚动视图。然后当图像准备好时将它们加载到它们的容器中。有两种方法可以做到这一点。
首先将所有容器添加到滚动视图。 (您可能需要一些加载指示器或默认图像来显示其加载)
1) 创建一个后台线程来准备图像。当图像准备好后,将其添加到其容器中。 (我发现这种方式工作量更大,而且有点痛苦)
2) 创建自定义容器,让自定义容器在镜像准备好后添加自己的镜像。
例如,我正在从服务器加载图像。所以我创建了 AsyncImage 类,它是 UIImageView 的自定义类。我创建了一个函数,我将图像 url 发送到它并处理其余部分。它创建一个 NSURLConnection 并在加载数据时调用self.image = [UIImage imageWithData:data];
【讨论】:
谢谢,但您所描述的已经通过这条线完成:[MVProject asynchronousImageLoad:button.imageView urlpath:[d objectForKey:@"thumb"] nsuserdefaultpath:nsuserdefault];
这是我目前正在尝试处理的容器的创建。我不希望 button.imageViews 批量加载(是否带有活动指示器),我希望它们在创建时一个一个地绘制到屏幕上。请参阅上面接受的答案^^以上是关于UIScrollView setNeedsDisplay 不工作,还是别的啥?的主要内容,如果未能解决你的问题,请参考以下文章
UIScrollView 内的 UIScrollView 时滚动
UIScrollView里面的UIScrollView:滚动