Android獲取View的寬高與View.measure詳解
在oncreate()中無論利用view.getWidth()或是view.getHeiht()還是view.getMeasuredHeight或view.getMeasuredWidth()來獲取view的寬和高,看似沒有問題,其實他們取得值是0,並不是你想要的結果。這是因為每個佈局都要經過如下三個步驟:
測量:onMeasure 設定自己顯示在螢幕上的寬高
佈局:onLayout 設定自己顯示在螢幕上的位置(只有在自定義ViewGroup中才用到)
繪製:onDraw 控制顯示在螢幕上的樣子(viewgroup沒有這個過程)
如上的步驟是非同步進行的,在oncreate()中介面處於不可見狀態,記憶體載入元件還沒有繪製出來,所以是無法獲取他的尺寸。
那如何在繪製元件之前能獲取到該元件的尺寸大小呢?
方法一(最常用的方法):
//手動呼叫測量方法。
//制定測量規則 引數表示size + mode
int width =View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
int height =View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
view.measure(width,height);
//呼叫measure方法之後就可以獲取寬高。
int height=view.getMeasuredHeight();
int width=view.getMeasuredWidth();
方法二(設定樹樁結構監聽器):
ViewTreeObserver vto =view.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
@Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int height =view.getMeasuredHeight();
int width =view.getMeasuredWidth();
}
});
方法三(增加元件繪製之前的監聽):
ViewTreeObserver vto =view.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
int height =view.getMeasuredHeight();
int width =view.getMeasuredWidth();
}
});
詳解View.measure:
measure()方法是實際測量的方法,而在繪製佈局過程中呼叫的onMeasure()只是制定測量規則.
在自定義佈局中我們一般重寫onMeasure()方法,measure()方法是final的,子類無法重寫。
看到measure函式有2個引數,int widthMeasureSpec 和 int heightMeasureSpec表示具體的測量規則。
這兩個數值不是普通的數值, 它表示: size + mode
例如:
int widthMeasureSpec= View.MeasureSpec.makeMeasureSpec(1000,View.MeasureSpec.EXACTLY);
int heightMeasureSpec= View.MeasureSpec.makeMeasureSpec(1000,View.MeasureSpec.AT_MOST);
模式分為:
View.MeasureSpec.EXACTLY:表示父檢視希望子類的大小是specSize中制定的大小.
View.MeasureSpec.AT_MOST:父試圖希望子類的大小最高不超過specSize中制定的大小.
View.MeasureSpec.UNSPECIFIED:父試圖不對子類實施任何限制,子試圖可以得到自己想得到的任意大小.
需求:
在TextView中通過程式碼呼叫setText()動態的設定文字,要求在設定文字之後獲取其寬高.
TextView的佈局方式為width:match_parent height:wrap_content
int width=textView.getMeasuredWidth(); // 開始寬度
textView.getLayoutParams().height= ViewGroup.LayoutParams.WRAP_CONTENT;// 高度包裹內容
int widthMeasureSpec=View.MeasureSpec.makeMeasureSpec(width,View.MeasureSpec.EXACTLY);
//寬度是match_parent.即是View.MeasureSpec.EXACTLY
int heightMeasureSpec= View.MeasureSpec.makeMeasureSpec(1000,View.MeasureSpec.AT_MOST);
//讓高度最大為1000
textView.measure(widthMeasureSpec, heightMeasureSpec);
return des_content.getMeasuredHeight();
這樣就獲取到Textview的高的,根據文字的多少獲取不同高度。之前很多人可能直接measure(0,0)來測量看,其實就是:
int widthMeasureSpec=View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
int heightMeasureSpec= View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
利於這個方法為ImageView設定寬高比例顯示:
<com.example.view.MyRatioLayout
android:id="@+id/rl_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp" >
<ImageView
android:id="@+id/item_icon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitCenter"
android:src="@drawable/ic_default" />
</com.example.view.MyRatioLayout>
通過一個自定義佈局把ImageView包裹起來:
重寫這個自定義佈局的onMeasure()方法修改其測量規則,讓其款高按一定比例顯示:
int ratio = 2.43
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// widthMeasureSpec 寬度的規則 包含了兩部分 模式 值
int widthMode = MeasureSpec.getMode(widthMeasureSpec); // 模式
int widthSize = MeasureSpec.getSize(widthMeasureSpec);// 寬度大小
int width = widthSize - getPaddingLeft() - getPaddingRight();// 去掉左右兩邊的padding
int heightMode = MeasureSpec.getMode(heightMeasureSpec); // 模式
int heightSize = MeasureSpec.getSize(heightMeasureSpec);// 高度大小
int height = heightSize - getPaddingTop() - getPaddingBottom();// 去掉上下兩邊的padding
//如果width是match_parent
if (widthMode == MeasureSpec.EXACTLY
&& heightMode != MeasureSpec.EXACTLY) {
// 修正一下 高度的值 讓高度=寬度/比例
height = (int) (width / ratio + 0.5f); // 保證4舍五入
} else if (widthMode != MeasureSpec.EXACTLY
&& heightMode == MeasureSpec.EXACTLY) {
// 由於高度是精確的值 ,寬度隨著高度的變化而變化
width = (int) ((height * ratio) + 0.5f);
}
// 重新制作了新的規則
widthMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.EXACTLY,
width + getPaddingLeft() + getPaddingRight());
heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.EXACTLY,
height + getPaddingTop() + getPaddingBottom());
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
相關推薦
android獲取螢幕寬高與獲取控制元件寬高
// 獲取螢幕寬高(方法1) int screenWidth = getWindowManager().getDefaultDisplay().getWidth(); // 螢幕寬(畫素,如:480px) int screenHeight = getWindowManager().getDe
Android獲取View的寬高與View.measure詳解
在oncreate()中無論利用view.getWidth()或是view.getHeiht()還是view.getMeasuredHeight或view.getMeasuredWidth()來獲取view的寬和高,看似沒有問題,其實他們取得值是0,並不是你
Android 獲取layout寬高之前呼叫View.measure(0,0)的原因
private ConstraintLayout constraintLayout; constraintLayout=findViewById(R.id.screen_test); constraintLayout.measure(0,0); Log.i(TAG,"onCreate:"+const
Android獲取螢幕寬高,狀態列寬高,actionbar寬高,layout寬高,導航欄高度的方法彙總
看這個部落格你可以知道 獲取螢幕寬高,狀態列寬高,actionbar寬高,layout寬高,導航欄(虛擬按鍵欄)高度的方法 目錄順序為 程式碼測試的機型 狀態列高度 actionbar高度 螢幕高度 導航欄(虛擬按鍵欄)高度 layout寬高 總
Android獲取裝置寬高,以及狀態列高度
//獲取裝置寬度和高度 DisplayMetrics dm=new DisplayMetrics();WindowManager manager= (WindowManager) this.getSystemService(this.WINDOW_SERVICE);mana
Android 獲取本地儲存路徑的各種方法詳解
Android 中獲取本地儲存路徑,有四個方法, getCacheDir()、getFilesDir()、getExternalFilesDir()、getExternalCacheDir()。 接下來介紹下每個方法的特點以及路徑地址 getCacheDir(
Android——View寬高的設定和多種獲取寬高的方法、layout_grivaty與grivaty的區別
一、設定控制元件寬高 設定Layout_width/height引發的寬高思考 方式一: 結果不符合預期。 執行結果: 方式二: 結果符合預期。 如下圖: Android控制元件寬高的規則: Android下的控制元件預設沒有寬高,是由
android onCreate中獲取view寬高為0的多種解決方法
這個問題大家肯定遇到過不止一次,其實很簡單,解決它也很容易,但是咱們追求的畢竟不是解決它,而是找到幾種方法去解決,並且這麼解決的原理是什麼。 這裡列出4種解決方案: Activity/View#onWindowFocusChanged 這個函式
Android中獲取View寬高方法
Android開發中經常需要獲取控制元件的寬高,比如前不久我在寫一個圖片載入庫時,因為需要對Bitmap進行裁剪就遇到了需要獲取ImageView寬高的問題。 如果稍微瞭解過一下View的繪製過程,就會知道直接在onCreate()等生命週期回撥方法中獲取寬高,獲取到的值是0
android在程式碼中獲取view寬/高為0解決方法
在專案中,我們要在程式碼中獲取view的寬高資訊,有可能就會在onCreat或者onResume方法中去獲取,原因就是view的measure過程與Activity的生命週期不是同步執行的,因此無法保證在onCreat,onResume,onStart時這個vi
Activity正確獲取View寬高
在View的measure完成後,一般可以通過getMeasureWidth/getMeasureWidth方法可以正確的獲取View的寬高,而在特殊情況下,可能需要多次measure才能確定最終的測量寬高,onMeasure無法獲取正確的寬高,但可以在onLayout方法中獲取測量寬高。
Android-View寬高測量研究
前言 平時寫自定義控制元件包括之前寫下拉重新整理庫的時候,有時候都需要預先知道View的寬度或者高度,這樣能夠幫助我們很好地實現效果,但是我們都或多或少知道View的度量和繪製是立刻完成的操作,所以當我初始化一個View之後,是無法立刻拿到它的寬度和高度值的,
獲取View寬高的幾種方式及View和ViewGroup測量的簡單實現
自己指定測量規則 //這裡自己指定寬wrap_content 高100, view = (Button) findViewById(R.id.button1); int widthMeasureSpec = MeasureSpec.makeMeasureS
iOS xib View寬高不能改變
table 單獨 ios 寬高 p s none post url htm IOS - xib(Interface Builder,view) - can‘t change view size(view不能改變大小問題) 今天在試著swift語言寫個demo,,當
測量 View 寬高,測到的數值是 px值,然後轉為 dp
實現效果:(button點選後,吐司彈出寬高) 主程式碼 final ViewTreeObserver vto =view.getViewTreeObserver(); vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawLi
菜鳥學android——獲取listview某個item的view物件
網上查了查,發現這個問題很冷門,可現在又有這個需求,而且不是從OnItemClickListener中呼叫,只好自己摸索一下了。 首先說,listview有個getChildAt(int position)的方法,但是這個方法只計算可視的item,也就是說position
Android螢幕適配3-動態獲取螢幕寬高及動態設定控制元件寬高
1、問題 在螢幕適配中,要求應用在不同的螢幕上顯示一樣的效果時,我們的佈局可以採用百分比來定位,也就是 layout_weight,但對於一些層層巢狀或更加複雜的情況下,使用百分比的效果並不是很好,頁無法解決一些問題,比如文字大小。 2、解決思路 我們
Android中自定義樣式與View的建構函式中的第三個引數defStyle的意義
零、序 零、序 系統自帶的View可以在xml中配置屬性,對於寫的好的Custom View同樣可以在xml中配置屬性,為了使自定義的View的屬性可以在xml中配置,需要以下4個步驟: 通過<declare-styleable>為自定
Android獲取螢幕寬和高
WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics dm = new DisplayMetrics(); wm.getDefault
android 開發 View _14 MotionEvent和事件處理詳解,與實踐自定義滑動條View
MotionEvent MotionEvent物件是與使用者觸控相關的時間序列,該序列從使用者首次觸控式螢幕幕開始,經歷手指在螢幕表面的任何移動,直到手指離開螢幕時結束。手指的初次觸控(ACTION_DOWN操作),滑動(ACTION_MOVE操作)和擡起(ACTION