每日一問:LayoutParams 你知道多少?

前面的文章中著重講解了 View 的測量流程。其中我提到了一句非常重要的話:**View 的測量匡高是由父控件的 MeasureSpec 和 View 自身的 `LayoutParams 共同決定的。**我們在前面的 每日一問:談談對 MeasureSpec 的理解 把 MeasureSpec 的重點進行了講解,其實另外一個 LayoutParams 同樣是非常非常重要。

從概念講起

LayoutParams,顧名思義,就是布局參數。而且大多數人對此都是司空見慣,我們 XML 文件里面的每一個 View 都會接觸到 layout_xxx 這樣的屬性,這實際上就是對布局參數的描述。大概大家也就清楚了,layout_ 這樣開頭的東西都不屬于 View,而是控制具體顯示在哪里。

LayoutParams 都有哪些初始化方法

通常來說,我們都會把我們的控件放在 XML 文件中,即使我們有時候需要對屏幕做比較「取巧」的適配,會直接通過 View.getLayoutParams() 這樣的方法獲取 LayoutParams 的實例,但我們接觸的少并不代表它的初始化方法不重要。

實際上,用代碼寫出來的 View 加載效率要比在 XML 中加載快上大約 1 倍。只是在如今手機配置都比較高的情況下,我們常常忽略了這種方式。

我們來看看 ViewGroup.LayoutParams 到底有哪些構造方法。

public LayoutParams(Context c, AttributeSet attrs) {TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);setBaseAttributes(a,R.styleable.ViewGroup_Layout_layout_width,R.styleable.ViewGroup_Layout_layout_height);a.recycle();
}public LayoutParams(int width, int height) {this.width = width;this.height = height;
}public LayoutParams(LayoutParams source) {this.width = source.width;this.height = source.height;
}LayoutParams() {  }
復制代碼

MarginLayoutParams

除去最后一個放給 MarginLayoutParams 做處理的方法外,我們在 ViewGroup 中還有 3 個構造方法。他們分別負責給 XML 處理、直接讓用戶指定寬高、還有類似集合的 addAll() 這樣的方式的賦值方法。

實際上,ViewGroup 的子類的 LayoutParams 類擁有更多的構造方法,感興趣的自己翻閱源碼查看。在這里我想更加強調一下我上面提到的 MarginLayoutParams

MarginLayoutParams 繼承于 ViewGroup.LayoutParams

public static class MarginLayoutParams extends ViewGroup.LayoutParams {@ViewDebug.ExportedProperty(category = "layout")public int leftMargin;@ViewDebug.ExportedProperty(category = "layout")public int topMargin;@ViewDebug.ExportedProperty(category = "layout")public int rightMargin;@ViewDebug.ExportedProperty(category = "layout")public int bottomMargin;@ViewDebug.ExportedProperty(category = "layout")private int startMargin = DEFAULT_MARGIN_RELATIVE;@ViewDebug.ExportedProperty(category = "layout")private int endMargin = DEFAULT_MARGIN_RELATIVE;public MarginLayoutParams(Context c, AttributeSet attrs) {super();TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);setBaseAttributes(a,R.styleable.ViewGroup_MarginLayout_layout_width,R.styleable.ViewGroup_MarginLayout_layout_height);int margin = a.getDimensionPixelSize(com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);if (margin >= 0) {leftMargin = margin;topMargin = margin;rightMargin= margin;bottomMargin = margin;} else {int horizontalMargin = a.getDimensionPixelSize(R.styleable.ViewGroup_MarginLayout_layout_marginHorizontal, -1);// ... something}// ... something}
}
復制代碼

一看代碼,自然就清楚了,為什么我們以前會發現在 XML 布局里, layout_margin 屬性的值會覆蓋 layout_marginLeftlayout_marginRight 等屬性的值。

實際上,事實上,絕大部分容器控件都是直接繼承 ViewGroup.MarginLayoutParams 而非 ViewGroup.LayoutParams。所以我們再自定義 LayoutParams 的時候記得繼承 ViewGroup.MarginLayoutParams

在代碼里面使用 LayoutParams

前面介紹了 LayoutParams 的幾種構造方法,我們下面以 LinearLayout.LayoutParams 來看看幾種簡單的使用方式。

val textView1 = TextView(this)
textView1.text = "不指定 LayoutParams"
layout.addView(textView1)val textView2 = TextView(this)
textView2.text = "手動指定 LayoutParams"
textView2.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
layout.addView(textView2)val textView3 = TextView(this)
textView3.text = "手動傳遞 LayoutParams"
textView3.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams(100, 100))
layout.addView(textView3)
復制代碼

我們看看 addView() 都做了什么。

public void addView(View child) {addView(child, -1);
}public void addView(View child, int index) {if (child == null) {throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");}LayoutParams params = child.getLayoutParams();if (params == null) {params = generateDefaultLayoutParams();if (params == null) {throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");}}addView(child, index, params);
}@Override
protected LayoutParams generateDefaultLayoutParams() {if (mOrientation == HORIZONTAL) {return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);} else if (mOrientation == VERTICAL) {return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);}return null;
}public void addView(View child, int index, LayoutParams params) {if (DBG) {System.out.println(this + " addView");}if (child == null) {throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");}requestLayout();invalidate(true);addViewInner(child, index, params, false);
}private void addViewInner(View child, int index, LayoutParams params,boolean preventRequestLayout) {// ...if (!checkLayoutParams(params)) {params = generateLayoutParams(params);}// ...
}@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {return p instanceof LinearLayout.LayoutParams;
}
復制代碼

看起來 ViewGroup 真是煞費苦心,如果我們沒有給 View 設置 LayoutParams,則系統會幫我們根據 orientation 設置默認的 LayoutParams。甚至是我們即使在 addView() 之前設置了錯誤的 LayoutParams 值,系統也會我們幫我們進行糾正。

雖然系統已經做的足夠完善,幫我們各種矯正錯誤,但在 addView() 之后,我們還強行設置錯誤的 LayoutParams,那還是一定會報 ClassCastException 的。

LayoutParams 很重要,每一名 Android 開發都應該盡力地去掌握,只有弄清楚了系統的編寫方式,應對上面類似簡書的流式布局才能更好處理。

實際上 Google 出的 FlexboxLayout 已經做的相當完美。 當然如果使用的 RecyclerView,還可以自己寫一個 FlowLayoutManager 進行處理。

原文較多地參考自:blog.csdn.net/yisizhu/art…

轉載于:https://juejin.im/post/5d00f3a6f265da1bb003b7f8

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/387600.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/387600.shtml
英文地址,請注明出處:http://en.pswp.cn/news/387600.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

kuangbin專題十六 KMP擴展KMP HDU2594 Simpsons’ Hidden Talents

Homer: Marge, I just figured out a way to discover some of the talents we weren’t aware we had. Marge: Yeah, what is it? Homer: Take me for example. I want to find out if I have a talent in politics, OK? Marge: OK. Homer: So I take some politician’s na…

SNI: 實現多域名虛擬主機的SSL/TLS認證

為什么80%的碼農都做不了架構師?>>> 一. 介紹 早期的SSLv2根據經典的公鑰基礎設施PKI(Public Key Infrastructure)設計,它默認認為:一臺服務器(或者說一個IP)只會提供一個服務,所以在SSL握手時…

echo(),print(),print_r(),var_dump()的區別

echo可以一次輸出多個值,多個值之間用逗號分隔。echo是語言結構(language construct),而并不是真正的函數,因此不能作為表達式的一部分使用。echo是php的內部指令,不是函數,無返回值。 print():函數print()…

我心目中的牛程序員、我們可以對比看看(人家還是看多年朋友面子上才肯幫忙1周,至少需支付1萬元辛苦費)...

為什么80%的碼農都做不了架構師?>>> 最近碰到客戶整個網站改版的需要,非常短的時間里只有1周時間里,需要把整個B2C網站徹底的進行版面,我自己估算了一下,就是往死里干一天工作48個小時,1周也干…

c#做端口轉發程序支持正向連接和反向鏈接

3389的時候 例子1:連接a機器的3389端口連不上,因為對方防火墻或者網關做了限制,只能訪問a機器的個別端口比如80。 例子2:連接a機器的幾乎所有端口都連不上(對方乃內網或者防火墻網關做了限制)&#xff0c…

Spring Boot(十四):spring boot整合shiro-登錄認證和權限管理

Spring Boot(十四):spring boot整合shiro-登錄認證和權限管理 使用Spring Boot集成Apache Shiro。安全應該是互聯網公司的一道生命線,幾乎任何的公司都會涉及到這方面的需求。在Java領域一般有Spring Security、Apache Shiro等安全框架,但是由…

通用權限管理系統組件 (GPM - General Permissions Manager) 不改數據庫、甚至不寫代碼就集成銅墻鐵壁權限管理組件...

為什么80%的碼農都做不了架構師?>>> 越成熟的東西,越牛X的東西,越簡單才對,簡單才是硬道理,蘋果的手機只有少數幾個按鍵,蘋果Ipad也很少的按鈕,甚至連蘋果的筆記本鍵盤都少一排&…

數學符號及讀法大全

數學符號及讀法大全 常用數學輸入符號: ≈ ≡ ≠ = ≤≥ < > ≮ ≯ ∷ + - / ∫ ∮ ∝ ∞ ∧ ∨ ∑ ∏ ∪ ∩ ∈ ∵ ∴ ⊥ ‖ ∠ ⌒ ≌ ∽ √ () 【】&#xff5b…

在使用win 7 無線承載網絡時,啟動該服務時,有時會提示:組或資源的狀態不是執行請求操作的正確狀態。 網上有文章指出,解決這個問題的方法是在設備管理器中啟動“Microsoft托管網絡虛擬適配

在使用win 7 無線承載網絡時,啟動該服務時,有時會提示:組或資源的狀態不是執行請求操作的正確狀態。 網上有文章指出,解決這個問題的方法是在設備管理器中啟動“Microsoft托管網絡虛擬適配器”,見 http://jingyan.baid…

阿里一年,聊聊我成長了什么,入職阿里的職業生涯感悟

2018.5.31~2019.5.31,一段精彩的旅程,渡過了在阿里一年的時光,這段時光有快樂、有焦慮、有迷茫、更有思考,思考的是自己過去的種種不足、思考的是一些現在看來之前錯誤的想法、思考的是如何成為一個更好的技術人,將這一…

偏差-方差分解(轉)

1、定義 這里所說的偏差-方差分解就是一種解釋模型泛化性能的一種工具。它是對模型的期望泛化錯誤率進行拆解。 樣本可能出現噪聲,使得收集到的數據樣本中的有的類別與實際真實類別不相符。對測試樣本 x,另 yd 為 x 在數據集中的標記,y 為真實…

用過C#的朋友可能認為它是一種十分安全的語言,其實C#也可以做到經典的緩沖區溢出。 本文章將用一個實例來描述C#究竟是如何發生緩沖區溢出的! 首先建立一個C# Console工程,并開啟工程的“允許

用過C#的朋友可能認為它是一種十分安全的語言,其實C#也可以做到經典的緩沖區溢出。 本文章將用一個實例來描述C#究竟是如何發生緩沖區溢出的! 首先建立一個C# Console工程,并開啟工程的“允許不安全代碼”選項 鍵入代碼: [csharp]…

COOKIE偽造登錄網站后臺

1.關于XSS(跨站腳本攻擊)和CSRF(跨站請求偽造)的知識,xss表示Cross Site Scripting(跨站腳本攻擊),它與SQL注入攻擊類似,SQL注入攻擊中以SQL語句作為用戶輸入,從而達到查詢/修改/刪除…

Spring Cloud 學習 (五) Zuul

Zuul 作為路由網關組件,在微服務架構中有著非常重要的作用,主要體現在以下 6 個方面: Zuul, Ribbon 以及 Eureka 相結合,可以實現智能路由和負載均衡的功能,Zuul 能夠將請求流量按某種策略分發到集群狀態的多個服務實例…

如何利用445端口進行入侵滲透 445端口入侵原因詳細解析。大家在進行入侵滲透個人電腦的時候,經常會碰到各種各樣的端口,比如135,1433,445,3306等端口,現在小編就給大家講解下445端口如

如何利用445端口進行入侵滲透 445端口入侵原因詳細解析。大家在進行入侵滲透個人電腦的時候,經常會碰到各種各樣的端口,比如135,1433,445,3306等端口,現在小編就給大家講解下445端口如何入侵。 445端口入侵…

項目復盤

前言 最近一年半多一直在做一個CMS項目,做了快兩年了也沒有上線,而且開發還走了不少,其中有不少原因是因為開發中頻繁改動需求導致開發人員失去耐心,但是其中還有一個重要的原因就是架構設計的不好,導致很多服務的邊界…

父、子頁面之間頁面元素的獲取,方法的調用

一、在iframe頁面上調取父級頁面元素 1.在父頁面上獲取iframe頁面元素(在父頁面修改子頁面div的背景色為紅色) js代碼如下&#xff1a; 1 <script type"text/javascript"> 2 window.onload function(){ 3 var iframe document.getElementById(iframeId)…

fiddler,他和其他抓包軟件有什么區別,如何使用fiddler進行抓包

前言&#xff1a;本文章是搭配《批量獲取微信公眾號》一文&#xff0c;介于群里朋友很熱情&#xff0c;我就趁著上班測完bug 來撰寫該文章&#xff0c;那么讀完本文&#xff0c;你會學習到什么呢&#xff1f; 什么是fiddler&#xff0c;他和其他抓包軟件有什么區別&#xff0c…

Vue導入非模塊化的第三方插件功能無效解決方案

一、問題&#xff1a; 最近在寫vue項目時&#xff0c;想引入某些非模塊化的第三方插件時&#xff0c;總是發現會有報錯。且在與本地運行插件測試對比時發現插件根本沒有注入到jQuery中&#xff08;console.log($.fn)查看當前jq有哪些方法&#xff09;&#xff0c;例如&#xff…

ES6筆記 -- 字符串拓展

字符串拓展 Unicode 相關 JS 允許使用/uxxxx的Unicode方式顯示字符, 但是只限于碼點在/u0000~/uFFFF之間, 超過該范圍的碼點必須用雙字節形式表示ES6 中, 將碼點放入大括號內, 就可以解讀JS 不能處理4個字節的字符, 字符串長度會被誤判為2ES6 提供了codePointAt方法, 能夠正確處…