首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在UITableView中显示可下载内容的正确方式(使用ProgressBar等)

在UITableView中显示可下载内容的正确方式(使用ProgressBar等)
EN

Stack Overflow用户
提问于 2012-08-31 08:04:58
回答 2查看 8.2K关注 0票数 6

我认为这是一个相当复杂的问题。我有一个TableView,可以显示许多可下载的内容。当你点击单元格中的一个按钮,下载就开始了。

但我遇到了几个问题:1.如何确保progressBar始终显示(即使用户滚动滚动,单元格将被重新加载)2.如何确保用户可以同时下载2个文件。我担心这会导致问题,因为我使用了一些实例变量。在某种程度上,它的工作方式应该有点像在音乐应用程序中从iCloud下载

以下是我的代码

代码语言:javascript
运行
复制
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil];   
    }
    //cell.tag = indexPath.row*10;
    Uebungsblaetter *uebungCell = [uebungsblattArray objectAtIndex:indexPath.row];
    cell.tag = indexPath.row*10;
    cell.textLabel.text = [self getFileNameOutOf:uebungCell.url];
    cell.textLabel.textColor = [UIColor grayColor];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    UIButton *dl = [UIButton buttonWithType:UIButtonTypeCustom];
    dl.tag = indexPath.row*10;
    [dl setBackgroundImage:[UIImage imageNamed:@"downloadButton.png"] forState:UIControlStateNormal];
    [dl setBackgroundImage:[UIImage imageNamed:@"downloadButtonH.png"] forState:UIControlStateHighlighted];
    [dl setFrame:CGRectMake(230.0, (cell.frame.size.height-28)/2, 28, 28)];
    [dl addTarget:self action:@selector(downloadFileWhenPressedButton:) forControlEvents:UIControlEventTouchUpInside];
    [cell.contentView addSubview:dl];
    UIProgressView *dlProgress = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
    dlProgress.frame = CGRectMake(cell.frame.size.width-150, 17, 50, 9);
    dlProgress.tag =indexPath.row*10+1;
    dlProgress.progress = 0.0;
    [cell.contentView addSubview:dlProgress];
    [dlProgress setHidden:YES];   

    return cell;
}

//download methods
- (void)downloadFileWhenPressedButton:(UIButton*)sender{
    sender.hidden = YES;
    dlIndex = sender.tag/10;
    Uebungsblaetter *selectedUB = [uebungsblattArray objectAtIndex:dlIndex];
    NSURL *theUrl = [NSURL URLWithString:selectedUB.url];
    NSURLRequest *req=[NSURLRequest requestWithURL:theUrl cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:120];
    dlCell = (UITableViewCell *)[[sender superview]superview];
    currDlProgress = (UIProgressView* )[dlCell.contentView viewWithTag:dlIndex*10+1];
    currDlProgress.hidden = NO;
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    dlFilePath = [NSString stringWithFormat:@"%@/%@_%@", [paths objectAtIndex:0],self.courseLable.text,[self getFileNameOutOf:selectedUB.url]];
    NSURLConnection *con=[[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];
    if (con) {
        myWebData = [NSMutableData data];
    }

}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    UIApplication* app = [UIApplication sharedApplication];
    app.networkActivityIndicatorVisible = YES;
    currDlProgress.progress = 0;
    _totalFileSize = response.expectedContentLength;
    NSLog(@"%@",@"connection established");
    [myWebData setLength: 0];



}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    _receivedDataBytes += [data length];
    currDlProgress.progress = _receivedDataBytes / (float)_totalFileSize;

    NSLog(@"%@",@"connection receiving data");
    [myWebData appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"%@",@"connection failed");
    //  [AlertViewHandler showAlertWithErrorMessage:@"Sorry, there is no network connection. Please check your network and try again."];
    //  [self parserDidEndDocument:nil];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    UIApplication* app = [UIApplication sharedApplication];
    app.networkActivityIndicatorVisible = NO;
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.35];
    [currDlProgress setAlpha:0];
    [UIView commitAnimations];
    [myWebData writeToFile:dlFilePath atomically:YES];
    Uebungsblaetter *loadedUB = [uebungsblattArray objectAtIndex:dlIndex];
    loadedUB.downloaded = [NSNumber numberWithBool:YES];
    [courseTable reloadData];
}

如果有人有线索或很好的代码示例就更好了

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-08-31 13:17:43

重要的是要认识到,进度条不会一直显示(例如,用户可以滚动表格,一旦离开屏幕,相同的单元格就可以在不同内容的另一个索引位置重用)。因此,您需要做的是在某个地方存储有关任何活动下载的数据,包括表中的索引位置、总文件大小和到目前为止下载的字节数。然后,无论何时绘制单元格,都需要检查当前是否正在下载该单元格的项目,如果是,则显示带有适当百分比进度的条形图。

要做到这一点,最简单的方法是向视图控制器添加一个属性来存储此信息。它可以是一个包含NSMutableDictionary对象集合的NSMutablerray,每个字典都包含有关活动下载的必要信息。

代码语言:javascript
运行
复制
@property (nonatomic, strong) NSMutableArray *activeConnections;

首先,您将在viewDidLoad:中初始化数组

代码语言:javascript
运行
复制
- (void)viewDidLoad
{
    [super viewDidLoad];
    //...

    self.activeConnections = [[NSMutableArray alloc] init];
}

无论何时按下按钮,都会向数组中添加一个包含所需信息的NSMutableDictionary对象。

