android中Viewtreeobserver解析

作用:通过名字就可以知道它是View树的观察者,当View树的发生变化的时候会发出通知。ViewTreeObserver是不能被应用程序实例化的,因为它是由视图提供的,通过view.getViewTreeObserver()获取。

熟悉观察者模式的人应该很容易想到,为了能够相应的通知,我们肯定需要注册监听。下面来看看我们可以注册哪些监听。

1、当在一个视图树中的焦点状态或者可见性发生改变时调用OnGlobalFocusChangeListener的onGlobalFocusChanged()函数。

public void addOnGlobalFocusChangeListener (ViewTreeObserver.OnGlobalFocusChangeListener listener)

2、当在一个视图树中的焦点状态或者可见性发生改变时调用OnGlobalFocusChangeListener的onGlobalFocusChanged()函数。

public void addOnGlobalLayoutListener (ViewTreeObserver.OnGlobalLayoutListener listener)

3、当一个视图树将要绘制时调用OnPreDrawListener的onPreDraw()函数

public void addOnPreDrawListener (ViewTreeObserver.OnPreDrawListener listener)

4、当一个视图发生滚动时调用OnScrollChangedListener的onScrollChanged()函数

public void addOnScrollChangedListener (ViewTreeObserver.OnScrollChangedListener listener)  

5、当一个触摸模式发生改变时调用OnTouchModeChangeListener的onTouchModeChanged()函数

public void addOnTouchModeChangeListener (ViewTreeObserver.OnTouchModeChangeListener listener)

6、当一个视图树绘制时调用OnDrawListener的onDraw()函数

addOnDrawListener(ViewTreeObserver.OnDrawListener listener) 

7、当View树绑定到window上的时候回调OnWindowAttachListener的onWindowAttached() 函数,当它从window上解绑时调用OnWindowAttachListener的onWindowDetached()

addOnWindowAttachListener(ViewTreeObserver.OnWindowAttachListener listener) 

8、当window的焦点状态发生改变时,调用OnWindowFocusChangeListener的onWindowFocusChanged函数

addOnWindowFocusChangeListener(ViewTreeObserver.OnWindowFocusChangeListener listener) 

对应这些注册的监听,还有相应的删除监听

public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)

public void removeOnGlobalFocusChangeListener (ViewTreeObserver.OnGlobalFocusChangeListener victim)

public void removeOnPreDrawListener (ViewTreeObserver.OnPreDrawListener victim)

public void removeOnScrollChangedListener (ViewTreeObserver.OnScrollChangedListener victim)

public void removeOnTouchModeChangeListener (ViewTreeObserver.OnTouchModeChangeListener victim)

public void removeOnDrawListener(ViewTreeObserver.OnDrawListener victim) 

public void removeOnWindowAttachListener(ViewTreeObserver.OnWindowAttachListener victim) 

public void removeOnWindowFocusChangeListener(ViewTreeObserver.OnWindowFocusChangeListener victim) 

上面注册的监听都是View树发生变化的时候,会被自动触发回调,如果我们希望手动触发回调,可以调用下面函数

public final void dispatchOnGlobalLayout ()

手动触发OnGlobalLayoutListener的onGlobalLayout()函数回调

public final boolean dispatchOnPreDraw ()

手动触发OnPreDrawListener的onPreDraw()函数的回调

另外还是一个指示当前的ViewTreeObserver是否可用的函数。

public boolean isAlive ()

当observer不可用时,任何方法的调用(除了这个方法)都将抛出一个异常。

应用场景1:获取View的宽高

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final MyImageView myImageView = (MyImageView) findViewById(R.id.imageview);
    int height = 0;
    int width =  0 ;
    ViewTreeObserver vto = myImageView.getViewTreeObserver();
    vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        public boolean onPreDraw() {
            int height = myImageView.getMeasuredHeight();
            int width = myImageView.getMeasuredWidth();
            return true;
        }
    });
}

因为回调OnPreDrawListener的onPreDraw,表示这个View准备进行绘制,在绘制之前,这个View的宽高肯定是已经测量好了,所以这个时机是可以得到view的宽高的。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final MyImageView myImageView = (MyImageView) findViewById(R.id.imageview);
    int height = 0;
    int width =  0 ;

    ViewTreeObserver vto = myImageView.getViewTreeObserver();
    vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            myImageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            int height = myImageView.getHeight();
            int width = myImageView.getWidth();
        }
    }); 
}

当view的可见状态发生变化的时候回调OnGlobalLayoutListener的onGlobalLayout()函数,这个时候View的宽高肯定也是已经测量好了,所以这个时机是可以得到view的宽高的。

应用场景2:Activity跳转动画

ViewTreeObserver还可以用来监听根布局,用来实现Activity跳转动画,核心代码如下:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_second);
    rootView = findViewById(R.id.root);
    if (savedInstanceState == null) {
        rootView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                rootView.getViewTreeObserver().removeOnPreDrawListener(this);
                startRootAnimation();
                return true;
            }
        });
    }
}

因为在绘制之前会触发OnPreDrawListener的onPreDraw()函数,这个时候可以执行跳转动画。

应用场景3:测量软键盘状态和高度

ViewTreeObserver.OnGlobalLayoutListener mListener = new ViewTreeObserver
            .OnGlobalLayoutListener() {
        public void onGlobalLayout() {
            Rect r1 = new Rect();
            root.getWindowVisibleDisplayFrame(r1);
            Log.e("TAG",r1.bottom+"") ; 
        }
    };
root.getViewTreeObserver().addOnGlobalLayoutListener(mListener);

在根布局加入GlobalLayoutListener监听,通过getWindowVisibleDisplayFrame方法可以观察可见区域的变化,键盘打开后 会影响可见区域的大小,导致Rect的底部r1.bottom变小。

Viewtreeobserver解析

欢迎关注微信公众号:DroidMind
精品内容独家发布平台


呈现与博客不一样的技术干货

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值