iOS項目重構

前言app

因爲以前項目比較急,因此對界面的佈局沒有太多的要求,遺留下不少的問題,如今一直在作重構的工做,並非說把代碼寫得如何的完美,而是把代碼的邏輯梳理得更加的清楚,更加便於後期迭代開發或者是維護。重構分爲了UI重構和邏輯重構,今天講的是一個UI重構的問題,在項目中糾結了一段時間,選擇何種方式來佈局,會比較好管理;下面來講一下個人想法;ide

 

(一)場景;函數

界面頭部有一個tab切換的功能,中間部分的ui是提供給用戶輸入時間信息的,而後還有一個查詢的按鈕;底部是帶tab的列表;主要要解決的問題就是頭部和底部tab切換的邏輯管理。佈局

(二)個人思路;ui

按照常理,如今不少市面上的app,只要包括有tab的列表大部分採用的是scrollview滾動切換,再配合tab點擊的切換;還有一種就是使用addChildViewController,而後配合tab點擊進行切換(主要的缺點就是,不能左右滑動切換)。個人這個場景裏面顯然的包含兩級切換邏輯,兩層切換邏輯都是用scrollView來控制的話,就會讓人感受左右切換的效果太多,有點不太舒服;最終我採用的是頭部tab使用addChildViewController來控制顯示底部的帶tab的列表控制器,而後底部的控制器中經過scrollView來控制其子控制器。atom

(三)關鍵代碼;code

這個NTContainViewController控制器,就是底部帶tab的容器控制器,能夠設置子控制器以及tab標籤。orm

#import <UIKit/UIKit.h>

@interface NTContainViewController : UIViewController

- (instancetype)initWithTitle:(NSString *)title andSubTitles:(NSArray *)subTitles andControllers:(NSArray *)controllers;
- (instancetype)initWithTitle:(NSString *)title andSubTitles:(NSArray *)subTitles andControllers:(NSArray *)controllers topOffset:(CGFloat)topOffset;
@property (nonatomic, assign) CGFloat topOffset;

- (void)refreshTableView;


#import "NTContainViewController.h"
#import "NTSubViewController.h"
#import "NTTitleBarView.h"

@interface NTContainViewController () <UIScrollViewDelegate>

@property (nonatomic, strong) UIScrollView *containScroll;
@property (nonatomic, strong) NSArray *controllers;
@property (nonatomic, strong) NSArray *subTitles;
@property (nonatomic, strong) NSString *navigationTitle;
@property (nonatomic, strong) NTTitleBarView *titleBarView;
@property (nonatomic, assign) NSInteger currentIndex;

@end

@implementation NTContainViewController

- (instancetype)initWithTitle:(NSString *)title andSubTitles:(NSArray *)subTitles andControllers:(NSArray *)controllers {
    
    return [self initWithTitle:title andSubTitles:subTitles andControllers:controllers topOffset:0];
}

