自定义的UITableView节索引

是否有可能自定义UITableView的部分索引? 我的意思是,改变字体样式/大小,背景(默认是半透明的)等。我猜测答案是否定的。

那么,有没有可用于实现自定义UITableView节索引的开源解决scheme? 如果不是,我应该如何去创build这样的组件/控制/视图?

更新(2017-08-31):最后编辑了ARC,现代Objective-C和iOS SDK(API弃用)。

我前段时间做了这个课。 随意使用它作为参考。 它没有任何属性来设置外观,但可以直接在源代码中修改它们(它有许多硬编码的常量,距离,颜色等)

接口:

#import <UIKit/UIKit.h> @class TableIndexView; @protocol TableIndexViewDelegate <NSObject> - (void) tableIndexView:(TableIndexView*) tableIndexView didSwipeToSection:(NSUInteger) section; @end @interface TableIndexView : UIView @property (nonatomic, weak) id<TableIndexViewDelegate> delegate; @property (nonatomic) NSUInteger numberOfSections; - (id)initWithTableView:(UITableView *)tableView; @end 

执行:

 #import "TableIndexView.h" #import <QuartzCore/QuartzCore.h> #define TableIndexViewDefaultWidth 20.0f #define TableIndexViewDefaultMargin 16.0f @interface TableIndexView() @property (nonatomic) NSUInteger currentSection; @property (nonatomic, strong) UIView* backgroundView; @property (nonatomic, strong) UIView* contentView; - (void)show; - (void)hide; @end @implementation TableIndexView @synthesize delegate = _delegate; @synthesize numberOfSections = _numberOfSections; - (id)initWithTableView:(UITableView *)tableView { CGRect tableBounds = [tableView bounds]; CGRect outerFrame = CGRectZero; outerFrame.origin.x = tableBounds.size.width - (40 + TableIndexViewDefaultWidth); outerFrame.origin.y = 0; outerFrame.size.width = (40 + TableIndexViewDefaultWidth); outerFrame.size.height = tableBounds.size.height; CGRect indexFrame = CGRectZero; indexFrame.origin.x = tableBounds.size.width - (TableIndexViewDefaultWidth + TableIndexViewDefaultMargin); indexFrame.origin.y = TableIndexViewDefaultMargin; indexFrame.size.width = TableIndexViewDefaultWidth; indexFrame.size.height = tableBounds.size.height - 2*TableIndexViewDefaultMargin; if ((self = [super initWithFrame:outerFrame])) { // Initialization code self.backgroundColor = [UIColor clearColor]; [self setUserInteractionEnabled:YES]; // Content View (Background color, Round Corners) indexFrame.origin.x = 20; _backgroundView = [[UIView alloc] initWithFrame:indexFrame]; _backgroundView.backgroundColor = [UIColor colorWithRed:1.00f green:1.00f blue:1.00f alpha:0.75f]; CGFloat radius = 0.5f*TableIndexViewDefaultWidth; _backgroundView.layer.cornerRadius = radius; [self addSubview:_backgroundView]; _numberOfSections = [[tableView dataSource] numberOfSectionsInTableView:tableView]; CGRect contentFrame = CGRectZero; contentFrame.origin.x = 0; contentFrame.origin.y = radius; contentFrame.size.width = TableIndexViewDefaultWidth; contentFrame.size.height = indexFrame.size.height - 2*radius; _contentView = [[UIView alloc] initWithFrame:contentFrame]; _contentView.backgroundColor = [UIColor clearColor]; [_backgroundView addSubview:_contentView]; CGFloat labelWidth = contentFrame.size.width; CGFloat labelHeight = 12; CGFloat interLabelHeight = (contentFrame.size.height - (_numberOfSections)*labelHeight)/(_numberOfSections - 1.0); CGFloat fontSize = 12; for (NSUInteger i=0; i < _numberOfSections; i++) { if ( _numberOfSections > 20 && i%2 == 0 ) { // Skip even section labels if count is greater than, say, 20 continue; } CGRect labelFrame = CGRectZero; labelFrame.size.width = labelWidth; labelFrame.size.height = labelHeight; labelFrame.origin.x = 0; labelFrame.origin.y = i*(labelHeight+interLabelHeight); UILabel* label = [[UILabel alloc] initWithFrame:labelFrame]; label.text = [NSString stringWithFormat:@"%lu", i+1]; label.textAlignment = NSTextAlignmentCenter; label.textColor = [UIColor blackColor]; label.backgroundColor = [UIColor clearColor]; label.font = [UIFont systemFontOfSize:floorf(1.0f*fontSize)]; [_contentView addSubview:label]; } [_backgroundView setHidden:YES]; } return self; } #pragma mark - Control Actions - (void)didTap:(id) sender { [_backgroundView setHidden:NO]; } - (void)didRelease:(id) sender { [_backgroundView setHidden:YES]; } #pragma mark - Internal Operation - (void)show { [self didTap:nil]; } - (void)hide { [self didRelease:nil]; } #pragma mark - UIResponder Methods - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch* touch = [touches anyObject]; CGPoint location = [touch locationInView:_contentView]; CGFloat ratio = location.y / _contentView.frame.size.height; NSUInteger newSection = ratio*_numberOfSections; if (newSection != _currentSection) { _currentSection = newSection; [_delegate tableIndexView:self didSwipeToSection:_currentSection]; } [_backgroundView setHidden:NO]; } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch* touch = [touches anyObject]; CGPoint location = [touch locationInView:_contentView]; CGFloat ratio = location.y / _contentView.frame.size.height; NSUInteger newSection = ratio*_numberOfSections; if (newSection != _currentSection) { _currentSection = newSection; if (newSection < _numberOfSections) { if (_delegate) { [_delegate tableIndexView:self didSwipeToSection:_currentSection]; } else{ // **Perhaps call the table view directly } } } [_backgroundView setHidden:NO]; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [_backgroundView setHidden:YES]; } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [_backgroundView setHidden:YES]; } @end 

