日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

AutoLayout源码解析(1)

發(fā)布時間:2023/12/10 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 AutoLayout源码解析(1) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

鴻神的AutoLayout堪稱適配終結(jié)者,雖然項目已經(jīng)不再維護,對于一些好的框架和實現(xiàn)原理我們還是有學習意義的!現(xiàn)在讓我們一起來學習AutoLayout的源碼吧!

首先我們應該思考這樣一個問題:對于一個框架如何去學習呢?

難道是下載源碼后,一個類一個類的去看嗎? 這肯定不行,這樣會浪費大量的時間,而且還不一定能很好的理解他

正確的流程應該是從如何去使用入手,然后根據(jù)調(diào)用流程一步一步的去理解,這樣就能很好的理解框架的整個流程了!

現(xiàn)在讓我們來看一下AutoLayout的使用流程:

1、將Autolayout添加到我們的項目依賴中

dependencies {// 其他依賴// ...implementation 'com.zhy:autolayout:1.4.5' }

2、在AndroidManifest.xml標明設(shè)計稿尺寸

<!--ui設(shè)計稿提供的手機尺寸--> <meta-data android:name="design_width" android:value="768"/> <meta-data android:name="design_height" android:value="1280"/>

3、在Application中進行初始化

AutoLayoutConifg.getInstance().useDeviceSize().init(this);

4、讓你的Activity繼承AutoLayoutActivity或者直接在xml使用AutoLinearLayout、AutoRelativeLayout、AutoFrameLayout

首先出現(xiàn)在我們眼前的有AutoLayoutConifg、AutoLayoutActivity、AutoLinearLayout、AutoRelativeLayout、AutoFrameLayout這些類

那我們就按順序分別去看這些類做了那些事情

1、AutoLayoutConifg

首先這是一個單例類

private static AutoLayoutConifg sIntance = new AutoLayoutConifg();private AutoLayoutConifg() { }public static AutoLayoutConifg getInstance() {return sIntance; }

它有這些屬性

// 屏幕的寬度 private int mScreenWidth; // 屏幕的高度 private int mScreenHeight; // 設(shè)計圖的寬度 private int mDesignWidth; // 設(shè)計圖的高度 private int mDesignHeight; // 暫時不知道這個參數(shù)是啥,字面意思是使用設(shè)備大小 private boolean useDeviceSize;

接下來我們來看init里面做了啥

public void init(Context context) {// 通過方法名我們猜想應該是從AndroidManifest讀取MetaData里面的設(shè)計尺寸getMetaData(context);// 這里是獲取實際屏幕的大小,傳入了useDeviceSize屬性???int[] screenSize = ScreenUtils.getScreenSize(context, useDeviceSize);// 給mScreenWidth賦值mScreenWidth = screenSize[0];// 給mScreenHeight賦值mScreenHeight = screenSize[1];L.e(" screenWidth =" + mScreenWidth + " ,screenHeight = " + mScreenHeight); }

接下來我們來看getMetaData方法里的代碼

private void getMetaData(Context context) {PackageManager packageManager = context.getPackageManager();ApplicationInfo applicationInfo;try{applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);if (applicationInfo != null && applicationInfo.metaData != null){// 給mDesignWidth賦值mDesignWidth = (int) applicationInfo.metaData.get(KEY_DESIGN_WIDTH);// 給mDesignHeight賦值mDesignHeight = (int) applicationInfo.metaData.get(KEY_DESIGN_HEIGHT);}} catch (PackageManager.NameNotFoundException e){throw new RuntimeException("you must set " + KEY_DESIGN_WIDTH + " and " + KEY_DESIGN_HEIGHT + " in your manifest file.", e);}L.e(" designWidth =" + mDesignWidth + " , designHeight = " + mDesignHeight); }

這里印證了我們的猜想:這個方法就是從AndroidManifest讀取MetaData里面的設(shè)計尺寸,然后賦值給屬性[mDesignWidth、mDesignHeight]

接下來我們看 ScreenUtils.getScreenSize(context, useDeviceSize)方法是如何獲取真實的屏幕大小,順便確定useDeviceSize屬性的意思

??? ????? int[] size = new int[2];// 這部分的代碼是獲取屏幕寬高的代碼,有多種寫法,寫法也比較固定WindowManager w = (WindowManager) ????????context.getSystemService(Context.WINDOW_SERVICE);Display d = w.getDefaultDisplay();DisplayMetrics metrics = new DisplayMetrics();d.getMetrics(metrics);int widthPixels = metrics.widthPixels;int heightPixels = metrics.heightPixels;// since SDK_INT = 1;if (!useDeviceSize){size[0] = widthPixels;size[1] = heightPixels - getStatusBarHeight(context);return size;}

我們看紅色注釋部分,可以看到從SDK1開始,只有useDeviceSize為false才會走進來

?????? ??// includes window decorations (statusbar bar/menu bar)if (Build.VERSION.SDK_INT >= 14 && Build.VERSION.SDK_INT < 17)try{widthPixels = (Integer) Display.class.getMethod("getRawWidth").invoke(d);heightPixels = (Integer) Display.class.getMethod("getRawHeight").invoke(d);} catch (Exception ignored){}// includes window decorations (statusbar bar/menu bar)if (Build.VERSION.SDK_INT >= 17)try{Point realSize = new Point();Display.class.getMethod("getRealSize", Point.class).invoke(d,realSize);widthPixels = realSize.x;heightPixels = realSize.y;} catch (Exception ignored){}size[0] = widthPixels;size[1] = heightPixels;return size;

可以看到接下來部分的代碼都不同版本的適配代碼,所以我們可以這樣理解useDeviceSize:根據(jù)版本來適配獲取屏幕真實寬高的,所以當我們項目的最低版本大于等于14時,應該在Application里面去將useDeviceSize配置為true。因為現(xiàn)在構(gòu)建工程的最低版本基本都是19或21了,所以應該將useDeviceSize設(shè)置為true。

那么如果我們不設(shè)置會出現(xiàn)什么問題呢?

通過DisplayMetrics獲取到的heightPixels的值在高版本中是已經(jīng)減去了狀態(tài)欄高度的,而代碼里面又減了一次狀態(tài)欄高度,會導致減去了2次狀態(tài)欄的高度,從而導致適配的縮放比例存在誤差

其實看完這個類如果我們善于思考的話,已經(jīng)能夠猜到它的大致原理了

比如設(shè)計圖上有一個384px*640px的View,設(shè)計圖是768x1280,我們的手機分辨率是1440x3168,所以:

mScreenWidth = 1440; mScreenHeight = 3168; mDesignWidth = 768; mDesignHeight = 1280;

可以看到設(shè)計圖上這個View占用了屏幕的4分之1,我們要在1440x3168的屏幕上也顯示4分之1,怎么辦呢?

我們用1440*384/760 = 720,3168*640/1280 = 1584,所以我們想要在1440x3168的屏幕上顯示相同的效果這個控件的大小應該是720px*1584px,目前大致能想到是就這么多了,接下來我們繼續(xù)看源碼是如何實現(xiàn)的!

總結(jié)

以上是生活随笔為你收集整理的AutoLayout源码解析(1)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。