1. 程式人生 > >美麗說蘑菇街首頁效果(UITableView和UIScrollerView聯動)

美麗說蘑菇街首頁效果(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];

至於什麼時候滑動,什麼時候不滑動,程式碼裡面寫的很清楚了,這裡面的邏輯當然還可以優化的,有興趣的朋友可以研究下,如果有不正確的地方請大家指正!

第一次寫部落格,純手打!累~~~~,不喜勿噴!