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

时间: 2024-10-25 00:28:42

Android自定义View实现纵向跑马灯效果详解的相关文章

Android自定义View中attrs.xml的实例详解

Android自定义View中attrs.xml的实例详解 我们在自定义View的时候通常需要先完成attrs.xml文件 在values中定义一个attrs.xml 然后添加相关属性 这一篇先详细介绍一下attrs.xml的属性. <?xml version="1.0" encoding="utf-8"?> <resources> //自定义属性名,定义公共属性 <attr name="titleText" for

css3 跑马灯效果详解

在手机端实现跑马灯效果,可以直接使用css3实现: 具体代码实现: 首先指定溢出时滚动: overflow:-webkit-marquee; 跑马灯样式,分三种: -webkit-marquee-style:scroll | slide | alternate; scroll,从一端滚动到另一端,内容完全滚入(消失)时重新开始. slide,从一端滚到另一端,内容接触到另一端后,立马重新开始.(ios实测和scroll一致) alternate,内容不跑到显示区域外,在里面来回碰壁反弹.这里主要

Android自定义View实现绘制虚线的方法详解

前言 说实话当第一次看到这个需求的时候,第一反应就是Canvas只有drawLine方法,并没有drawDashLine方法啊!这咋整啊,难道要我自己做个遍历不断的drawLine?不到1秒,我就放弃这个想法了,因为太恶心了.方法肯定是有的,只不过我不知道而已. 绘制方法 最简单的方法是利用ShapeDrawable,比如说你想用虚线要隔开两个控件,就可以在这两个控件中加个View,然后给它个虚线背景. 嗯,理论上就是这样子的,实现上也很简单. <!-- drawable 文件 --> <

Android 自定义View实现芝麻分曲线图效果_Android

1.简介 其实这个效果几天之前就写了,但是一直没有更新博客,本来想着把芝麻分雷达图也做好再发博客的,然后今天看到鸿洋的微信公众号有朋友发了芝麻分的雷达图,所以就算了,算是一个互补吧.平时文章也写的比较少,所以可能有点杂乱,有什么需要改进的地方欢迎给出建议,不胜感激. 效果图: 2.步骤: 初始化View的属性 初始化画笔 绘制代表最高分和最低分的两根虚线 绘制文字 绘制代表月份的属性 绘制芝麻分折线 绘制代表芝麻分的圆点 绘制选中分数的悬浮文字以及背景 处理点击事件 3.编码: 初始化View属

Android基于TextView实现的跑马灯效果实例_Android

本文实例讲述了Android基于TextView实现的跑马灯效果.分享给大家供大家参考,具体如下: package sweet.venst.act; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStrea

Android基于TextView实现的跑马灯效果实例

本文实例讲述了Android基于TextView实现的跑马灯效果.分享给大家供大家参考,具体如下: package sweet.venst.act; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStrea

Android自定义View控件实现刷新效果_Android

三种得到LinearInflater的方法 a. LayoutInflater inflater = getLayoutInflater(); b. LayoutInflater localinflater = (LayoutInflater)context.getSystemService (Context.LAYOUT_INFLATER_SERVICE); c. LayoutInflater inflater = LayoutInflater.from(context); onDraw 方法

Android自定义View 实现水波纹动画引导效果

一.实现效果图 二.实现代码 1.自定义view package com.czhappy.showintroduce.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Pat

Android自定义View控件实现刷新效果

三种得到LinearInflater的方法 a. LayoutInflater inflater = getLayoutInflater(); b. LayoutInflater localinflater = (LayoutInflater)context.getSystemService (Context.LAYOUT_INFLATER_SERVICE); c. LayoutInflater inflater = LayoutInflater.from(context); onDraw 方法