轉(zhuǎn)載請標(biāo)明出處http://www.reibang.com/p/71a68addb357
前言:現(xiàn)在的Android開發(fā)環(huán)境下笆环,手機適配是一直沒有消失,長存的問題躁劣。就連IOS環(huán)境下的屏幕也都變得多樣。反觀Android環(huán)境下的各個廠家的各種尺寸屏幕手機的適配账忘,是個難辦的問題。在這環(huán)境之下鳖擒,其實Android屏幕適配的解決,還是有幾套方案可以實行的蒋荚。包括常用的針對你所需要適配的手機屏幕的分辨率各自建立一個文件夾。hongyang大神文章里還有自動生成文件夾的工具圆裕,這里不贅述,這里說一種更低成本的吓妆,頭條團隊提供的方案。在此之下先說一下分辨率相關(guān)的幾個基礎(chǔ)知識點行拢。
1. 分辨率
分辨率就是手機屏幕的像素點數(shù),一般描述成屏幕的“寬×高”舟奠,720×1280表示此屏幕在寬度方向有720個像素,在高度方向有1280個像素沼瘫。在進行屏幕適配時,不要直接通過分辨率適配耿戚,應(yīng)該通過屏幕尺寸和屏幕密度來適配
2. 屏幕大小
屏幕尺寸是指屏幕的物理尺寸,是通過測量屏幕的對角線測量出來的坛猪。以英寸(inch)為單位。指對角線的尺寸墅茉,比如6寸×2.54厘米/寸=15.24厘米。
3. 屏幕密度(dpi)
屏幕物理區(qū)域中的像素量就斤,通常稱為dpi/ppi(每英寸的像素點數(shù),ios為ppi,anroid為dpi)。密度越高战转,成像的效果越好搜立,越細(xì)膩。有些廠家會推出2k,3k刁标,4k的屏幕,用戶體驗的確是很好的膀懈。
4. px (像素)
px 即 pixel,像素點启搂,電子屏幕上組成圖像的最基本單位,在上面描述屏幕分辨率時使用到該單位胳赌。
5. dp (也稱 dip,與dpi區(qū)別)
Density-independent pixel (dp)獨立像素密度疑苫。標(biāo)準(zhǔn)是160dip.即1dp對應(yīng)1個pixel,計算公式如:px = dp * (dpi / 160)捍掺,屏幕密度越大,1dp對應(yīng) 的像素點越多挺勿。
6. sp (可縮放獨立像素)
在安卓系統(tǒng)里,sp 與 dp 類似满钟,不同的是 sp 可以根據(jù)用戶的字體大小首選項進行縮放,而 dp 則不會湃番。 盡量使用 dp 作為空間大小單位,sp 作為文字相關(guān)大小單位吠撮,例如:新聞類和短信類等大篇幅文本讲竿,推薦使用 sp 為單位。
android中的dp在渲染前會將dp轉(zhuǎn)為px题禀。根據(jù)這個公式。
px = density * dp;
density = dpi / 160;
px = dp * (dpi / 160);
而dpi是這么計算出來的迈嘹。
即勾股定理出對角線全庸,除以屏幕尺寸融痛,就是dpi大小了。
這樣會出現(xiàn)一個問題雁刷,就是當(dāng)手機的dpi越大的時候,使用dp計算出來的px值是會越來越大的沛励。假設(shè)你UI設(shè)計圖是按360dp設(shè)計。
若實際手機是大于360dp的目派,那么顯示效果,px值就會偏大址貌。
所以為了解決這個問題,頭條團隊提供了一個方案练对,就是在設(shè)置系統(tǒng)density的值,通過獲得UI圖dpi和手機真實寬px計算,最終設(shè)置系統(tǒng)的density螟凭。
這個核心處理工具類
public class MyDensityUtil {
//屏幕密度
private static float sComponentDensity;
//屏幕顯示的字體的密度
private static float sComponentScaledDensity;
/**
* 設(shè)置自定義的屏幕密度
* 在BaseActivity中的onCreate()方法中調(diào)用
*/
static void setCustomDensity(Activity activity, final Application application) {
//顯示器的一般信息類
final DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();
if (sComponentDensity ==0) {
//屏幕密度
sComponentDensity = appDisplayMetrics.density;
//屏幕顯示的字體的密度
sComponentScaledDensity = appDisplayMetrics.scaledDensity;
//字體切換監(jiān)聽,防止切換字體再返回應(yīng)用字體并沒有變化
application.registerComponentCallbacks(new ComponentCallbacks() {
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (newConfig !=null && newConfig.fontScale >0) {
sComponentScaledDensity =application.getResources().getDisplayMetrics().scaledDensity;
}
}
@Override
public void onLowMemory() {
}
});
}
//實際顯示器的絕對寬度與UI寬度比例
final float targetDensity = appDisplayMetrics.widthPixels /1080F;//以1080dp和寬維度來適配的
//通過原本的ScaledDensity和density獲取比例從而得出現(xiàn)在的實際顯示器字體密度
final float targetScaledDensity = targetDensity * (sComponentScaledDensity /sComponentDensity);
//DENSITY_DEFAULT棒厘,默認(rèn)參考密度
final int targetDensityDpi = (int) (DENSITY_DEFAULT * targetDensity);
//賦值到application中的density中
appDisplayMetrics.density = targetDensity;
appDisplayMetrics.scaledDensity = targetScaledDensity;
appDisplayMetrics.densityDpi = targetDensityDpi;
//下面賦值到activity中的density中
final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
activityDisplayMetrics.density = targetDensity;
activityDisplayMetrics.scaledDensity = targetScaledDensity;
activityDisplayMetrics.densityDpi = targetDensityDpi;
}
使用如下:
public class BaseDensityActivity extends Activity {
/**
* px = density * dp;
* density = dpi / 160;
* px = dp * (dpi / 160);
* @param savedInstanceState
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyDensityUtil.setCustomDensity(this,getApplication());
setContentView(R.layout.activity_main);
}
}
代碼比較簡單下隧,而且最重要的,這些都是公開的可操作的api淆院,而并非是通過反射,hook去操作了系統(tǒng)非公開的私有api土辩,是穩(wěn)定,低入侵的方案拷淘。