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的观察者,在绘制控件前的一刹那进行回调,这样速度上又不耽误,得到的数据由是准确的。

引用自:http://it.warmtel.com/?p=813

方法一:

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的宽高了

时间: 2024-11-03 21:09:02

android获取控件宽高和屏幕宽高的相关文章

android获取屏幕宽高与获取控件宽高

获取屏幕宽高 // 获取屏幕宽高(方法1) int screenWidth = getWindowManager().getDefaultDisplay().getWidth(); // 屏幕宽(像素,如:480px) int screenHeight = getWindowManager().getDefaultDisplay().getHeight(); // 屏幕高(像素,如:800p) Log.e(TAG + " getDefaultDisplay", "screen

android 获取屏幕宽高 和 获取控件坐标

一.获取屏幕宽高: (1). WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE); int width = wm.getDefaultDisplay().getWidth(); int height = wm.getDefaultDisplay().getHeight(); (2). WindowManager wm = this.getWindowManager(); int width = wm

【Android】获取控件的宽和高

有时候我们须要在Activity的时候获取控件的宽和高来做一些操作,以下介绍三种获取宽和高的方式: 1. onWindowFocusChanged @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { int width = image.getMeasuredWidth(); int height = image.ge

uwp - 获取控件的宽高

在wpf可以通过控件.Width/Height来获取宽高,来到uwp上却没效果,在微软的开发人员中心找到了答案. 所以,我们要在后台获取控件的宽高应该是:控件.ActualHeight/ActualWidth.

获取控件的高和宽

问题 如何获取一个控件的长和高,相信很多朋友第一眼看见这个问题都会觉得很简单,直接在onCreate里面调用getWidth.getMeasuredWidth不就可以获得了吗,但是,事实上是并没有简单的,不信的话,你可以去试一下,在onCreate里面,你是无法获得长宽值的,始终为0. 原因 这是为什么呢,其实熟悉view绘制流程的朋友应该一眼就看出来了,在onCreate中,我们的控件其实还并没有画好,换句话说,等onCreate方法执行完了,我们定义的控件才会被度量(measure),所以我

Android得到控件在屏幕中的坐标

getLocationOnScreen ,计算该视图在全局坐标系中的x,y值,(注意这个值是要从屏幕顶端算起,也就是索包括了通知栏的高度)//获取在当前屏幕内的绝对坐标 getLocationInWindow ,计算该视图在它所在的widnow的坐标x,y值,//获取在整个窗口内的绝对坐标 (不是很理解= =.) getLeft , getTop, getBottom, getRight, 这一组是获取相对在它父亲里的坐标 如果在Activity的OnCreate()事件输出那些参数,是全为0,

Android学习Scroller(三)——控件平移划过屏幕 (Scroller简单使用)

MainActivity如下: package cc.cn; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.app.Activity; /** * Demo描述: * Scroller使用示例--让控件平移划过屏幕 * * 参考资料: * http://blog.cs

js获取浏览器宽高、网页宽高、屏幕宽高、鼠标位置等(带图片说明)

网页可见区域宽: document.body.clientWidth;网页可见区域高: document.body.clientHeight;(点击查看大图) 网页可见区域宽: document.body.offsetWidth (包括边线的宽);网页可见区域高: document.body.offsetHeight (包括边线的宽);(点击查看大图)有没有发现,offsetWidth和clientWidth的区别,offsetWidt是连滚动条一起包含在内的. 网页正文全文宽: documen

android 下动态获取控件的id

有时候我们需要动态的取得一个一个控件的id,然后进行操作,经过在网上查找,找到了一下方法getResources().getIdentifier("textView01", "id", "cn.xxx.xxx"); 第一个参数为ID名,第二个为资源属性是ID或者是Drawable,第三个为包名. 以下是从网上找到资料:主要由两种方法,个人建议第二种. 1. 不把图片放在res/drawable下,而是存放在src某个package中(如:com.