- iPhone UIKit詳解
- 王志剛 王中元 朱蕾編著
- 2090字
- 2019-01-01 07:04:24
2.3 UIView嵌套
2.3.1 追加子元素
UIView中擁有addSubView:這樣的實例方法,可以在UIView中追加UIView作為子元素。當然UILabel及UIButton等UIView的子類也可以使用addSubView:方法自由地追加。這里首先看一個實例,在UIButton中使用addSubView:方法追加子元素的UIButton。
// 追加1-1按鈕 UIButton* button11 = [UIButton buttonWithType:UIButtonTypeRounde dRect]; button11.frame = CGRectMake(10,10,300,300); [button11 setTitle:@”1-1” forState:UIControlStateNormal]; [button11 addTarget:self action:@selector(button11DidPush:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button11]; // 追加1-1-1按鈕 UIButton* button111 = [UIButton buttonWithType:UIButtonTypeRound edRect]; button111.frame = CGRectMake(20,20,260,100); [button111 setTitle:@”1-1-1” forState:UIControlStateNormal]; [button111 addTarget:self action:@selector(button111DidPush:) forControlEvents:UIControlEventTouchUpInside]; [button11 addSubview:button111]; // 追加1-1-2按鈕 UIButton* button112 = [UIButton buttonWithType:UIButtonTypeRound edRect]; button112.frame = CGRectMake(20,180,260,100); [button112 setTitle:@”1-1-2” forState:UIControlStateNormal]; [button112 addTarget:self action:@selector(button112DidPush:) forControlEvents:UIControlEventTouchUpInside]; [button11 addSubview:button112]; // 追加1-1-2-1按鈕 UIButton* button1121 = [UIButton buttonWithType:UIButtonTypeRoun dedRect]; button1121.frame = CGRectMake(10,10,95,80); [button1121 setTitle:@”1-1-2-1” forState:UIControlStateNormal]; [button1121 addTarget:self action:@selector(button1121DidPush:) forControlEvents:UIControlEventTouchUpInside]; [button112 addSubview:button1121]; // 追加1-1-2-2按鈕 UIButton* button1122 = [UIButton buttonWithType:UIButtonTypeRoun dedRect]; button1122.frame = CGRectMake(155,10,95,80); [button1122 setTitle:@”1-1-2-2” forState:UIControlStateNormal]; [button1122 addTarget:self action:@selector(button1122DidPush:) forControlEvents:UIControlEventTouchUpInside]; [button112 addSubview:button1122];
此段實例代碼的執行結果如圖2-10所示。

