前提
平時xml中view的寬高單位都是dp居多,我們的設計師一般會選擇一款機型的屏幕尺寸作爲設計的目標尺寸。
那麼,如何根據目標尺寸的屏幕密度,適配我們種類繁多的機型?
實現目標
將以dp作爲單位,以目標尺寸標註的寬高,和當前機型的比例,動態進行屏幕適配。
例如:設計尺寸爲360dp寬,我們的view設置180dp寬。那麼,該view在任何屏幕尺寸下,都將佔用屏幕一半的尺寸;
瞭解參數
在上代碼前,先了解下待會用到的參數含義:
- density
當前機型的屏幕密度,標準屏幕密度是每平方英寸有160個像素,如果當前機型每平方英寸有320個像素,即density = (320 / 160)= 2; - scaleDensity
代表的是字體的屏幕密度,默認情況下:scaleDensity = density; - densityDpi
表示的就是每平方英寸顯示的像素點個數。
如:160個像素點 即densityDpi=160;
上代碼
代碼其實非常簡單,直接從DisplayMetrics中獲取。
private final static float WIDTH = 360;//適配機型的寬爲360dp,屏幕寬/屏幕密度=360dp
private static float appDensity;
private static float appScaleDensity;
public static void setDensity(Application application, Activity activity) {
//獲取當前app的屏幕顯示信息
DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();
appDensity = displayMetrics.density;
appScaleDensity = displayMetrics.scaledDensity;
//計算等比縮放後的density和scaleDensity
//WIDTH相對於所有屏幕寬度都是相等的,它是用dp作爲單位,所以 屏幕寬度/屏幕密度=WIDTH
//targetDensity = targetWidht/WIDTH
float targetDensity = displayMetrics.widthPixels / WIDTH;
//appScaleDensity/appDensity=targetScaleDensity/targetDensity;
float targetScaleDensity = targetDensity * (appScaleDensity / appDensity);
int targetDensityDpi = (int) (targetDensity * 160);
//替換activity的density,appdensity,densityDpi
DisplayMetrics aDisplayMertics = activity.getResources().getDisplayMetrics();
aDisplayMertics.density = targetDensity;
aDisplayMertics.scaledDensity = targetScaleDensity;
aDisplayMertics.densityDpi = targetDensityDpi;
}
}
思路講解,計算
首先我們需要獲取當前機型的屏幕密度信息:appDensity,appScaleDensity
我們的設計尺寸會根據默認機型計算出一個固定的以dp爲單位的寬度:WIDTH
比如:默認機型的寬高爲1080*1920,該設備的屏幕密度爲3
那麼WIDTH = 1080/3 = 360dp;因此所有適配機型的寬也就等於360dp。
根據 屏幕寬度 / 屏幕密度=WIDTH公式,現在知道屏幕寬度和WIDTH,也就能求出:屏幕密度=屏幕寬度 / WIDHT;
現在屏幕寬度(dp):targetDensity = displayMetrics.widthPixels / WIDTH 求出。
接下來,就需要求出適配機型的scaleDensity
appScaleDensity / appDensity = targetScaleDensity / targetDensity ;
targetScaleDensity = targetDensity * (appScaleDensity / appDensity) ;
densityDpi = density * 160 ;
最後,把獲取到的數據,設置到activity的displayMetrics中。
計算出來後,我們需要在繪製view之前先設置好
在onCreate中的setContentView之前添加
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//在繪製前設置density
DensityUtils.setDensity(this.application, this)
setContentView(R.layout.activity_screen_adapter2)
}
現在,我們的設計尺寸寬度爲360dp,我們設置view的寬度爲180dp,應該是佔用屏幕一半尺寸。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android”
xmlns:tools=“http://schemas.android.com/tools”
android:layout_width=“match_parent”
android:layout_height=“match_parent”
tools:context=“.screenAdapter2.ScreenAdapter2Activity”>
<TextView
android:id=“@+id/tv1”
android:layout_width=“180dp”
android:layout_height=“180dp”
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:background="#f00" />
<TextView
android:layout_width="180dp"
android:layout_height="180dp"
android:layout_below="@id/tv1"
android:layout_toRightOf="@id/tv1"
android:background="#0f0" />
</RelativeLayout>
顯示效果:
字體的縮放監聽
以上代碼在字體發生改變時,不會根據字體設置相應的發生改變
我們需要監聽字體改變事件,再重新計算scaleDensity;
//完整代碼
public static void setDensity(final Application application, Activity activity) {
//獲取當前app的屏幕顯示信息
DisplayMetrics displayMetrics = application.getResources().getDisplayMetrics();
appDensity = displayMetrics.density;
appScaleDensity = displayMetrics.scaledDensity;
//監聽字體改變,重新獲取scaleDensity
application.registerComponentCallbacks(new ComponentCallbacks() {
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (newConfig != null && newConfig.fontScale > 0) {
appScaleDensity = application.getResources().getDisplayMetrics().scaledDensity;
}
}
@Override
public void onLowMemory() {
}
});
//計算等比縮放後的density和scaleDensity
//WIDTH相對於所有屏幕寬度都是相等的,它是用dp作爲單位,所以 屏幕寬度/屏幕密度=WIDTH
//targetDensity = targetWidht/WIDTH
float targetDensity = displayMetrics.widthPixels / WIDTH;
//appScaleDensity/appDensity=targetScaleDensity/targetDensity;
float targetScaleDensity = targetDensity * (appScaleDensity / appDensity);
int targetDensityDpi = (int) (targetDensity * 160);
//替換activity的density,appdensity,densityDpi
DisplayMetrics aDisplayMertics = activity.getResources().getDisplayMetrics();
aDisplayMertics.density = targetDensity;
aDisplayMertics.scaledDensity = targetScaleDensity;
aDisplayMertics.densityDpi = targetDensityDpi;
}
最後
如果你看到了這裏,覺得文章寫得不錯就給個讚唄!歡迎大家評論討論!如果你覺得那裏值得改進的,請給我留言。一定會認真查詢,修正不足,定期免費分享技術乾貨。感興趣的小夥伴可以點一下關注哦。謝謝!