自定义 UITableView 部分索引
Posted
技术标签:
【中文标题】自定义 UITableView 部分索引【英文标题】:Custom UITableView section index 【发布时间】:2011-05-13 04:58:09 【问题描述】:是否可以自定义 UITableView 的section index?我的意思是,更改字体样式/大小、背景(默认为半透明)等。我猜答案是否定的。
那么,是否有任何开源解决方案可用于实现?如果没有,我应该如何创建这样的组件/控件/视图?
【问题讨论】:
可能重复的问题 - ***.com/questions/2643400/… 【参考方案1】:更新 (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) 更新 ARC,2) 可能有关如何将视图添加到表视图的一些细节以及 3) 有关如何生成正确索引标题的一些指示,但我认为无论如何它都值得赏金。它在这里出现了很多,并且没有简单的方法来自定义内置索引。 我还没有过渡到 ARC,坦率地说,我有点不情愿,不知何故(感觉!)。您将视图添加到承载表视图的同一视图中(当然是在表上方)。理想情况下,同一个视图控制器应该同时管理表和索引视图。目前,索引名称只是整数:1、2、3 等(不能用于电话通讯簿),但应该很容易自定义。 索引视图在初始化时传递给表,并从那里获取表边界。我可以让它自己添加为表格的子视图,但这感觉不对(两个视图都是管理视图控制器的子视图 - 或者更确切地说是它的视图 - 所以索引视图不会自行附加)。 是的,您必须将其添加为对等级视图 - 这意味着您不能将其作为表视图控制器的一部分。而且你不能将它添加为表格视图的子视图,因为它是一个滚动视图,所以它会离开屏幕...... 我要添加:1) 设置外观的属性(宽度、颜色,可能是索引画布的阴影或边框),2) 索引视图委托的“数据源”方法提供自定义索引条目。【参考方案2】:self.tableView.sectionIndexColor = [UIColor brownColor];
self.tableView.sectionIndexBackgroundColor = [UIColor clearColor];
self.tableView.sectionIndexTrackingBackgroundColor = [UIColor blueColor];
【讨论】:
从 iOS6 开始,这绝对是最好的答案,至少对于基本自定义而言。【参考方案3】:在 iOS 6 中,您可以在 UITableView 上使用以下方法配置表格索引:
sectionIndexMinimumDisplayRowCount sectionIndexColor sectionIndexTrackingBackgroundColor【讨论】:
【参考方案4】:我最终使用了自定义视图。无法自定义表格索引。
【讨论】:
您是如何准确实现这样的自定义视图的?你将它添加到 UITableView 还是什么?【参考方案5】:Swift 版本:
tableView.sectionIndexBackgroundColor = UIColor.clearColor()
tableView.sectionIndexTrackingBackgroundColor = UIColor.clearColor()
tableView.sectionIndexColor = UIColor.redColor()
自定义索引视图高度(仅限UITableViewStylePlain
样式):
tableView.sectionIndexMinimumDisplayRowCount = 15
【讨论】:
我很惊讶这不是选定的答案。因为它是最简单的解决方案,而且效果很好。tableView.sectionIndexMinimumDisplayRowCount = 15
是做什么的?它如何影响节索引?
安德烈,developer.apple.com/reference/uikit/uitableview/…【参考方案6】:
如果您可以访问私有属性,则可以对其进行调整。 我相信这会通过商店的批准,但不要相信我的话。 以下是您可以访问的属性/功能。 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()
【讨论】:
【参考方案7】:https://github.com/Hyabusa/CMIndexBar
使用 Hyabusa 的这个插件。 允许设置颜色的 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;
【讨论】:
【参考方案8】:我在 GitHub 上开始了表索引的自定义实现。你可以试试这个:https://github.com/r-dent/RGIndexView 随意贡献。
【讨论】:
【参考方案9】:它对 ios 6 和 ios 7&8 的帮助
if ([tableview respondsToSelector:@selector(setSectionIndexColor:)])
if(!IS_IOS6)
tableview.sectionIndexBackgroundColor = [UIColor clearColor];
tableview.sectionIndexColor = [UIColor whiteColor];
【讨论】:
以上是关于自定义 UITableView 部分索引的主要内容,如果未能解决你的问题,请参考以下文章
UITableView 中的自定义绘图在 5 个单元格后失败
尝试从 iOS 中 UITableView 的自定义单元格内的 textField 获取活动单元格的索引