利用Android中的TextView实现逐字显示动画

所属分类: 软件编程 / Android 阅读数: 1019
收藏 0 赞 0 分享

前言

Android的TextView只能设置整个TextView的动画,而不能设置每个文字的动画。即使是使用TextSwitcher,也很难实现我想要的效果。
 

所以选择自定义一个。大体思路是:继承ViewGroup,设置Text的时候,每个文字为一个TextView,每隔一个固定时间,启动每个TextView的动画。

 定义一个CTextView,继承ViewGroup:

实现主要代码:

public class CTextView extends ViewGroup { 
} 

向外提供一个方法setText(String text, final Animation animation, int duration),text为要显示的字符串,animation为每个字符的动画,duration为字符动画的播放间隔。

该方法实现如下:

public void setText(String text, final Animation animation, int duration) { 
  int time = 0; 
  if(text != null && !text.isEmpty()) { 
    char[] characters = text.toCharArray(); 
    for(char c : characters) { 
      final TextView t = new TextView(context); 
      //遍历传入的字符串的每个字符,生成一个TextView,并设置它的动画 
      t.setText(String.valueOf(c)); 
      t.setTextSize(28); 
      Handler h = new Handler(); 
      //每隔duration时间,播放下一个TextView的动画 
      h.postDelayed(new Runnable() { 
        @Override 
        public void run() { 
          addView(t); 
          t.setAnimation(animation); 
        } 
      }, time); 
 
      time += duration; 
 
    } 
  } 
} 

CTextView完整实现如下:

import android.content.Context; 
import android.os.Handler; 
import android.util.AttributeSet; 
import android.view.View; 
import android.view.ViewGroup; 
import android.view.animation.Animation; 
import android.widget.TextView; 
 
/** 
 * Created by cchen on 2014/9/2. 
 */ 
public class CTextView extends ViewGroup { 
  private Context context; 
 
  public CTextView(Context context) { 
    super(context); 
    this.context = context; 
  } 
 
  public CTextView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    this.context = context; 
  } 
 
  public CTextView(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 
    this.context = context; 
  } 
 
  public void setText(String text, final Animation animation, int duration) { 
    int time = 0; 
    if(text != null && !text.isEmpty()) { 
      char[] characters = text.toCharArray(); 
      for(char c : characters) { 
        final TextView t = new TextView(context); 
        //遍历传入的字符串的每个字符,生成一个TextView,并设置它的动画 
        t.setText(String.valueOf(c)); 
        t.setTextSize(28); 
        Handler h = new Handler(); 
        //每隔duration时间,播放下一个TextView的动画 
        h.postDelayed(new Runnable() { 
          @Override 
          public void run() { 
            addView(t); 
            t.setAnimation(animation); 
          } 
        }, time); 
 
        time += duration; 
 
      } 
    } 
  } 
 
  @Override 
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    int measureWidth = measureWidth(widthMeasureSpec); 
    int measureHeight = measureHeight(heightMeasureSpec); 
    // 计算自定义的ViewGroup中所有子控件的大小 
    measureChildren(widthMeasureSpec, heightMeasureSpec); 
    // 设置自定义的控件MyViewGroup的大小 
    setMeasuredDimension(measureWidth, measureHeight); 
  } 
 
  @Override 
  protected void onLayout(boolean changed, int l, int t, int r, int b) { 
    int childLeft = 0; 
    // 遍历所有子视图 
    int childCount = getChildCount(); 
    for (int i = 0; i < childCount; i++) { 
      View childView = getChildAt(i); 
 
      // 获取在onMeasure中计算的视图尺寸 
      int measureHeight = childView.getMeasuredHeight(); 
      int measuredWidth = childView.getMeasuredWidth(); 
 
      //将他们横向排列 
      childView.layout(childLeft, 0, childLeft + measuredWidth, measureHeight); 
 
      childLeft += measuredWidth; 
    } 
  } 
 
  private int measureWidth(int pWidthMeasureSpec) { 
    int result = 0; 
    int widthMode = MeasureSpec.getMode(pWidthMeasureSpec);// 得到模式 
    int widthSize = MeasureSpec.getSize(pWidthMeasureSpec);// 得到尺寸 
 
    switch (widthMode) { 
      /** 
       * mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY, 
       * MeasureSpec.AT_MOST。 
       * 
       * 
       * MeasureSpec.EXACTLY是精确尺寸, 
       * 当我们将控件的layout_width或layout_height指定为具体数值时如andorid 
       * :layout_width="50dip",或者为FILL_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。 
       * 
       * 
       * MeasureSpec.AT_MOST是最大尺寸, 
       * 当控件的layout_width或layout_height指定为WRAP_CONTENT时 
       * ,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可 
       * 。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。 
       * 
       * 
       * MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView, 
       * 通过measure方法传入的模式。 
       */ 
      case MeasureSpec.AT_MOST: 
      case MeasureSpec.EXACTLY: 
        result = widthSize; 
        break; 
    } 
    return result; 
  } 
 
  private int measureHeight(int pHeightMeasureSpec) { 
    int result = 0; 
 
    int heightMode = MeasureSpec.getMode(pHeightMeasureSpec); 
    int heightSize = MeasureSpec.getSize(pHeightMeasureSpec); 
 
    switch (heightMode) { 
      case MeasureSpec.AT_MOST: 
      case MeasureSpec.EXACTLY: 
        result = heightSize; 
        break; 
    } 
    return result; 
  } 
} 

