UIScrollView setNeedsDisplay 不起作用,还是其他什么?
此问题的最终解决方案在问题下方给出
我的目标是创建一个图像选择器,该图像选择器最初在滚动视图内创建每个图像视图,然后将该图像视图的引用传递给一种使用适当图像异步更新 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];
}
Final solution to this issue is given below the question
My goal is to create an image picker that initially creates each image view inside of a scroll view, and then passes a reference for that image view to a method that will asynchronously update the imageview.image with the appropriate image.
This works great as is.
The issue I run into is that the scroll view only shows the image views in a batch at the end of the method, whereas I'd like for them to print one by one as they are created (image available or not).
If I touch the scroll view to scroll, it works the way I want it to, but if I make no touch at all, the screen stays white until all of the images, not just image views, have finished loading.
I've tried placing setNeedsDisplay everywhere, for every view, including self.view, scrollview, and each individual imageview. What's going on?
- (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];
}
}
}
Edit on Feb 7, 2012 3:26 PM
these changes fixed all issues related to the code given in the question
thanks to @Eugene for pointing me in the right direction
/* ---------- ---------- ---------- ---------- ---------- */
- (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];
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您无法在后台线程上进行绘图。每次添加子视图时,您都应该在主线程中执行此操作。因此,对您的救赎是在同步块中使用绘图代码,该代码在主队列上运行
You cannot work with drawing on the background thread. Each time you add subview you should do this in the main thread. So the salvation for you would be to use your drawing code in a sync block, that's run on the main queue
您遇到的问题是设置图像。您想要做的是将所有图像容器添加到滚动视图中。然后,当图像准备好时,将它们加载到容器中。有两种方法可以做到这一点。
首先将所有容器添加到滚动视图中。 (您可能需要一些加载指示器或默认图像来显示其加载)
1) 创建一个后台线程来准备图像。当图像准备好后,将其添加到其容器中。 (我发现这种方式需要更多工作,而且有点痛苦)
2)创建一个自定义容器,并让自定义容器在其图像准备好时添加自己的图像。
例如,我正在从服务器加载图像。所以我创建了 AsyncImage 类,它是 UIImageView 的自定义类。我创建了一个函数,将图像 url 发送到其中,它会处理其余的事情。它创建一个 NSURLConnection,并在加载数据时调用 self.image = [UIImage imageWithData:data];
The problem your having is with setting the images. What your trying to do is add all the image containers to the scrollview. Then as the images are ready load them into their container. There are 2 ways to go about doing this.
First off add all the containers to the scrollview. (You might want some loading indicator or default image to show its loading)
1) Create a background thread for getting the images ready. When the image is ready add it to its container. (I find this way to be more work and kinda a pain)
2) Create a custom container, and let the custom container add its own image when its image is ready.
For example, I am loading images from a server. So I created AsyncImage class that is a custom class of UIImageView. And I created a function that I send the image url to and it handles the rest. It creates an NSURLConnection and when the data is loaded it calls
self.image = [UIImage imageWithData:data];