杂货铺

动态获取textview的高度,对它进行设置展开与隐藏。

以前呢,本渣渣是不知道还有这个知识点的,今天看到后感觉自己以前太笨了。下面就介绍一下这个强大的暂且叫它工具吧。

Android ViewTreeObserver简介

一、结构

public final class ViewTreeObserver extends Object
    java.lang.Object
         android.view.ViewTreeObserver

二、概述
    
这是一个注册监听视图树的观察者(observer),在视图树种全局事件改变时得到通知。这个全局事件不仅还包括整个树的布局,从绘画过程开始,触摸模式的改变等。ViewTreeObserver不能够被应用程序实例化,因为它是由视图提供,参照getViewTreeObserver()以查看更多信息。

三、内部类
    
interface  ViewTreeObserver.OnGlobalFocusChangeListener         
当在一个视图树中的焦点状态发生改变时,所要调用的回调函数的接口类


interface  ViewTreeObserver.OnGlobalLayoutListener
当在一个视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变时,所要调用的回调函数的接口类


interface  ViewTreeObserver.OnPreDrawListener
当一个视图树将要绘制时,所要调用的回调函数的接口类


interface  ViewTreeObserver.OnScrollChangedListener
当一个视图树中的一些组件发生滚动时,所要调用的回调函数的接口类


interface  ViewTreeObserver.OnTouchModeChangeListener
当一个视图树的触摸模式发生改变时,所要调用的回调函数的接口类

四、公共方法

  public void addOnGlobalFocusChangeListener (ViewTreeObserver.OnGlobalFocusChangeListener listener)
  注册一个回调函数,当在一个视图树中的焦点状态发生改变时调用这个回调函数。
  参数
                   listener    将要被添加的回调函数
                 异常
                   IllegalStateException       如果isAlive() 返回false
 
  public void addOnGlobalLayoutListener (ViewTreeObserver.OnGlobalLayoutListener listener)
  注册一个回调函数,当在一个视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变时调用这个回调函数。
  参数
                   listener    将要被添加的回调函数
                 异常
                   IllegalStateException       如果isAlive() 返回false
 
  public void addOnPreDrawListener (ViewTreeObserver.OnPreDrawListener listener)
  注册一个回调函数,当一个视图树将要绘制时调用这个回调函数。
  参数
                   listener    将要被添加的回调函数
                 异常
                   IllegalStateException       如果isAlive() 返回false
 
  public void addOnScrollChangedListener (ViewTreeObserver.OnScrollChangedListener listener)     
  注册一个回调函数,当一个视图发生滚动时调用这个回调函数。
  参数
                   listener    将要被添加的回调函数
                 异常
                   IllegalStateException       如果isAlive() 返回false
 
  public void addOnTouchModeChangeListener (ViewTreeObserver.OnTouchModeChangeListener listener)


  注册一个回调函数,当一个触摸模式发生改变时调用这个回调函数。
  参数
                   listener    将要被添加的回调函数
                 异常
                   IllegalStateException       如果isAlive() 返回false

  public final void dispatchOnGlobalLayout ()

  当整个布局发生改变时通知相应的注册监听器。如果你强制对视图布局或者在一个没有附加到一个窗口的视图的层次结构或者在GONE状态下,它可以被手动的调用

  public final boolean dispatchOnPreDraw ()

  当一个视图树将要绘制时通知相应的注册监听器。如果这个监听器返回true,则这个绘制将被取消并重新计划。如果你强制对视图布局或者在一个没有附加到一个窗口的视图的层次结构或者在一个GONE状态下,它可以被手动的调用
                   返回值
                            当前绘制能够取消并重新计划则返回true,否则返回false。
  public boolean isAlive ()


  指示当前的ViewTreeObserver是否可用(alive)。当observer不可用时,任何方法的调用(除了这个方法)都将抛出一个异常。如果一个应用程序保持和ViewTreeObserver一个历时较长的引用,它应该总是需要在调用别的方法之前去检测这个方法的返回值。
                   返回值
                            但这个对象可用则返回true,否则返回false   
  public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
  移除之前已经注册的全局布局回调函数。
  参数
                   victim 将要被移除的回调函数
                 异常
                   IllegalStateException       如果isAlive() 返回false   
 
  public void removeOnGlobalFocusChangeListener (ViewTreeObserver.OnGlobalFocusChangeListener victim)
  移除之前已经注册的焦点改变回调函数。
  参数
                   victim 将要被移除的回调函数
                 异常
                   IllegalStateException       如果isAlive() 返回false 
 
  public void removeOnPreDrawListener (ViewTreeObserver.OnPreDrawListener victim)
  移除之前已经注册的预绘制回调函数。
  参数
                   victim 将要被移除的回调函数
                 异常
                   IllegalStateException       如果isAlive() 返回false  
 
  public void removeOnScrollChangedListener (ViewTreeObserver.OnScrollChangedListener victim)
  移除之前已经注册的滚动改变回调函数。
  参数
                   victim 将要被移除的回调函数
                 异常
                   IllegalStateException       如果isAlive() 返回false 
 
  public void removeOnTouchModeChangeListener (ViewTreeObserver.OnTouchModeChangeListener victim)
  移除之前已经注册的触摸模式改变回调函数
  参数
                   victim 将要被移除的回调函数
                 异常
                   IllegalStateException       如果isAlive() 返回false

举个栗子:

 

