IOS development-custom list controls
In the past two days, projects are relatively idle. When you are idle, You can implement the list control by yourself. It took about one day from the start of the project to the preliminary completion. At present, simple functions of the list are implemented. In the future, we will consider adding cell reuse mechanisms, inertial features, deletion of cell and other functions. The project code has been put on github at: https://github.com/wanglichun/customtableview.
Before implementation, you need to understand the operating principle of the list control. In my previous blog, "How to Implement list control", I introduced it. Last year, due to project requirements, I used the lua language to customize the dual list (large list nested small list). This time I switched to the objc implementation. The implementation idea is the same as before, but I only changed the language, therefore, the speed is relatively fast. The following steps describe the implementation process.
Overall directory structure:
Directory structure description: <喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD4KPHA + logs/logs + logs/dfToaM8L3A + logs/7 Kwrz + o6y2 + MrHtKu13bj4uLi/2Lz + logs/Co7o8L3A + logs/logs = "brush: java; "> # import @ Interface CSTableViewCell: UIView + (CSTableViewCell *) csTableViewCell;-(void) setTitle :( NSString *) title; @ end
Implementation file:
# 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];} // pass the event to the parent control CSTableView for processing-(BOOL) pointInside :( CGPoint) point withEvent :( UIEvent *) event {return NO;}-(void) setTitle :( NSString *) title {self. titleLabel. text = title ;}
Step 2: implement the list control CSTableView
Key steps: If you have a good understanding of the operating principles of the list, the following code is easier to understand. Note that at present, the list is simply implemented in the form of destruction creation, and the cell reuse mechanism is not used, so there will be time to complete it later. DataSouce and Delegate are defined by reference to UITableViewDataSouce and UITableViewDelegate. Currently, only several typical methods are defined.
Header file:
#import
@class CSTableView;@class CSTableViewCell;@protocol CSTableViewDataSource
@required- (NSInteger)tableView:(CSTableView *)tableView numberOfRowsInSection:(NSInteger)section;- (CSTableViewCell *)tableView:(CSTableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;@end@protocol CSTableViewDataDelegate
@optional- (CGFloat)tableView:(CSTableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;@end@interface CSTableView : UIView@property (nonatomic,assign)id
dataSource;@property (nonatomic,assign)id
delegate;+ (CSTableView *)csTableView;- (void)reloadData;@end
Implementation file:
# Import "CSTableView. h "# import" CSTableViewCell. h "static const CGFloat finished = 27366f; @ interface CSTableView () {CGPoint _ touchBeginPoint; CGPoint _ touchMovePoint; CGPoint _ touchEndPoint; NSInteger _ finished; CGFloat _ top; NSInteger _ startIndex; NSInteger _ endIndex; CGFloat _ startY; CGFloat _ dataTotalHeight; // logical height of CSTableView} @ end @ implementation CSTableView + (CSTableView *) csTableView {NSArray * views = [[NSBundle mainBundle] loadNibNamed: @ "CSTableView" owner: nil options: nil]; return views [0];}-(void) awakeFromNib {// cannot be put here. At this time, the delegate and dataSource are both nil. We made a mistake before, and moved to layoutSubviews // [self reloadData];}-(void) layoutSubviews {[self reloadData];} # pragma mark -- touches events-(void) updateUIWithMoveDist :( CGFloat) moveDist {// control speed 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 // calculates the display range-(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 ;}}// update UI-(void) updateUI {[self calculateStartIndexAndEndIndex]; NSLog (@ "startIndex = % ld", _ startIndex); NSLog (@ "endIndex = % ld", _ endIndex); CGFloat totalHeight = 0.0f; for (NSInteger I = _ startIndex; I <= _ endIndex; I ++) {// create a cell. If no custom cell exists, A default cell CSTableViewCell * cell is generated. 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: @ "Default cell"];} // set the cell location 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) ;}// Add the cell to CSTabelView [self addSubview: cell] ;}// reload the data. Currently, the cell reuse mechanism is not used, after adding // delete data, call this function to reload the 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 data records are displayed by default.} _ 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;} // update UI [self updateUI];} @ end
Step 3: Test Cases
# Import "RootViewController. h" # import "CSTableView. h" # import "CSTableViewCell. h" @ interface RootViewController ()
@ 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 didreceivemorywarning]; // 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: @ "Test Data % 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