AndroidGUI13:ViewTreeObserver的常用技巧

A view tree observer is used to register listeners that can be notified of global changes in the view tree. Such global events include, but are not limited to, layout of the whole tree, beginning of the drawing pass, touch mode change.... A ViewTreeObserver should never be instantiated by applications as it is provided by the views hierarchy. Refer toView.getViewTreeObserver() for more information.

从上面的描述中,不难看出,ViewTreeObserver是用来帮助我们监听某些View的某些变化的。

 

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

interface ViewTreeObserver.OnGlobalFocusChangeListener

interface ViewTreeObserver.OnGlobalLayoutListener

interface ViewTreeObserver.OnPreDrawListener

interface ViewTreeObserver.OnScrollChangedListener

interface ViewTreeObserver.OnTouchModeChangeListener

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

 

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

<? xml version = "1.0" encoding = "utf-8" ?>

< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"

android:id = "@+id/full_screen"

    android:orientation = "vertical"

    android:layout_width = "fill_parent"

    android:layout_height = "fill_parent"

>  

   

    < TextView

                   android:id = "@+id/tv_show"

             android:layout_width = "fill_parent"

             android:layout_height = "wrap_content"

             android:text = ""

             android:textSize = "32px"

             android:textColor = "#FFFF00"

    />

   

    < 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 代码如下:

public class ControlViewTreeObserver 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 ;

   

    @Override

    public void onCreate(Bundle savedInstanceState)

    {

        super .onCreate(savedInstanceState);

        setContentView(R.layout. main );

       

        tv_show = (TextView) this .findViewById(R.id. tv_show );

        all this .findViewById(R.id. full_screen );                                  // 得到整个屏幕对象  因为顶层 layout  width height 都是 fill_parent

        vto = (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 );                          // 增加对应的 Listener

        vto .addOnGlobalFocusChangeListener( this );                        // 增加对应的 Listener

        vto .addOnPreDrawListener( this );                                               // 增加对应的 Listener

        vto .addOnGlobalLayoutListener( this );                                      // 增加对应的 Listener

    }

 

    // onTouchModeChanged 是接口 ViewTreeObserver.OnTouchModeChangeListener

    // 中定义的方法。

         @Override

         public void onTouchModeChanged( boolean isInTouchMode)

         {

                   if (isInTouchMode) tv_show .setText( "In touch mode" );

                   else tv_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

         @Override

         public void onGlobalLayout()

         {

                   if ( btnClicked )

                   {

                            if (! ed2 .isShown())

                                     ed1 .setText( " 第二个 EditText 不见了 " );

                            else

                                     ed1 .setText( " 第二个 EditText 出来了 " );

                   }

         }

 

         // onPreDraw 是接口 ViewTreeObserver.OnPreDrawListener

        // 中定义的方法。

         @Override

         public boolean onPreDraw()

         {

                   // 在屏幕上画出 ed1 控件之间  给它增加一个提示  并改变其字体大小

                   ed1 .setHint( "  onPreDraw 方法中增加一个提示信息 " );

                   ed1 .setTextSize(( float ) 20.0);

                  

                   //return false;    // Return true to proceed with the current drawing pass, or false to cancel.

                   return true ;        // 如果此处不返回 true  则整个界面不能完整显示。

         }                                            

 

         // onGlobalFocusChanged 是接口 ViewTreeObserver.OnGlobalFocusChangeListener

         // 中定义的方法。

         // 焦点发生变化时,会触发这个方法的执行

         @Override

         public void onGlobalFocusChanged(View oldFocus, View newFocus)

         {

                   if (oldFocus != null && newFocus != null )

                   {

                            tv_display .setText( "Focus /nFROM:/t" + oldFocus.toString() + "/n     TO:/t" + newFocus.toString());

                   }

         }

 

         @Override

         public void onClick(View v)

         {

                   // 改变 ed2 的可见性  会触发 onGlobalLayout 方法的执行

                   btnClicked true ;

                   if (v.getId() == R.id. button )

                   {

                            if ( ed2 .isShown())

                                     ed2 .setVisibility(View. INVISIBLE );

                            else

                                     ed2 .setVisibility(View. VISIBLE );

                   }

         }

}

 

3.     运行结果:

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

用鼠标点击屏幕上的第二个 EditText ,

 

有两个变化:

一个是有 Not in touch mode 变成了 In touch mode ,二是显示了焦点变化方面的信息。它们分别是onTouchModeChanged 和 onGlobalFocusChanged 这两个方法所输出的信息。

 

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

 

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

  

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值