iOS開發--自訂欄表控制項

來源:互聯網
上載者:User

標籤:

   這兩天項目比較閑,在空餘之際,嘗試自己實現清單控制項。從動工到初步完成大概花了一天時間,目前實現了列表的簡易功能,後續將考慮加入cell重用機制、慣性特徵以及刪除cell等功能。項目代碼已經放到了github上,地址:https://github.com/wanglichun/CustomTableView。

   在實現之前,需要瞭解清單控制項的運行原理,我之前的一篇部落格《清單控制項實現原理解析》中有介紹。去年由於項目需要,使用lua語言自訂過雙重列表(大列表嵌套小列表),這次改用objc實現,實現的思路和以前相同,只是換了個語言,因此速度比較快。下面分步驟介紹實現過程。

    總體目錄結構:


    目錄結構說明:

1、TablewView目錄:CSTableView(CustomTableView的縮寫)為自訂的清單控制項,CSTableViewCell為列表的單元格;

2、RootViewController中包含了一個CSTableView的測試例子。


步驟一:列表單元格CSTableViewCell實現

    為了節省時間,我採用xib的方式構建了cell,並且cell中只包含了標題資訊,使用者如果想實現複雜的cell,可以繼承CSTableViewCell擴充cell。需要注意的是,cell這一層並不處理觸摸事件,而是傳遞給父控制項CSTableView處理。

代碼如下:

標頭檔:

#import <UIKit/UIKit.h>@interface CSTableViewCell : UIView+ (CSTableViewCell *)csTableViewCell;- (void)setTitle:(NSString *)title;@end

實現檔案:

#import "CSTableViewCell.h"@interface  CSTableViewCell()@property (weak, nonatomic) IBOutlet UILabel *titleLabel;@end@implementation CSTableViewCell+ (CSTableViewCell *)csTableViewCell{    NSArray *views = [[NSBundle mainBundle] loadNibNamed:@"CSTableViewCell" owner:nil options:nil];    return views[0];}//將事件傳遞給父控制項CSTableView處理- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{    return NO;}- (void)setTitle:(NSString *)title{    self.titleLabel.text = title;}

步驟二:清單控制項CSTableView實現

   關鍵步驟,如果對列表的運行原理非常瞭解,下面的代碼比較容易理解。需要注意,目前只是簡單的採用銷毀建立形式實現列表,未採用cell重用機制,後續有時間補上。DataSouce和Delegate參照UITableViewDataSouce和UITableViewDelegate定義,目前只是定義了幾個典型的方法。

標頭檔:

#import <UIKit/UIKit.h>@class CSTableView;@class CSTableViewCell;@protocol CSTableViewDataSource<NSObject>@required- (NSInteger)tableView:(CSTableView *)tableView numberOfRowsInSection:(NSInteger)section;- (CSTableViewCell *)tableView:(CSTableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;@end@protocol CSTableViewDataDelegate <NSObject>@optional- (CGFloat)tableView:(CSTableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;@end@interface CSTableView : UIView@property (nonatomic,assign)id<CSTableViewDataSource> dataSource;@property (nonatomic,assign)id<CSTableViewDataDelegate> delegate;+ (CSTableView *)csTableView;- (void)reloadData;@end

實現檔案:

