欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android自定义View实现纵向跑马灯效果详解

程序员文章站 2024-03-31 17:06:34
首先看看效果图(录制的gif有点卡,真实的效果还是很流畅的) 实现思路 通过上面的gif图可以得出结论,其实它就是同时绘制两条文本信息,然后通过动画不断的改...

首先看看效果图(录制的gif有点卡,真实的效果还是很流畅的)

Android自定义View实现纵向跑马灯效果详解

实现思路

通过上面的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等等都可以实现,大家有兴趣可以自己尝试。希望本文的内容对大家的学习或者工作能有所帮助,如果有疑问大家可以留言交流。