[html] view plain copy  在CODE上查看代码片派生到我的代码片

  1. package com.example.textviewtest;  
  2.   
  3. import android.annotation.SuppressLint;  
  4. import android.app.Activity;  
  5. import android.os.Bundle;  
  6. import android.util.Log;  
  7. import android.view.View;  
  8. import android.view.View.OnClickListener;  
  9. import android.view.ViewTreeObserver;  
  10. import android.widget.Button;  
  11. import android.widget.TextView;  
  12.   
  13. public class MainActivity extends Activity {  
  14.   
  15.     private TextView text;  
  16.     private Button button;  
  17.   
  18.     @SuppressLint("NewApi")  
  19.     @Override  
  20.     protected void onCreate(Bundle savedInstanceState) {  
  21.         super.onCreate(savedInstanceState);  
  22.         setContentView(R.layout.activity_main);  
  23.         text = (TextView) findViewById(R.id.text2);  
  24.         button = (Button) findViewById(R.id.button);  
  25.         text.setText("广西新闻网-南国今报柳州讯 一消费者到发廊美发,因对美发效果不满,索要数千至1万元赔偿,并经工商调解不成,进而大"  
  26.                 + "闹发廊骚扰店主,并惊动了警方。警方介入耐心做工作,消费者在警方及工商见证后,接受店主提出的赔偿方案,双方化干戈为玉帛");  
  27.         //获取视图树的全局事件改变时得到通知  
  28.         ViewTreeObserver vto = text.getViewTreeObserver();  
  29.         //监听获取回掉函数  
  30.         vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {  
  31.             @Override  
  32.             public boolean onPreDraw() {  
  33.                 //获取text View 的高度  
  34.                 int lineCount = text.getLineCount();  
  35.             
  36.                 //逻辑判断,如果大于2显示按钮,如果行数小于或者等于2 则隐藏。  
  37.                 if(lineCount>2){  
  38.                     button.setVisibility(View.VISIBLE);  
  39.                 }else{  
  40.                     button.setVisibility(View.GONE);  
  41.                 }  
  42.                 return true;  
  43.             }  
  44.         });  
  45.   
  46.       
  47.           
  48.         button.setOnClickListener(new OnClickListener() {  
  49.             Boolean flag = true;  
  50.   
  51.             @Override  
  52.             public void onClick(View arg0) {  
  53.                 // TODO Auto-generated method stub  
  54.             
  55.                 if (flag) {  
  56.                     flag = false;  
  57.                     text.setEllipsize(null);// 展开  
  58.                     text.setSingleLine(flag);  
  59.                     button.setText("隐藏");  
  60.                 } else {  
  61.                     flag = true;  
  62.                     text.setMaxLines(2);// 收缩  
  63.                     button.setText("显示");  
  64.                   text.setEllipsize(TruncateAt.END);  
  65.                 }  
  66.             }  
  67.         });  
  68.           
  69.     }  
  70. }  
  71.  

这是很简单的应用了,不过在一些APP中也经常可以用到。

 

 

关于屏幕刷新和自动清屏

 

* invalidate() :*
请求重绘View树,即draw()过程。把例子中他是整个刷新着UI,并且从头到尾并不会触发onMeasure()方法(控制大小用)。如果是View就重绘View,如果是ViewGroup就全部重绘。invalidate()是用来刷新View的,必须是在UI线程中进行工作。比如在修改某个view的显示时,调用invalidate()才能看到重新绘制的界面。invalidate()的调用是把之前的旧的view从主UI线程队列中pop掉。 
对于屏幕刷新有以下集中情况可以考虑: 
1.不使用多线程和双缓冲 
     这种情况最简单了,一般只是希望在View发生改变时对UI进行重绘。你只需在Activity中显式地调用View对象中的invalidate()方法即可。系统会自动调用 View的onDraw()方法。 
2.使用多线程和不使用双缓冲 
     这种情况需要开启新的线程,新开的线程就不好访问View对象了。强行访问的话会报:android.view.ViewRoot$CalledFromWrongThreadException:Only the original thread that created a view hierarchy can touch its views. 
     这时候你需要创建一个继承了android.os.Handler的子类,并重写handleMessage(Message msg)方法。android.os.Handler是能发送和处理消息的,你需要在Activity中发出更新UI的消息,然后再你的Handler(可以使用匿名内部类)中处理消息(因为匿名内部类可以访问父类变量, 你可以直接调用View对象中的invalidate()方法 )。也就是说:在新线程创建并发送一个Message,然后再主线程中捕获、处理该消息。 
3.使用多线程和双缓冲 
    Android中SurfaceView是View的子类,她同时也实现了双缓冲。你可以定义一个她的子类并实现SurfaceHolder.Callback接口。由于实现SurfaceHolder.Callback接口,新线程就不需要android.os.Handler帮忙了。SurfaceHolder中lockCanvas()方法可以锁定画布,绘制玩新的图像后调用unlockCanvasAndPost(canvas)解锁(显示),还是比较方便得。 

* requestLayout()*
他跟invalidate()相反,他只调用measure()和layout()过程,不会调用draw()。
局部刷新,使用 requestFocus()方法,他只刷新你要刷新的地方。 他是让我们的某一部分获取焦点,获取焦点的会导致view的重绘。

           差不多就这些啦,觉得大家对杂货铺不是很喜欢,应该大家有问题了才会针对着去学习吧。但是闲的时候还是多看看吧,或许下次就用的到也说不定呢。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值