开源中文网

您的位置: 首页 > Android开发 > 正文

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

来源: 网络整理  作者: 佚名

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

Tags:跑马灯 纵向 效果
关于开源中文网 - 联系我们 - 广告服务 - 网站地图 - 版权声明