知識是無窮無盡,技術須要積累,記錄一點一滴,讓成長的時間軸上變得充實一些。 今天就講講UITableView/UICollectionView的一些使用技巧。結合本身項目狀況進行展開。ui
有時候咱們須要設置 TableView 的頭部和尾部的間距,頭部尾部的高度只須要在代理裏面設置高度就行。atom
示例代碼以下:spa
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 0.01f;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, 20)];
view.backgroundColor = [UIColor clearColor];
return view;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return 10;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth, 1)];
view.backgroundColor = [UIColor clearColor];
return view;
}
複製代碼
小結:經過上面的代碼實現的效果能夠看出,當自定義頭部和尾部視圖時,即便自定義頭部和尾部視圖設置了高度。高度最終仍是由tableView:heightForHeaderInSection:
和tableView:heightForFooterInSection:
兩個代理方法決定。當沒有實現這兩個代理方法時,高度爲默認高度。3d
TableView的懸停功能只有在 Style
是 UITableViewStylePlain
的時候纔有。若是有這麼一種需求,就是須要有Header懸停,同時每一個section之間須要有間隔。 效果以下:代理
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return kHeaderHeight+9;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
BillListModel *model = _sectionArr[section];
UIView *header = ({
UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, kHeaderHeight+9)];
bgView.backgroundColor = [UIColorTools colorWithTheme:UIColorThemeAppBgColor];
UILabel *titleLab = [[UILabel alloc] initWithFrame:CGRectMake(0, 9, KScreenWidth, kHeaderHeight)];
titleLab.backgroundColor = [UIColorTools colorWithTheme:UIColorThemeWhite];
titleLab.textColor = [UIColorTools colorWithTheme:UIColorThemeBlack];
titleLab.text = model.time;
[bgView addSubview:titleLab];
UIImageView *lineHBottom = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, titleLab.mj_max_y - 0.5, KScreenWidth, 0.5)];
lineHBottom.backgroundColor = [UIColorTools colorWithTheme:UIColorThemeSeparatorColor];
[bgView addSubview:lineHBottom];
bgView;
});
return header;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView == _tableView) {
UITableView *tableview = (UITableView *)scrollView;
CGFloat sectionHeaderHeight = kHeaderHeight;
CGFloat sectionFooterHeight = 9;
CGFloat offsetY = tableview.contentOffset.y;
if (offsetY >= 0 && offsetY <= sectionFooterHeight) {
tableview.contentInset = UIEdgeInsetsMake(-offsetY, 0, -sectionHeaderHeight, 0);
} else if (offsetY >= sectionFooterHeight && offsetY <= tableview.contentSize.height - tableview.frame.size.height - sectionHeaderHeight) {
tableview.contentInset = UIEdgeInsetsMake(-sectionFooterHeight, 0, 0, 0);
} else if (offsetY >= 0 && tableview.contentSize.height >= tableview.contentSize.height) {
tableview.contentInset = UIEdgeInsetsMake(-sectionFooterHeight, 0, 0, 0);
}
}
}
複製代碼
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if (section == 0) {
return 10.f;
} else if (section == 2) {
return 0;
}
return kHeight4_7(35);
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return 10.f;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *headerView = [UIView new];
headerView.backgroundColor = [UIColorTools colorWithTheme:UIColorThemeWhite];
if (section == 0) {
headerView.backgroundColor = [UIColor clearColor];
}
return headerView;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
UIView *footerView = [[UIView alloc] init];
footerView.backgroundColor = [UIColor clearColor];
return footerView;
}
複製代碼
CollectionView的懸停功能只有在 Style
是 UITableViewStylePlain
的時候纔有。若是有這麼一種需求,就是須要有Header懸停,同時每一個section之間須要有間隔。 效果以下:code
可能經過decelerationRate的屬性來設置,它的值域是(0.0,1.0),當decelerationRate設置爲0.1時,當手指touch up時就會很慢的停下來。cdn
這裏中止滑動的意思要明確一下,有兩種:blog
一、第一種是指手指中止ScrollView。事件
當手指中止滑動時,iOS會調UIScrollView的delegate圖片
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
複製代碼
若是decelerate還爲NO時,它最終停下,不然它還沒最終停下
二、第二種是指ScrollView中止滑動,指的滾動條徹底中止下來。
當decelerate = true時,iOS纔會調UIScrollView的delegate
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
複製代碼
那UIScrollView真正中止滑動,應該怎麼判斷呢? 解決方法以下:
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if(!decelerate) {
//OK,真正中止了,do something
}
}
//而後
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
//OK,真正中止了,do something
}
複製代碼
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat contentOffsetX = scrollView.contentOffset.x;
if (contentOffsetX<=0 || contentOffsetX>=kScreenWidth) {
//當滑動到最左邊或者最右邊時,禁止繼續滑動
scrollView.scrollEnabled = NO;
} else {
scrollView.scrollEnabled = YES;
}
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
scrollView.scrollEnabled = YES;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
scrollView.scrollEnabled = YES;
}
複製代碼
當手指觸摸後,scrollView會暫時攔截觸摸事件,使用一個計時器,假如在計時器到點後,沒有發生手指移動事件,那麼,scrollView發送tracking events到被點擊的subView。 假如在計時器到點前,發生了移動事件,那麼scrollView取消tracking本身發生滾動。
子類能夠重載touchesShouldBegin:withEvent:inContentView:
決定本身是否接收touch事件。 當pagingEnabled
值爲YES
,會自動滾動到subView的邊界,默認是NO
。
touchesShouldCancelInContentView:
開始發送tracking messages消息給subView的時候 調用這個方法,決定是否發送tracking messages消息到subview,假如返回NO
,則發送,YES
則不發送。
假如canCancelContentTouches
屬性是NO
,則不調用這個方法來影響如何處理滾動手勢。
實現原理就是監聽滾動狀況,重設scrollView.contentInset便可 效果以下:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat contentOffsety = scrollView.contentOffset.y;
_contentOffSet_y = contentOffsety;
//這個header實際上是section的header到頂部的距離
CGFloat header = kBannerHight+[HSFuntionCell cellHeight]+kFooterViewHeight-64;
NSLog(@"=======%lf=====%lf", contentOffsety, header);
if (contentOffsety<=header&&contentOffsety>=0) {
//當視圖滑動的距離小於header時
scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
self.headerView.layer.borderColor = [UIColorTools colorWithTheme:UIColorThemeWhite].CGColor;
} else if (contentOffsety>header) {
//當視圖滑動的距離大於header時,這裏就能夠設置section的header的位置,設置的時候要考慮到導航欄的透明對滾動視圖的影響
scrollView.contentInset = UIEdgeInsetsMake(64, 0, 0, 0);
self.headerView.layer.borderColor = [UIColorTools colorWithTheme:UIColorThemeSeparatorColor].CGColor;
}
self.headerView.borderWhich = DDViewBorderTop;
//設置導航條透明度
[self setNavigationColor:contentOffsety];
}
複製代碼
實現思路:自定義一個ViewA,做爲TableView的headerView,而後監聽TableView的滾動,將回調傳遞給ViewA便可。
效果以下:
.h文件
@interface MOActivityTopView : UIView
@property (nonatomic, strong) MOActivityModel *model;
- (void)didScroll:(CGFloat)contentOffSetY;
@end
複製代碼
.m文件
#import "MOActivityTopView.h"
#define kViewHeight (kScreenWidth*340/750.)
#define kTopHeight (kScreenWidth*240/750.)
#define kBottomHeight (kScreenWidth*100/750.)
@interface MOActivityTopView ()
/// 背景圖
@property (nonatomic, strong) UIImageView *backgroundImgV;
/// 毛玻璃
@property (nonatomic, strong) UIVisualEffectView *visualEffectView;
/// 活動圖
@property (nonatomic, strong) UIImageView *activityImgV;
/// 活動名稱
@property (nonatomic, strong) UILabel *activityLab;
@end
@implementation MOActivityTopView
- (instancetype)init {
if (self = [super initWithFrame:CGRectMake(0, 0, kScreenWidth, kViewHeight)]) {
[self setUp];
}
return self;
}
#pragma mark - Getter
-(UIImageView *)backgroundImgV {
if (_backgroundImgV == nil) {
_backgroundImgV = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, self.dd_w, kTopHeight)];
[_backgroundImgV setContentMode:UIViewContentModeScaleAspectFill];
[_backgroundImgV setClipsToBounds:YES];
}
return _backgroundImgV;
}
- (void)setUp {
[self addSubview:self.backgroundImgV];
UIVisualEffect *blurEffect;
blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
_visualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
// _visualEffectView.alpha = 0.8;
_visualEffectView.frame = self.backgroundImgV.frame;
[self addSubview:_visualEffectView];
UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(0, self.backgroundImgV.dd_max_y, kScreenWidth, kBottomHeight)];
bgView.backgroundColor = [UIColorTools colorWithTheme:UIColorThemeWhite];
[self addSubview:bgView];
CGFloat height = (kScreenWidth*160/750.);
CGFloat width = height/(16/21.);
_activityImgV = [[UIImageView alloc] initWithFrame:CGRectMake(15, bgView.dd_h-7-height, width, height)];
[bgView addSubview:_activityImgV];
_activityLab = [[UILabel alloc] initWithFrame:CGRectMake(_activityImgV.dd_max_x+8, 0, kScreenWidth-_activityImgV.dd_max_x-8-15, kBottomHeight)];
_activityLab.textColor = [UIColorTools colorWithTheme:UIColorThemeBlack];
_activityLab.numberOfLines = 2;
// _activityLab.adjustsFontSizeToFitWidth = YES;
[bgView addSubview:_activityLab];
}
- (void)layoutSubviews {
[super layoutSubviews];
_activityImgV.clipsToBounds = YES;
_activityImgV.layer.masksToBounds = YES;
_activityImgV.layer.borderWidth = 1.5;
_activityImgV.layer.borderColor = [UIColorTools colorWithTheme:UIColorThemeWhite].CGColor;
_activityImgV.layer.cornerRadius = kViewCornerRadius;
}
- (void)setModel:(MOActivityModel *)model {
_model = model;
[_activityImgV sd_setImageWithURL:kMOImageUrlSet(model.ActivityURL) placeholderImage:[UIImage placeholderImage_activity]];
[_backgroundImgV sd_setImageWithURL:kMOImageUrlSet(model.ActivityURL) placeholderImage:kImageSet(@"Icon-noti")];
_activityLab.text = model.ActivityName;
}
- (void)didScroll:(CGFloat)contentOffSetY {
//圖片高度
CGFloat imageHeight = self.dd_h;
//圖片寬度
CGFloat imageWidth = kScreenWidth;
//圖片上下偏移量
CGFloat imageOffsetY = contentOffSetY;
// NSLog(@"圖片上下偏移量 imageOffsetY:%f ->",imageOffsetY);
//下拉
if (imageOffsetY < 0) {
CGFloat totalOffset = imageHeight + ABS(imageOffsetY);
CGFloat f = totalOffset / imageHeight;
self.backgroundImgV.frame = CGRectMake(-(imageWidth * f - imageWidth) * 0.5, imageOffsetY, imageWidth * f, totalOffset);
}
// //上拉
// if (imageOffsetY > 0) {
// CGFloat totalOffset = imageHeight - ABS(imageOffsetY);
// CGFloat f = totalOffset / imageHeight;
// [self.backgroundImgV setFrame:CGRectMake(-(imageWidth * f - imageWidth) * 0.5, imageOffsetY, imageWidth * f, totalOffset)];
// }
_visualEffectView.frame = self.backgroundImgV.frame;
}
@end
複製代碼
- (UIView *)topHeaderView {
if (!_topHeaderView) {
_topHeaderView = [[MOActivityTopView alloc] init];
_topHeaderView.model = _model;
}
return _topHeaderView;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat contentOffSetY = scrollView.contentOffset.y;
[self.topHeaderView didScroll:contentOffSetY];
}
複製代碼
再一次感謝您花費時間閱讀這篇文章!
微博: @Danny_呂昌輝
博客: SuperDanny