在之前的有篇文章講述了利用HeaderView來寫類似QQ好友列表的表視圖。
這里寫的天貓抽屜其實也可以用該方法實現,具體到細節每個人也有所不同。這里采用的是點擊cell對cell進行運動處理以展開“抽屜”。
最后完成的效果大概是這個樣子。
主要的環節:
點擊將可視的Cell動畫彈開。
其他的Cell覆蓋一層半透明視圖,將視線焦點集中在彈出來的商品細分類別中。
再次點擊選中的或其他Cell,動畫恢復到點擊之前所在的位置。
商品細分類別屬于之前寫過的九宮格實現。這里就不貼代碼了。之前的文章:點擊打開鏈接
這里的素材都來自之前版本天貓的IPA。
加載數據
?
- (void)loadData
{NSString *path = [[NSBundle mainBundle] pathForResource:@"shops" ofType:@"plist"];NSArray *array = [NSArray arrayWithContentsOfFile:path];NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:array.count];[array enumerateObjectsUsingBlock:^(NSDictionary *dict, NSUInteger idx, BOOL *stop) {ProductType *proType = [[ProductType alloc] init];proType.name = dict[@"name"];proType.imageName = dict[@"imageName"];proType.subProductList = dict[@"subClass"];[arrayM addObject:proType];}];self.typeList = arrayM;
}
?
一個ProductType數據模型,記錄名稱,圖片名稱等。
單元格數據源方法
?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{TypeCell *cell = [tableView dequeueReusableCellWithIdentifier:RTypeCellIdentifier];[cell bindProductKind:_typeList[indexPath.row]];return cell;
}
將數據模型的信息綁定到自定義類中進行處理,這個類在加載視圖之后由tableview進行了注冊。
?
下面看看自定義單元格中的代碼
初始化
?
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{self = [super initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];if (self) {self.contentView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"tmall_bg_main"]];//設置clear可以看到背景,否則會出現一個矩形框self.textLabel.backgroundColor = [UIColor clearColor];self.detailTextLabel.backgroundColor = [UIColor clearColor];self.selectionStyle = UITableViewCellSelectionStyleNone;//coverView 用于遮蓋單元格,在點擊的時候可以改變其alpha值來顯示遮蓋效果_coverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, RScreenWidth, RTypeCellHeight)];_coverView.backgroundColor = [UIColor whiteColor];_coverView.alpha = 0.0;[self addSubview:_coverView];}return self;
}
?
綁定數據
?
- (void)bindProductKind:(ProductType *)productType
{self.imageView.image = [UIImage imageNamed:productType.imageName];self.textLabel.text = productType.name;NSArray *array = productType.subProductList;NSMutableString *detail = [NSMutableString string];[array enumerateObjectsUsingBlock:^(NSDictionary *dict, NSUInteger idx, BOOL *stop) {NSString *string;if (idx < 2){string = dict[@"name"];[detail appendFormat:@"%@/", string];}else if (idx == 2){string = dict[@"name"];[detail appendFormat:@"%@", string];}else{*stop = YES;}}];self.detailTextLabel.text = detail;
}
遍歷array然后進行判斷,對string進行拼接然后顯示到細節label上。
?
然后是對點擊單元格事件的響應處理,處理過程會稍微復雜一點
?
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{if (!_animationCells){_animationCells = [NSMutableArray array];}if (!_open){[self openTableView:tableView withSelectIndexPath:indexPath];}else{[self closeTableView:tableView withSelectIndexPath:indexPath];}
}
_animationCells用于之后記錄運動的單元格,以便進行恢復。
?
?
- (CGFloat)offsetBottomYInTableView:(UITableView *)tableView withIndexPath:(NSIndexPath *)indexPath
{UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];CGFloat screenHeight = RScreenHeight - RNaviBarHeight;CGFloat cellHeight = RTypeCellHeight;CGFloat frameY = cell.frame.origin.y;CGFloat offY = self.tableView.contentOffset.y;CGFloat bottomY = screenHeight - (frameY - offY) - cellHeight;return bottomY;
}
一個私有方法,為了方便之后獲取偏移的高度,這個高度記錄點擊的單元格的高度到屏幕底部的距離。以便進行判斷。
?
比如我們假設彈出的抽屜視圖高度為200,那么如果點擊的單元格到底部的距離超過200,則點擊的單元格以及以上的不用向上偏移,只要將下面的單元格向下移動即可。
但是如果距離小于200,則所有單元格都要進行響應的移動才能給抽屜視圖騰出空間。
按照思路進行開閉操作
?
- (void)openTableView:(UITableView *)tableView withSelectIndexPath:(NSIndexPath *)indexPath
{/******獲取可見的IndexPath******/NSArray *paths = [tableView indexPathsForVisibleRows];CGFloat bottomY = [self offsetBottomYInTableView:tableView withIndexPath:indexPath];if (bottomY >= RFolderViewHeight){_down = RFolderViewHeight;[paths enumerateObjectsUsingBlock:^(NSIndexPath *path, NSUInteger idx, BOOL *stop) {TypeCell *moveCell = (TypeCell *)[tableView cellForRowAtIndexPath:path];if (path.row > indexPath.row){[self animateCell:moveCell WithDirection:RMoveDown distance:_down andStatus:YES];[_animationCells addObject:moveCell];}if (path.row != indexPath.row){//遮蓋視圖改變透明度 讓其他單元格變暗moveCell.coverView.alpha = RCoverAlpha;}}];}else{_up = RFolderViewHeight - bottomY;_down = bottomY;[paths enumerateObjectsUsingBlock:^(NSIndexPath *path, NSUInteger idx, BOOL *stop) {TypeCell *moveCell = (TypeCell *)[tableView cellForRowAtIndexPath:path];if (path.row != indexPath.row){moveCell.coverView.alpha = RCoverAlpha;}if (path.row <= indexPath.row){[self animateCell:moveCell WithDirection:RMoveUp distance:_up andStatus:YES];}else{[self animateCell:moveCell WithDirection:RMoveDown distance:_down andStatus:YES];}[_animationCells addObject:moveCell];}];}//禁止滾動表格視圖tableView.scrollEnabled = NO;
}
主要對可視的單元格進行了判斷移動,
?
其中[self animateCell:moveCell WithDirection:RMoveDown distance:_down andStatus:YES];是一個私有的重構后的方法。
不過一般情況下,動畫的方法盡量在所有需求完成后再進行重構,因為畢竟不同的情況可能處理會很不同(動畫方式,動畫后的處理),放到一個方法后之后可能會發生需要再改回去。
看下這個方法
?
- (void)animateCell:(TypeCell *)cell WithDirection:(RMoveDirection)direction distance:(CGFloat)dis andStatus:(BOOL)status
{CGRect newFrame = cell.frame;cell.direction = direction;switch (direction){case RMoveUp:newFrame.origin.y -= dis;break;case RMoveDown:newFrame.origin.y += dis;break;default:NSAssert(NO, @"無法識別的方向");break;}[UIView animateWithDuration:RCellMoveDurationanimations:^{cell.frame = newFrame;} completion:^(BOOL finished) {_open = status;}];
}
傳入參數為單元格,動畫方向,運動的距離以及一個判斷是否打開的標識位。
?
最后看下閉合操作
?
- (void)closeTableView:(UITableView *)tableView withSelectIndexPath:(NSIndexPath *)indexPath
{[_animationCells enumerateObjectsUsingBlock:^(TypeCell *moveCell, NSUInteger idx, BOOL *stop) {if (moveCell.direction == RMoveUp){[self animateCell:moveCell WithDirection:RMoveDown distance:_up andStatus:NO];}else{[self animateCell:moveCell WithDirection:RMoveUp distance:_down andStatus:NO];}}];NSArray *paths = [tableView indexPathsForVisibleRows];for (NSIndexPath *path in paths){TypeCell *typeCell = (TypeCell *)[tableView cellForRowAtIndexPath:path];typeCell.coverView.alpha = 0;}_up = 0; //對一系列成員進行處理。_down = 0;tableView.scrollEnabled = YES;[_animationCells removeAllObjects];
}
?
Demo源碼:點擊打開鏈接
不過這個素材來自于之前天貓客戶端的版本,現在的天貓客戶端對商品列表進行了改變。也是彈出,不過彈出的列表內容更多,占據了整個屏幕。
最近一直在寫TableView的博客,常用的大部分都包含到了。
傳送門:
IOS詳解TableView——性能優化及手工繪制UITableViewCell
IOS詳解TableView —— QQ好友列表的實現
IOS詳解TableView——對話聊天布局的實現
IOS詳解TableView——實現九宮格效果
IOS詳解TableView——靜態表格使用以及控制器間通訊
以上就是本篇博客全部內容,歡迎指正和交流。轉載注明出處~
?