Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android獲取控件寬高和屏幕寬高

android獲取控件寬高和屏幕寬高

編輯:關於Android編程

一、獲取屏幕寬高

1、android界面簡單介紹

要獲取屏幕寬高,我們可以先從android的界面構成了解

 

android的界面主要由三部分構成:1、狀態欄 2、標題欄 3、內容區域

\\

 

(1)狀態欄

狀態欄主要用來顯示一些系統圖標,應用的通知圖標和系統時間。

(2)標題欄

android中標題欄主要用來顯示當前位置,3.0過後添加了ActionBar,擁有了導航和OptionMenu的功能,5.0又新添加了ToolBar控件,和ActionBar類似,但自定義的空間更充足

(3)內容區域

android中的內容區域,實際上是一塊系統默認的名為android.id.content的單幀布局,setContentView()方法相當於添加View到這個單幀布局中,並覆蓋。

 


2、獲取屏幕寬高

 

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DisplayMetrics dm = new DisplayMetrics();
        // 獲取屏幕信息
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        int screenWidth = dm.widthPixels;
        int screenHeigh = dm.heightPixels;
        Log.v("獲取屏幕寬度", "寬度:" + screenWidth + ",高度:" + screenHeigh);
    }

獲取到的屏幕寬高打印出來

 

\

二、獲取控件寬高

控件View有getHeight()和getwidth()方法可以獲取寬高,但是如果直接在onCreate()方法中獲取控件寬高,獲取到的值是0,至於原因的是因為onCreate()方法中只是提供了數據初始化此時還沒有正式繪制圖形。而繪制圖形在OnDraw中進行,此時計算又顯得太晚。容易想到的辦法是:希望能在程序剛剛測量好某個指定控件後,拿到它的寬度和高度立刻進行計算或數據初始化。這就需要有一個方法來監聽到這個事件的發生,幸好Android提供了這樣的機制,利用View類中的getViewTreeObserver方法,可以獲取到指定View的觀察者,在繪制控件前的一剎那進行回調,這樣速度上又不耽誤,得到的數據由是准確的。

 

方法一:

 

public class MainActivity extends AppCompatActivity {
    TextView firstTxt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        firstTxt = (TextView) findViewById(R.id.hello_word_txt);
        ViewTreeObserver viewTreeObserver = firstTxt.getViewTreeObserver();
        viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                int height = firstTxt.getHeight();
                int width = firstTxt.getWidth();
                Log.v("獲取TextView寬高", "寬度:" + width + ",高度:" + height);
                return true;
            }
        });

    }
}

獲取到的寬高打印顯示:

 

\

 

方法二:

關於方法二,下面有一段我自己的簡單理解

 

將一個runnable添加到Layout隊列中:View.post()
簡單地說,只要用View.post()一個runnable就可以了。runnable對象中的方法會在View的measure、layout等事件後觸發UI事件隊列會按順序處理事件。在setContentView()被調用後,事件隊列中會包含一個要求重新layout的message,所以任何你post到隊列中的東西都會在Layout發生變化後執行。
 

 firstTxt.post(new Runnable() {
            @Override
            public void run() {
                firstTxt.getHeight(); //height is ready
                firstTxt.getWidth();
            }
        }

關於方法二的一些理解

 

上面提到過繪制控件是在ondraw()方法中進行,在ondraw中獲取控件寬高則太晚,而在onMeasure()中測量又太早。那我們嘗試在onLayout()中獲取控件寬高是否可行。 onLayout()和ondraw()都是控件View生命周期中的回調方法。至於View的生命周期,我也還沒接觸過,等後面深入學習了再總結一下。

 

首先新建一個類繼承自TextView,然後重寫裡面的onLayout()和onMeasure()方法

 

public class MyTextView extends TextView {

 public MyTextView(Context context) {
        super(context);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public MyTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public MyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    //===========上面為繼承TextView默認的實現方法,我們可以不管
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		//獲取MyTextView當前實例的高
        int height = this.getHeight();
		//獲取MyTextView當前實例的寬
        int width = this.getWidth();
		
		//通過Log.v打印輸出顯示
        Log.v("onMeasure獲取控件寬高", "高:" + height + ",寬:" + width);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
		//獲取MyTextView當前實例的高
        int height = this.getHeight();
		//獲取MyTextView當前實例的寬
        int width = this.getWidth();

		//通過Log.v打印輸出顯示
        Log.v("onLayout獲取控件寬高", "高:" + height + ",寬:" + width);
    }
	
}


 


再在程序入口的Acitvity中的onCreate()方法中實例化自定義的MyTextView

 

public class MainActivity extends AppCompatActivity {
    MyTextView mMyTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mMyTextView = (MyTextView) findViewById(R.id.mytextview_txt);
    }
}

