Android 获取View的高度和宽度

来源:互联网 发布:磁力解析在线播放软件 编辑:程序博客网 时间:2024/05/17 04:48

View宽高值为什么是0

如果我们想获取View的高度和宽度,通过在onCreate()或者onStart()或者onResume()等生命周期中直接获取,像下面这样处理会获取到View的高度吗?

package com.wjj.imagepull;import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.widget.ScrollView;import android.widget.TextView;public class MainActivity extends Activity{    ScrollView scrollView;    public static final String TAG = "VIEW_PARAM";    @Override    protected void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        scrollView = (ScrollView) findViewById(R.id.scroll_view);        getHeightAndWidth("onCreate()");    }    private void getHeightAndWidth(String method)    {        int height = 0;        int width = 0;        if (scrollView != null)        {            height = scrollView.getHeight();            width = scrollView.getWidth();        }        Log.i(MainActivity.TAG, method + " has been called: " + System.currentTimeMillis() + " height: " + height + " width: " + width);    }    @Override    protected void onStart()    {        super.onStart();        getHeightAndWidth("onStart()");    }    @Override    protected void onResume()    {        super.onResume();        getHeightAndWidth("onResume()");    }    @Override    public boolean onCreateOptionsMenu(Menu menu)    {        // Inflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.menu_main, menu);        return true;    }    @Override    public boolean onOptionsItemSelected(MenuItem item)    {        // Handle action bar item clicks here. The action bar will        // automatically handle clicks on the Home/Up button, so long        // as you specify a parent activity in AndroidManifest.xml.        int id = item.getItemId();        //noinspection SimplifiableIfStatement        if (id == R.id.action_settings)        {            return true;        }        return super.onOptionsItemSelected(item);    }}

接下来在自定义的组件PullScrollView中适当的方法中加入一些测试log:

public class PullScrollView extends ScrollView{    View view;    int sacTopMargin;    float lastY;    float offsetY;    public PullScrollView(Context context, AttributeSet attrs)    {        super(context, attrs);     }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)    {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        Log.i(MainActivity.TAG, "onMeasure() has been called: " + System.currentTimeMillis());    }    @Override    protected void onDraw(Canvas canvas)    {        super.onDraw(canvas);        Log.i(MainActivity.TAG, "onDraw() has been called: " + System.currentTimeMillis());    }    ...}

然后运行后看一下Log
此处输入图片的描述

通过上面的方法,显然不能获取到View的高度和宽度,关于为什么获取不到View的这些参数值,原因很简单,因为当前Activity中持有的WindowPhone实例还尚未将View添加到DecorView上来,所以无法获取View的高度和宽度,一般在onResume生命周期过后300ms左右时间才会将需要显示的View添加到DecorView上去,代码像下面这样处理:

如何获取View宽高值

@Overrideprotected void onResume(){    super.onResume();    getHeightAndWidth("onResume()");    scrollView.postDelayed(new Runnable()    {        @Override        public void run()        {            getHeightAndWidth("onResume()_postDelayed()");        }    }, 300);}

此处输入图片的描述
这样就获取了View的宽高值,当然这个方法不太保险,因为你不能确保在onResume之后300ms 就能将View添加到DecorView中去,那么保险的方式是什么呢?相信读过Android源代码的同学对ViewTreeObserver.OnGlobalLayoutListener并不陌生,当一个view的布局加载完成或者布局发生改变时OnGlobalLayoutListener可以监听到,利用这点我们可以在布局加载完成的瞬间获得一个view的宽高。

public class PullScrollView extends ScrollView implements ViewTreeObserver.OnGlobalLayoutListener{    public PullScrollView(Context context, AttributeSet attrs)    {        super(context, attrs);        ViewTreeObserver observer = getViewTreeObserver();        if (null != observer)            observer.addOnGlobalLayoutListener(this);    }    @Override    public void onGlobalLayout()    {        MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();        sacTopMargin = -params.topMargin;        Log.d(MainActivity.TAG, "" + sacTopMargin);        getViewTreeObserver()                .removeGlobalOnLayoutListener(this);    }    ...}

OnGlobalLayoutListener的onGlobalLayout被回调之前是没有值的。由于布局状态可能会发生多次改变,因此OnGlobalLayoutListener的onGlobalLayout可能被回调多次,所以我们在 第一次获得值之后就将listener注销掉

当然关于如何获取View的高度和宽度值,还有很多方法,这里仅仅测试了两种比较靠谱的方法,感兴趣的同学可以继续深究。

0 0