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

2.4 UIView的外觀

2.4.1 外觀定制

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

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

// 定義UIView的子類
// 子類中擁有child1_以及child2_兩個標簽子元素
@interface LayoutTest :UILabel
{
 @private
  UILabel* child1_;
  UILabel* child2_;
}
@end
// 實現LayoutTest類
@implementation LayoutTest
// 釋放處理
-(void)dealloc {
  [child1_ release];
  [child2_ release];
  [super dealloc];
}
// 初始化處理
-(id)init {
  if((self = [super init])){
    // 調整自己的大小,追加兩個標簽
    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;
}
// 外觀調整方法
-(void)layoutSubviews {
  // 調用父類中的相同方法
  [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方法,其中完成了將一個標簽放置在左下角顯示,另一個標簽放置在右上角顯示的外觀調整。將此LayoutTest追加到畫面中后,將顯示如圖2-14所示的外觀效果。

圖2-14 由layoutSubviews方法實現的外觀調整

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

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

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

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

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

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

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

2.4.2 子元素的自動尺寸調整

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

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

續表

續表

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

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)。

主站蜘蛛池模板: 南汇区| 山西省| 浙江省| 调兵山市| 丰城市| 荣昌县| 酒泉市| 林芝县| 师宗县| 应城市| 普宁市| 衡南县| 昌邑市| 依兰县| 五台县| 涿鹿县| 顺义区| 武山县| 榆中县| 永嘉县| 任丘市| 万盛区| 蒙阴县| 滦平县| 太康县| 微博| 合川市| 平乡县| 滨州市| 宝坻区| 尤溪县| 疏附县| 龙口市| 康马县| 黎平县| 准格尔旗| 岐山县| 临漳县| 抚远县| 南丹县| 牟定县|