最后,索引视图的委托(理想情况下是表视图的委托/数据源)在通知时执行此操作:

(例如,UITableViewController子类的实现)

 - (void) tableIndexView:(TableIndexView *)tableIndexView didSwipeToSection:(NSUInteger)section { [_tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section] atScrollPosition:UITableViewScrollPositionTop animated:NO]; } 

或者,您可以让TableIndexView保留一个指向UIVableView的指针,并在滑动中直接操作表视图(不需要委托)。 但索引视图不拥有表视图,所以这种感觉错了。

 self.tableView.sectionIndexColor = [UIColor brownColor]; self.tableView.sectionIndexBackgroundColor = [UIColor clearColor]; self.tableView.sectionIndexTrackingBackgroundColor = [UIColor blueColor]; 

在iOS 6中,您可以使用以下UITableView上的方法来configuration表索引:

  • sectionIndexMinimumDisplayRowCount
  • sectionIndexColor
  • sectionIndexTrackingBackgroundColor

我结束了使用自定义视图。 无法自定义表格索引。

Swift版本:

 tableView.sectionIndexBackgroundColor = UIColor.clearColor() tableView.sectionIndexTrackingBackgroundColor = UIColor.clearColor() tableView.sectionIndexColor = UIColor.redColor() 

自定义索引视图高度(仅限于UITableViewStylePlain风格):

 tableView.sectionIndexMinimumDisplayRowCount = 15 

https://github.com/Hyabusa/CMIndexBar

使用Hyabusa的这个插件。 UITableView索引的简单replace,允许设置颜色

 CMIndexBar *indexBar = [[CMIndexBar alloc] initWithFrame:CGRectMake(self.view.frame.size.width-35, 10.0, 28.0, self.view.frame.size.height-20)]; [indexBar setIndexes:[NSMutableArray arrayWithObjects:@"A",@"B",@"C",@"D",@"E",@"F",@"G", nil]]; [self.view addSubview:indexBar]; [indexBar release]; 

代表

 - (void)indexSelectionDidChange:(CMIndexBar *)IndexBar:(int)index:(NSString*)title; 

我开始在GitHub上的表索引的自定义实现。 你可以试试这个: https : //github.com/r-dent/RGIndexView随意贡献。

它的帮助为ios 6和ios 7&8

 if ([tableview respondsToSelector:@selector(setSectionIndexColor:)]) { if(!IS_IOS6) { tableview.sectionIndexBackgroundColor = [UIColor clearColor]; } tableview.sectionIndexColor = [UIColor whiteColor]; } 

如果你可以访问私有属性,可以调整它。 我相信这会通过商店的批准,但不要听我的话。 以下是您可以访问的属性/function。 https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/UIKit.framework/UITableViewIndex.h

我testing了更改字体与以下,它的工作。

 func viewDidLoad() { super.viewDidLoad() DispatchQueue.main.async { [unowned self] in if let tableViewIndex = self.tableView.subviews.first(where: { String(describing: type(of: $0)) == "UITableViewIndex" }) { tableViewIndex.setValue(*Insert Font Here*, forKey: "font") self.tableView.reloadSectionIndexTitles() } } }