- (instancetype)initWithTitle:(NSString *)title andSubTitles:(NSArray *)subTitles andControllers:(NSArray *)controllers topOffset:(CGFloat)topOffset {
    self = [super init];
    if (self) {
        
        self.subTitles = subTitles;
        self.navigationTitle = title;
        self.controllers = controllers;
        self.topOffset = topOffset;
    }
    
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor lightGrayColor];
    if (_navigationTitle) {
        
        self.navigationItem.title = _navigationTitle;
    }
    
    self.currentIndex = 0;
    CGFloat titleBarHieght = 36.0f;
    self.titleBarView = [[NTTitleBarView alloc] initWithFrame:({
        CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, titleBarHieght);
        frame;
        
    }) titles:_subTitles];
    [self.view addSubview:_titleBarView];
    
    self.containScroll = [[UIScrollView alloc] initWithFrame:({
        
        CGRect frame = CGRectMake(0, titleBarHieght, self.view.frame.size.width, self.view.frame.size.height - titleBarHieght);
        frame;
    })];
    _containScroll.delegate = self;
    _containScroll.bounces = NO;
    _containScroll.showsHorizontalScrollIndicator = NO;
    _containScroll.pagingEnabled = YES;
    [self.view addSubview:_containScroll];
    
    if (_controllers) {
        [_controllers enumerateObjectsUsingBlock:^(UIViewController *controller, NSUInteger idx, BOOL * _Nonnull stop) {
            
            [self addChildViewController:controller];
            CGRect childRect = CGRectMake(self.view.frame.size.width * idx, 0, self.view.frame.size.width, self.view.frame.size.height - 64 - 100 - 36);
            controller.view.frame = childRect;
            
            [self.containScroll addSubview:controller.view];
        }];
    }
    
    _containScroll.contentSize = CGSizeMake(self.view.frame.size.width * _controllers.count, _containScroll.frame.size.height);
    
    __weak typeof(_containScroll) weakScroll = _containScroll;
    _titleBarView.titleButtonClicked = ^(NSUInteger index) {
        
        [weakScroll setContentOffset:CGPointMake(self.view.frame.size.width * index, 0) animated:NO];
        _currentIndex = index;
    };
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    
    [self scrollToStop:YES];
}

- (void)scrollToStop:(BOOL)stop {
    
    CGFloat offsetX = _containScroll.contentOffset.x;
    CGFloat scrollWidth = _containScroll.frame.size.width;
    
    NSInteger focusIndex = (offsetX + (scrollWidth / 2)) / scrollWidth;
    if (stop) {
        
        [self titleBarViewButtonsAtIndex:focusIndex];
        _currentIndex = focusIndex;
    }
}

- (void)titleBarViewButtonsAtIndex:(NSInteger)index {
    
    UIButton *currentButton = _titleBarView.subviews[index];
    [_titleBarView.subviews enumerateObjectsUsingBlock:^(UIButton *button, NSUInteger idx, BOOL * _Nonnull stop) {
        
        [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    }];
    
    [currentButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
}

- (void)refreshTableView {
    
    NTSubViewController *currentVC = (NTSubViewController *)_controllers[_currentIndex];
    [currentVC refreshTableViewWithType:[NSString stringWithFormat:@"tableView%ld",_currentIndex]];
}
@end

下面的這個代碼,是寫在父視圖控制器上面的,有tab切換的view,查詢按鈕,並將上面說到的NTContainViewController控制器當作子控制器並進行管理,經過開發

[strongSelf transitionFromViewController:strongSelf.currentVC toViewController:newViewController duration:0.3f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ rem

        } completion:^(BOOL finished) {

            [newViewController didMoveToParentViewController:strongSelf];

            [strongSelf.currentVC willMoveToParentViewController:nil];

            [strongSelf.currentVC removeFromParentViewController];

            strongSelf.currentVC = newViewController;

        }];函數進行切換。

具體代碼;

#import "NTTestViewController.h"
#import "NTContainViewController.h"
#import "NTSubViewController.h"
#import "NTTitleBarView.h"

@interface NTTestViewController () {
    
}

@property (nonatomic, strong) NTTitleBarView *testBarView;
@property (nonatomic, strong) NSArray *controllers;
@property (nonatomic, strong) UIViewController *currentVC;
@property (nonatomic, strong) NSInteger currentIndex;

@end

@implementation NTTestViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.navigationItem.title = @"tab切換";
    self.view.backgroundColor = [UIColor whiteColor];
    self.testBarView = [[NTTitleBarView alloc] initWithFrame:({
        CGRect frame = CGRectMake(0, 64, self.view.frame.size.width, 36);
        frame;
        
    }) titles:@[@"左邊", @"右邊"]];
    
    [self.view addSubview:_testBarView];
    
    UIButton *searchButton = [UIButton buttonWithType:UIButtonTypeCustom];
    searchButton.frame = CGRectMake(0, 120, self.view.frame.size.width, 30);
    [searchButton setTitle:@"查詢" forState:UIControlStateNormal];
    searchButton.backgroundColor = [UIColor lightGrayColor];
    [searchButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    [searchButton addTarget:self action:@selector(excuteCode) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:searchButton];
    [self addChildVC];
    
    __weak typeof(self) weakSelf = self;
    __strong typeof(self) strongSelf = weakSelf;
    _testBarView.titleButtonClicked = ^(NSUInteger index) {
        
        if (strongSelf.currentIndex != index) {
            UIViewController *newViewController = strongSelf.controllers[index];
            [strongSelf addChildViewController:newViewController];
            
            [strongSelf transitionFromViewController:strongSelf.currentVC toViewController:newViewController duration:0.3f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
                
            } completion:^(BOOL finished) {
                
                [newViewController didMoveToParentViewController:strongSelf];
                [strongSelf.currentVC willMoveToParentViewController:nil];
                [strongSelf.currentVC removeFromParentViewController];
                strongSelf.currentVC = newViewController;
                strongSelf.currentIndex = index;
            }];
        }
    };
}