運行打印顯示:

 

\

 

從上面可以看出MyTextView第一次回調onMeasure()方法時,還沒有獲取到控件的寬高數據。上面提到過"如果直接在onCreate()方法中獲取控件寬高,獲取到的值是0",那我們可以假設一下activity的onCreate()方法執行時在View執行第一次onMeasure()方法之前,我們嘗試通過以下方法看能否驗證這一假設

 

首先在上面新建的MyTextView中添加兩個我們自定義的方法,一個是setMyTextViewSize(),另外一個是getMyTextViewSize(),代碼如下:

 

public class MyTextView extends TextView {
    int mMyTextViewHeight;
    int mMyTextViewWidth;

    public MyTextView(Context context) {
        super(context);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public MyTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public MyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    //===========上面為繼承TextView默認的實現方法,我們可以不管

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //獲取MyTextView當前實例的高
        int height = this.getHeight();
        //獲取MyTextView當前實例的寬
        int width = this.getWidth();

        //調用setMyTextViewSize,使其他類可以通過getMyTextViewSize()可以獲取到
        //mMyTextViewHeight和mMyTextViewWidth變量的值,即高和寬
        setMyTextViewSize(height, width);
        
        //通過Log.v打印輸出顯示
        Log.v("onMeasure獲取控件寬高", "高:" + height + ",寬:" + width);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        //獲取MyTextView當前實例的高
        int height = this.getHeight();
        //獲取MyTextView當前實例的寬
        int width = this.getWidth();
        //與上同理
        setMyTextViewSize(height, width);
        
        //通過Log.v打印輸出顯示
        Log.v("onLayout獲取控件寬高", "高:" + height + ",寬:" + width);
    }

    public void setMyTextViewSize(int height, int width) {
        mMyTextViewHeight = height;
        mMyTextViewWidth = width;
    }

    public int[] getMyTextViewSize() {
        int[] viewSize = new int[]{mMyTextViewHeight, mMyTextViewWidth};
        return viewSize;

    }
}

 

再在程序入口的Acitvity的onCreate()方法中上面已經實例化得到的MyTextView的getMyTextViewsize()方法嘗試獲取控件寬高

 

public class MainActivity extends AppCompatActivity {
    MyTextView mMyTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mMyTextView = (MyTextView) findViewById(R.id.mytextview_txt);
        int[] myTextViewSize = mMyTextView.getMyTextViewSize();
        Log.v("入口acitivity的onCreate獲取控件寬高", "高:" + myTextViewSize[0] + ",寬:" + myTextViewSize[1]);
    }
}
運行打印輸出顯示:

 

\

通過上圖可以發現Acitivity的onCreate()方法執行時機是在View的第一次回調onMeasure()之前,View第一次回調onMeasure()方法的時候還沒有獲取到寬高,自然Acitivity的onCreate()方法中也無法獲取到控件寬高。那麼,通過上面的打印信息,我們可以設想如果在onLayout()方法已經獲取到View的寬高時,Activity的onCreate()再獲取寬高就行了。我想到的一種思路是在Acitivity的onCreate()方法循環調用MyTextView的onLayout()方法,但是我們直到在android的主線程也就是UI線程中執行死循環會導致頁面無法顯示,那麼我們應該在onCreate()方法中開辟一條子線程 ,方法循環調用MyTextView的onLayout()方法,直到獲取到寬高。要實現這個思路的話,我們可以用到Handler。

 

下面是具體的代碼實現:

 

public class MainActivity extends AppCompatActivity {
    MyTextView mMyTextView;
    //使用Handler默認的無參構造方法時,Handler執行的線程即聲明Handler的線程,在這裡是在主線程,也就是UI線程中
    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Log.v("Handler獲取控件寬高", "高:" + msg.arg1 + ",寬:" + msg.arg2);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mMyTextView = (MyTextView) findViewById(R.id.mytextview_txt);
        new Thread(new Runnable() {
            @Override
            public void run() {
                int[] viewSize = mMyTextView.getMyTextViewSize();
                Log.v("onCreate()獲取控件寬高", "高:" + viewSize[0] + ",寬:" + viewSize[1]);
                while (viewSize[0] == 0) {
                    viewSize = mMyTextView.getMyTextViewSize();
                    if (viewSize[0] != 0) {
                        Message msg = Message.obtain();
                        msg.arg1 = viewSize[0];
                        msg.arg2 = viewSize[1];
                        mHandler.sendMessage(msg);
                    }
                }
            }
        }).start();
    }
}

運行打印輸出顯示:

 

\

通過上面的方法我們就可以在onCreate()方法中獲取View的寬高了

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved