官术网_书友最值得收藏!

  • iPhone UIKit詳解
  • 王志剛 王中元 朱蕾編著
  • 1862字
  • 2019-01-01 07:04:24

2.4 UIView的外觀

2.4.1 外觀定制

繼承UIView的子類中,可以擁有自己獨特的各種子元素。但是當UIView通過其frame屬性任意改變其位置以及尺寸的情況下,其子元素的位置往往也會出現(xiàn)變化,甚至出現(xiàn)混亂。問題是,我們到底有沒有辦法避免這種混亂情況的出現(xiàn)呢?

首先我們能想到的是,提前編寫些調(diào)整UIView外觀的方法,當frame屬性發(fā)生改變后及時調(diào)用這些方法。只要不忘調(diào)用這些方法,就可以實現(xiàn)我們的目的。實際上,UIView中已經(jīng)提供了這種調(diào)整外觀用的方法。而且是當UIView的尺寸發(fā)生變化,需要重新調(diào)整外觀的時候會自動調(diào)用此方法。這個外觀自動調(diào)整的方法為layoutSubviews。在UIView的子類中,只需要重新調(diào)用layoutSubviews方法,就可以實現(xiàn)外觀的自動調(diào)整。以下是重寫調(diào)用layoutSubviews方法的實例代碼。

// 定義UIView的子類
// 子類中擁有child1_以及child2_兩個標簽子元素
@interface LayoutTest :UILabel
{
 @private
  UILabel* child1_;
  UILabel* child2_;
}
@end
// 實現(xiàn)LayoutTest類
@implementation LayoutTest
// 釋放處理
-(void)dealloc {
  [child1_ release];
  [child2_ release];
  [super dealloc];
}
// 初始化處理
-(id)init {
  if((self = [super init])){
    // 調(diào)整自己的大小,追加兩個標簽
    self.frame = CGRectMake(0,0,320,320);
    child1_ = [[UILabel alloc] initWithFrame:CGRectZero];
    child1_.text = @"CHILD 1";
    [child1_ sizeToFit];
    child1_.backgroundColor = [UIColor redColor];
    child1_.textColor = [UIColor whiteColor];
    child2_ = [[UILabel alloc] initWithFrame:CGRectZero];
    child2_.text = @"CHILD 2";
    [child2_ sizeToFit];
    child2_.backgroundColor = [UIColor blueColor];
    child2_.textColor = [UIColor whiteColor];
     child2_.center = CGPointMake(child2_.center.x,child2_.center.y + 30);
    [self addSubview:child1_];
    [self addSubview:child2_];
  }
  return self;
}
// 外觀調(diào)整方法
-(void)layoutSubviews {
  // 調(diào)用父類中的相同方法
  [super layoutSubviews];
  // 再顯示子元素
  // 將child1_移動到左下
  CGRect newRect = child1_.frame;
  newRect.origin.x = 0;
  newRect.origin.y = self.frame.size.height - child1_.frame.size.height;
  child1_.frame = newRect;
  // 將child2_移動到右上
  newRect = child2_.frame;
   newRect.origin.x = self.frame.size.width - child2_.frame.size.width;
  newRect.origin.y = 0;
  child2_.frame = newRect;
}
@end

在上述實例中定義UIView的子類LayoutTest,其中擁有兩個標簽子元素。這里我們重新編寫了layoutSubviews方法,其中完成了將一個標簽放置在左下角顯示,另一個標簽放置在右上角顯示的外觀調(diào)整。將此LayoutTest追加到畫面中后,將顯示如圖2-14所示的外觀效果。

圖2-14 由layoutSubviews方法實現(xiàn)的外觀調(diào)整

這里我們直接改變標簽子元素的位置與尺寸后,可以看外觀是否會自動調(diào)整。將圖2-14中的“CHILD1”標簽的frame屬性作一下改變后,圖2-15顯示外觀并沒有作出自動調(diào)整。

圖2-15 直接修改子元素的frame屬性后不進行外觀自動調(diào)整

像上述這樣直接改變子元素的位置與尺寸時,layoutSubviews方法并沒有被調(diào)用。如果要改變這種狀況,我們需要調(diào)用setNeedsLayout方法。當UIView中發(fā)生某些改變后,再調(diào)用setNeedsLayout方法時,將會通知UIView需要調(diào)用其layoutSubviews方法,這樣一來就完成了外觀的自動調(diào)整。具體的代碼如下所示。

