利用Android中的TextView实现逐字显示动画
前言
Android的TextView只能设置整个TextView的动画,而不能设置每个文字的动画。即使是使用TextSwitcher,也很难实现我想要的效果。
所以选择自定义一个。大体思路是:继承ViewGroup,设置Text的时候,每个文字为一个TextView,每隔一个固定时间,启动每个TextView的动画。
定义一个CTextView,继承ViewGroup:
实现主要代码:
publicclassCTextViewextendsViewGroup{
}
向外提供一个方法setText(Stringtext,finalAnimationanimation,intduration),text为要显示的字符串,animation为每个字符的动画,duration为字符动画的播放间隔。
该方法实现如下:
publicvoidsetText(Stringtext,finalAnimationanimation,intduration){
inttime=0;
if(text!=null&&!text.isEmpty()){
char[]characters=text.toCharArray();
for(charc:characters){
finalTextViewt=newTextView(context);
//遍历传入的字符串的每个字符,生成一个TextView,并设置它的动画
t.setText(String.valueOf(c));
t.setTextSize(28);
Handlerh=newHandler();
//每隔duration时间,播放下一个TextView的动画
h.postDelayed(newRunnable(){
@Override
publicvoidrun(){
addView(t);
t.setAnimation(animation);
}
},time);
time+=duration;
}
}
}
CTextView完整实现如下:
importandroid.content.Context;
importandroid.os.Handler;
importandroid.util.AttributeSet;
importandroid.view.View;
importandroid.view.ViewGroup;
importandroid.view.animation.Animation;
importandroid.widget.TextView;
/**
*Createdbycchenon2014/9/2.
*/
publicclassCTextViewextendsViewGroup{
privateContextcontext;
publicCTextView(Contextcontext){
super(context);
this.context=context;
}
publicCTextView(Contextcontext,AttributeSetattrs){
super(context,attrs);
this.context=context;
}
publicCTextView(Contextcontext,AttributeSetattrs,intdefStyle){
super(context,attrs,defStyle);
this.context=context;
}
publicvoidsetText(Stringtext,finalAnimationanimation,intduration){
inttime=0;
if(text!=null&&!text.isEmpty()){
char[]characters=text.toCharArray();
for(charc:characters){
finalTextViewt=newTextView(context);
//遍历传入的字符串的每个字符,生成一个TextView,并设置它的动画
t.setText(String.valueOf(c));
t.setTextSize(28);
Handlerh=newHandler();
//每隔duration时间,播放下一个TextView的动画
h.postDelayed(newRunnable(){
@Override
publicvoidrun(){
addView(t);
t.setAnimation(animation);
}
},time);
time+=duration;
}
}
}
@Override
protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){
intmeasureWidth=measureWidth(widthMeasureSpec);
intmeasureHeight=measureHeight(heightMeasureSpec);
//计算自定义的ViewGroup中所有子控件的大小
measureChildren(widthMeasureSpec,heightMeasureSpec);
//设置自定义的控件MyViewGroup的大小
setMeasuredDimension(measureWidth,measureHeight);
}
@Override
protectedvoidonLayout(booleanchanged,intl,intt,intr,intb){
intchildLeft=0;
//遍历所有子视图
intchildCount=getChildCount();
for(inti=0;i<childCount;i++){
ViewchildView=getChildAt(i);
//获取在onMeasure中计算的视图尺寸
intmeasureHeight=childView.getMeasuredHeight();
intmeasuredWidth=childView.getMeasuredWidth();
//将他们横向排列
childView.layout(childLeft,0,childLeft+measuredWidth,measureHeight);
childLeft+=measuredWidth;
}
}
privateintmeasureWidth(intpWidthMeasureSpec){
intresult=0;
intwidthMode=MeasureSpec.getMode(pWidthMeasureSpec);//得到模式
intwidthSize=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方法传入的模式。
*/
caseMeasureSpec.AT_MOST:
caseMeasureSpec.EXACTLY:
result=widthSize;
break;
}
returnresult;
}
privateintmeasureHeight(intpHeightMeasureSpec){
intresult=0;
intheightMode=MeasureSpec.getMode(pHeightMeasureSpec);
intheightSize=MeasureSpec.getSize(pHeightMeasureSpec);
switch(heightMode){
caseMeasureSpec.AT_MOST:
caseMeasureSpec.EXACTLY:
result=heightSize;
break;
}
returnresult;
}
}
然后在布局文件中使用该自定义组件:
<LinearLayoutxmlns: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方法,传入相关参数即可:
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.view.animation.AnimationUtils;
publicclassTestActivityextendsActivity{
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_network_test);
CTextViewcTextView=(CTextView)findViewById(R.id.cTextView);
cTextView.setText("Helloworld",AnimationUtils.loadAnimation(this,R.anim.myanim),300);
}
}
其中的第二个参数为动画,我想要的效果是从透明到不透明,myanim.xml:
<?xmlversion="1.0"encoding="utf-8"?> <setxmlns:android="http://schemas.android.com/apk/res/android"> <alpha android:duration="1000" android:fromAlpha="0.0" android:toAlpha="1.0"/> </set>
如果想实现文字逐个从右侧飞入:
<?xmlversion="1.0"encoding="utf-8"?> <setxmlns: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实现逐字动画的全部内容,实现后效果还是很赞的,感兴趣的小伙伴们自己动手实践起来吧。如果有疑问可以留言讨论。