view变化监听器ViewTreeObserver介绍

来源:互联网 发布:linux vim 命令 编辑:程序博客网 时间:2024/05/18 02:58

转载地址:http://blog.csdn.net/liguangzhenghi/article/details/8076121#comments

在原作者blog的基础上略微修改,ViewTreeObserver是用来帮助我们监听某些View的某些变化的。

 

在 ViewTreeObserver 中,包含了以下几个接口:

interfaceViewTreeObserver.OnGlobalFocusChangeListener 当布局中的处理焦点发生变化时触发

interfaceViewTreeObserver.OnGlobalLayoutListener 当布局发生变化是触发

interface ViewTreeObserver.OnPreDrawListener  事件出发前的准备工作

interfaceViewTreeObserver.OnScrollChangedListener 当发生滑动事件时触发

interfaceViewTreeObserver.OnTouchModeChangeListener 当接触模式发生变化时触发

本文将测试除 ViewTreeObserver.OnScrollChangedListener外的四个接口

小结

在Android TouchMode模式下是不存在focus的。所谓的focus是指被选中的意思,类似于windows平台下单击一个文件夹后鼠标的焦点(focus)就在该文件夹上面。既然不存在focus,也就不存在FocusChange的问题。

对于一个拥有触摸屏功能的设备而言, 一旦用户用手点击屏幕, 设备立刻进入touch mode . 这时候被点击的控件只有isFocusableInTouchMode()方法返回true的时候才会 focusable ,通常只有诸如EditText这样的对象才能在选中时获得焦点。而其他对象(如Button),由于它们可以在用户触屏时被直接选中,所以不必获得焦点就可以出发行为,它们只是简单地执行onClick事件而已。可将下面的代码拷贝运行测试一下。

当用户直接使用keys或trackball与UI进行交互的时候, 必须先使目标控件获取焦点(比如按钮),这样用户才会注意到是什么控件接收输入. 然而如果设备支持触摸手势的话, 用户可能使用触摸屏与UI进行交互, 这个时候就没有必要将目标控件高亮显示了(即,获取焦点). 因此就产生了这样一种交互模式叫"touch mode ."任何时候只要用户点击key或滚动trackball, 设备就会退出touch mode ,并且找一个view将焦点置于其上. 此时用户可以不使用触摸手势了.

touch mode 在整个系统运行期间都是有效的(在任何activities中). 如果想要查询当前处于何种状态, 你可以调用View#isInTouchMode()来看看当前是否处于touch mode .


如果想在TouchMode下面使Button使用这个监听器可以使用如下两种方法:

1. 增加一句代码:mImageButton.setFocusableInTouchMode(true);l

2.在main.xml中mImageButton标签中加入一个子标签:android:focusableInTouchMode="true"。

这两种方法的作用都是使得focus在TouchMode下恢复作用。


1.    创建一个 Android Project ,修改 main.xml 使之如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/full_screen"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical"    tools:context=".MainActivity" >    <TextView        android:id="@+id/tv_show"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:text=""        android:textSize="32px" />    <EditText        android:id="@+id/ed_enter1"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:text="" />    <EditText        android:id="@+id/ed_enter2"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:text="" />    <TextView        android:id="@+id/tv_display"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:text="" />    <Button        android:id="@+id/button"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:text="OK" /></LinearLayout>

注意:给 layout 增加一个 id : full_screen

 

2.    Activity 对应的 Java 代码如下:

