UITableView的樣式有兩種,一種是Grouped(左圖),另一種是Plain(右圖),如下圖,它的屬性是style,類型為UITableViewStyle,枚舉值分別是UITableViewStyleGrouped和UITableViewStylePlain;
用這個控件的ViewController可以使用UITableViewController,使用了這個ViewController可以不需要另外創建UITableView,裡面也包含了UITableViewDataSource和UITableViewDelegate這兩個實現,這兩個類稍後討論,但是也有不方便的地方,默認情況下使用UITableViewController創建的tableView是充滿全屏的,如果需要用到tableView是不充滿全屏的話,我們應該使用UIViewController。
UITableView的數據可以通過靜態綁定和動態綁定,控件默認是動態綁定的,在StoryBoard裡面設置Content屬性,它有兩個值Static Cell和Dynamic,顧名思義了。如果設置了Static Cell,點擊Section的標題則可以控制UITableView的行數,添加了行數則可以。若要往行裡添加內容可以直接把控件拖入單元格裡面。
如果要動態的往UITableView添加內容,則需要實現UITableViewDataSource和UITableViewDelegate的幾個方法。其實這兩個方法的共同作用有點類似於Andriod中的各種Adapter,Android中的Adapter是指定了列表中各個元素的布局,列表的數據源,而這兩個協議要實現的方法是傳遞數據源的情況還有各個數據單元格的定義情況。
//返回分組的數量 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { } //每個分組裡面行數 -(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { } //定義單元格的內容,並返回。 -(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { }
如果使用了UITableViewController,則可以直接去實現這幾個方法,假如用的是UIViewController,則在類聲明的地方顯式實現UITableViewDataSource和UITableViewDelegate。
UITableView的每個單元格對象都是UITableViewCell類型的。在上面最後的一個方法裡面構造並返回,單元格的布局類型有幾種,它是UITableViewCellStyle類型的枚舉,一般在初始化函數中設置它的類型。
每個單元格的布局都是分左中右三塊,最左邊是圖標,最右邊是附件視圖,附件一般是箭頭,它通過UITableViewCellAccessoryType類型的屬性accessoryType,它的值有以下幾個
官方文檔上是上面五個值,但是我的環境是iOS6的,只有截圖的那幾個值(None除外)。附件區域也可以自己添加控件,如下面這樣的形式可以在每一行中添加了一個開關控件
cell.accessoryView= [[UISwitch alloc]init];
UITableViewCell提供了imageView來設置每一個單元格的圖標它是一個UIImageView類型的屬性,可以直接通過設置它的image屬性來給每一行添加一個圖標如
cell.imageView.image=[UIImage imageNamed:@"African Daisy.gif"];
假如這些控件還是太少的話,還可以通過Cell的contentCell的addSubview方法來添加控件到單元格裡面,如下所示。
[cell.contentView addSubview:label];
但是要控制好添加到Cell裡面控件的數量,因為如果控件數量多於3、4個的話,會比較影響效率,在列表滾動的時候會出現卡頓了。
在UITableView的表頭表尾,分組頭分組尾都可以添加視圖,如果添加表頭表尾的視圖的話可以通過設置UITableVIew的tableHeaderView和tableFoorterView兩個屬性,如下所示
self.tableView.tableHeaderView=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"bd_logo1.png"] highlightedImage:nil]; self.tableView.tableFooterView=[[UISwitch alloc]init];
那添加分組頭和分組尾時就可以通過實現下面兩個方法
-(NSString *) tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { } -(NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { }
之前說了那麼多,現在給個簡單的例子來說明動態綁定的步驟
這裡用到的數據源是自己填充上去的,
@property(nonatomic,strong) NSArray *carGroups; -(NSArray*)carGroups { if(_carGroups==nil) { // 1.創建模型 HGTableviewModel *cg1 =[[HGTableviewModel alloc]init]; cg1.group=@"日本仔車"; cg1.desc=@"日系車"; cg1.cars=@[@"本田",@"豐田",@"日產"]; HGTableviewModel *cg2 = [[HGTableviewModel alloc] init]; cg2.group=@"鬼佬車"; cg2.desc=@"德國車"; cg2.cars=@[@"大眾",@"別克",]; // 2.將模型添加到數組中 _carGroups = @[cg1, cg2]; } return _carGroups; }
在viewDidLoad方法中給tableView指定數據源
self.tableView.dataSource=self;
在這個方法裡面可以對tableView做其他設置,這裡不一一例舉了,最後就實現之前獲取分組數量,每個分組的列數,構造單元格的三個方法
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return self.carGroups.count; } -(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { HGTableviewModel *item= self.carGroups[section]; return item.cars.count; } -(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell=nil; if(indexPath.section==0) cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:nil]; else cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil]; HGTableviewModel *item=self.carGroups[indexPath.section]; cell.textLabel.text= item.cars[indexPath.row]; cell.accessoryType= UITableViewCellAccessoryDetailDisclosureButton; cell.detailTextLabel.text=item.desc; if(indexPath.section==0) cell.imageView.image=[UIImage imageNamed:@"African Daisy.gif"]; else cell.accessoryView= [[UISwitch alloc]init];//[UIButton buttonWithType:UIButtonTypeContactAdd]; return cell; }
如果要給選中單元格這個事件綁定方法,只需要實現下面這個方法則可,如下面代碼所示,選中了某行後彈出一個框說明當前選中了是哪個品牌
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { NSString *msg=[[NSString alloc]initWithFormat:@"你選中了 %@", ((HGTableviewModel*)self.carGroups[indexPath.section]).cars[indexPath.row]]; UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"選中行" message:msg delegate:self cancelButtonTitle:nil otherButtonTitles:@"確定", nil]; [alert show]; }
UIDatePickerView是一個日期時間選取的空間,它是以一個滾輪的形式呈現出來,可以通過設置它的當前顯示時間,最大最小時間范圍,這些值都是NSDate類型的,
NSDateFormatter *formatter=[[NSDateFormatter alloc]init]; [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; self.dtpDateTime.minimumDate= [formatter dateFromString:@"2011-01-01 00:00:00"]; self.dtpDateTime.maximumDate=[formatter dateFromString:@"2015-01-01 00:00:00"]; self.dtpDateTime.date=[formatter dateFromString:@"2015-03-01 00:00:00"];
它有一個datePickerMode屬性來設置DatePicker的顯示類型,它是一個UIDatePickerMode類型的枚舉,分別有下面這些值
效果圖按順序如下圖所示
UIDatePicker有個ValueChange事件,是在控件的Value發生改變之後觸發的,需要綁定事件,通過StoryBoard或者使用addTargetWithActionForControlEvents方法,下面則是改變了值之後輸出當前的日期
- (IBAction)dtpValueChanged:(id)sender { NSLog(@"當前日期是 %@",self.dtpDateTime.date); }
UIPickerView是把數據列表以滾輪的形式呈現給用戶,與UITableVIew類似,它的數據綁定需要實現UIPickerViewDataSource和UIPickerViewDelegate兩個協議,但是這個UIPickerView卻不支持靜態綁定數據。綁定數據主要是實現兩個協議的下面這些方法
//返回顯示的列數 -(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { } //返回當前列顯示的行數 -(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { } //下面的方法是PickerDelegate協議的方法,可以二選一,主要是返回每一項顯示的內容 - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component { } - (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view { }
加入滾輪中只是一些單純的文本信息則可以使用返回String的那個方法,如果是每一項都是一些文本以外的內容,則需要使用返回UIView的那個方法,既然是返回View則說明可以返回任何的控件,包括自定義的也可以。
假如要在UIPickerView被選中後觸發事件執行方法,則實現下面的方法則可
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { NSLog([[NSString alloc]initWithFormat:@"SELECT Item %@ " ,[pickerDs objectAtIndex:row] ] ); }
下面則給出一個例子完整說明給一個UIPicker綁定數據的過程,裡面的數據抄襲了某位網友的博文,莫怪。
首先是要實現兩個協議
@interface HGDatePickerViewController : UIViewController<UIPickerViewDataSource,UIPickerViewDelegate > @end
通過StoryBoard建立了關聯的變量picker和定義數據源一個NSArray的變量,然後在viewDidLoad裡面添加下面這些代碼,其中設置deletage的最為關鍵
pickerDs=[[NSArray alloc]initWithObjects:@"許嵩",@"周傑倫",@"梁靜茹",@"許飛",@"鳳凰傳奇",@"阿杜",@"方大同",@"林俊傑",@"胡夏",@"邱永傳", nil]; self.picker.delegate=self;
然後實現之前提到的方法,在這裡把兩個UIPickerViewDelegate的方法列舉出來了,返回View的那種是返回一個UILabel,它們的效果圖分別列舉
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { return 1; } -(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { return [pickerDs count]; } - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component { return [pickerDs objectAtIndex:row]; } - (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view { UILabel *myView = nil; myView = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 180, 30)]; myView.text = [pickerDs objectAtIndex:row]; myView.textAlignment = UITextAlignmentCenter; myView.font = [UIFont systemFontOfSize:14]; myView.backgroundColor = [UIColor clearColor]; return myView; }
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component實現的效果
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view實現的效果
其實UIPicker可以實現像以前在BS或CS開發中的下拉菜單多級聯動效果的,這裡都不詳細列舉了,主要是通過-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component方法根據當前級別的數據來調用[self.picker reloadComponent:xxx];方法來出發下一級別的值重新載入。
UIActionSheet這個控件是在之前看UIDatePicker時別人用了而發現的,感覺也比較有用所以也記錄下來,本人沒有iOS的設備,故有哪些控件都不太了解,之前在一個界面原型圖中見過這個控件,但不知道它是ActionSheet。這個ActionSheet個人感覺和AlertView很像。也能給界面彈出按鈕選擇框,同時具備遮罩的效果。
使用這個UIActionSheet需要實現UIActionSheetDelegate協議,構造和初始化ActionSheet的代碼如下
UIActionSheet *as=[[UIActionSheet alloc]initWithTitle:@"This is my First ActionSheet" delegate:self cancelButtonTitle:@"Cancle" destructiveButtonTitle:@"Sure" otherButtonTitles:@"First Btn",@"Second Btn", nil];
在上述參數中有兩個比較特殊的按鈕,cancelButton和destructiveButton,在ActionSheet中按鈕也是有一定序列的,如AlertView那樣,所有按鈕都是有一定順序的,按默認的情況下,destructiveButton是排在第一,是一個紅色的按鈕,接著是到ortherButton,它們的順序由添加進去的順序而定,最後的是cancelButton,是一個黑色的按鈕。在上面的初始化函數中如果那個按鈕不需要的話則可以傳入nil則可。上面的ActionSheet顯示的效果如下圖
添加OtherButton也可以調用下面方法來添加
[as addButtonWithTitle:@"addButton"];
destructiveButton也可以更替由其他按鈕來充當,通過下面這個屬性的設置則可
as.destructiveButtonIndex=1;
效果如下圖
顯示ActionSheet則調用下面的方法
[as showInView:self.view];
在開發過程中,發現有時候UIActionSheet的最後一項點擊失效,點最後一項的上半區域時有效,這是在特定情況下才會發生,這個場景就是試用了UITabBar的時候才有。解決辦法:
在showView時這樣使用,[actionSheet showInView:[UIApplication sharedApplication].keyWindow];或者[sheet showInView:[AppDelegate sharedDelegate].tabBarController.view];這樣就不會發生遮擋現象了。
ActionSheet的actionSheetStyle屬性是設置ActionSheet的樣式,它是一個UIActionSheetStyle類型的枚舉,它是值有下面三種
與UIAlertView類似,UIActionSheet也是有一組方法在ActionSheet裡面出現,點擊,消失各個時候觸發調用的
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { } -(void)willPresentActionSheet:(UIActionSheet *)actionSheet { } -(void)didPresentActionSheet:(UIActionSheet *)actionSheet { } -(void)actionSheetCancel:(UIActionSheet *)actionSheet{ } -(void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex{ } -(void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex{ }
到這裡遇到了在UIAlert中一樣知什麼時候會觸發的actionSheetCancel方法,這些方法的觸發順序如下(actionSheetCancel是按照UIAlertView中的順序推斷出來的)
willPresentActionSheet——>didPresentActionSheet
點擊了按鈕之後
actionSheetclickedButtonAtIndex——>willDismissWithButtonIndex——>didDismissWithButtonIndex