iOS自定義控制元件:簡易下拉控制元件

一個孤獨的搬碼猿發表於2019-03-05

寶兒姐鎮樓

最近自由時間有點多,就開始擼控制元件。這個是我們常用的一個下拉分類控制元件,看了很多別人寫的,都是用TableView或者CollectionView整合在一起的感覺自定義性沒有那麼強,所以就嘗試用把TableView和CollectionView替換成UIViewController。其他廢話不多說了。

1、 介面檔案

#import <UIKit/UIKit.h>

UIKIT_EXTERN NSString *lzDropViewNotification;

NS_ASSUME_NONNULL_BEGIN

@class LZDropView;
@protocol LZDropViewDataSource <NSObject>

@required

/** Height corresponding to controller display */
- (NSArray<NSNumber *> *)setupCategoryControllerHeightInDropView:(LZDropView *)dropView;
/** Title corresponding controller array */
- (NSArray<UIViewController *> *)setupCategoryControllerInDropView:(LZDropView *)dropView;
/** Default display of Title Array */
- (NSArray<NSString *> *)setupCategoryTitleNameInDropView:(LZDropView *)dropView;

@end

@protocol LZDropViewDelegate <NSObject>

/** Click the column and select the information. */
- (void)dropView:(LZDropView *)dropView didSelectAtColumn:(NSInteger)column info:(NSString *)info;

@end

@interface LZDropView : UIView
/** Simple page configuration */
@property (nonatomic, weak) id <LZDropViewDataSource> dataSorce;
/** Click proxy event<##> */
@property (nonatomic, weak) id <LZDropViewDelegate> delegate;

@end

NS_ASSUME_NONNULL_END
複製程式碼

2、 實現檔案

#import "LZDropView.h"

NSString *lzDropViewNotification = @"nitification";

@interface LZDropView ()

@property (nonatomic, strong) NSArray<UIViewController *> *controllerArray;
@property (nonatomic, strong) NSArray<NSString *> *titleArray;
@property (nonatomic, strong) UIButton *containerView;
@property (nonatomic, strong) NSArray<NSNumber *> *controllerHeightArray;
@property (nonatomic, strong) NSMutableArray<UIButton *> *buttonArray;

@end

@implementation LZDropView

#pragma mark - Release memory

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

#pragma mark - Initialization

- (instancetype)init {
    self = [super init];
    if (self) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationAction:) name:lzDropViewNotification object:nil];
    }
    return self;
}

#pragma mark - Draw the page

- (void)setupTitleButton:(NSArray<NSString *> *)array {
    CGFloat width = UIScreen.mainScreen.bounds.size.width / array.count;
    self.buttonArray = [NSMutableArray array];
    for (NSString *name in array) {
        NSInteger index = [array indexOfObject:name];
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.titleLabel.font = [UIFont systemFontOfSize:15];
        [button setTitle:[NSString stringWithFormat:@"%@ ▼", name] forState:UIControlStateNormal];
        [button setTitle:[NSString stringWithFormat:@"%@ ▲", name] forState:UIControlStateSelected];
        [button setTitleColor:UIColor.grayColor forState:UIControlStateNormal];
        [button setTitleColor:UIColor.orangeColor forState:UIControlStateSelected];
        button.frame = CGRectMake(width * index, 0, width, 45);
        button.tag = index + 1000;
        [button addTarget:self action:@selector(buttonTouched:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:button];
        [self.buttonArray addObject:button];
    }
}

#pragma mark - Button click event

- (void)buttonTouched:(UIButton *)sender {
    if (sender.selected) {
        [self closeControllerView];
    } else {
        [self openControllerViewWithButton:sender];
    }
}

- (void)backButtonTouched:(UIButton *)sender {
    [self closeControllerView];
}

#pragma mark - Notification event

- (void)notificationAction:(NSNotification *)notification {    
    if (![self.controllerArray containsObject:notification.object]) {
        return;
    }
    
    NSInteger index = [self.controllerArray indexOfObject:notification.object];
    UIButton *button = self.buttonArray[index];
    [button setTitle:[NSString stringWithFormat:@"%@ ▼", notification.userInfo.allValues.firstObject] forState:UIControlStateNormal];
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(dropView:didSelectAtColumn:info:)]) {
        [self.delegate dropView:self didSelectAtColumn:index info:notification.userInfo.allValues.firstObject];
    }
    
    [self closeControllerView];
}

#pragma mark - Close all controllers.

- (void)closeControllerView {
    
    [UIView animateWithDuration:0.8 animations:^{
        self.containerView.alpha = 0;
        self.containerView.frame = CGRectMake(0, CGRectGetMaxY(self.frame), UIScreen.mainScreen.bounds.size.width, 0);
    } completion:^(BOOL finished) {
        [self.containerView removeFromSuperview];
    }];
    
    for (UIButton *button in self.buttonArray) {
        button.selected = false;
    }
}

