ios裡的UITableView,功能是很強大的。但是沒有Android類似Grid的效果。比如類似解決ListView滾動卡的問題。因為UITableView的每行只支援顯示一個視圖。如果細粒度的比如類似gallery的效果,就需要自己解決了。
最近寫的一個類似效果的原型:
主要解決了:
實現grid效果有兩個辦法:
- 自己編程實現,這次我就是自己實現的
- 使用第三方庫實現,這次沒有用,主要是時間太緊,怕陷進去再有品質問題,影響工期,等有時間了再好好看看。
這裡提到的第三方庫是AQGridView。項目首頁在這裡:https://github.com/AlanQuatermain/AQGridView
使用它產生視圖的效果:
看起來還是不錯的。見這裡:http://quatermain.tumblr.com/post/528737778/aqgridview-lives-for-my-ipad-dev-camp-hackathon,是作者的部落格。
首先說一下實現grid的做法。
建立一個UIView:
@interface CdGridView : UIView <UITableViewDelegate,UITableViewDataSource>{
UITableView *_tableView;
NSArray *_cdInfos;
int _columnSize;
}
封裝了table view,以及一個數組(資料模型),另外,每行顯示的列數。
重載了該UIView的init方法:
- (id)initWithFrame:(CGRect)frame columnSize:(int)columnSize cdInfos:(NSArray *)cdInfos{
self = [super initWithFrame:frame];
if (self) {
_tableView=[[UITableView alloc] initWithFrame:frame];
_tableView.dataSource=self;
_tableView.delegate=self;
[_tableView setSeparatorStyle:UITableViewCellEditingStyleNone];//設定取消列表的分割線
_tableView.allowsSelection=NO;//設定不允許挑選清單條目
[self addSubview:_tableView];
_columnSize=columnSize;//設定列數
_cdInfos=cdInfos;
}
return self;
}
這裡通過table view屬性取消了列表分割線,以及禁用了挑選清單條目。
另外幾個方法:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier=@"SimpleTableIdentifier";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if(cell==nil){
cell=[[[CdGridCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:simpleTableIdentifier
columnSize:_columnSize]
autorelease];
}
for (int i=0; i<_columnSize; i++) {
UIView *rowView=[cell.contentView.subviews objectAtIndex:0];
UIView *imageContainerView=[rowView.subviews objectAtIndex:i];
UIImageView *imageView=[imageContainerView.subviews objectAtIndex:0];
if ([indexPath row]*_columnSize+i<[_cdInfos count]) {
CdInfo *cdInfo=[_cdInfos objectAtIndex:[indexPath row]*_columnSize+i];
imageView.image=[UIImage imageNamed:cdInfo.coverPhotoPath];
imageView.layer.shadowOpacity = 1.0;
}else {
imageView.image=nil;
imageView.layer.shadowOpacity = 0;
}
}
if ([[tableView indexPathsForVisibleRows] count]>0) {//剛建立的時候table view是空的
int _firstIndex=[[[tableView indexPathsForVisibleRows] objectAtIndex:0] row]*_columnSize;
NSNumber *currentFirstRecordIndex=[NSNumber numberWithInt:_firstIndex];
NSDictionary *params=[[NSDictionary alloc] initWithObjectsAndKeys:currentFirstRecordIndex,@"currentFirstRecord",nil];
[[NSNotificationCenter defaultCenter] postNotificationName:@"current.first.record" object:self userInfo:params];
//目前不是很准,當移動到第一行的時候,first index還是第二行的首記錄
}
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
NSInteger numberOfRows=ceil([_cdInfos count]*1.0/_columnSize);
return numberOfRows;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return WIDTH/_columnSize;
}
-(void)setFistVisibleRecord:(int)recordIndex{
[_tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:recordIndex/_columnSize inSection:0]
atScrollPosition:UITableViewScrollPositionTop animated:NO];
}
用來實現table view要求的delegate,以及輔助方法。最後一個setFistVisibleRecord:方法,是用於設定列表顯示的首記錄。有時候我們需要顯示比如從第17個記錄開始,這個方法可以協助將第17個記錄所在行顯示在頁面的第一行上。
往下,說一下陰影製作效果的實現,其實就是在原有的UIImageView下面再顯示一個半透明陰影的矩形框,矩形框的邊緣是圓弧的,這樣看起來比較自然。
可通過類似下面的代碼來實現:
imageView.layer.shadowColor=[UIColor darkGrayColor].CGColor;
imageView.layer.shadowOffset = CGSizeMake(MARGIN-2, MARGIN-2);
imageView.layer.shadowOpacity = 0.8;
imageView.layer.shadowRadius = 3.0;
imageView.layer.shadowPath = [UIBezierPath bezierPathWithRect:imageView.bounds].CGPath;
這裡用到了貝茲路徑來設定陰影的path,否則效能比較差。
看下這個,就知道陰影的效果了:
這是屏蔽了設定UIImage後的樣子,即沒有設定圖片,只有陰影的樣子。