AutoLayout源码解析(1)
鴻神的AutoLayout堪稱適配終結者,雖然項目已經不再維護,對于一些好的框架和實現原理我們還是有學習意義的!現在讓我們一起來學習AutoLayout的源碼吧!
首先我們應該思考這樣一個問題:對于一個框架如何去學習呢?
難道是下載源碼后,一個類一個類的去看嗎? 這肯定不行,這樣會浪費大量的時間,而且還不一定能很好的理解他
正確的流程應該是從如何去使用入手,然后根據調用流程一步一步的去理解,這樣就能很好的理解框架的整個流程了!
現在讓我們來看一下AutoLayout的使用流程:
1、將Autolayout添加到我們的項目依賴中
dependencies {// 其他依賴// ...implementation 'com.zhy:autolayout:1.4.5' }2、在AndroidManifest.xml標明設計稿尺寸
<!--ui設計稿提供的手機尺寸--> <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
首先出現在我們眼前的有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; // 設計圖的寬度 private int mDesignWidth; // 設計圖的高度 private int mDesignHeight; // 暫時不知道這個參數是啥,字面意思是使用設備大小 private boolean useDeviceSize;接下來我們來看init里面做了啥
public void init(Context context) {// 通過方法名我們猜想應該是從AndroidManifest讀取MetaData里面的設計尺寸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里面的設計尺寸,然后賦值給屬性[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:根據版本來適配獲取屏幕真實寬高的,所以當我們項目的最低版本大于等于14時,應該在Application里面去將useDeviceSize配置為true。因為現在構建工程的最低版本基本都是19或21了,所以應該將useDeviceSize設置為true。
那么如果我們不設置會出現什么問題呢?
通過DisplayMetrics獲取到的heightPixels的值在高版本中是已經減去了狀態(tài)欄高度的,而代碼里面又減了一次狀態(tài)欄高度,會導致減去了2次狀態(tài)欄的高度,從而導致適配的縮放比例存在誤差
其實看完這個類如果我們善于思考的話,已經能夠猜到它的大致原理了
比如設計圖上有一個384px*640px的View,設計圖是768x1280,我們的手機分辨率是1440x3168,所以:
mScreenWidth = 1440; mScreenHeight = 3168; mDesignWidth = 768; mDesignHeight = 1280;可以看到設計圖上這個View占用了屏幕的4分之1,我們要在1440x3168的屏幕上也顯示4分之1,怎么辦呢?
我們用1440*384/760 = 720,3168*640/1280 = 1584,所以我們想要在1440x3168的屏幕上顯示相同的效果這個控件的大小應該是720px*1584px,目前大致能想到是就這么多了,接下來我們繼續(xù)看源碼是如何實現的!
總結
以上是生活随笔為你收集整理的AutoLayout源码解析(1)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Visual Studio的调试技巧
- 下一篇: 第一部分 Java:面向对象理解