圖2-10 addSubView:方法實例
另外,在UIView中還有superview屬性及subviews屬性。通過superview屬性可以取得追加自己的UIView(父元素),而subviews可以以數組NSArray的形式取得追加到自己之下的所有UIView(子元素)。單擊圖2-10中的任意按鈕,顯示其父元素以及子元素列表的代碼如下所示。以下實例代碼是緊接著上面實例代碼的。
-(void)button11DidPush:(id)sender { [self alertMessage:sender]; } -(void)button111DidPush:(id)sender { [self alertMessage:sender]; } -(void)button112DidPush:(id)sender { [self alertMessage:sender]; } -(void)button1121DidPush:(id)sender { [self alertMessage:sender]; } -(void)button1122DidPush:(id)sender { [self alertMessage:sender]; } -(void)alertMessage:(UIButton*)button { // 顯示self的標題作為警告框的標題 NSString* title = [NSString stringWithFormat:@"self = %@",button.titleLabel.text]; // 取得superview的標題 // 但是當superview為非UIButton的情況下,以“UIViewController”替代 NSString* superViewName; if([button.superview isKindOfClass:[UIButton class]]){ superViewName =((UIButton*)button.superview).titleLabel.text; } else { superViewName = @"UIViewController"; } // 取得subviews的標題 NSMutableString* subviews = [[[NSMutableString alloc] initWithCapacity:64] autorelease]; [subviews setString:@""]; for(id view in button.subviews){ NSString* addString; if([view isKindOfClass:[UIButton class]]){ // 如果子元素為UIButton時,取titleLabel的text屬性值 addString =((UIButton*)view).titleLabel.text; } else if([view isKindOfClass:[UILabel class]]){ // 如果為UILabel時取其text屬性值 addString =((UILabel*)view).text; } else { // 上述以外的情況 addString = [view description]; } if([subviews length] > 0){ [subviews appendString:@","]; } [subviews appendString:addString]; } NSString* message = [NSString stringWithFormat:@"superview =%@\r\nsubviews = %@",superViewName,subviews]; UIAlertView* alert = [[[UIAlertView alloc] initWithTitle:title message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:@”OK”,nil ] autorelease]; [alert show];}
例如,當觸摸[1-1-2]時,將顯示如圖2-11所示的警告框。

圖2-11 顯示superview與subviews的信息
此時,[1-1-2]的父元素為[1-1],子元素為[1-1-2]與[1-1-2-1]及[1-1-2-2]。之所以[1-1-2]會包含于其中而作為UIButton的子元素,是因為管理自身標題的UILabel也是其子元素之一。
2.3.2 子元素的插入與刪除
上一小節我們介紹了如何使用addSubview:方法進行子元素的追加。實際上,追加子元素的方法除 addSubView:之外,還有insertSubview:atIndex:方法、insertSubview:aboveSubview:方法以及insertSubview:belowSubview:方法。另外,從父元素中刪除特定的子元素時可使用removeFromSuperview:方法。
除上述方法外,用于管理UIView子元素狀態的方法還有:交換兩個子元素順序的exchangeSubviewAtIndex:withSubviewAtIndex:方法以及檢查是否為某元素的子元素的isDescendantOfView:方法。
上述六個方法使用實例代碼如下所示。
// 追加父標簽 parent_ = [[UILabel alloc] initWithFrame:CGRectMake(0,0,320,320)]; parent_.textAlignment = UITextAlignmentCenter; parent_.text = @"PARENT"; [self.view addSubview:parent_]; // 追加1個子標簽 UILabel* child3 = [[[UILabel alloc] initWithFrame:CGRectZero] autorelease]; child3.text = @"CHILD 3"; [child3 sizeToFit]; [parent_ insertSubview:child3 atIndex:0]; // 在上一個標簽CHILD 3 下插入 CHILD 1 UILabel* child1 = [[[UILabel alloc] initWithFrame:CGRectZero] autorelease]; child1.text = @"CHILD 1"; [child1 sizeToFit]; [parent_ insertSubview:child1 belowSubview:child3]; // 在CHILD 1 上追加 CHILD 2 UILabel* child2 = [[[UILabel alloc] initWithFrame:CGRectZero] autorelease]; child2.text = @"CHILD 2"; [child2 sizeToFit]; [parent_ insertSubview:child2 aboveSubview:child1]; // 讓CHILD 1 與 CHILD 3 交換 [parent_ exchangeSubviewAtIndex:0 withSubviewAtIndex:2]; // 如果CHILD 3 為 PARENT 子元素的話 if([child3 isDescendantOfView:parent_]){ // 刪除CHILD 3 [child3 removeFromSuperview]; }
2.3.3 UIView的靠前顯示與退后隱藏
多個UIView追加到同一畫面上時,此時肯定會出現其中幾個相互重疊的情況。這種情況下,我們可以調用bringSubviewToFront:方法將特定的UIView放置在前方,也可以調用sendSubviewToBack:方法將特定的UIView移動到后方。例如,我們在畫面上追加了labelA_與labelB_兩個標簽,依次追加 labelA_與labelB_的代碼如下。
[self.view addSubview:labelA_]; [self.view addSubview:labelB_];
畫面顯示的效果如圖2-12所示。

圖2-12 重疊的UIView
labelB_是后面追加進來的,因此labelB_必然是在前方顯示。此時如果想讓labelA_標簽在前方顯示,可以調用bringSubviewToFront:方法,代碼如下。
[self.view bringSubviewToFront:labelA_];
執行后顯示的效果如圖2-13所示。

圖2-13 將A標簽置前
相反,如果我們再次想讓labelA_移動到后方顯示時,可調用sendSubviewToBack:方法,代碼如下。
[self.view sendSubviewToBack:labelA_];
此時將畫面返回如圖2-13所示的狀態。
2.3.4 附加標簽(tag)及UIView的檢索
UIView中定義有tag屬性。在此tag屬性中開發人員可以自行設置數值。但是就算設置了此屬性值也不會影響程序本身的運行。tag屬性通常只是被開發人員作為標記來使用。明確設置了tag屬性的UIView可以使用viewWithTag:方法很簡單地檢索到,以下是tag屬性的使用實例,注意此處僅羅列了主要的代碼。
-(void)viewDidLoad { [super viewDidLoad]; // 背景設置成黑色 self.view.backgroundColor = [UIColor blackColor]; // 追加父標簽 parent_ = [[UILabel alloc] initWithFrame:CGRectMake(0,0,320,320)]; parent_.textAlignment = UITextAlignmentCenter; parent_.text = @"PARENT"; [self.view addSubview:parent_]; // 追加10個子標簽 for(int i = 1;i <= 10;++i){ UILabel* child = [[[UILabel alloc] initWithFrame:CGRectZero] autorelease]; child.text = [NSString stringWithFormat:@"CHILD %d",i];[child sizeToFit]; CGPoint newPoint = child.center;newPoint.y += 30 * i; child.center = newPoint; [parent_ addSubview:child]; // 將第8個標簽的tag設置成999 if(8 == i){ child.tag = 999; } } // 追加search按鈕 UIButton* searchButton = [UIButton buttonWithType:UIButtonTypeRo undedRect]; searchButton.frame = CGRectMake(0,0,150,40); CGPoint newPoint = self.view.center; newPoint.y = self.view.frame.size.height - 40; searchButton.center = newPoint; [searchButton setTitle:@"search 999" forState:UIControlState Normal]; [searchButton addTarget:self action:@selector(searchDidPush) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:searchButton]; } #pragma mark ----- Private Methods ----- -(void)searchDidPush { NSString* message; // 從parent_的子元素中檢索tag為999的元素,找到后顯示警告框 UILabel* label =(UILabel*)[parent_ viewWithTag:999]; if(label){ message = label.text; } else { message = @"nothing"; } UIAlertView* alert = [[[UIAlertView alloc] initWithTitle:@"search 999" message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK",nil ] autorelease]; [alert show]; }