然后在布局文件中使用该自定义组件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  xmlns:tools="http://schemas.android.com/tools" 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" 
  android:orientation="vertical" 
  tools:context=".NetworkTestActivity"> 
 
  <com.network.cchen.network.CTextView 
    android:id="@+id/cTextView" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 
  </com.network.cchen.network.CTextView> 
 
</LinearLayout> 

在Activity中,调用CTextView的setText方法,传入相关参数即可:

import android.app.Activity; 
import android.os.Bundle; 
import android.view.animation.AnimationUtils; 
 
public class TestActivity extends Activity { 
 
  @Override 
  public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
 
    setContentView(R.layout.activity_network_test); 
 
    CTextView cTextView = (CTextView) findViewById(R.id.cTextView); 
    cTextView.setText("Hello world", AnimationUtils.loadAnimation(this, R.anim.myanim), 300); 
  } 
} 

其中的第二个参数为动画,我想要的效果是从透明到不透明,myanim.xml:

<?xml version="1.0" encoding="utf-8"?> 
<set xmlns:android="http://schemas.android.com/apk/res/android"> 
  <alpha 
    android:duration="1000" 
    android:fromAlpha="0.0" 
    android:toAlpha="1.0" /> 
</set>  

如果想实现文字逐个从右侧飞入:

<?xml version="1.0" encoding="utf-8"?> 
<set xmlns:android="http://schemas.android.com/apk/res/android"> 
  <translate 
    android:duration="1000" 
    android:fillAfter="true" 
    android:fromXDelta="50%p" 
    android:interpolator="@android:anim/anticipate_interpolator" 
    android:toXDelta="0" /> 
</set> 

以上就是利用Android中的TextView实现逐字动画的全部内容,实现后效果还是很赞的,感兴趣的小伙伴们自己动手实践起来吧。如果有疑问可以留言讨论。

更多精彩内容其他人还在看

Android中加入名片扫描功能实例代码

这篇文章主要介绍了Android中加入名片扫描功能实例代码的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

Android仿微信发表说说实现拍照、多图上传功能

这篇文章主要为大家详细介绍了Android仿微信发表说说实现拍照、多图上传功能,使用Retrofit2.0技术,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

设置Android系统永不锁屏永不休眠的方法

在进行Android系统开发的时候,有些特定的情况需要设置系统永不锁屏,永不休眠。本篇文章给大家介绍Android 永不锁屏,开机不锁屏,删除设置中休眠时间选项,需要的朋友一起学习吧
收藏 0 赞 0 分享

Android Retrofit 2.0框架上传图片解决方案

这篇文章主要介绍了Android Retrofit 2.0框架上传一张与多张图片解决方案,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android自定义等待对话框

这篇文章主要为大家详细介绍了Android自定义等待对话框的实现方法,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android中Window添加View的底层原理

这篇文章主要介绍了Android中Window添加View的底层原理,需要的朋友可以参考下
收藏 0 赞 0 分享

Android调用系统默认浏览器访问的方法

这篇文章主要介绍了Android调用系统默认浏览器访问的方法的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

Android开发退出程序的方法汇总

Android程序有很多Activity,比如说主窗口A,调用了子窗口B,子窗口B又调用子窗口C,back返回子窗口B后,在B中如何关闭整个Android应用程序呢? 下面脚本之家小编就给大家介绍android开发退出程序的几种方法,感兴趣的朋友参考下吧
收藏 0 赞 0 分享

Android程序开发中单选按钮(RadioGroup)的使用详解

在android程序开发中,无论是单选按钮还是多选按钮都非常的常见,接下来通过本文给大家介绍Android程序开发中单选按钮(RadioGroup)的使用,需要的朋友参考下吧
收藏 0 赞 0 分享

Android实现仿网易今日头条等自定义频道listview 或者grideview等item上移到另一个view中

这篇文章主要介绍了Android实现仿网易今日头条等自定义频道listview 或者grideview等item上移到另一个view中 的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多