关于ViewTreeObserver的理解

    xiaoxiao2021-12-14  16

    作用:通过名字就可以知道它是View树的观察者,当View树的发生变化的时候会发出通知。ViewTreeObserver是不能被应用程序实例化的,因为它是由视图提供的,通过view.getViewTreeObserver()获取。 熟悉观察者模式的人应该很容易想到,为了能够相应的通知,我们肯定需要注册监听。下面来看看我们可以注册哪些监听。 1、当在一个视图树中的焦点状态或者可见性发生改变时调用OnGlobalFocusChangeListener的onGlobalFocusChanged()函数。 public void addOnGlobalFocusChangeListener (ViewTreeObserver.OnGlobalFocusChangeListener listener) 1 1 2、当在一个视图树中的焦点状态或者可见性发生改变时调用OnGlobalFocusChangeListener的onGlobalFocusChanged()函数。 public void addOnGlobalLayoutListener (ViewTreeObserver.OnGlobalLayoutListener listener) 1 1 3、当一个视图树将要绘制时调用OnPreDrawListener的onPreDraw()函数 public void addOnPreDrawListener (ViewTreeObserver.OnPreDrawListener listener) 1 1 4、当一个视图发生滚动时调用OnScrollChangedListener的onScrollChanged()函数 public void addOnScrollChangedListener (ViewTreeObserver.OnScrollChangedListener listener)   1 1 5、当一个触摸模式发生改变时调用OnTouchModeChangeListener的onTouchModeChanged()函数 public void addOnTouchModeChangeListener (ViewTreeObserver.OnTouchModeChangeListener listener) 1 1 6、当一个视图树绘制时调用OnDrawListener的onDraw()函数 addOnDrawListener(ViewTreeObserver.OnDrawListener listener)  1 1 7、当View树绑定到window上的时候回调OnWindowAttachListener的onWindowAttached() 函数,当它从window上解绑时调用OnWindowAttachListener的onWindowDetached() addOnWindowAttachListener(ViewTreeObserver.OnWindowAttachListener listener)  1 1 8、当window的焦点状态发生改变时,调用OnWindowFocusChangeListener的onWindowFocusChanged函数 addOnWindowFocusChangeListener(ViewTreeObserver.OnWindowFocusChangeListener listener)  1 1 对应这些注册的监听,还有相应的删除监听 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)  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 上面注册的监听都是View树发生变化的时候,会被自动触发回调,如果我们希望手动触发回调,可以调用下面函数 public final void dispatchOnGlobalLayout () 手动触发OnGlobalLayoutListener的onGlobalLayout()函数回调 public final boolean dispatchOnPreDraw () 手动触发OnPreDrawListener的onPreDraw()函数的回调 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8 另外还是一个指示当前的ViewTreeObserver是否可用的函数。 public boolean isAlive () 当observer不可用时,任何方法的调用(除了这个方法)都将抛出一个异常。 1 2 3 1 2 3 应用场景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;         }     }); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 因为回调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();         }     });  } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 当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变小。
    转载请注明原文地址: https://ju.6miu.com/read-964402.html

    最新回复(0)