代码语言:javascript
运行
复制
- (void)downloadFileWhenPressedButton:(UIButton*)sender
{
    // ...

    //  then create dictionary
    NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
    [dict setObject:con forKey:@"connection"];  // save connection so we can reference later
    [dict setObject:[NSNumber numberWithInt:[sender.tag]/10] forKey:@"row"];  // this is the row index from your table
    [dict setObject:[NSNumber numberWithInt:999] forKey:@"totalFileSize"];  // dummy size, we will update when we know more
    [dict setObject:[NSNumber numberWithInt:0] forKey:@"receivedBytes"];

    [self.activeConnections addObject:dict];
}

此外,我们还将创建两个实用程序方法,以便使用connection对象本身或表中的行索引位置轻松地从数组中检索连接信息。

代码语言:javascript
运行
复制
- (NSDictionary*)getConnectionInfo:(NSURLConnection*)connection
{
    for (NSDictionary *dict in self.activeConnections) {
        if ([dict objectForKey:@"connection"] == connection) {
            return dict;
        }
    }
    return nil;
}

- (NSDictionary*)getConnectionInfoForRow:(int)row
{
    for (NSDictionary *dict in self.activeConnections) {
        if ([[dict objectForKey:@"row"] intValue] == row) {
            return dict;
        }
    }
    return nil;
}

建立连接后,使用预期长度更新您的字典。

代码语言:javascript
运行
复制
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    // ...

    NSDictionary *dict = [self getConnectionInfo:connection];
    [dict setObject:[NSNumber numberWithInt:response.expectedContentLength] forKey:@"totalFileSize"];
}

在接收数据时,您将更新接收到的字节数,并告诉tableView重新绘制包含进度条的单元格。

代码语言:javascript
运行
复制
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    // ...

    NSDictionary *dict = [self getConnectionInfo:connection];
    NSNumber bytes = [data length] + [[dict objectForKey:@"receivedBytes"] intValue];

    [dict setObject:[NSNumber numberWithInt:response.expectedContentLength] forKey:@"receivedBytes"];

    int row = [[dict objectForKey:@"row"] intValue];
    NSIndexPath *indexPath = [NSIndexPathindexPathForRow:row inSection:0];
    [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
                          withRowAnimation:UITableViewRowAnimationNone];
}

当您的连接下载完成后,您应该从activeConnections数组中删除该连接,并重新加载表格单元格。

代码语言:javascript
运行
复制
- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{
    // ...

    NSDictionary *dict = [self getConnectionInfo:connection];
    [self.activeConnections removeObject:dict];

    int row = [[dict objectForKey:@"row"] intValue];
    NSIndexPath *indexPath = [NSIndexPathindexPathForRow:row inSection:0];
    [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
                          withRowAnimation:UITableViewRowAnimationNone];
}

最后,在cellForRowAtIndexPath:中,您需要根据activeConnections数组中的信息绘制单元格的进度条。

代码语言:javascript
运行
复制
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // ...

    // remove any previous buttons or progress bars from this cell
    for (UIView *view in [cell.contentView subViews]) {

        if ([view isKindOfClass:[UIProgressView class]] || [view isKindOfClass:[UIButton class]]) {
            [view removeFromSuperView];
        }
    }

    // look for active connecton for this cell
    NSDictionary *dict = [self getConnectionInfoForRow:indexPath.row];

    if (dict) {
        // there is an active download for this cell, show a progress bar

        UIProgressView *dlProgress = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
        dlProgress.frame = CGRectMake(cell.frame.size.width-150, 17, 50, 9);
        dlProgress.tag = indexPath.row*10+1;
        dlProgress.progress = [[dict objectForKey:@"receivedBytes"] intValue] / [[dict objectForKey:@"totalFileSize"] intValue];

        [cell.contentView addSubview:dlProgress];

    } else {
        // no active download, show the download button

        UIButton *dl = [UIButton buttonWithType:UIButtonTypeCustom];
        dl.tag = indexPath.row*10;
        [dl setBackgroundImage:[UIImage imageNamed:@"downloadButton.png"] forState:UIControlStateNormal];
        [dl setBackgroundImage:[UIImage imageNamed:@"downloadButtonH.png"] forState:UIControlStateHighlighted];
        [dl setFrame:CGRectMake(230.0, (cell.frame.size.height-28)/2, 28, 28)];
        [dl addTarget:self action:@selector(downloadFileWhenPressedButton:) forControlEvents:UIControlEventTouchUpInside];
        [cell.contentView addSubview:dl];
    }
}
票数 22
EN

Stack Overflow用户

发布于 2012-08-31 08:47:47

你的问题是你混淆了你的数据和UI。您依赖于每个表视图单元来存储它的当前下载状态,这将导致问题。相反,您应该创建一个自定义对象,该对象可以存储单元格所需的数据(例如,指示是否正在下载、当前下载进度、下载的数据等的布尔值)。然后,您应该拥有这些对象的可变数组,这样objectAtIndex:0就是表中第一个单元格的数据,依此类推。

当下载开始时,更新数组中的相关对象。理想情况下,当您创建表格视图单元格时,您应该使用NSKeyValueObserving protocol,以便在底层数据发生更改时自动通知它们,并可以适当地更新它们的数据。当一个单元格被重用时,这是很好的,因为存储它的数据的对象仍然在那里,如果因为它即将回到屏幕上而需要再次创建它,那么它将能够使用这些数据来正确地显示。

如果你需要进一步的解释,请告诉我。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12207288

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档