package com.example.touchmodechangeldg;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewTreeObserver;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;public class MainActivity extends Activity implements OnClickListener,ViewTreeObserver.OnTouchModeChangeListener, // 用于监听Touch和非Touch模式的转换ViewTreeObserver.OnGlobalLayoutListener, // 用于监听布局之类的变化,比如某个空间消失了ViewTreeObserver.OnPreDrawListener, // 用于在屏幕上画 View 之前,要做什么额外的工作ViewTreeObserver.OnGlobalFocusChangeListener { // 用于监听焦点的变化private TextView tv_show;private ViewTreeObserver vto;private View all;private EditText ed1;private EditText ed2;private TextView tv_display;private Button button;private boolean btnClicked;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv_show = (TextView) this.findViewById(R.id.tv_show);all = this.findViewById(R.id.full_screen); // 得到整个屏幕对象 , 因为顶层 layout// 的width 和 height// 都是fill_parentvto = (ViewTreeObserver) all.getViewTreeObserver(); // 通过getViewTreeObserver获得ViewTreeObserver对象tv_display = (TextView) this.findViewById(R.id.tv_display);ed1 = (EditText) this.findViewById(R.id.ed_enter1);ed2 = (EditText) this.findViewById(R.id.ed_enter2);button = (Button) this.findViewById(R.id.button);button.setOnClickListener(this);vto.addOnTouchModeChangeListener(this); // 增加对应的 Listenervto.addOnGlobalFocusChangeListener(this); // 增加对应的 Listenervto.addOnPreDrawListener(this); // 增加对应的 Listenervto.addOnGlobalLayoutListener(this); // 增加对应的 Listener}// onTouchModeChanged 是接口 ViewTreeObserver.OnTouchModeChangeListener中定义的方法。@Overridepublic void onTouchModeChanged(boolean isInTouchMode) {if (isInTouchMode)tv_show.setText("In touch mode");elsetv_show.setText("Not in touch mode");}// onGlobalLayout 是接口 ViewTreeObserver.OnGlobalLayoutListener中定义的方法。// Callback method to be invoked when the global layout state or the visibility of views within the view tree changes@Overridepublic void onGlobalLayout() {if (btnClicked) {if (!ed2.isShown())ed1.setText(" 第二个 EditText 不见了 ");elseed1.setText(" 第二个 EditText 出来了 ");}}// onPreDraw 是接口 ViewTreeObserver.OnPreDrawListener中定义的方法。@Overridepublic boolean onPreDraw() {// 在屏幕上画出 ed1 控件之间 , 给它增加一个提示 , 并改变其字体大小ed1.setHint(" 在 onPreDraw 方法中增加一个提示信息 ");ed1.setTextSize((float) 20.0);// return false; // Return true to proceed with the current drawing// pass, or falseto cancel.return true; // 如果此处不返回 true , 则整个界面不能完整显示。}@Overridepublic void onClick(View v) {// 改变 ed2 的可见性 , 会触发 onGlobalLayout 方法的执行btnClicked = true;if (v.getId() == R.id.button) {if (ed2.isShown())ed2.setVisibility(View.INVISIBLE);elseed2.setVisibility(View.VISIBLE);}}// onGlobalFocusChanged 是接口 ViewTreeObserver.OnGlobalFocusChangeListener中定义的方法。// 焦点发生变化时,会触发这个方法的执行@Overridepublic void onGlobalFocusChanged(View oldFocus, View newFocus) {// TODO Auto-generated method stubif (oldFocus != null && newFocus != null) {tv_display.setText("Focus /nFROM:/t" + oldFocus.toString()+ "/n    TO:/t" + newFocus.toString());}}}

3.    运行结果:

 

我运行了一下,并没有上面这个界面(Not in touch mode),而是直接出现了下面的界面(In touch mode),再研究一下吧。

 

可以看到第一个 EditText 中存在字体发生了变化的提示信息,这种效果是在 onPreDraw() 方法中实现的。

 

用鼠标点击屏幕上的第二个 EditText有两个变化:

一个是有 Not in touch mode 变成了 In touch mode(没发现)

二是显示了焦点变化方面的信息(这个有)

它们分别是 onTouchModeChanged 和 onGlobalFocusChanged 这两个方法所输出的信息。

如果用模拟器右边的键盘进行操作,将交掉移动到第一个 EditText ,则又会回到 Not in touch mode 的状态。

 

点击 OK 按钮,改变第二个 EditText 的可见性:

第一个 EditText 中的内容是在 onGlobalLayout 方法中设定的。


0 0
原创粉丝点击