// 取得child1_并使之尺寸變大
UIView* child1 =(UIView*)[label_.subviews objectAtIndex:0];
child1.frame = CGRectMake(0,0,160,160);
child1.center = label_.center;
// 此后,調(diào)用setNeedsLayout方法
// layoutSubviews方法將會被自動調(diào)用
[label_ setNeedsLayout];

經(jīng)過上述修改后,layoutSubviews方法將會被自動調(diào)用,最終效果如圖2-16所示,“CHILD1”標簽將會移動到左下的位置。

另外,如果想在調(diào)用setNeedsLayout 方法后不用等待而自動調(diào)用layoutSubviews方法,我們可以調(diào)用layoutIfNeeded方法,以強制調(diào)用layoutSubviews方法。調(diào)用layoutIfNeeded方法后,如果當UIView處于必須重新布局的情況下,將直接調(diào)用layoutSubviews方法。

圖2-16 使用 setNeedsLayout 方法后的效果

2.4.2 子元素的自動尺寸調(diào)整

當UIView中包含有子元素的情況下,如果其autoresizeSubviews屬性為YES時,當UIView發(fā)生尺寸調(diào)整時,其子元素將自動調(diào)整到合適的位置。autoresizeSubviews屬性的默認值就是YES,但是UIView中還存在一個必須設置的項目,就是子元素的autoresizingMask屬性。autoresizingMask屬性默認為UIViewAutoresizingNone,并不直接進行自動尺寸調(diào)整。autoresizingMask屬性中可以設置6種不同的標志,可以使用OR邏輯運算符將6種標志都設置上。表2-7中羅列了autoresizingMask屬性設置不同值時自動尺寸調(diào)整的變化情況。

表2-7 autoresizingMask屬性值及其變化效果

續(xù)表

續(xù)表

關于autoresizingMask屬性的實例在第4.2.2節(jié)有進一步的介紹,有興趣的讀者可以先行學習。

2.4.3 坐標變換

使用坐標時,有時取以特定對象為參照的相對坐標會更方便一些。例如,在[標簽1右側50像素處配置標簽2]的情況下。以標簽1的本地坐標為參照,標簽2的x坐標為[標簽1的寬度+50],這樣坐標的計算將變得更簡單。如果以父元素為參照,標簽2的x坐標將為[標簽1的x坐標+標簽1的寬度+50]。

用于坐標系變換的方法有:covertPoint:toView:方法convertPoint:fromView:方法convertRect:toView:方法convertRect:fromView:方法四個。作用分別如表2-8所示。

表2-8 坐標系變換方法列表

下面看一個具體的使用實例。如圖2-17所示,畫面中有“CHILD1”及“CHILD2”兩個標簽,分別以“CHILD1”及“CHILD2”的本地坐標系變換對方的坐標。

圖2-17 兩個標簽的相對坐標(長寬均為100像素)

首先,將“CHILD1”的本地坐標系中“CHILD1”的右下(100,100)的坐標,以及“CHILD1”的矩形(0,0,100,100)變換到“CHILD2”的本地坐標系的坐標變換代碼如下。

CGPoint newPoint = [child1_ convertPoint:CGPointMake(100,100)toView:child2_];
CGRect newFrame = [child1_ convertRect:CGRectMake(0,0,100,100)toView:child2_];

結果為,newPoint的坐標為(0,0),newFrame的坐標為(-100,-100,100,100)。

接著,將“CHILD2”的本地坐標系中“CHILD2”的左上(0,0)的坐標,以及“CHILD2”的矩形(0,0,100,100)變換到“CHILD1”的本地坐標系的坐標變換代碼如下。

CGPoint newPoint = [child1_ convertPoint:CGPointMake(0,0)fromView:child2_];
CGRect newFrame = [child1_ convertRect:CGRectMake(0,0,100,100)fromView:child2_];

變換結果為,newPoint的坐標為(100,100),newFrame的坐標為(100,100,100,100)。

主站蜘蛛池模板: 金川县| 青浦区| 宜章县| 沁水县| 寿阳县| 台南县| 玉门市| 黑河市| 章丘市| 东阳市| 长葛市| 诸城市| 香河县| 武定县| 大足县| 安远县| 新泰市| 岳阳县| 桓仁| 江都市| 宝坻区| 河源市| 北宁市| 伊吾县| 文山县| 牡丹江市| 图片| 乐都县| 肥乡县| 巴南区| 新竹市| 平乐县| 兴化市| 当涂县| 昭通市| 得荣县| 榆中县| 康乐县| 镶黄旗| 龙江县| 姜堰市|