Here is a table view class that can be inherited, to provide a header that sticks to the top of the visible area. It has these key features:
You have the option of providing a masking image, is cases where your header has transparency, and you therefore need to hide the scrolled table cells.
You can configure the height of the visible header area, from the view controller.
FixedHeaderTableView.h
/**
* Table with a fixed header. The header does not scroll off the top of the visible area, and it does not
* scroll down off the top of the header area. The scroll indicator insets are adjusted to go to the top of
* the table, below the header view.
*
* Instructions for use:
*
* 1) Create a table view that inherits from FixedHeaderTableView, and configure it:
* - set the delegate to your view controller
* - this allows you to implement UITableViewDelegate methods, and UIScrollViewDelegate method,
* scrollViewDidScroll:
* 2) Create a separate UIView with the same width as the table view, to be used as the fixed table header.
* 3) Implement scrollViewDidScroll: in your UITableViewDelegate, to simply delegate to your FixedHeaderTableView.
* 4) In viewDidLoad of your view controller, do the following:
* - Set the containerView property to the view controller's main view.
* - Create or get a masking view, if the table header is not fully opaque. This prevents the table cells
* from being shown behind the header view, when they are scrolled up.
* - Call setFixedTableHeaderView:visibleHeaderHeight:withMaskingImageView:maskingImageFrame: on your
* FixedHeaderTableView.
*/
@interface FixedHeaderTableView : UITableView {
UIView *_containerView;
UIView *_fixedTableHeaderView;
int _hiddenHeight;
//Used to mask cells behind a transparent header
UIImageView *_maskingImageView;
}
@property (strong, nonatomic) UIView *containerView;
/**
* To be called from the UITableViewDelegate, to delegate header view positioning and masking.
*/
- (void) scrollViewDidScroll:(UIScrollView *)scrollView;
/**
* Should be called from viewDidLoad of the view controller.
*
* This sets and configures the fixed table head view.
*
* @param fixedTableHeaderView UIView that is used as the sticky header
*
* @param visibleHeaderHeight The bottom portion of the header that will stay visible. This can
* be the same height as the header view, or lower. If it is out of
* this range, it is clamped to the closest value (0 or the height).
*
* @param maskingImage This is optional, and it only needed if your header view has
* transparent areas. Using a masking image provides much better
* performance than adjusting the masks of each cell, in the
* scrollViewDidScroll: delegate method.
*
* @param maskingImageFrame If the masking image is provided, this should be set to position
* the background image, so that it is equal to any other image position
* used in the background.
*/
- (void) setFixedTableHeaderView:(UIView *)fixedTableHeaderView
visibleHeaderHeight:(int)visibleHeaderHeight
withMaskingImage:(UIImage *)maskingImage
maskingImageFrame:(CGRect)maskingImageFrame;
@end
FixedHeaderTableView.m
#import “FixedHeaderTableView.h"
@interface FixedHeaderTableView ()
@property (assign, nonatomic) int hiddenHeight;
@property (strong, nonatomic) UIView *fixedTableHeaderView;
@property (strong, nonatomic) UIImageView *maskingImageView;
@end
@implementation FixedHeaderTableView
- (void) scrollViewDidScroll:(UIScrollView *)scrollView
{
CGRect tableHeaderRect = _fixedTableHeaderView.frame;
//Prevent table header from being dragging down from the top
tableHeaderRect.origin.y = MIN(0, -scrollView.contentOffset.y);
tableHeaderRect.origin.y += self.frame.origin.y;
//Prevent table header from scrolling completely off the top
if (scrollView.contentOffset.y > _hiddenHeight) {
tableHeaderRect.origin.y = -_hiddenHeight;
_maskingImageView.hidden = FALSE;
} else {
_maskingImageView.hidden = TRUE;
}
self.fixedTableHeaderView.frame = tableHeaderRect;
}
- (void) setFixedTableHeaderView:(UIView *)fixedTableHeaderView
visibleHeaderHeight:(int)visibleHeaderHeight
withMaskingImage:(UIImage *)maskingImage
maskingImageFrame:(CGRect)maskingImageFrame
{
self.fixedTableHeaderView = fixedTableHeaderView;
//Quietly ensure the value is not out of acceptable range
if (visibleHeaderHeight > _fixedTableHeaderView.frame.size.height) {
visibleHeaderHeight = _fixedTableHeaderView.frame.size.height;
} else if (visibleHeaderHeight < 0) {
visibleHeaderHeight = 0;
}
self.hiddenHeight = _fixedTableHeaderView.frame.size.height - visibleHeaderHeight;
//Shift the scrolling insets to span the height of the table's rows
self.scrollIndicatorInsets = UIEdgeInsetsMake(_fixedTableHeaderView.frame.size.height, 0, 0, 0);
CGRect tableHeaderFrame = _fixedTableHeaderView.frame;
tableHeaderFrame.origin.x = self.frame.origin.x;
tableHeaderFrame.origin.y = self.frame.origin.y;
_fixedTableHeaderView.frame = tableHeaderFrame;
[self.superview addSubview:_fixedTableHeaderView];
self.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, _fixedTableHeaderView.frame.size.height)];
//Table header view sits behind the fixed header view
if (maskingImage) {
maskingImageFrame.origin.y += _hiddenHeight;
UIImageView *maskingImageView = [[UIImageView alloc] initWithFrame:maskingImageFrame];
maskingImageView.image = maskingImage.copy;
[_fixedTableHeaderView addSubview:maskingImageView];
[_fixedTableHeaderView sendSubviewToBack:maskingImageView];
_fixedTableHeaderView.clipsToBounds = TRUE;
self.maskingImageView = maskingImageView;
_maskingImageView.hidden = TRUE;
}
}
@end
Here is a table view class that can be inherited, to provide a header that sticks to the top of the visible area. It has these key features:
FixedHeaderTableView.h
FixedHeaderTableView.m
Here is how you create your Header view for your UITableView
Now return the height of the
Hope this helps you.