今⽇头条Android适配⽅案,android今⽇头条的屏幕适配理解前⼀段时间⽆意中看到今⽇头条的适配⽅案,使⽤到项⽬中,感觉真的是⽆⽐丝滑。所以特意写⼀篇⽂章分享给⼩伙伴们!
本⽂知识点:
为什么要做屏幕适配
今⽇头条的适配⽅案(划重点)
今⽇头条的适配⽅案的⼀些问题
1. 为什么要做屏幕适配
做Android开发的都了解,由于Android屏幕碎⽚化严重,虽然Android官⽅提供了dp为单位的适配⽅案,但是由于各种千奇百怪的机型,所以变现往往不尽如⼈意。所以需要进⾏屏幕适配。说⽩了就是让所有机型都进⾏保持UI的设计原貌!
2. 今⽇头条的适配⽅案
终于到了本⽂的重点了。为了⼤家能深刻理解其中的含义,这⾥从最基本的开始说起。
2.1 传统的dp适配的流程
android中的dp在渲染前会将dp转为px,计算公式:
px = density * dp;
density = dpi / 160;
px = dp * (dpi / 160);
复制代码
⽽dpi是根据屏幕真实的分辨率和尺⼨来计算的,每个设备都可能不⼀样的。那么dpi是怎么计算的呢?
上⾯图⽚说明dpi是怎么计算得来的。举个例⼦,当屏幕分辨率为1920 * 1080屏幕尺⼨为5⼨的⼿机。计算得来的dpi为440。不信的话可以计算⼀下!
那么问题来了?
假设我们UI设计图是按屏幕宽度为360dp来设计的,那么在上述设备上,屏幕宽度其实为1080/(440/160)=392.7dp,也就是屏幕是⽐设计图要宽的。这种情况下, 即使使⽤dp也是⽆法在不同设备上显⽰为同样效果的。 同时还存在部分设备屏幕宽度不⾜360dp,这时就会导致按360dp宽度来开发实际显⽰不全的情况。
⽽且上述屏幕尺⼨、分辨率和像素密度的关系,很多设备并没有按此规则来实现, 因此dpi的值⾮常乱,没有规律可循,从⽽导致使⽤dp适配效果差强⼈意。
3.2 今⽇头条的适配⽅式说明
其实,当我们拿到设计图的时候,⼀般都是根据苹果的6进⾏设计的,往往在Android中,存在16:9和4:3的⼀些机型,那么这些机型中的宽⾼⽐不同,如果想完全按照设计图进⾏适配是不可能的,也是不现实的。但是如果我们以⼀个维度,也就是宽这个维度来进⾏适配的话,如果⾼度超出了屏幕我们就使⽤可滑动的控件进⾏展⽰。这就是今⽇头条的适配⽅案。
因此,采⽤以宽度为标准去进⾏适配,保持该维度上和设计图⼀致
2.3 今⽇头条的适配⽅案
先科普⼏个内容,
dp和px的转换公式为:px = dp * density
dp转换的场景都是通过DisplayMetrics来进⾏计算的,
小孩牙痛怎么办DisplayMetrics#density 就是上述的density
DisplayMetrics#densityDpi 就是上述的dpi
DisplayMetrics#scaledDensity 字体的缩放因⼦,正常情况下和density相等,但是调节系统字体⼤⼩后会改变这个值
因为所有关于dp的计算都是通过DisplayMetrics这个类进⾏的。所以只需要针对这个类进⾏操作就可以了。
我简单把DisplayMetrics类分为三个层⾯,第⼀个是System(可以理解成初始分配)的,第⼆个是APP(
可以理解成Application)的,第三个是Activity的。当你适配的时候,尽量不要去修改第⼀个System中的Displaymetris的,因为可能第三⽅的库不会按照你的⽅式去适配,所以这⾥只修改后⾯两个就可以了。第⼀个不修改是便于之后的还原
以下是三个层⾯获取DisplayMetrics中的代码:
// 系统的屏幕尺⼨
final DisplayMetrics systemDm = System().getDisplayMetrics();
// app整体的屏幕尺⼨
final DisplayMetrics appDm = App().getResources().getDisplayMetrics();
// activity的屏幕尺⼨
final DisplayMetrics activityDm = Resources().getDisplayMetrics();
复制代码
接下来我们看看需要怎么适配,这⾥就只以屏幕宽度为基准进⾏相应的适配了。这⾥模拟360dp为基
准的适配,当然这个值你是可以修改成任何尺⼨的!
先计算⼀下屏幕的宽度
//这⾥widthPixels代表屏幕的宽度
activityDm.density = activityDm.widthPixels / 360;
复制代码计算⼀下字体的density
//这⾥通过⼀个⽐例确定activity字体的density
activityDm.scaledDensity = activityDm.density * (systemDm.scaledDensity / systemDm.density);
复制代码计算相应的dpi
//上⾯有相应的公式
activityDm.densityDpi = (int) (160 * activityDm.density);
复制代码复制相应的内容
/
/进⾏相应的赋值操作
appDm.density = activityDm.density;
appDm.scaledDensity = activityDm.scaledDensity;
appDm.densityDpi = activityDm.densityDpi;
复制代码
整体代码如下:武姓
/**
* 适配的主要代码
*
* @param activity 上下⽂
* @param sizeInPx 你要适配的相应尺⼨
* @param isVerticalSlide ⽔平还是垂直为参考
*/
private static void adaptScreen(final Activity activity,
final int sizeInPx,
final boolean isVerticalSlide){
园林论文// 系统的屏幕尺⼨
final DisplayMetrics systemDm = System().getDisplayMetrics();
// app整体的屏幕尺⼨
final DisplayMetrics appDm = App().getResources().getDisplayMetrics();
// activity的屏幕尺⼨
final DisplayMetrics activityDm = Resources().getDisplayMetrics();
if (isVerticalSlide) {
activityDm.density = activityDm.widthPixels / (float) sizeInPx;
Log.e(TAG, "adaptScreen: "+activityDm.widthPixels );
} el {
activityDm.density = activityDm.heightPixels / (float) sizeInPx;
狍子养殖}
// 字体的缩放因⼦,这个是通过⼀个⽐例计算得来的!
activityDm.scaledDensity = activityDm.density * (systemDm.scaledDensity / systemDm.density); // 计算得到相应的dpi
activityDm.densityDpi = (int) (160 * activityDm.density);
//进⾏相应的赋值操作
appDm.density = activityDm.density;
appDm.scaledDensity = activityDm.scaledDensity;
appDm.densityDpi = activityDm.densityDpi;
}
复制代码
因为上⾯涉及到横竖屏的问题,所以这⾥有个if判断。上⾯是主要代码。
3 今⽇头条的适配⽅案的⼀些问题
阿昔洛韦副作用
3.1 适配之后Toast的问题?
进⾏上⾯的适配之后,Toast会变得很⼩。其实也不难理解,因为你修改了APP的density,所以整个图⽚的界⾯都会发⽣相应的变化也就很好理解了。那么怎么解决呢?其实就想上⾯说的,使⽤System的density对App和Activity进⾏还原。怎么说呢?其实就是在show()⽅法之前还原,在之后在进⾏适配。
怎么取消呢?看下⾯的代码。
public static void cancelAdaptScreen(final Activity activity){
final DisplayMetrics systemDm = System().getDisplayMetrics();
final DisplayMetrics appDm = App().getResources().getDisplayMetrics();
final DisplayMetrics activityDm = Resources().getDisplayMetrics();
activityDm.density = systemDm.density;
activityDm.scaledDensity = systemDm.scaledDensity;
activityDm.densityDpi = systemDm.densityDpi;
appDm.density = systemDm.density;暑假日记
appDm.scaledDensity = systemDm.scaledDensity;
appDm.densityDpi = systemDm.densityDpi;
}
复制代码
其实就是使⽤System的density把APP和Activity的density修改回来就可以了!
然后在show()⽅法之后使⽤下⾯⽅法重新对界⾯进⾏适配!
生命的本质public static void restoreAdaptScreen(Activity activity, boolean isVerticalSlide, int sizeInPx){
final DisplayMetrics systemDm = System().getDisplayMetrics();
final DisplayMetrics appDm = App().getResources().getDisplayMetrics();
final DisplayMetrics activityDm = Resources().getDisplayMetrics();
if (isVerticalSlide) {
activityDm.density = activityDm.widthPixels / (float) sizeInPx;
} el {
activityDm.density = activityDm.heightPixels / (float) sizeInPx;
}
activityDm.scaledDensity = activityDm.density * (systemDm.scaledDensity / systemDm.density);
activityDm.densityDpi = (int) (160 * activityDm.density);
appDm.density = activityDm.density;
appDm.scaledDensity = activityDm.scaledDensity;
appDm.densityDpi = activityDm.densityDpi;
}
复制代码
调⽤代码就变成了这个样⼦
//取消适配
ScreenUtils.cancelAdaptScreen(this);
/
/弹出Toast
Toast.makeText(this, "点击了第⼀个内容", Toast.LENGTH_SHORT).show();
//重新适配
复制代码
像什么Toast、dialog什么的都会出现上⾯的情况,所以解决办法是⼀样的
3.2 webview加载后发现density复原
由于 WebView 初始化的时候会还原 density 的值导致适配失效,继承 WebView,重写如下⽅法:@Override
public void tOverScrollMode(int mode){
super.tOverScrollMode(mode);
牛牛碰在线storeAdaptScreen();
}
复制代码