首页 > 系统 > Android > 正文

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

2019-12-12 04:46:52
字体:
来源:转载
供稿:网友

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表