是否可以自定义UITableView的部分索引?我的意思是,更改字体样式/大小,背景(默认情况下为半透明)等。我猜测答案将是“否”。

那么,是否有任何开源解决方案可用于实现自定义UITableView节索引?如果没有,我应该如何创建这样的组件/控件/ View ?

最佳答案

更新(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

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

(例如,UITableViewController子类实现)
- (void) tableIndexView:(TableIndexView *)tableIndexView didSwipeToSection:(NSUInteger)section {
    [_tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]
                      atScrollPosition:UITableViewScrollPositionTop
                              animated:NO];
}

或者,您可以让TableIndexView在ivar中保留指向UITableView的指针,然后在滑动时直接操作表 View (无需委托(delegate))。但是索引 View 不拥有表 View ,因此感觉有点不对。

关于ios - 自定义UITableView节索引,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5987399/

10-13 07:48
查看更多