IOS uitableview encapsulation-pull-up-asynchronous image loading

Source: Internet
Author: User
Preface

Anyone who has worked on mobile development knows that list controls are one of the most commonly used controls. The list control in IOS is uitableview. In fact, Apple developers are well-designed for uitableview (easy to use and highly scalable ).

However, you can still feel a little complicated about displaying mobile-end system software with a single logic (maybe programmers are naturally a bit lazy ).

Let's see where it is complicated. First, it is often used too frequently; second, it is usually not just to present the data, it will generally follow the pull-down refresh, load more functions, of course, it is usually necessary to deal with the network to download data and images. Third, the MVC mode is the usual mode for iOS development, followed by the implementation of a lot of protocols (whether you write it again or not, copy it. It seems boring to do this ).

With this in mind, we have encapsulated the common usage modes of uitableview today. Specifically, we have done the following:

1. embedded with the drop-down refresh (egorefreshtableheaderview), loading more (loadmoretablefooterview)

2. the built-in uitableviewdatasource and uitableviewdelegate protocols are usually required. The self-implemented logic is open to the customer's code in the form of blocks.

3. built-in implementation of the callback protocol for the two components mentioned in 1. Same as above, the self-implemented logic is open to the outside in the form of blocks.

4. The uiscrollviewdelegate protocol required for interaction between egorefreshtableheaderview, loadmoretablefooterview and uitableview is built in.

5. built-in asynchronous image download (optional)

 

You can go to myGitHubTo view the source code. Eltableviewcontroller is the first letter of egorefreshtableheaderview and loadmoretablefooterview.

This Code contains a sample program and three essential components:

1. egorefreshtableheaderview

2. loadmoretablefooterview (modified version, the original version cannot adapt to any size height)

3. The icondownloader (icondownloader) provided by Apple for asynchronous download of images in uitableview is only applicable to downloading user portraits similar to those in social networks. It is not recommended to use it to download those large images, because it is not even cached (sdimage is recommended if the image is large)

Code explanation

It has built in to implement these protocols, so you do not need to set and implement it when using it.

@interface ELTableViewController : UIViewController<UITableViewDelegate,UITableViewDataSource,EGORefreshTableHeaderDelegate,LoadMoreTableFooterDelegate,IconDownloaderDelegate>

For the ever-changing business logic, all blocks to be implemented are provided here:

//blocks for UITableView delegatetypedef UITableViewCell* (^cellForRowAtIndexPathDelegate) (UITableView *,NSIndexPath *);typedef CGFloat (^heightForRowAtIndexPathDelegate) (UITableView *,NSIndexPath *);typedef void (^didSelectRowAtIndexPathDelegate) (UITableView *,NSIndexPath *);//blocks for refresh and load moretypedef void (^refreshDataSourceFunc) (void);typedef void (^loadMoreDataSourceFunc) (void);typedef void (^refreshDataSourceCompleted) (void);typedef void (^loadMoreDataSourceCompleted) (void);//use to load image (async)typedef void (^loadImagesForVisiableRowsFunc) (void);typedef void (^appImageDownloadCompleted) (NSIndexPath *);

They are made public in the form of attributes:

//property for blocks@property (nonatomic,copy) cellForRowAtIndexPathDelegate cellForRowAtIndexPathDelegate;@property (nonatomic,copy) heightForRowAtIndexPathDelegate heightForRowAtIndexPathDelegate;@property (nonatomic,copy) didSelectRowAtIndexPathDelegate didSelectRowAtIndexPathDelegate;@property (nonatomic,copy) loadMoreDataSourceFunc loadMoreDataSourceFunc;@property (nonatomic,copy) refreshDataSourceFunc refreshDataSourceFunc;@property (nonatomic,copy) refreshDataSourceCompleted refreshDataSourceCompleted;@property (nonatomic,copy) loadMoreDataSourceCompleted loadMoreDataSourceCompleted;@property (nonatomic,copy) loadImagesForVisiableRowsFunc loadImagesForVisiableRowsFunc;@property (nonatomic,copy) appImageDownloadCompleted appImageDownloadCompleted;

The functions such as loading more, refresh down, and asynchronous image loading are optional. They exist as components. For example, when instantiating the controller, you can set whether the top-up and drop-down functions are available. For image downloading, as long as you do not implement the corresponding block, it will not impose additional burden on you.