#pragma mark - Open the corresponding controller.

- (void)openControllerViewWithButton:(UIButton *)sender {
    for (UIButton *button in self.buttonArray) {
        button.selected = false;
    }
    
    self.containerView.alpha = 1;
    
    for (UIView *view in self.containerView.subviews) {
        [view removeFromSuperview];
    }
    
    UIViewController *vc = self.controllerArray[sender.tag - 1000];
    double vcHeight = [self.controllerHeightArray[sender.tag - 1000] doubleValue];
    
    self.containerView.frame = CGRectMake(0, CGRectGetMaxY(self.frame), self.frame.size.width, 0);
    vc.view.frame = CGRectMake(0, 0, UIScreen.mainScreen.bounds.size.width, 0);
    [self.superview addSubview:self.containerView];
    [self.containerView addSubview:vc.view];
    
    [UIView animateWithDuration:0.6 animations:^{
        self.containerView.frame = CGRectMake(0, CGRectGetMaxY(self.frame), self.frame.size.width, UIScreen.mainScreen.bounds.size.height);
        vc.view.frame = CGRectMake(0, 0, UIScreen.mainScreen.bounds.size.width, vcHeight);
    } completion:^(BOOL finished) {
        
    }];
    sender.selected = true;
}

#pragma mark - Getter

- (UIView *)containerView {
    if (!_containerView) {
        _containerView = [[UIButton alloc] init];
        _containerView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.1];
        [_containerView addTarget:self action:@selector(backButtonTouched:) forControlEvents:UIControlEventTouchUpInside];
    }
    return _containerView;
}

#pragma mark - Setter

- (void)setDataSorce:(id<LZDropViewDataSource>)dataSorce {
    _dataSorce = dataSorce;
    
    if (self.dataSorce && [self.dataSorce respondsToSelector:@selector(setupCategoryControllerInDropView:)]){
        self.controllerArray = [self.dataSorce setupCategoryControllerInDropView:self];
    }
    
    if (self.dataSorce && [self.dataSorce respondsToSelector:@selector(setupCategoryTitleNameInDropView:)]){
        self.titleArray = [self.dataSorce setupCategoryTitleNameInDropView:self];
        [self setupTitleButton:self.titleArray];
    }
    
    if (self.dataSorce && [self.dataSorce respondsToSelector:@selector(setupCategoryControllerHeightInDropView:)]) {
        self.controllerHeightArray = [self.dataSorce setupCategoryControllerHeightInDropView:self];
    }
    
    if (self.controllerArray.count != self.titleArray.count ||
        self.controllerArray.count != self.controllerHeightArray.count) {
        @throw [NSException exceptionWithName:NSStringFromClass([self class]) reason:@"The number of corresponding arrays is inconsistent." userInfo:nil];
    }
}

@end
複製程式碼

使用方式

1.遵循協議

<LZDropViewDataSource, LZDropViewDelegate>
複製程式碼

2.初始化

LZDropView *view     = [[LZDropView alloc] init];
    view.dataSorce       = self;
    view.delegate        = self;
    view.backgroundColor = UIColor.whiteColor;
    view.frame           = CGRectMake(0, 100, UIScreen.mainScreen.bounds.size.width, 45);
    [self.view addSubview:view];
複製程式碼
  1. 實現代理和資料來源
#pragma mark - LZDropViewDataSource

- (NSArray<UIViewController *> *)setupCategoryControllerInDropView:(LZDropView *)dropView {
    return @[[[TableViewController alloc] init],
             [[TableViewController alloc] init],
             [[TableViewController alloc] init],
             [[TableViewController alloc] init]];
}

- (NSArray<NSString *> *)setupCategoryTitleNameInDropView:(LZDropView *)dropView {
    return @[@"全部",
             @"附近",
             @"只能排序",
             @"篩選"];
}

- (NSArray<NSNumber *> *)setupCategoryControllerHeightInDropView:(LZDropView *)dropView {
    return @[[NSNumber numberWithFloat:300],
             [NSNumber numberWithFloat:400],
             [NSNumber numberWithFloat:410],
             [NSNumber numberWithFloat:420]];
}

#pragma mark - LZDropViewDelegate

- (void)dropView:(LZDropView *)dropView didSelectAtColumn:(NSInteger)column info:(NSString *)info {
    NSLog(@"%ld---%@", column, info);
}

複製程式碼
  1. 點選controller中的資料顯示在按鈕的標題中,這因為跨介面顯示,我暫時沒有想到好的辦法,所以使用強大的通知傳值。
  2. 記錄選中狀態,應該是控制器裡面的操作,這裡就沒有實現
[[NSNotificationCenter defaultCenter] postNotificationName:lzDropViewNotification object:self userInfo:@{@"key":[NSString stringWithFormat:@"第%ldcell", indexPath.row]}];
複製程式碼

效果圖

如果有什麼不好如果建議的地方,請批評指正!

相關文章