利用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实现逐字动画的全部内容,实现后效果还是很赞的,感兴趣的小伙伴们自己动手实践起来吧。如果有疑问可以留言讨论。