IOS開發之絕對佈局和相對佈局(屏幕適配)

以前若是作過Web前端頁面的小夥伴們,看到絕對定位和相對定位並不陌生,而且使用起來也挺方便。在IOS的UI設計中也有絕對定位和相對定位,和咱們的web前端的絕對定位和相對定位有所不一樣但又有類似之處。下面會結合兩個小demo來學習一下咱們IOS開發中UI的絕對定位和相對定位。在前面的博客中所用到的UI事例用的全是絕對定位,用咱們Storyboard拖拽出來的控件全是絕對定位的,就是咱們能夠同改變組件的frame來改變組件的位置和大小。而相對定位則不一樣,相對定位是參考組件周圍的元素來肯定組件的大小或位置,相對定位即約束和周圍組件的距離來佈局的,即layoutConstraint. 在佈局中LayoutConstraint和Fram佈局方式是不能並存的。前端

上面說了這麼多了,可能說的不太明白,仍是那句話,怎麼能少的了代碼和實例的支持呢,下面會經過屏幕適配的事例來用絕對佈局和相對佈局同時實現下面的描述效果。程序員

 咱們要實現的效果:當上面的view的大小及位置改變時,爲了避免覆蓋掉下面的view,咱們同時要改變下view的位置。 或者說在咱們4.0寸正常顯示的內容,在3.5寸屏上也能正常顯示,即一般咱們所說的屏幕的適配。爲了便於觀察效果,咱們能夠用Slider控件來動態的改變上面view的大小,觀察下面view的位置變化,下面是咱們要實現的效果圖:web


  

 用絕對佈局來實現上述效果,爲了節省咱們代碼編寫的時間,上面的控件是經過storyborad來實現的,而後在對應的ViewController裏添加組件和控件回調的方法,主要是在slider滑動的時候來獲取slider的值,而後動態的設置上面View的frame座標(固然,若是讓view往四周擴展得計算一下新的fram的值,而後動態的修改),上面的view位置和大小改變了,那麼下面的view不能被上面的覆蓋掉,因此也得修改blackView的fram的值。這種經過修改frame的值的方式來肯定組件位置即爲絕對佈局ide

下面是由storyboard拖拽過來的屬性:佈局

1
2
3
4
5
6
//把最上邊的view拖拽到咱們的代碼中
@property (strong, nonatomic) IBOutlet UIView *myView;
//添加slider
@property (strong, nonatomic) IBOutlet UISlider *mySlider;
//添加下面黑色的view
@property (strong, nonatomic) IBOutlet UIView *blackView;

下面是當slider的值改變時要回調的方法:學習

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//當slider的值改變的時候回調的方法
- (IBAction)sliderFunction:(id)sender
{
     //獲取slider的當前值(在storyboard設置的範圍爲0-120)
     double  value = self.mySlider.value;
 
     //獲取myView的位置
     CGRect frame = self.myView.frame;
 
     //根據slider的值動態的設置myView的座標和寬高,設置的時候view中心不變
     frame.origin.x =  120-value;
     frame.origin.y = 66 * (1-value/120);
     frame.size.height = 320-frame.origin.x*2;
     frame.size.width = 320-frame.origin.x*2;
 
     //更新myView的位置
     self.myView.frame = frame;
     //同時改變下面黑色view的座標
     CGRect bf = self.blackView.frame;
     bf.origin.y = frame.size.height + frame.origin.y + 30;
     self.blackView.frame = bf;
 
}

 

上面是咱們的絕對佈局的方式,接下來要學習一下相對佈局的方式。相對佈局使用起來會比絕對佈局要複雜一些,下面先作屏幕適配的例子,圖一是在iPhone的4.0寸的效果圖, 當咱們不作任何處理的時候在3.5寸屏上是顯示不出來的如第二張圖:atom


  

咱們如何讓在3.5寸屏上也顯示正常呢,接下啦就是相對佈局出出場的時候了,咱們用相對佈局的方式把最下面的view的位置改成相對於主視圖的底部和左邊的像素值固定,同時設置slider的位置相對於下面的view的位置相對固定。也就是下面的veiw的位置改變,則上面的slider的位置也會改變,用storyboard修改以下:(第一張圖是修改最下面view的相對位置,第二張圖是設置咱們slider爲相對佈局) ,不須要在ViewController中添加任何動態嗎咱們就能夠實現屏幕的適配。spa


  

    

        

