关于ViewTreeObserver的理解
作用:通过名字就可以知道它是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的理解相关推荐
- 从Android源码出发理解【易观】埋点
大数据时代互联网产品针对用户数据采集和分析是十分重要的一环,作为一个Android开发者一直以来对于埋点(特别是可视化埋点)十分感兴趣.最近了解[易观]数据统计开源了其Sdk源码在GitHub,通过理 ...
- Android高级:内部类的理解,多态,run和start,wait和seelp,线程安全,堆和栈,synchronized 和volatile ,AsyncTask,Binder的机,view的原理
目录 成员内部类.静态内部类.局部内部类和匿名内部类的理解,以及项目中的应用 哪些情况下的对象会被垃圾回收机制处理掉? Java中实现多态的机制是什么? String为什么要设计成不可变的? Obje ...
- 通用解题法——回溯算法(理解+练习)
积累算法经验,积累解题方法--回溯算法,你必须要掌握的解题方法! 什么是回溯算法呢? 回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就&quo ...
- stream流对象的理解及使用
我的理解:用stream流式处理数据,将数据用一个一个方法去 . (点,即调用) 得到新的数据结果,可以一步达成. 有多种方式生成 Stream Source: 从 Collection 和数组 Co ...
- Linux shell 学习笔记(11)— 理解输入和输出(标准输入、输出、错误以及临时重定向和永久重定向)
1. 理解输入和输出 1.1 标准文件描述符 Linux 系统将每个对象当作文件处理.这包括输入和输出进程.Linux 用文件描述符(file descriptor)来标识每个文件对象.文件描述符是一 ...
- java局部变量全局变量,实例变量的理解
java局部变量全局变量,实例变量的理解 局部变量 可以理解为写在方法中的变量. public class Variable {//类变量static String name = "小明&q ...
- 智能文档理解:通用文档预训练模型
预训练模型到底是什么,它是如何被应用在产品里,未来又有哪些机会和挑战? 预训练模型把迁移学习很好地用起来了,让我们感到眼前一亮.这和小孩子读书一样,一开始语文.数学.化学都学,读书.网上游戏等,在脑子 ...
- 熵,交叉熵,散度理解较为清晰
20210511 https://blog.csdn.net/qq_35455503/article/details/105714287 交叉熵和散度 自己给自己编码肯定是最小的 其他的编码都会比这个 ...
- mapreduce理解_大数据
map:对不同的数据进行同种操作 reduce:按keys 把数据规约到一起 看这篇文章请出去跑两圈,然后泡一壶茶,边喝茶,边看,看完你就对hadoop 与MapReduce的整体有所了解了. [前言 ...
最新文章
- 国行版HomePod售价2799元,本周五发售
- 从mysql数据库中读取二进制文件_数据库技术之在MYSQL数据库中如何存取二进制文件...
- Normalization
- 《TCP/IP详解 卷1:协议》第4章 ARP:地址解析协议
- 借助 SAP 电商云 Spartacus UI 提供的 Schematics 辅助您的前端项目升级
- mysql 目录更改 php,Linux下更改MySQL目录
- 开源的酷炫猜歌喝酒小程序
- 深入解读华为云细粒度文本情感分析及其应用
- sp_configure
- 打印机驱动 - HP LaserJet P1008(适用于大部分惠普打印机)
- c专家编程(C专家编程pdf)
- 基于JavaSwing开发中国象棋对战游戏+实验报告 课程设计 大作业
- eMMC mmcblk0boot0
- 职场智慧:君子应处木雁之间,当有龙蛇之变
- 秒杀年费258的同款APP,微软、联想、Adobe、腾讯的这些良心产品太香了
- 用python画竹子_智慧职教moocPython程序设计基础期末考试查题公众号答案
- 【雅思阅读】王希伟阅读P4(matching2段落信息配对题【困难】)
- 洪小文谈科研:自信与谦虚并行
- 卿斯汉:未来是公有云的天下
- 中国企业服务八荣八耻
热门文章
- [Android] AlertDialog获取网上天气并显示各城市天气
- C# 系统应用之注册表使用详解
- iOS之深入解析Block的底层原理
- iOS之深入解析图片解压缩到渲染的过程与原理
- G6 图可视化引擎——核心概念——节点/边/Combo——内置节点——Rect
- sys.argv[] 的使用详解
- 2017/National _C_C++_B/2/磁砖样式
- 【机器视觉】 dev_set_lut算子
- 【Tools】VNC Server 6.7安装详解
- 【Tools】VMware虚拟机三种网络模式详解和操作