Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><strong>Update (2017-08-31):</strong> Finally edited for ARC, modern Objective-C and iOS SDK (API deprecations).</p> <p>I made this class some time ago. Feel free to use it as reference. It does not have any properties to set the appearance, but you can modify those directly in the source code (it has lots of hard-coded constants, distances, colors etc.)</p> <h3>Interface:</h3> <pre><code>#import &lt;UIKit/UIKit.h&gt; @class TableIndexView; @protocol TableIndexViewDelegate &lt;NSObject&gt; - (void) tableIndexView:(TableIndexView*) tableIndexView didSwipeToSection:(NSUInteger) section; @end @interface TableIndexView : UIView @property (nonatomic, weak) id&lt;TableIndexViewDelegate&gt; delegate; @property (nonatomic) NSUInteger numberOfSections; - (id)initWithTableView:(UITableView *)tableView; @end </code></pre> <h3>Implementation:</h3> <pre><code>#import "TableIndexView.h" #import &lt;QuartzCore/QuartzCore.h&gt; #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 &lt; _numberOfSections; i++) { if ( _numberOfSections &gt; 20 &amp;&amp; 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 &lt; _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 </code></pre> <p>And finally, the index view's delegate (which ideally is the table view's delegate/data source) does this on notification:</p> <p>(e.g., UITableViewController subclass implementation)</p> <pre><code>- (void) tableIndexView:(TableIndexView *)tableIndexView didSwipeToSection:(NSUInteger)section { [_tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section] atScrollPosition:UITableViewScrollPositionTop animated:NO]; } </code></pre> <p>Alternatively, you can have the TableIndexView keep a pointer to the UITableView in an ivar, and on swipe, manipulate the table view directly (obviating the need for a delegate). but the index view does not own the table view, so it kind of feels wrong.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload