作用:通过名字就可以知道它是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变小。

关于ViewTreeObserver的理解相关推荐

  1. 从Android源码出发理解【易观】埋点

    大数据时代互联网产品针对用户数据采集和分析是十分重要的一环,作为一个Android开发者一直以来对于埋点(特别是可视化埋点)十分感兴趣.最近了解[易观]数据统计开源了其Sdk源码在GitHub,通过理 ...

  2. Android高级:内部类的理解,多态,run和start,wait和seelp,线程安全,堆和栈,synchronized 和volatile ,AsyncTask,Binder的机,view的原理

    目录 成员内部类.静态内部类.局部内部类和匿名内部类的理解,以及项目中的应用 哪些情况下的对象会被垃圾回收机制处理掉? Java中实现多态的机制是什么? String为什么要设计成不可变的? Obje ...

  3. 通用解题法——回溯算法(理解+练习)

    积累算法经验,积累解题方法--回溯算法,你必须要掌握的解题方法! 什么是回溯算法呢? 回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就&quo ...

  4. stream流对象的理解及使用

    我的理解:用stream流式处理数据,将数据用一个一个方法去 . (点,即调用) 得到新的数据结果,可以一步达成. 有多种方式生成 Stream Source: 从 Collection 和数组 Co ...

  5. Linux shell 学习笔记(11)— 理解输入和输出(标准输入、输出、错误以及临时重定向和永久重定向)

    1. 理解输入和输出 1.1 标准文件描述符 Linux 系统将每个对象当作文件处理.这包括输入和输出进程.Linux 用文件描述符(file descriptor)来标识每个文件对象.文件描述符是一 ...

  6. java局部变量全局变量,实例变量的理解

    java局部变量全局变量,实例变量的理解 局部变量 可以理解为写在方法中的变量. public class Variable {//类变量static String name = "小明&q ...

  7. 智能文档理解:通用文档预训练模型

    预训练模型到底是什么,它是如何被应用在产品里,未来又有哪些机会和挑战? 预训练模型把迁移学习很好地用起来了,让我们感到眼前一亮.这和小孩子读书一样,一开始语文.数学.化学都学,读书.网上游戏等,在脑子 ...

  8. 熵,交叉熵,散度理解较为清晰

    20210511 https://blog.csdn.net/qq_35455503/article/details/105714287 交叉熵和散度 自己给自己编码肯定是最小的 其他的编码都会比这个 ...

  9. mapreduce理解_大数据

    map:对不同的数据进行同种操作 reduce:按keys 把数据规约到一起 看这篇文章请出去跑两圈,然后泡一壶茶,边喝茶,边看,看完你就对hadoop 与MapReduce的整体有所了解了. [前言 ...

最新文章

  1. 国行版HomePod售价2799元,本周五发售
  2. 从mysql数据库中读取二进制文件_数据库技术之在MYSQL数据库中如何存取二进制文件...
  3. Normalization
  4. 《TCP/IP详解 卷1:协议》第4章 ARP:地址解析协议
  5. 借助 SAP 电商云 Spartacus UI 提供的 Schematics 辅助您的前端项目升级
  6. mysql 目录更改 php,Linux下更改MySQL目录
  7. 开源的酷炫猜歌喝酒小程序
  8. 深入解读华为云细粒度文本情感分析及其应用
  9. sp_configure
  10. 打印机驱动 - HP LaserJet P1008(适用于大部分惠普打印机)
  11. c专家编程(C专家编程pdf)
  12. 基于JavaSwing开发中国象棋对战游戏+实验报告 课程设计 大作业
  13. eMMC mmcblk0boot0
  14. 职场智慧:君子应处木雁之间,当有龙蛇之变
  15. 秒杀年费258的同款APP,微软、联想、Adobe、腾讯的这些良心产品太香了
  16. 用python画竹子_智慧职教moocPython程序设计基础期末考试查题公众号答案
  17. 【雅思阅读】王希伟阅读P4(matching2段落信息配对题【困难】)
  18. 洪小文谈科研:自信与谦虚并行
  19. 卿斯汉:未来是公有云的天下
  20. 中国企业服务八荣八耻

热门文章

  1. [Android] AlertDialog获取网上天气并显示各城市天气
  2. C# 系统应用之注册表使用详解
  3. iOS之深入解析Block的底层原理
  4. iOS之深入解析图片解压缩到渲染的过程与原理
  5. G6 图可视化引擎——核心概念——节点/边/Combo——内置节点——Rect
  6. sys.argv[] 的使用详解
  7. 2017/National _C_C++_B/2/磁砖样式
  8. 【机器视觉】 dev_set_lut算子
  9. 【Tools】VNC Server 6.7安装详解
  10. 【Tools】VMware虚拟机三种网络模式详解和操作