高度自定義的STDPickerView

scratXu發表於2018-03-19

年前的某天,公司的UI拿了張設計圖讓我看下能否實現,隨意一瞥發現只是個PickerView,心想著用UIPickerView封裝一下還不是so easy的事情,然而接下去了解了需求後才發現沒那麼簡單......

高度自定義的STDPickerView

需要實現的效果

具體需求如下:

  • 需要能自定義選中顏色及未選中顏色,且跟隨滾動實時變化;
  • 需要能自定義選中指示器;
  • 需要滾動效果是平面滾動;

根據上面的需求,翻看了下UIPickerView的介面並寫程式碼測試了下後發現情況不容樂觀:

  • UIPickerView預設不支援選中顏色設定,可通過自定義view實現,但是無法跟隨滾動實時變化;
  • UIPickerView原生不支援設定選中指示器樣式;
  • UIPickerView預設滾動效果為類曲面滾動,且不支援設定;

到現在已經基本確定UIPickerView的方案已經被斃了,不過沒關係,原生沒法實現那麼就自己實現一個,於是 STDPickerView 就在這種情況下誕生了:

STDPickerView 是什麼 STDPickerView 是基於 UICollectionView 封裝的選擇控制元件,相容UIPickerView大部分介面,並增加了多個定製化介面,可實現更多的效果!STDPickerView 效果圖如下:

高度自定義的STDPickerView

預設樣式

高度自定義的STDPickerView

分割選中指示器

高度自定義的STDPickerView

垂直分割線

高度自定義的STDPickerView

自定義view

STDPickerView 怎麼使用

  • 初始化
STDPickerView *pickerView = [[STDPickerView alloc] init];
      
pickerView.dataSource = self;
pickerView.delegate = self;
  
/*
    STDPickerViewSelectionIndicatorStyleNone:無選中指示器
    STDPickerViewSelectionIndicatorStyleDefault:預設選中指示器
    STDPickerViewSelectionIndicatorStyleDivision: 分段選中指示器
    STDPickerViewSelectionIndicatorStyleCustom:自定義選中指示器,需實現 selectionIndicatorViewInPickerView: 代理方法
*/
pickerView.selectionIndicatorStyle = STDPickerViewSelectionIndicatorStyleDefault;
  
/* 
    預設情況下,如果同時實現了titleForRow以及viewForRow資料來源方法,
    則會優先使用viewForRow方法返回自定義view,
    此時可設定 forceItemTypeText = YES 來指定使用titleForRow方法
*/
pickerView.forceItemTypeText = YES;
  
//是否顯示垂直分割線
pickerView.showVerticalDivisionLine = YES;
      
//設定pickerView四周的間距
pickerView.edgeInsets = UIEdgeInsetsMake(0, 20, 0, 20);
  
//設定component之間的間距
pickerView.spacingOfComponents = 30;
  
//僅在文字模式下有效
pickerView.textColor = kLightTextColor;
pickerView.selectedTextColor = kGlobalColor;
pickerView.font = [UIFont systemFontOfSize:16];
  
...
  
[self.view addSubview:pickerView];
複製程式碼
  • 通用資料來源及代理方法
#pragma mark - STDPickerViewDataSource
  
//返回component數目
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    return 1;
}
  
//返回row數目
- (NSInteger)pickerView:(STDPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    return self.items.count;
}
  
  
#pragma mark - STDPickerViewDelegate
  
//返回條目高度
- (CGFloat)pickerView:(STDPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
    return 60;
}
  
//選中了某個條目
- (void)pickerView:(STDPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    NSLog(@"pickerView - didSelectRow %zd inComponent %zd", row, component);
}
  
//若selectionIndicatorStyle = STDPickerViewSelectionIndicatorStyleCustom,則需實現以下方法
- (UIView *)selectionIndicatorViewInPickerView:(STDPickerView *)pickerView
{
    UIView *view = [[UIView alloc] init];
      
    view.backgroundColor = kGlobalColorWithAlpha(0.3);
      
    view.layer.cornerRadius = 5;
    view.layer.masksToBounds = YES;
      
    return view;
}
  
...
複製程式碼
  • 預設選中樣式
#pragma mark - STDPickerViewDataSource
  
// 返回item的標題
(注:若同時實現了 pickerView: viewForRow:forComponent:reusingView: 優先採用後者,此時可通過設定 forceItemTypeText = YES 來強制使用本方法)
- (NSString *)pickerView:(STDPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    return self.items[row];
}
複製程式碼
  • 自定義選中樣式
#pragma mark - STDPickerViewDataSource
  
// 返回item的自定義view,優先順序較高
(注:若同時實現了 pickerView: titleForRow:forComponent: 且 forceItemTypeText = YES 則本方法無效)
- (UIView *)pickerView:(STDPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
    UILabel *label = (UILabel *)view;
      
    if (!label) {
        label = [[UILabel alloc] init];
          
        label.textAlignment = NSTextAlignmentCenter;
    }
      
    label.textColor = kLightTextColor;
    label.transform = CGAffineTransformIdentity;
    label.text = self.items[row];
      
    return label;
}
  
#pragma mark - STDPickerViewDelegate
  
//可在此方法及willDeselectRow中實現自定義的切換效果
- (void)pickerView:(STDPickerView *)pickerView willSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    UILabel *label = (UILabel *)[pickerView viewForRow:row forComponent:component];
      
    [UIView animateWithDuration:0.25 animations:^{
        label.transform = CGAffineTransformMakeScale(1.5, 1.5);
    }];
      
    label.textColor = kGlobalColor;    
}
  
- (void)pickerView:(STDPickerView *)pickerView willDeselectRow:(NSInteger)row inComponent:(NSInteger)component
{
    UILabel *label = (UILabel *)[pickerView viewForRow:row forComponent:component];
      
    [UIView animateWithDuration:0.25 animations:^{
        label.transform = CGAffineTransformIdentity;
    }];
      
    label.textColor = kLightTextColor;
}
複製程式碼

目前 STDPickerView 已經開源到GitHub上並支援CocoaPods整合,歡迎大家下載與star!

GitHub: https://github.com/XuQibin/STDPickerView

相關文章