- (void)addChildVC {
    
    NTSubViewController *subVC1 = [[NTSubViewController alloc] initWithTitle:@"test1"];
    NTSubViewController *subVC2 = [[NTSubViewController alloc] initWithTitle:@"test2"];
    NTSubViewController *subVC3 = [[NTSubViewController alloc] initWithTitle:@"test3"];
    
    NTContainViewController *testVC1 = [[NTContainViewController alloc] initWithTitle:@"test" andSubTitles:@[@"test1",@"test2",@"test3"] andControllers:@[subVC1, subVC2, subVC3] topOffset:100.0f];
    testVC1.view.frame = CGRectMake(0, 64 + 100, self.view.frame.size.width, self.view.frame.size.height - 100 - 64);
    
    
    NTSubViewController *subVC4 = [[NTSubViewController alloc] initWithTitle:@"test4"];
    NTSubViewController *subVC5 = [[NTSubViewController alloc] initWithTitle:@"test5"];
    NTSubViewController *subVC6 = [[NTSubViewController alloc] initWithTitle:@"test6"];
    
    NTContainViewController *testVC2 = [[NTContainViewController alloc] initWithTitle:@"test" andSubTitles:@[@"test4",@"test5",@"test6"] andControllers:@[subVC4, subVC5, subVC6] topOffset:100.0f];
    testVC2.view.frame = CGRectMake(0, 64 + 100, self.view.frame.size.width, self.view.frame.size.height - 100 - 64);
    
    self.controllers = @[testVC1, testVC2];
    self.currentVC = testVC1;
    [self addChildViewController:_currentVC];
    [self.view addSubview:_currentVC.view];
}

- (void)excuteCode {
    
    NTContainViewController *currentVC = (NTContainViewController *)_currentVC;
    [currentVC refreshTableView];
}
@end

(四)還有一個關鍵的地方,那就是父子控制器之間的交互;

由於這個界面的主要功能就是經過主視圖的查詢按鈕,操做底部控制器(NTContainViewController控制器中的子控制器),固然最簡單的方法就是發送通知,子控制器接收通知就行;可是我採用的是另外的方法,就是經過NTContainViewController這個容器控制器做爲橋樑,主控制器發送消息至當前顯示的NTContainViewController容器控制器,在經過這個容器控制器找到當前顯示的子控制器,而後發送消息到這個控制器。上面的代碼- (void)excuteCode、- (void)refreshTableView、- (void)refreshTableViewWithType:(NSString *)type;一層一層往下傳遞發送消息的。

 

總結

整個解決問題的思路,即解決了tab聯動切換的問題,也解決了父控制器向子控制器發送消息的問題,項目中遇到的問題就可以解決,剩下的就只有子控制器的佈局以及獲取數據的部分了,而這個部分所涉及的內容已經不多,就是tableview的基本使用,上下拉刷新。

相關文章
相關標籤/搜索