西部数码主机 | 阿里云主机| 虚拟主机 | 服务器 | 返回乐道官网

Android通过自定义View实现纵向跑马灯效果

时间:2016-11-05 09:48来源:未知 作者:好模板 点击:
录制的gif有点卡,真实的效果还是很流畅的。 跑马灯在我们日常使用的app中还是很常见的,以前做外卖app的时候商家公告就使用了此效果,但是它是横向滚动的,横向滚动多适用于单条

录制的gif有点卡,真实的效果还是很流畅的。

跑马灯在我们日常使用的app中还是很常见的,以前做外卖app的时候商家公告就使用了此效果,但是它是横向滚动的,横向滚动多适用于单条信息;但凡涉及到多条信息的滚动展示,用纵向滚动效果会有更好的用户体验,今天我们通过自定义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等等都可以实现,大家有兴趣可以自己尝试。

(责任编辑:好模板)
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
栏目列表
热点内容