很想和你们唠叨几句,聊聊入行后我下移的发际线是怎么做到的!奈何不善言谈,虽心有千言万语,竟只能对着屏幕叹一声下次再聊。
本人学识有限,错误之处还望各位大佬斧正。[]( ̄▽ ̄)*下面进入正题。
1.使用dp、sp、wrap_content、match_parent
2.布局中使用weight或者ConstraintLayout等灵活布局
3.通配符适配,如:layout-sw320dp、values-sw320dp
4.头条方案
使用1、2两种方法,也是我们开发中最常用的方法,基本能满足我们大部分(80%左右)机型的适配,但是还有小部分的机型显示会出现问题,这时候我们就要用到了3、4两种方法的一种。
通配符
先来说说通配符,通配符适配是Google早期为了能让APP能同时适配手机和平板而提供的功能,后被用于解决Android手机屏幕尺寸碎片化引起的适配问题。
通配符的格式:文件名+通配符限制,中间用“-”连接。
我们常用的分辨率适配:drawbale-1920*1080、drawbale-1280*720等
宽度适配:values-sw320dp、values-sw360dp等
├── src/main
│ ├── res
│ ├── ├──values
│ ├── ├──values-sw320dp
│ ├── ├──values-sw360dp
│ ├── ├──values-sw400dp
│ ├── ├──values-sw411dp
│ ├── ├──values-sw480dp
│ ├── ├──...
│ ├── ├──values-sw600dp
│ ├── ├──values-sw640dp
上面是我公司项目使用的通配符适配目录。是不是很熟悉?没错,这个基本是个固定的目录格式,已经有大神帮我设计好了,我们只要照搬这个目录就可以了。(你要是觉的不够精细,可以自己增加 ̄▽ ̄)既然我们用了通配符,那么values中的dimens.xml想必是不一样(*^▽^*),下面我举个例子来说明dimens中值是怎么计算出来的!
假设UI给的设计图尺寸是1280*750,我要计算的是sw320dp-》dimens
屏幕宽度320dp、设计图750px,
如果要把屏幕占满我们需要设置view的宽度为320dp或者750px、
如果占一半view的宽度为160dp或者375px、
依次类推我们能看出dp和px之间的比例是固定的320/750=160/375....=0.43。也就是说1px=0.43dp。总体来看就是我们把320dp的屏幕分成了750份,用每份来替换dp值(如:1px(pb_px_1)=0.43dp)。
<dimen name="base_dpi">320dp</dimen>
<dimen name="qb_px_0">0.00dp</dimen>
<dimen name="qb_px_1">0.43dp</dimen>
<dimen name="qb_px_2">0.85dp</dimen>
<dimen name="qb_px_3">1.28dp</dimen>
<dimen name="qb_px_4">1.71dp</dimen>
<dimen name="qb_px_5">2.13dp</dimen>
<dimen name="qb_px_6">2.56dp</dimen>
<dimen name="qb_px_7">2.99dp</dimen>
<dimen name="qb_px_8">3.41dp</dimen>
<dimen name="qb_px_9">3.84dp</dimen>
...
<dimen name="qb_px_719">306.77dp</dimen>
<dimen name="qb_px_720">307.20dp</dimen>
...
<dimen name="qb_px_750">320dp</dimen>
同理,sw360dp也是把屏幕分成750份、每份360/750=0.48
Android Studio自动生成dimens插件下载
由于Android的碎片化,会有各种稀奇古怪的手机宽度是上面没有的通配宽度,(sw -> small width 最小宽度通配符) ,遇到这种情况系统会自动帮我想下查找最近的通配宽度。
假如有一台340dp的手机,而我们的统配符有没有340dp,那么会自动先下查找到并使用sw320dp的参数。但是我们手机的宽度明明是340dp,却用的320dp的参数,这不是产生了误差。没错,但是这种误差基本可以忽略,下面我们来简单算算。
340/750=0.45
320/750=0.43
如果一个view的高度是30dp,那么两者的误差为0.6dp,0.6/30*100=2%
一个30dp的view,误差小于1dp(2%),这点差异完全可以忽略,显示效果用眼睛看不出差异。
所以通过增加通配符各种不同的尺寸,能让我们的UI适配更完善。但是,相应的也会增加app的体积。
小结:
优点:兼容性好、无性能消耗、
缺点:侵入高
ps:因为代码遗留问题,我公司app中的dimens中的计算错误,造成现在只能将错就错,如果修改dimens,整个app的布局参数都要改...想想就头皮发麻
头条方案
先来看看几个公式:
- 屏幕宽度(px) = 屏幕(设计图)宽度(dp)* density;
- density = dpi / 160;
- dpi =对角线长度(px)/对角线长度(英寸)
假如我们的手机分辨率为1920*1080、5寸,则像素密度为2203/5=440dpi
通过上面公式我们能得出:屏幕宽度 1080/(440/160)=392.7dp
实际宽度392dp,但是我们设计图是360dp,所以实际显示效果要比UI要小。
1080px是屏幕的宽度,不可改变,为了让宽度是360dp,我们只能统通过修改density是宽度维持在360dp。
到这里你应该看出来我们要修改的是density指,没错头条的方案就是修改系统的density。
代码很简单,下面贴出来。
public void setCustomDensity(Application application, Activity activity){
DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();
DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
scaledDensity = appDisplayMetrics.scaledDensity;
density = appDisplayMetrics.density;
registerComponentCallbacks(new ComponentCallbacks() {
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (newConfig != null && newConfig.fontScale > 0) {
scaledDensity = getResources().getDisplayMetrics().scaledDensity;
}
}
@Override
public void onLowMemory() {
}
});
float targerDensity = appDisplayMetrics.widthPixels / 360;
float targerScaleDensity = targerDensity * (scaledDensity / density);
int targerDpi = (int) (targerDensity * 160);
appDisplayMetrics.density = targerDensity;
appDisplayMetrics.scaledDensity = targerScaleDensity;
appDisplayMetrics.densityDpi = targerDpi;
activityDisplayMetrics.density = targerDensity;
activityDisplayMetrics.scaledDensity = targerScaleDensity;
activityDisplayMetrics.densityDpi = targerDpi;
}
小结:
优点:没有性能消耗、侵入低
缺点:没什么明显的缺点
3、4两种方案在适配效果上都相当不俗,完全能满足大部分公司的适配需求。作为开发者我们选哪个呢?嘿嘿,怎么选择看个人意愿啦,两者没有优劣之分。
网友评论