#import "CSTableView.h"#import "CSTableViewCell.h"static const CGFloat kDefaultCellHeight = 27.0f;@interface CSTableView(){    CGPoint _touchBeginPoint;    CGPoint _touchMovePoint;    CGPoint _touchEndPoint;        NSInteger   _numberOfRows;    CGFloat     _top;    NSInteger   _startIndex;    NSInteger   _endIndex;    CGFloat     _startY;    CGFloat     _dataTotalHeight; //CSTableView的邏輯高度}@end@implementation CSTableView+ (CSTableView *)csTableView{    NSArray *views = [[NSBundle mainBundle] loadNibNamed:@"CSTableView" owner:nil options:nil];    return views[0];}- (void)awakeFromNib{    //不能放在這裡,此時delegate和dataSource都為nil,之前犯錯誤了,後面移到了layoutSubviews    //[self reloadData];}- (void)layoutSubviews{    [self reloadData];}#pragma mark -- touches events- (void)updateUIWithMoveDist:(CGFloat)moveDist{    //調控速度    moveDist = 0.2 * moveDist;        _top += moveDist;    if (_top < 0) {        _top = 0;    }    if (_dataTotalHeight > self.frame.size.height) {        if (_top > _dataTotalHeight - self.frame.size.height) {            _top = _dataTotalHeight - self.frame.size.height;        }        [self updateUI];    }}- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{    UITouch *touch=[touches anyObject];    _touchBeginPoint = [touch locationInView:self];}- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{    UITouch *touch=[touches anyObject];    _touchEndPoint = [touch locationInView:self];    CGFloat moveDist = _touchBeginPoint.y - _touchEndPoint.y;    [self updateUIWithMoveDist:moveDist];}- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{    UITouch *touch=[touches anyObject];    CGPoint point = [touch locationInView:self];    CGFloat moveDist =  _touchBeginPoint.y - point.y;    [self updateUIWithMoveDist:moveDist];}#pragma mark -- reloadData//計算顯示範圍- (void)calculateStartIndexAndEndIndex{    _startIndex = -1;    CGFloat totalHeight = 0;    if ([self.delegate respondsToSelector:@selector(tableView:heightForRowAtIndexPath:)]) {        for (NSInteger i = 0; i < _numberOfRows; i++) {            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:1];            CGFloat cellHeight = [self.delegate tableView:self heightForRowAtIndexPath:indexPath];            totalHeight += cellHeight;            if (totalHeight > _top && _startIndex == -1) {                _startY = (totalHeight - cellHeight) - _top;                _startIndex = i;            }            if (totalHeight > _top + self.frame.size.height || i == _numberOfRows - 1) {                _endIndex = i;                break;            }        }    }else{        for (NSInteger i = 0; i < _numberOfRows; i++) {            totalHeight += kDefaultCellHeight;            if (totalHeight > _top && _startIndex == -1) {                _startY = (totalHeight - kDefaultCellHeight) - _top;                _startIndex = i;            }                        if (totalHeight > _top + self.frame.size.height || i == _numberOfRows - 1) {                _endIndex = i;                break;            }        }    }}//更新UI- (void)updateUI{    [self calculateStartIndexAndEndIndex];    NSLog(@"startIndex = %ld", _startIndex);    NSLog(@"endIndex = %ld", _endIndex);        CGFloat totalHeight = 0.0f;    for (NSInteger i = _startIndex; i <= _endIndex; i++) {        //建立cell,如果使用者沒有自訂cell,則產生一個預設的cell        CSTableViewCell *cell;        if ([self.dataSource respondsToSelector:@selector(tableView:cellForRowAtIndexPath:)]) {            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:1];            cell = [self.dataSource tableView:self cellForRowAtIndexPath:indexPath];        }else{            cell = [CSTableViewCell csTableViewCell];            [cell setTitle:@"預設的cell"];        }                //設定cell的位置        if ([self.delegate respondsToSelector:@selector(tableView:heightForRowAtIndexPath:)]) {                NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:1];                CGFloat cellHeight = [self.delegate tableView:self heightForRowAtIndexPath:indexPath];                totalHeight += cellHeight;                cell.frame = CGRectMake(0, (totalHeight - cellHeight) + _startY, cell.frame.size.width, cell.frame.size.height);        }else{            cell.frame = CGRectMake(0, (i - _startIndex) *kDefaultCellHeight + _startY, cell.frame.size.width, cell.frame.size.height);        }                //將cell添加到CSTabelView        [self addSubview:cell];    }}//重新載入資料, 暫時沒有採用cell重用機制,後面有時間再加上//刪除資料後,調用該函數,重新載入UI- (void)reloadData{    for (UIView *subView in self.subviews) {        [subView removeFromSuperview];    }        if ([self.dataSource respondsToSelector:@selector(tableView:numberOfRowsInSection:)]) {        _numberOfRows = [self.dataSource tableView:self numberOfRowsInSection:1];    }else{        _numberOfRows = 10; //預設顯示10條資料    }        _dataTotalHeight = 0.0f;    if ([self.delegate respondsToSelector:@selector(tableView:heightForRowAtIndexPath:)]) {        for (NSInteger i = 0; i < _numberOfRows; i++) {            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:1];            CGFloat cellHeight = [self.delegate tableView:self heightForRowAtIndexPath:indexPath];            _dataTotalHeight += cellHeight;        }    }else{        _dataTotalHeight = kDefaultCellHeight * _numberOfRows;    }        //更新UI    [self updateUI];}@end


步驟三:測試案例

#import "RootViewController.h"#import "CSTableView.h"#import "CSTableViewCell.h"@interface RootViewController ()<CSTableViewDataSource, CSTableViewDataDelegate>@property (nonatomic, strong)CSTableView *csTableView;@end@implementation RootViewController- (void)viewDidLoad {    [super viewDidLoad];        self.csTableView = [CSTableView csTableView];    self.csTableView.dataSource = self;    self.csTableView.delegate = self;    self.csTableView.frame = CGRectMake(0, 0, self.csTableView.frame.size.width, self.csTableView.frame.size.height);    [self.view addSubview:self.csTableView];}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}#pragma mark -- CSTableViewDataSource- (NSInteger)tableView:(CSTableView *)tableView numberOfRowsInSection:(NSInteger)section{    return 50;}- (CSTableViewCell *)tableView:(CSTableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{    CSTableViewCell *cell = [CSTableViewCell csTableViewCell];    NSString *title = [[NSString alloc] initWithFormat:@"測試資料%ld", indexPath.row];    [cell setTitle:title];    return cell;}#pragma mark -- CSTableViewDataDelegate- (CGFloat)tableView:(CSTableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{    if (indexPath.row < 10) {        return 20;    }else if (indexPath.row >= 10 && indexPath.row < 20){        return 30;    }else{        return 40;    }        //return 27;}@end




iOS開發--自訂欄表控制項

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.