This commit is contained in:
wu736139669
2015-11-24 23:55:56 +08:00
parent a858d6fc5d
commit 011e153b4c
1322 changed files with 92213 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
Copyright (C) 2011 by BJ Basañes, http://shikii.net
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+28
View File
@@ -0,0 +1,28 @@
STableViewController
====================================================================================================
STableViewController is a custom table view controller that supports **pull-to-refresh** and
**load-more**. It was designed to have views and behaviors that can be easily customized.
See the demo project in `Demo/Demo.xcodeproj`.
Usage
----------------------------------------------------------------------------------------------------
To start, simply copy `STableViewController.h` and `STableViewController.m` into your project file.
STableViewController is not very useful on its own. It has to be subclassed to apply your custom
views and adjust any behavior. To get started quickly, you may include these files for reference:
* `DemoTableViewController` - subclass of `STableViewController`. This declares what views
to use for pull-to-refresh and load-more. Also includes samples on what methods to override
for data loading and a sample customization to interact with the header and footer views
depending on the situation.
* `DemoTableHeaderView` - the view used for pull-to-refresh
* `DemoTableFooterView` - the view used for load-more
You may also opt to implement your own subclass for `STableViewController` and use your own
views for pull-to-refresh and load-more.
See `STableViewController.h` for more information on the methods available.
@@ -0,0 +1,103 @@
//
// STableViewController.h
//
// @author Shiki
//
#import <UIKit/UIKit.h>
@interface STableViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
@protected
BOOL isDragging;
BOOL isRefreshing;
BOOL isLoadingMore;
// had to store this because the headerView's frame seems to be changed somewhere during scrolling
// and I couldn't figure out why >.<
CGRect headerViewFrame;
}
// The view used for "pull to refresh"
@property (nonatomic, retain) UIView *headerView;
// The view used for "load more"
@property (nonatomic, retain) UIView *footerView;
@property (nonatomic, retain) UITableView *tableView;
@property (readonly) BOOL isDragging;
@property (readonly) BOOL isRefreshing;
@property (readonly) BOOL isLoadingMore;
@property (nonatomic) BOOL canLoadMore;
@property (nonatomic) BOOL pullToRefreshEnabled;
// Defaults to YES
@property (nonatomic) BOOL clearsSelectionOnViewWillAppear;
// Just a common initialize method
- (void) initialize;
#pragma mark - Pull to Refresh
// The minimum height that the user should drag down in order to trigger a "refresh" when
// dragging ends.
- (CGFloat) headerRefreshHeight;
// Will be called if the user drags down which will show the header view. Override this to
// update the header view (e.g. change the label to "Pull down to refresh").
- (void) willShowHeaderView:(UIScrollView *)scrollView;
// If the user is dragging, will be called on every scroll event that the headerView is shown.
// The value of willRefreshOnRelease will be YES if the user scrolled down enough to trigger a
// "refresh" when the user releases the drag.
- (void) headerViewDidScroll:(BOOL)willRefreshOnRelease scrollView:(UIScrollView *)scrollView;
// By default, will permanently show the headerView by setting the tableView's contentInset.
- (void) pinHeaderView;
// Reverse of pinHeaderView.
- (void) unpinHeaderView;
// Called when the user stops dragging and, if the conditions are met, will trigger a refresh.
- (void) willBeginRefresh;
// Override to perform fetching of data. The parent method [super refresh] should be called first.
// If the value is NO, -refresh should be aborted.
- (BOOL) refresh;
// Call to signal that refresh has completed. This will then hide the headerView.
- (void) refreshCompleted;
#pragma mark - Load More
// The value of the height starting from the bottom that the user needs to scroll down to in order
// to trigger -loadMore. By default, this will be the height of -footerView.
- (CGFloat) footerLoadMoreHeight;
// Override to perform fetching of next page of data. It's important to call and get the value of
// of [super loadMore] first. If it's NO, -loadMore should be aborted.
- (BOOL) loadMore;
// Called when all the conditions are met and -loadMore will begin.
- (void) willBeginLoadingMore;
// Call to signal that "load more" was completed. This should be called so -isLoadingMore is
// properly set to NO.
- (void) loadMoreCompleted;
// Helper to show/hide -footerView
- (void) setFooterViewVisibility:(BOOL)visible;
#pragma mark -
// A helper method that calls refreshCompleted and/or loadMoreCompleted if any are active.
- (void) allLoadingCompleted;
#pragma mark -
- (void) releaseViewComponents;
@end
@@ -0,0 +1,326 @@
//
// STableViewController.m
//
// @author Shiki
//
#import "STableViewController.h"
#define DEFAULT_HEIGHT_OFFSET 52.0f
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
@implementation STableViewController
@synthesize tableView;
@synthesize headerView;
@synthesize footerView;
@synthesize isDragging;
@synthesize isRefreshing;
@synthesize isLoadingMore;
@synthesize canLoadMore;
@synthesize pullToRefreshEnabled;
@synthesize clearsSelectionOnViewWillAppear;
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) initialize
{
pullToRefreshEnabled = YES;
canLoadMore = YES;
clearsSelectionOnViewWillAppear = YES;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (id) init
{
if ((self = [super init]))
[self initialize];
return self;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (id) initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super initWithCoder:aDecoder]))
[self initialize];
return self;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) viewDidLoad
{
[super viewDidLoad];
self.tableView = [[[UITableView alloc] init] autorelease];
tableView.frame = self.view.bounds;
tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
tableView.dataSource = self;
tableView.delegate = self;
[self.view addSubview:tableView];
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (clearsSelectionOnViewWillAppear) {
NSIndexPath *selected = [self.tableView indexPathForSelectedRow];
if (selected)
[self.tableView deselectRowAtIndexPath:selected animated:animated];
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - Pull to Refresh
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) setHeaderView:(UIView *)aView
{
if (!tableView)
return;
if (headerView && [headerView isDescendantOfView:tableView])
[headerView removeFromSuperview];
[headerView release]; headerView = nil;
if (aView) {
headerView = [aView retain];
CGRect f = headerView.frame;
headerView.frame = CGRectMake(f.origin.x, 0 - f.size.height, f.size.width, f.size.height);
headerViewFrame = headerView.frame;
[tableView addSubview:headerView];
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (CGFloat) headerRefreshHeight
{
if (!CGRectIsEmpty(headerViewFrame))
return headerViewFrame.size.height;
else
return DEFAULT_HEIGHT_OFFSET;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) pinHeaderView
{
[UIView animateWithDuration:0.3 animations:^(void) {
self.tableView.contentInset = UIEdgeInsetsMake([self headerRefreshHeight], 0, 0, 0);
}];
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) unpinHeaderView
{
[UIView animateWithDuration:0.3 animations:^(void) {
self.tableView.contentInset = UIEdgeInsetsZero;
}];
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) willBeginRefresh
{
if (pullToRefreshEnabled)
[self pinHeaderView];
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) willShowHeaderView:(UIScrollView *)scrollView
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) headerViewDidScroll:(BOOL)willRefreshOnRelease scrollView:(UIScrollView *)scrollView
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL) refresh
{
if (isRefreshing)
return NO;
[self willBeginRefresh];
isRefreshing = YES;
return YES;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) refreshCompleted
{
isRefreshing = NO;
if (pullToRefreshEnabled)
[self unpinHeaderView];
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - Load More
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) setFooterView:(UIView *)aView
{
if (!tableView)
return;
tableView.tableFooterView = nil;
[footerView release]; footerView = nil;
if (aView) {
footerView = [aView retain];
tableView.tableFooterView = footerView;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) willBeginLoadingMore
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) loadMoreCompleted
{
isLoadingMore = NO;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (BOOL) loadMore
{
if (isLoadingMore)
return NO;
[self willBeginLoadingMore];
isLoadingMore = YES;
return YES;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (CGFloat) footerLoadMoreHeight
{
if (footerView)
return footerView.frame.size.height;
else
return DEFAULT_HEIGHT_OFFSET;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) setFooterViewVisibility:(BOOL)visible
{
if (visible && self.tableView.tableFooterView != footerView)
self.tableView.tableFooterView = footerView;
else if (!visible)
self.tableView.tableFooterView = nil;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) allLoadingCompleted
{
if (isRefreshing)
[self refreshCompleted];
if (isLoadingMore)
[self loadMoreCompleted];
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - UIScrollViewDelegate
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
if (isRefreshing)
return;
isDragging = YES;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) scrollViewDidScroll:(UIScrollView *)scrollView
{
if (!isRefreshing && isDragging && scrollView.contentOffset.y < 0) {
[self headerViewDidScroll:scrollView.contentOffset.y < 0 - [self headerRefreshHeight]
scrollView:scrollView];
} else if (!isLoadingMore && canLoadMore) {
CGFloat scrollPosition = scrollView.contentSize.height - scrollView.frame.size.height - scrollView.contentOffset.y;
if (scrollPosition < [self footerLoadMoreHeight]) {
[self loadMore];
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if (isRefreshing)
return;
isDragging = NO;
if (scrollView.contentOffset.y <= 0 - [self headerRefreshHeight]) {
if (pullToRefreshEnabled)
[self refresh];
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - UITableViewDelegate
////////////////////////////////////////////////////////////////////////////////////////////////////
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
return nil;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) releaseViewComponents
{
[headerView release]; headerView = nil;
[footerView release]; footerView = nil;
[tableView release]; tableView = nil;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) dealloc
{
[self releaseViewComponents];
[super dealloc];
}
////////////////////////////////////////////////////////////////////////////////////////////////////
- (void) viewDidUnload
{
[self releaseViewComponents];
[super viewDidUnload];
}
@end