美麗說蘑菇街首頁效果(UITableView和UIScrollerView聯動)
作為一名菜鳥iOS開發程式設計師,第一次寫文章,有點小激動!進入正題,最近專案中有個需求,類似美麗說蘑菇街首頁效果,在網上找了一些資料後自己研究了下終於搞定了!
先看效果:
接下來詳細的介紹下:
先說下佈局層次結構:
圖層結構大概就是這樣的,這個簡單,再說下思路:
1、要實現的效果是:當頭部的藍色View全部顯示時,下面的TableView可以下拉,最底層的紅色ScrollerView不能向下滑動,當向上滑動時,由於黃色選單View未到達頂部,TableView此時不能滑動,底部的ScrollerView向上滑動,當黃色選單View到達頂部時,底部的ScrollerView不能再繼續向上滑動,此時TableView向上滑動
2、難點:如何讓TableView和ScrollerView滑動和不滑動 怎麼控制?很多人說用 ScrollerView.scrollEnabled = NO;
當你上下滑動時手指並沒有擡起,經過試驗這個方法無效。還有就是,當你滑動TableView時,下面的ScrollerView如何響應滑動手勢?
直接上程式碼吧:
#import <UIKit/UIKit.h>
@interface ZXWScrollerView : UIScrollView
@end
#import "ZXWScrollerView.h" @implementation ZXWScrollerView - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; } @end
自定義一個ScrollView類(最底層的ScrollerView繼承該類),重寫上面的方法 這個程式碼的意思是:當ScrollerView上的View有手勢響應時,繼續向下傳遞,這樣當你滑動TableView時,下方的ScrollerView就會接收到該手勢
繼續看程式碼
首先建立下方的TableView的ViewControllerView
#import <UIKit/UIKit.h> @protocol oneDelegate <NSObject> -(void)oneDelegateDidScrollerToBottom:(UIScrollView*)scrView; @end @interface OneViewController : UIViewController @property (nonatomic,weak) id <oneDelegate>delegate; @property (nonatomic,strong)UITableView *tableView; @property (nonatomic, assign) BOOL canScroll; @end
#import "OneViewController.h"
static NSString *const kGoTopNotificationName = @"goTop";//進入置頂命令
static NSString *const kLeaveTopNotificationName = @"leaveTop";//離開置頂命令
@interface OneViewController ()<UITableViewDelegate,UITableViewDataSource>
{
NSMutableArray *mutarr;
}
@end
@implementation OneViewController
- (void)viewDidLoad {
[super viewDidLoad];
_tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height-50-64)];
[self.view addSubview:_tableView];
_tableView.delegate = self;
_tableView.dataSource = self;
mutarr = [[NSMutableArray alloc]init];
for (int i = 0 ; i<30; i++) {
[mutarr addObject:[NSString stringWithFormat:@"哈哈哈哈哈哈%d",i]];
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(acceptMsg:) name:kGoTopNotificationName object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(acceptMsg:) name:kLeaveTopNotificationName object:nil];//其中一個TAB離開頂部的時候,如果其他幾個偏移量不為0的時候,要把他們都置為0
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return mutarr.count;
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (cell==nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
}
cell.textLabel.text = mutarr[indexPath.row];
return cell;
}
-(void)acceptMsg : (NSNotification *)notification{
//NSLog(@"%@",notification);
NSString *notificationName = notification.name;
if ([notificationName isEqualToString:kGoTopNotificationName]) {
NSDictionary *userInfo = notification.userInfo;
NSString *canScroll = userInfo[@"canScroll"];
if ([canScroll isEqualToString:@"1"]) {
self.canScroll = YES;
self.tableView.showsVerticalScrollIndicator = YES;
}
}else if([notificationName isEqualToString:kLeaveTopNotificationName]){
self.tableView.contentOffset = CGPointZero;
self.canScroll = NO;
self.tableView.showsVerticalScrollIndicator = NO;
}
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (!self.canScroll) {
[scrollView setContentOffset:CGPointZero];
}
CGFloat offsetY = scrollView.contentOffset.y;
if (offsetY<0) {
[[NSNotificationCenter defaultCenter] postNotificationName:kLeaveTopNotificationName object:nil userInfo:nil];
[self.delegate oneDelegateDidScrollerToBottom:scrollView];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
接著就是重點了 ViewController
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
//
// ViewController.m
// 111111
//
// Created by ZXW on 2016/11/18.
// Copyright © 2016年 ZXW. All rights reserved.
//
#import "ViewController.h"
#import "ZXWScrollerView.h"
#import "OneViewController.h"
static NSString *const kGoTopNotificationName = @"goTop";//進入置頂命令
static NSString *const kLeaveTopNotificationName = @"leaveTop";//離開置頂命令
@interface ViewController ()<oneDelegate,UIScrollViewDelegate>
@property (nonatomic,strong) ZXWScrollerView *BtmScrollerView;
@property (nonatomic,strong) UIView *headView;
@property (nonatomic,strong) UIScrollView *MidScrollerView;
@property (nonatomic,strong) OneViewController *vc1;
@property (nonatomic,strong) OneViewController *vc2;
@property (nonatomic,strong) OneViewController *vc3;
@property (nonatomic,assign)BOOL BtmCanScrollerLast;
@property (nonatomic,assign)BOOL BtmCanScrollercurrent;
@property (nonatomic, assign) BOOL canScroll;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// self.automaticallyAdjustsScrollViewInsets = YES;
self.edgesForExtendedLayout = NO;
_BtmScrollerView = [[ZXWScrollerView alloc]initWithFrame:self.view.frame];
[self.view addSubview:_BtmScrollerView];
_BtmScrollerView.backgroundColor = [UIColor redColor];
_BtmScrollerView.delegate = self;
_BtmScrollerView.showsVerticalScrollIndicator = NO;
_BtmScrollerView.contentSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height+150+64) ;
_headView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 150)];
[_BtmScrollerView addSubview:_headView];
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 100, self.view.frame.size.width, 50)];
view.backgroundColor = [UIColor orangeColor];
[_headView addSubview:view];
_headView.backgroundColor = [UIColor blueColor];
_MidScrollerView = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 150, self.view.frame.size.width, self.view.frame.size.height)];
_MidScrollerView.backgroundColor = [UIColor whiteColor];
[_BtmScrollerView addSubview:_MidScrollerView];
_MidScrollerView.pagingEnabled = YES;
_MidScrollerView.contentSize = CGSizeMake(self.view.frame.size.width*3, self.view.frame.size.height);
_vc1 = [[OneViewController alloc]init];
_vc1.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height-50);
[_MidScrollerView addSubview:_vc1.view];
_vc1.delegate = self;
_vc1.view.backgroundColor = [UIColor colorWithRed:(arc4random()%256)/255.0 green:(arc4random()%256)/255.0 blue:(arc4random()%256)/255.0 alpha:1];
[self addChildViewController:_vc1];
_vc2 = [[OneViewController alloc]init];
_vc2.view.frame = CGRectMake(self.view.frame.size.width, 0, self.view.frame.size.width, self.view.frame.size.height-50);
_vc2.delegate = self;
[_MidScrollerView addSubview:_vc2.view];
_vc2.view.backgroundColor = [UIColor colorWithRed:(arc4random()%256)/255.0 green:(arc4random()%256)/255.0 blue:(arc4random()%256)/255.0 alpha:1];
[self addChildViewController:_vc2];
_vc3 = [[OneViewController alloc]init];
_vc3.view.frame = CGRectMake(2*self.view.frame.size.width, 0, self.view.frame.size.width, self.view.frame.size.height-50);
_vc3.delegate = self;
[_MidScrollerView addSubview:_vc3.view];
_vc3.view.backgroundColor = [UIColor colorWithRed:(arc4random()%256)/255.0 green:(arc4random()%256)/255.0 blue:(arc4random()%256)/255.0 alpha:1];
[self addChildViewController:_vc3];
_canScroll = YES;
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//當前的偏移量
CGFloat height = scrollView.contentOffset.y;
// NSLog(@"%f", scrollView.contentOffset.y);
if (height<100) {
_BtmCanScrollercurrent = YES;
}
if (height>=100) {
scrollView.contentOffset = CGPointMake(0, 100);
_BtmCanScrollercurrent = NO;
}
if (_BtmCanScrollercurrent != _BtmCanScrollerLast) {
if (!_BtmCanScrollerLast && _BtmCanScrollercurrent) {
NSLog(@"離開頂部");
//要離開定不時只有當tableview偏移量小於或等於0時才可以滑動 否則設定為1
if (!_canScroll) {
scrollView.contentOffset = CGPointMake(0, 100);
}
}
if (!_BtmCanScrollercurrent && _BtmCanScrollerLast) {
NSLog(@"到達頂部");
[[NSNotificationCenter defaultCenter] postNotificationName:kGoTopNotificationName object:nil userInfo:@{@"canScroll":@"1"}];
_canScroll = NO;
}
}
_BtmCanScrollerLast = _BtmCanScrollercurrent;
}
-(void)oneDelegateDidScrollerToBottom:(UIScrollView *)scrView
{
_canScroll = YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
還是解釋下吧 ScrollerView滑動時會呼叫-(void)scrollViewDidScroll:(UIScrollView *)scrollView這個方法 如果你不想ScrollerView滑動,那麼就把偏移量設定為0,
[scrollView setContentOffset:CGPointZero];
至於什麼時候滑動,什麼時候不滑動,程式碼裡面寫的很清楚了,這裡面的邏輯當然還可以優化的,有興趣的朋友可以研究下,如果有不正確的地方請大家指正!
第一次寫部落格,純手打!累~~~~,不喜勿噴!