- (id)initWithRefreshHeaderViewEnabled:(BOOL)enableRefreshHeaderView andLoadMoreFooterViewEnabled:(BOOL)enableLoadMoreFooterView;- (id)initWithRefreshHeaderViewEnabled:(BOOL)enableRefreshHeaderView           andLoadMoreFooterViewEnabled:(BOOL)enableLoadMoreFooterView                      andTableViewFrame:(CGRect)frame;

#pragma mark - UITableView Delegate -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{    if (nil==self.dataSource) {        return 0;    }        return [self.dataSource count];}- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    if (!self.cellForRowAtIndexPathDelegate) {        @throw [NSException exceptionWithName:@"Framework Error"                                        reason:@"Must be setting cellForRowAtIndexPathBlock for UITableView" userInfo:nil];    }    return self.cellForRowAtIndexPathDelegate(tableView,indexPath);}- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{    if (!self.heightForRowAtIndexPathDelegate) {        @throw [NSException exceptionWithName:@"Framework Error"                                        reason:@"Must be setting heightForRowAtIndexPathDelegate for UITableView" userInfo:nil];    }    return self.heightForRowAtIndexPathDelegate(tableView,indexPath);}- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{    if (self.didSelectRowAtIndexPathDelegate) {        self.didSelectRowAtIndexPathDelegate(tableView,indexPath);    }}#pragma mark - LoadMoreTableFooterDelegate Methods -- (void)loadMoreTableFooterDidTriggerRefresh:(LoadMoreTableFooterView *)view{    if (self.loadMoreDataSourceFunc&&self.loadMoreDataSourceCompleted) {        self.loadMoreDataSourceFunc();                double delayInSeconds = 3.0;        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);        dispatch_after(popTime, dispatch_get_main_queue(),                        self.loadMoreDataSourceCompleted);    }}- (BOOL)loadMoreTableFooterDataSourceIsLoading:(LoadMoreTableFooterView *)view{    return self.isLoadingMore;}#pragma mark - EGORefreshTableHeaderDelegate Methods --(void)egoRefreshTableHeaderDidTriggerRefresh:(EGORefreshTableHeaderView *)view{    if (self.refreshDataSourceFunc&&self.refreshDataSourceCompleted){        self.refreshDataSourceFunc();                double delayInSeconds = 3.0;        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);        dispatch_after(popTime, dispatch_get_main_queue(),                        self.refreshDataSourceCompleted);    }}-(BOOL)egoRefreshTableHeaderDataSourceIsLoading:(EGORefreshTableHeaderView *)view{    return self.isRefreshing;}-(NSDate *)egoRefreshTableHeaderDataSourceLastUpdated:(EGORefreshTableHeaderView *)view{    return [NSDate date];}#pragma mark - UIScrollViewDelegate Methods --(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{    self.currentOffsetPoint=scrollView.contentOffset;}-(void)scrollViewDidScroll:(UIScrollView *)scrollView{    CGPoint pt=scrollView.contentOffset;    if (self.currentOffsetPoint.y<pt.y) {        [self.loadMoreFooterView loadMoreScrollViewDidScroll:scrollView];    }else {        [self.refreshHeaderView egoRefreshScrollViewDidScroll:scrollView];    }}-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{    CGPoint pt=scrollView.contentOffset;    if (self.currentOffsetPoint.y<pt.y) {        [self.loadMoreFooterView loadMoreScrollViewDidEndDragging:scrollView];    }else {        [self.refreshHeaderView egoRefreshScrollViewDidEndDragging:scrollView];    }        if (!decelerate&&self.loadImagesForVisiableRowsFunc) {        self.loadImagesForVisiableRowsFunc();    }}-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{    if (self.loadImagesForVisiableRowsFunc) {        self.loadImagesForVisiableRowsFunc();    }}#pragma mark - download image async --(void)appImageDidLoad:(NSIndexPath *)indexPath{    if (self.appImageDownloadCompleted) {        self.appImageDownloadCompleted(indexPath);    }}

Use of eltableviewcontroller

Create a new controller inherited from: eltableviewcontroller;

Override parent class initblocks method:

