說起屏幕適配, 估計很多人都會想到autoLayout, 想到Masonry, 但是今天說的屏幕適配與這自動布局沒關系, 這是一種全局的方式.
故事背景
很多時候我們開發一個UI, 設計給出的標注都是按照某個機型來標注的, 里面的像素都是寫死的, 但實際上, 對于不同的屏幕, 這些值可能是需要變化的, 但是設計并不會在設計圖上說, 這東西可能會變化, 也不會說哪里變化, 哪里不變, 這就可能惡心到我們, 辛辛苦苦做的一個UI, 在小屏幕的手機上一運行發現顯示不下, 這就尷尬了, 這個鍋設計和產品肯定不背, 最后還是要我們開發撅著屁股去改.
由于公司的設計用的是iphone6, 所以所有的標注都是按照iphone6來的, 上圖的布局在iphone6下顯示是沒有問題的, 居中顯示, 下面是代碼.
static const CGFloat iphone6Width = 375.0f;
static const CGFloat iphone6Height = 667.0f;
@interface ViewController ()
@property (nonatomic, weak) UIView *redView;
@property (nonatomic, weak) UIView *blueView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initViews];
}
- (void)initViews {
UIView *redView = [[UIView alloc] init];
redView.backgroundColor = [UIColor redColor];
[self.view addSubview:redView];
self.redView = redView;
UIView *blueView = [[UIView alloc] init];
blueView.backgroundColor = [UIColor blueColor];
[self.view addSubview:blueView];
self.blueView = blueView;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.redView.frame = CGRectMake((iphone6Width - 250) * 0.5, 100, 250, 100);
self.blueView.frame = CGRectMake((iphone6Width - 250) * 0.5, CGRectGetMaxY(self.redView.frame) + 10, 250, 100);
}
@end
這應該是一個簡單不能再簡單的布局了, 然而, 這種寫法顯然是不對的, iphone6Width是固定的值, 到了其它屏幕顯示就會有問題.
但是可能我們開發的時候并沒有注意要多機型屏幕適配, 那就尷尬了, 如果不是2個view, VC中有幾十個view就尷尬大了, 不過沒關系, 用了今天的方法, 很快就能搞定.
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initViews];
}
- (void)initViews {
UIView *iphone6View = [[UIView alloc] init];
// iphone6View.backgroundColor = [UIColor greenColor];
[self.view addSubview:iphone6View];
self.iphone6View = iphone6View;
UIView *redView = [[UIView alloc] init];
redView.backgroundColor = [UIColor redColor];
[self.iphone6View addSubview:redView];
self.redView = redView;
UIView *blueView = [[UIView alloc] init];
blueView.backgroundColor = [UIColor blueColor];
[self.iphone6View addSubview:blueView];
self.blueView = blueView;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
float sx = self.view.bounds.size.width / iphone6Width;
float sy = self.view.bounds.size.height / iphone6Height;
self.iphone6View.transform = CGAffineTransformMakeScale(sx, sy);
[self layoutForIPhone6];
}
- (void)layoutForIPhone6 {
self.redView.frame = CGRectMake((iphone6Width - 250) * 0.5, 100, 250, 100);
self.blueView.frame = CGRectMake((iphone6Width - 250) * 0.5, CGRectGetMaxY(self.redView.frame) + 10, 250, 100);
}
@end
我們還是按照原來的方式去做, 只是把view都添加到iphone6View上, 而iphone6View是個虛擬的view, 我們把iphone6View進行放射變化, 里面的子view也隨之變換了, 我們根據設計的標注, 把子view都添加到iphone6View就可以了, 這樣還能解決不同屏幕下字體的縮放問題, 使用自動布局只能調整view自適應, 但是很難搞定不同尺寸下字體的問題.
在實際開發中, iphone6View還是要設置一個真實的frame才可以, 因為子view要取iphone6View作為參照.
- (void)initViews {
UIView *iphone6View = [[UIView alloc] init];
// iphone6View.backgroundColor = [UIColor greenColor];
[self.view addSubview:iphone6View];
self.iphone6View = iphone6View;
UIView *redView = [[UIView alloc] init];
redView.backgroundColor = [UIColor redColor];
[self.iphone6View addSubview:redView];
self.redView = redView;
UIView *blueView = [[UIView alloc] init];
blueView.backgroundColor = [UIColor blueColor];
[self.iphone6View addSubview:blueView];
self.blueView = blueView;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.iphone6View.bounds = CGRectMake(0, 0, iphone6Width, iphone6Height);
self.iphone6View.center = self.view.center;
float sx = self.view.bounds.size.width / iphone6Width;
float sy = self.view.bounds.size.height / iphone6Height;
self.iphone6View.transform = CGAffineTransformMakeScale(sx, sy);
[self layoutForIPhone6];
}
- (void)layoutForIPhone6 {
self.redView.frame = CGRectMake((self.iphone6View.bounds.size.width - 250) * 0.5, 100, 250, 100);
self.blueView.frame = CGRectMake((self.iphone6View.bounds.size.width - 250) * 0.5, CGRectGetMaxY(self.redView.frame) + 10, 250, 100);
}
@end
總結
本例在多屏幕的適配上取得了很好的效果, 在iphone現在機型長寬比差距不是很大的情況下, 進行等比例縮放不會有什么問題, 但如果日后出現很多新機型, 長寬比出現很大差距, 可能就要針對不同機型進行不同的縮放了.