在公司项目中,我用到了xib设置约束,Masonry,比例适配,三种适配方案的结合来达到项目中的页面适配,字体适配等。当然项目中对iPhone X的适配,我也有封装一个分类。
- 我相信xib设置约束和Masonry,我就不用详细介绍了,我主要介绍一下比例适配和iPhone X的适配。
一、比例适配
- 比例适配的原理在于:iphone 机型中除了iPhone X,其他机型都是宽高比都是基本相同,那么既然宽高比相同,我们就可以认为,当我们UI设计师给的图是任意一款苹果机的屏幕尺寸,咱们都能根据比例去适配其他手机屏幕。
第一步:创建一个.h头文件
第二步:在该文件里写下如下代码:
#ifndef Adaption_h
#define Adaption_h
#import <UIKit/UIKit.h>
#pragma 屏幕尺寸
#define kwidth [UIScreen mainScreen].bounds.size.width
#define kheight [UIScreen mainScreen].bounds.size.height
#pragma UI设计图尺寸
#define kBaseWidth 750
#define kBaseHeight 1334
//宏定义内联函数
#define Inline static inline
#pragma mark --设置比例
//实际屏幕宽度和设计图宽度的比例
Inline CGFloat AAdaptionWidth() {
return kwidth/kBaseWidth;
}
//传入设计图尺寸标注,转化为实际屏幕尺寸标注
Inline CGFloat AAdaption(CGFloat x) {
return x * AAdaptionWidth();
}
//传入设计图size,转化为实际屏幕的CGsize返回
Inline CGSize AAdaptionSize(CGFloat width, CGFloat height) {
CGFloat newWidth = width * AAdaptionWidth();
CGFloat newHeight = height * AAdaptionWidth();
return CGSizeMake(newWidth, newHeight);
}
//传入设计图Point,转化成CGpoint返回
Inline CGPoint AAadaptionPoint(CGFloat x, CGFloat y) {
CGFloat newX = x * AAdaptionWidth();
CGFloat newY = y * AAdaptionWidth();
return CGPointMake(newX, newY);
}
//传入设计图Rect,返回已适配真实屏幕的CGrect
Inline CGRect AAdaptionRect(CGFloat x, CGFloat y, CGFloat width, CGFloat height){
CGFloat newX = x*AAdaptionWidth();
CGFloat newY = y*AAdaptionWidth();
CGFloat newW = width*AAdaptionWidth();
CGFloat newH = height*AAdaptionWidth();
return CGRectMake(newX, newY, newW, newH);
}
Inline CGRect AAdaptionRectFromFrame(CGRect frame){
CGFloat newX = frame.origin.x*AAdaptionWidth();
CGFloat newY = frame.origin.y*AAdaptionWidth();
CGFloat newW = frame.size.width*AAdaptionWidth();
CGFloat newH = frame.size.height*AAdaptionWidth();
return CGRectMake(newX, newY, newW, newH);
}
//字体适配:传出设计图字体大小
Inline UIFont * AAFont(CGFloat font){
return [UIFont systemFontOfSize:font*AAdaptionWidth()];
}
//加粗字体适配
Inline UIFont * BoldFont(CGFloat font){
return [UIFont boldSystemFontOfSize:font*AAdaptionWidth()];
}
#endif /* Adaption_h */
第三步:在项目中使用
导入头文件
#import "Adaption.h"
-
代码调用与普通初始化类似
UIView *redView = [[UIView alloc]initWithFrame:AAdaptionRect(100, 100, 100, 100)]; redView.backgroundColor = [UIColor redColor]; [self.view addSubview:redView];
你现在可以试一下各个屏幕上显示的效果,肯定是能适配的,除了iPhone X
- 这个适配文件有一个缺点,只适配竖屏,横屏事得重新设置设计图设计图尺寸,或者用masonry适配。
iPhone X的适配:
- 首先在配置文件里定义几个宏
//宏定义常用的导航栏,tabbar,状态栏高度
#define TabBarH ((kheight == 812) ? 83 : 49)
#define NavH ((kheight == 812) ? 88 : 64)//这个包含状态栏在内
#define StuBarH ((kheight == 812) ? 44 : 20)
- 然后给UIViewController创建一个分类
- UIViewController+ContentView.h内容
#import <UIKit/UIKit.h>
@interface UIViewController (ContentView)
@property (nonatomic, strong) UIView *contentView;
@end
- UIViewController+ContentView.m内容
#import "UIViewController+ContentView.h"
#import <objc/runtime.h>
static const void *ContentView = &ContentView;
@implementation UIViewController (ContentView)
//用runtime重写setter,getter方法,来给分类添加属性
- (void)setContentView:(UIView *)contentView {
/*
OBJC_ASSOCIATION_ASSIGN; //assign策略
OBJC_ASSOCIATION_COPY_NONATOMIC; //copy策略
OBJC_ASSOCIATION_RETAIN_NONATOMIC; // retain策略
OBJC_ASSOCIATION_RETAIN;
OBJC_ASSOCIATION_COPY;
*/
/*
* id object 给哪个对象的属性赋值
const void *key 属性对应的key
id value 设置属性值为value
objc_AssociationPolicy policy 使用的策略,是一个枚举值,和copy,retain,assign是一样的,手机开发一般都选择NONATOMIC
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
*/
objc_setAssociatedObject(self, ContentView, contentView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
/**
contentView用来作为根视图代替self.view
注意:本项目是用的系统的导航栏,假如用的自定义的导航栏,
请在宏定义里改掉相应的导航栏高度和tabbar高度。
有一个缺点:当你由于需要,隐藏了导航栏,这儿检测不到,因为初始化Vc的时候先走这个方法
这个时候建议在相应vc中做坐标处理
*/
- (UIView *)contentView {
//利用runtime实现动态添加属性
UIView *view = objc_getAssociatedObject(self, ContentView);
//因为当界面上只有tableview控件时,在iOS7以上,iOS11以下系统,坐标零点都是从导航栏开始
//设置这个属性能够避免系统bug
self.automaticallyAdjustsScrollViewInsets = NO;
//判断vc是否为栈内第一个页面,来设置contenview的高度
//这儿默认每个页面都有导航栏,如果是自定义导航栏,只需要在self.view上添加即可,不会与contentView冲突
if (!view) {
if (self.navigationController.viewControllers.count > 1 ||self.navigationController.viewControllers.count == 0) {
view = [[UIView alloc]initWithFrame:CGRectMake(0, NavH, kwidth, kheight-NavH)];
}else{
view = [[UIView alloc]initWithFrame:CGRectMake(0, NavH, kwidth, kheight-NavH-TabBarH)];
}
view.backgroundColor = [UIColor clearColor];
self.contentView = view;
//让应用在ipad以滚动视图的方式正常显示,显示内容宽高和iphone5一样,这是为了苹果审核,要求iPad正常显示
if (kheight == 480) {
UIScrollView *scorollView = [[UIScrollView alloc]initWithFrame:self.view.bounds];
scorollView.contentSize = CGSizeMake(kwidth, 568);
view.frame = CGRectMake(0, 0, kwidth, 568);
[self.view addSubview:scorollView];
[scorollView addSubview:view];
}else{
[self.view addSubview:view];
}
}
return view;
}
- 外部调用:
UIView *redView = [[UIView alloc]initWithFrame:AAdaptionRect(100, 100, 100, 100)];
redView.backgroundColor = [UIColor redColor];
[self.contentView addSubview:redView];