#pragma mark - private methods -- (void)loadDataSource{    self.dataSource=[NSMutableArray array];    [self.dataSource addObject:@"dataSource_1"];    [self.dataSource addObject:@"dataSource_2"];    [self.dataSource addObject:@"dataSource_3"];    [self.dataSource addObject:@"dataSource_4"];    [self.dataSource addObject:@"dataSource_5"];    [self.dataSource addObject:@"dataSource_6"];    [self.dataSource addObject:@"dataSource_7"];    [self.dataSource addObject:@"dataSource_8"];    [self.dataSource addObject:@"dataSource_9"];    [self.dataSource addObject:@"dataSource_10"];}- (void)initBlocks{    __block TestViewController *blockedSelf=self;        //load more    self.loadMoreDataSourceFunc=^{        [blockedSelf.dataSource addObject:@"loadMoreDataSourceBlock_1"];        [blockedSelf.dataSource addObject:@"loadMoreDataSourceBlock_2"];        [blockedSelf.dataSource addObject:@"loadMoreDataSourceBlock_3"];        [blockedSelf.dataSource addObject:@"loadMoreDataSourceBlock_4"];        [blockedSelf.dataSource addObject:@"loadMoreDataSourceBlock_5"];                blockedSelf.isLoadingMore=YES;        [self.tableView reloadData];                NSLog(@"loadMoreDataSourceBlock was invoked");    };        //load more completed    self.loadMoreDataSourceCompleted=^{        blockedSelf.isLoadingMore=NO;        [blockedSelf.loadMoreFooterView loadMoreScrollViewDataSourceDidFinishedLoading:self.tableView];                NSLog(@"after loadMore completed");    };        //refresh    self.refreshDataSourceFunc=^{        blockedSelf.dataSource=[NSMutableArray array];        [blockedSelf.dataSource addObject:@"refreshDataSourceBlock_1"];        [blockedSelf.dataSource addObject:@"refreshDataSourceBlock_2"];        [blockedSelf.dataSource addObject:@"refreshDataSourceBlock_3"];        [blockedSelf.dataSource addObject:@"refreshDataSourceBlock_4"];        [blockedSelf.dataSource addObject:@"refreshDataSourceBlock_5"];                blockedSelf.isRefreshing=YES;        [self.tableView reloadData];                NSLog(@"refreshDataSourceBlock was invoked");    };        //refresh completed    self.refreshDataSourceCompleted=^{        blockedSelf.isRefreshing=NO;        [blockedSelf.loadMoreFooterView loadMoreScrollViewDataSourceDidFinishedLoading:self.tableView];                NSLog(@"after refresh completed");    };        self.cellForRowAtIndexPathDelegate=^(UITableView *tableView, NSIndexPath *indexPath){        static NSString *cellIdentifier=@"cellIdentifier";        UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIdentifier];        if (!cell) {            cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]autorelease];        }                cell.textLabel.text=[blockedSelf.dataSource objectAtIndex:indexPath.row];                NSLog(@"block:cellForRowAtIndexPathBlock has been invoked.");                return cell;    };        self.heightForRowAtIndexPathDelegate=^(UITableView *tableView, NSIndexPath *indexPath){        NSLog(@"block:heightForRowAtIndexPathBlock has been invoked.");        return 60.0f;    };        self.didSelectRowAtIndexPathDelegate=^(UITableView *tableView, NSIndexPath *indexPath){        NSLog(@"block:didSelectRowAtIndexPathDelegate has been invoked.");    };    }

Call the following in viewdidload:

[self initBlocks];    [self loadDataSource];    [self.tableView reloadData];

Finally, when instantiating the controller, you can specify whether to use the lift and drop-down

self.viewController = [[[TestViewController alloc] initWithRefreshHeaderViewEnabled:YES andLoadMoreFooterViewEnabled:YES]autorelease];

Conclusion

After writing it, I used it to reconstruct several views of kuaibo zhongzhong and Sina Weibo. It also saves some redundant code. If I used it during development, I still feel a little effort saved.

In fact, it is still relatively simple encapsulation, so it is not very relevant to the business. It can also be seen that it has many functions that can be further enhanced:

1. encapsulate the add, delete, modify, and query Functions

2. animation during encapsulation loading and Operation

3. unified implementation of encapsulated network loading

...................

Write it here first.

Two articles about IOS block are recommended:

Http://lldong.github.com/blog/2011/12/30/blocks/

Http://yannickloriot.com/2011/11/working-with-blocks/

Source Code address:

Https://github.com/yanghua/ELTableViewController

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.