那麼我如何用相對佈局實現上面那種view放大的效果呢,接下來咱們須要新建一個工程,由於相對佈局和絕對佈局在同一個組件中沒法並存。在新建工程中用storyboard把咱們用到的控件進行拖拽 ,界面和上面的是同樣的。設計

  • (1)首先給咱們最上面的View設置相對佈局的屬性,以下面的圖一
  • (2)  再給黑色的View設置相對佈局的屬性,入下面的圖二所示:
  • (3) 設置上面兩個View相對中心對齊,選中上面的View,按着Ctrl往下面的View中拖拽,在彈出的框中選中Center X入圖三

     

               

 給咱們相應的組件在storyboard中添加上約束之後,怎樣來動態的改變最上面view的寬和高的約束範圍呢?(即改變水平約束和垂直約束的值)第一部就得把最上面的view的水平約束和垂直約束從咱們的storyboard中把最上面View中咱們要用的約束拖入到咱們的Viewcontroller, 第一張圖是storyboard中約束所在的位置,第二張圖把約束添加到ViewController中。3d

          

至此咱們用storyboard的工做已經作完,程序員是少不了敲代碼的,也只有正兒八經的敲代碼,程序員纔會成長。因此嘍下面就是咱們在ViewController中添加的代碼部分。絕對佈局直接改frame的座標值就能夠啦,那麼在程序中咱們如何去動態的改變咱們約束的值呢?下面的代碼將會用到。 咱們要作的事情就是在ViewController中經過改變slider的值來改變最上面View的水平約束和垂直約束,水平約束和垂直約束的相關變量咱們已經拖拽過來了,下面就須要在Slider回調的方法中來改變水平和垂直約束的值。先段代碼,以後在說兩句。    ​    ​

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//slider的值改變調用的方法
- (IBAction)sliderChange:(id)sender
{
     //爲了不衝突移除myView的水平和垂直約束,注意是從主視圖上移除,由於約束是加載咱們的主視圖上,即相對於咱們的主視圖
     [self.view removeConstraint:self.widthC];
     [self.view removeConstraint:self.heightC];
     
     //獲取slider的值
     double  sliderValue = self.mySlider.value;
     
     //由slider的值重設咱們的約束值,H表明水平約束, V表明垂直約束
     NSString *widthValue = [NSString stringWithFormat:@ "H:[_myView(%lf)]" , sliderValue];
     NSString *heightValue = [NSString stringWithFormat:@ "V:[_myView(%lf)]" , sliderValue];
     
     //新建約束
     NSArray *widthConstraint = [NSLayoutConstraint constraintsWithVisualFormat:widthValue options:0 metrics:nil views:NSDictionaryOfVariableBindings(_myView)];
     //給水平約束從新賦值
     self.widthC = widthConstraint[0];
     
     //給垂直約束從新賦值
     NSArray * heightConstraint = [NSLayoutConstraint constraintsWithVisualFormat:heightValue options:0 metrics:nil views:NSDictionaryOfVariableBindings(_myView)];
     self.heightC = heightConstraint[0];
     
     //往主視圖上添加新的約束
     [self.view addConstraint:self.widthC];
     [self.view addConstraint:self.heightC];
}

    ​    ​    

​代碼說明:

  • 1.一個組件中只能有一中約束,如在myView中咱們已經有一個垂直約束,咱們若是再給他添加一個垂直約束的話,那麼程序在運行時就會報錯,錯誤內容:「Unable to simultaneously satisfy constraints.……」;
  • ​2.因此在添加新的約束以前,咱們得把以前加在咱們組件中相應的約束給去掉;約束是加在咱們對應組件的父視圖上,移除也得從組件的父視圖上移除;
  • 3.在設置約束的值的時候咱們是以字符串的形式把參數傳遞給約束的,如:H:[_myView(200)] H表明水平約束,V表明垂直約束。中括號裏是咱們要爲那個組件添加約束以及約束的值是多少;
  • ​4.給咱們的約束更新咱們新建的約束;
  • ​5.在把更新的約束添加到咱們的父視圖上,到此咱們就能夠實現上面咱們上面用絕對佈局實現的功能

    ​    ​   

補充說明:

在絕對佈局時咱們還能夠獲取屏幕的尺寸,經過屏幕的尺寸來計算咱們組件所在的位置,主要代碼以下:

1
2
3
4
5
6
//獲取屏幕大小
UIScreen *s = [UIScreen mainScreen];
//獲取屏幕邊界
CGRect bounds = s.bounds;
//獲取屏幕的高度
float  height = bounds.size.height;

​ 上面的總結暫且這麼說吧,是根據筆者本身的理解所總結的內容,難免有偏頗之處,歡迎批評指正,轉載請註明出處。

相關文章
相關標籤/搜索