是否可以自定义UITableView的节索引?我的意思是,改变字体样式/大小,背景(默认是半透明)等等。我猜测答案是否定的。
那么,有没有可用于实现自定义UITableView部分索引的开源解决方案?如果没有,我该如何创建这样的组件/控件/视图?
答案 0 :(得分:24)
更新(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在ivar中保留指向UITableView的指针,并在滑动时直接操作表视图(避免需要委托)。但是索引视图不拥有表视图,所以感觉有点不对。
答案 1 :(得分:14)
self.tableView.sectionIndexColor = [UIColor brownColor];
self.tableView.sectionIndexBackgroundColor = [UIColor clearColor];
self.tableView.sectionIndexTrackingBackgroundColor = [UIColor blueColor];
答案 2 :(得分:10)
在iOS 6中,您可以使用UITableView上的以下方法配置表索引:
答案 3 :(得分:7)
我最终使用自定义视图。无法自定义表索引。
答案 4 :(得分:6)
Swift版本:
tableView.sectionIndexBackgroundColor = UIColor.clearColor()
tableView.sectionIndexTrackingBackgroundColor = UIColor.clearColor()
tableView.sectionIndexColor = UIColor.redColor()
要自定义索引视图高度(仅UITableViewStylePlain
样式):
tableView.sectionIndexMinimumDisplayRowCount = 15
答案 5 :(得分:2)
https://github.com/Hyabusa/CMIndexBar
使用Hayabusa的这个插件。 简单替换允许设置颜色的UITableView索引
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;
答案 6 :(得分:1)
我在GitHub上启动了表索引的自定义实现。你可以尝试这个:https://github.com/r-dent/RGIndexView 随意贡献。
答案 7 :(得分:1)
对ios 6和ios 7&amp; 8的帮助
if ([tableview respondsToSelector:@selector(setSectionIndexColor:)])
{
if(!IS_IOS6)
{
tableview.sectionIndexBackgroundColor = [UIColor clearColor];
}
tableview.sectionIndexColor = [UIColor whiteColor];
}
答案 8 :(得分:1)
如果您可以访问私人媒体资源,则可以进行调整。 我相信这会通过商店的批准,但不会接受我的话。 以下是您可以访问的属性/功能。 https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/UIKit.framework/UITableViewIndex.h
我已经测试过使用以下内容更改字体并且有效。
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()
}
}
}