Android自定义View实现纵向跑马灯效果详解
程序员文章站
2024-03-31 17:06:34
首先看看效果图(录制的gif有点卡,真实的效果还是很流畅的)
实现思路
通过上面的gif图可以得出结论,其实它就是同时绘制两条文本信息,然后通过动画不断的改...
首先看看效果图(录制的gif有点卡,真实的效果还是很流畅的)
实现思路
通过上面的gif图可以得出结论,其实它就是同时绘制两条文本信息,然后通过动画不断的改变两条文本信息距离顶部的高度,以此来实现滚动的效果。
具体实现
首先定义一些要用到的属性
<declare-styleable name="marqueeviewstyle"> <attr name="textsize" format="dimension" /> <attr name="textcolor" format="color" /> <attr name="paddingleft" format="dimension" /> <attr name="paddingtop" format="dimension" /> <attr name="paddingbottom" format="dimension" /> <attr name="paddingtopbottom" format="dimension"/> <attr name="startdelaytime" format="integer"/> 动画开始延迟时间 <attr name="rerepeatdelaytime" format="integer"/> 动画重复延迟时间 <attr name="itemanimationtime" format="integer"/> 单个动画的执行时间 </declare-styleable>
接下来解析属性值
private void init(context context, attributeset attrs) { typedarray typedarray = context.obtainstyledattributes(attrs, r.styleable.marqueeviewstyle); mtextcolor = typedarray.getcolor(r.styleable.marqueeviewstyle_textcolor, color.black); mtextsize = typedarray.getdimensionpixelsize(r.styleable.marqueeviewstyle_textsize, 45); mpaddingleft = typedarray.getdimensionpixelsize(r.styleable.marqueeviewstyle_paddingleft, 15); mpaddingtop = mpaddingbottom = typedarray.getdimensionpixelsize(r.styleable.marqueeviewstyle_paddingtopbottom, 25); mpaddingtop = typedarray.getdimensionpixelsize(r.styleable.marqueeviewstyle_paddingtop, mpaddingtop); mpaddingbottom = typedarray.getdimensionpixelsize(r.styleable.marqueeviewstyle_paddingbottom, mpaddingbottom); itemanimationtime = typedarray.getinteger(r.styleable.marqueeviewstyle_itemanimationtime, 1000); rerepeatdelaytime = typedarray.getinteger(r.styleable.marqueeviewstyle_rerepeatdelaytime, 1000); startdelaytime = typedarray.getinteger(r.styleable.marqueeviewstyle_startdelaytime, 500); typedarray.recycle(); mpaint = new paint(); mpaint.setantialias(true); mpaint.settextsize(mtextsize); mpaint.setcolor(mtextcolor); mpaint.settextalign(paint.align.left);}
重写onmeasure方法
protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { if(mtextarray == null || mtextarray.length == 0) { super.onmeasure(widthmeasurespec, heightmeasurespec); } else { int width = measurespec.getsize(widthmeasurespec); int height = measurespec.getsize(heightmeasurespec); viewgroup.layoutparams lp = getlayoutparams(); setmeasureddimension(getviewwidth(lp, width), getviewheight(lp, height)); } }
数据为空时调用父类的方法,设置数据以后根据不同的布局计算宽高。
设置数据
public void settextarray(string[] textarray) { if(textarray == null || textarray.length <= 1) return; mtextarray = textarray; inittextrect(); settextcurrentornextstatus(0, 1, true); startanimation();}
inittextrect()
方法是计算出单个文本的高度和数组中最大文本的宽度,文本的高度用来计算绘制文本时的位置,文本的最大宽度在onmeasure()
方法的时候会用到。
settextcurrentornextstatus()
方法设置当前的position,文本以及下一个position,文本。还有文本距离顶部的初始化高度。
startanimation()
方法 开始执行动画。
动画实现
private void startanimation() { va = valueanimator.offloat(0, 1); va.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator animation) { mprogress = (float) animation.getanimatedvalue(); . int moveoffset = (int) (mtextmoveoffset * mprogress); mcurrenttextmovemargintop = mcurrenttextinitmargintop - moveoffset; mnexttextmovemargintop = mnexttextinitmargintop - moveoffset; postinvalidate(); } }); va.addlistener(new animatorlisteneradapter() { @override public void onanimationrepeat(animator animation) { va.pause(); settextcurrentornextstatus(mnexttextposition, mnexttextposition + 1, false); handler.postdelayed(new runnable() { @override public void run() { va.resume(); } }, rerepeatdelaytime); } }); va.setrepeatcount(-1); va.setduration(itemanimationtime); va.setstartdelay(startdelaytime); va.start(); }
va.setrepeatcount(-1);
设置动画无限重复
onanimationupdate()
方法得到动画执行的进度,计算出text距离顶部的距离,调用postinvalidate()
方法刷新界面。
onanimationrepeat()
方法,通过handler延迟rerepeatdelaytime时间,再重新执行动画。
绘制
protected void ondraw(canvas canvas) { if(mtextarray == null || mtextarray.length == 0) { super.ondraw(canvas); } else { canvas.drawtext(mcurrenttext, mpaddingleft, mcurrenttextmovemargintop, mpaint); canvas.drawtext(mnexttext, mpaddingleft, mnexttextmovemargintop, mpaint); } }
总结
到这里所有的代码已经分析完毕,其实实现这个效果还有很多种方法,通过继承viewgroup等等都可以实现,大家有兴趣可以自己尝试。希望本文的内容对大家的学习或者工作能有所帮助,如果有疑问大家可以留言交流。
上一篇: 详解django中自定义标签和过滤器