在UITableView中显示可下载内容的正确方法(使用ProgressBar等) [英] Correct way to show downloadable content in UITableView (with ProgressBar etc.)

查看:105
本文介绍了在UITableView中显示可下载内容的正确方法(使用ProgressBar等)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我认为这是一个相当复杂的问题。我有一个TableView显示一些可下载的内容。当您单击单元格中的按钮时,下载开始。



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



这是我的代码


$ b $ (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];

返回单元格;
}

//下载方法
- (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 :Url cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:120];
dlCell =(UITableViewCell *)[[发送者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 *)连接didReceiveResponse :( NSURLResponse *)响应{
UIApplication * app = [ UIApplication sharedApplication];
app.networkActivityIndi​​catorVisible = YES;
currDlProgress.progress = 0;
_totalFileSize = response.expectedContentLength;
NSLog(@%@,@建立连接);
[myWebData setLength:0];



}

- (void)连接:(NSURLConnection *)连接didReceiveData:(NSData *)data {
_receivedDataBytes + = [数据长度];
currDlProgress.progress = _receivedDataBytes /(float)_totalFileSize;

NSLog(@%@,@连接接收数据);
[myWebData appendData:data];


- (void)连接:(NSURLConnection *)连接didFailWithError:(NSError *)错误{
NSLog(@%@,@连接失败) ;
// [AlertViewHandler showAlertWithErrorMessage:@对不起,没有网络连接,请检查您的网络,然后重试。
// [self parserDidEndDocument:nil];
}

- (void)connectionDidFinishLoading :( NSURLConnection *)连接{
UIApplication * app = [UIApplication sharedApplication];
app.networkActivityIndi​​catorVisible = 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];
}

如果有人有一个线索或一个很好的代码示例, >

解决方案

重要的是要意识到,您的进度条不会一直显示(即用户可以滚动表,相同的单元格可以在不同内容的另一索引位置重复使用)。所以你需要做的就是存储有关任何活动下载的数据,包括表中的索引位置,总文件大小以及到目前为止下载的字节数。然后,每当您的单元格被绘制时,您将需要检查该单元格的项目当前是否正在下载,如果是,则显示具有适当百分比进度的栏。



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

  @property(nonatomic,strong)NSMutableArray * activeConnections; 

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

   - (void)viewDidLoad 
{
[super viewDidLoad];
// ...

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

每当按下一个按钮时,您将向您的数组添加一个NSMutableDictionary对象与您需要的信息。

   - (void)downloadFileWhenPressedButton :( UIButton *)发件人
{
// ...

//然后创建字典
NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
[dict setObject:con forKey:@connection]; //保存连接,以便稍后引用
[dict setObject:[NSNumber numberWithInt:[sender.tag] / 10] forKey:@row]; //这是表的行索引
[dict setObject:[NSNumber numberWithInt:999] forKey:@totalFileSize]; //虚拟大小,当我们知道更多
[dict setObject:[NSNumber numberWithInt:0] forKey:@receivedBytes]时,我们将更新。

[self.activeConnections addObject:dict];
}

此外,我们将创建两个实用程序方法,以便我们可以方便地找到连接来自我们的数组的信息,使用连接对象本身或表中的行索引位置。

   - (NSDictionary *) getConnectionInfo:(NSURLConnection *)连接
{
for(NSDictionary * dict in self.activeConnections){
if([dict objectForKey:@connection] == connection){
return dict
}
}
return nil;

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

当建立连接时,请按预期的长度更新您的字典&连接:(NSURLConnection *)连接didReceiveResponse :( NSURLResponse *)响应
{
/ b

  / ... 

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

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

   - (void)connection:(NSURLConnection *)连接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数组中删除连接,并重新加载表格单元格。

   - (void)connectionDidFinishLoading:(NSURLConnection *)连接
{
// ...

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数组中的信息绘制单元格的进度条。

   - (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath :( NSIndexPath *)indexPath 
{
// ...

//从此单元格中删除任何以前的按钮或进度条
(UIView * view in [cell.contentView subViews]){

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

//寻找这个单元格的活动连接
NSDictionary * dict = [self getConnectionInfoForRow:indexPath.row];

if(dict){
//这个单元格有一个活动的下载,显示一个进度条

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 {
//没有活动下载,显示下载按钮

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];
}
}


I think this a rather complex question. I have a TableView that displays a number of downloadable content. When you click it on a button within the cell the download starts.

But I'm having several issues: 1.How can I make sure that the progressBar will be shown all the time (even if the user scrolls scrolls and the cell will be reloaded) 2.How can I make sure that the user can download 2 files at once. I'm afraid it causes issues because I use some instance Variables. In a way it should work a bit like downloading from iCloud in the Music App

Here is my code

- (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];
}

Would be nice if somebody has a clue or a nice code example

解决方案

It's important to realize that your progress bars will not be shown all the time (i.e. the user can scroll the table, and once offscreen that same cell can be reused at another index position for different content). So what you will need to do is have somewhere you can store the data about any active downloads, including the index position in the table, the total file size, and the number of bytes downloaded so far. Then, whenever your cell is drawn, you'll need to check whether the item for that cell is currently being downloaded and if so, show the bar with the appropriate percentage progress.

The easiest way to do this would be to add a property to your view controller to store this info. It can be an NSMutablerray that will hold a collection of NSMutableDictionary objects, each dictionary will contain the necessary info about an active download.

@property (nonatomic, strong) NSMutableArray *activeConnections;

First you'll initialize the array in viewDidLoad::

- (void)viewDidLoad
{
    [super viewDidLoad];
    //...

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

Whenever a button is pressed, you'll add an NSMutableDictionary object to your array with the info you'll need.

- (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];
}

Also we'll create two utility methods so we can find easily retrieve the connection info from our array, using either the connection object itself, or the row index position in the table.

- (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;
}

When the connection is established, update your dictionary with the expected length 

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    // ...

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

As you receive data, you'll update the number of received bytes and tell your tableView to redraw the cell containing the progress bar.

- (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];
}

When your connection is done downloading, you should remove the connection from your activeConnections array, and reload the table cell.

- (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];
}

Finally, in cellForRowAtIndexPath: you'll need to draw the cell's progress bar based on the info in your activeConnections array.

- (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];
    }
}

这篇关于在UITableView中显示可下载内容的正确方法(使用ProgressBar等)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