上下滚动文字自定义控件

原创 2016年05月31日 10:36:35

创建自定义控件VerticalRollingTextView

public class VerticalRollingTextView extends View {

    DataSetAdapter mDataSetAdapter;

    private final Paint mPaint;

    private int mCurrentIndex;
    private int mNextIndex;

    Rect bounds = new Rect();

    private float mCurrentOffsetY;

    private float mOrgOffsetY = -1;

    private final float mTextTopToAscentOffset;
    private float mOffset;

    private InternalAnimation mAnimation = new InternalAnimation();

    /*防止动画结束的回调触发以后动画继续进行出现的错乱问题*/
    private boolean mAnimationEnded;

    private boolean isRunning;
    /*动画时间*/
    private int mDuration = 1000;
    /*动画间隔*/
    private int mAnimInterval = 2000;

    public VerticalRollingTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.BLACK);
        mPaint.setTypeface(Typeface.DEFAULT);

        parseAttrs(context, attrs);

        Paint.FontMetricsInt metricsInt = mPaint.getFontMetricsInt();
        mTextTopToAscentOffset = metricsInt.ascent - metricsInt.top;

        mAnimation.setDuration(mDuration);
    }

    private void parseAttrs(Context context, AttributeSet attrs) {
        float density = getResources().getDisplayMetrics().density;
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.VerticalRollingTextView);
        mPaint.setColor(typedArray.getColor(R.styleable.VerticalRollingTextView_android_textColor, Color.BLACK));
        mPaint.setTextSize(typedArray.getDimensionPixelOffset(R.styleable.VerticalRollingTextView_android_textSize, (int) (density * 14)));
        mDuration = typedArray.getInt(R.styleable.VerticalRollingTextView_android_duration, mDuration);
        mAnimInterval = typedArray.getInt(R.styleable.VerticalRollingTextView_animInterval, mAnimInterval);

        typedArray.recycle();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // 绘制文本
        if (mDataSetAdapter == null || mDataSetAdapter.isEmpty()) {
            return;
        }

        String text1 = mDataSetAdapter.getText(mCurrentIndex);
        String text2 = mDataSetAdapter.getText(mNextIndex);

        //只需要进行一次测量
        if (mOrgOffsetY == -1) {
            mPaint.getTextBounds(text1, 0, text1.length(), bounds);
            mOffset = (getHeight() + bounds.height()) * 0.5f;
            mOrgOffsetY = mCurrentOffsetY = mOffset - mTextTopToAscentOffset;
            mAnimation.updateValue(mOrgOffsetY, -2 * mTextTopToAscentOffset);
        }

        canvas.drawText(text1, 0, mCurrentOffsetY, mPaint);
        canvas.drawText(text2, 0, mCurrentOffsetY + mOffset + mTextTopToAscentOffset, mPaint);
    }

    public void setDataSetAdapter(DataSetAdapter dataSetAdapter) {
        mDataSetAdapter = dataSetAdapter;
        confirmNextIndex();
        invalidate();
    }

    /**
     * 开始转动,界面可见的时候调用
     */
    public void run() {
        if (isRunning) {
            return;
        }

        isRunning = true;
        mAnimation.updateValue(mCurrentOffsetY, -2 * mTextTopToAscentOffset);
        post(mRollingTask);
    }

    /**
     * @return true代表正在转动
     */
    public boolean isRunning() {
        return isRunning;
    }

    /**
     * 停止转动,界面不可见的时候调用
     */
    public void stop() {
        isRunning = false;
        removeCallbacks(mRollingTask);
    }

    Runnable mRollingTask = new Runnable() {
        @Override
        public void run() {
            mAnimationEnded = false;
            startAnimation(mAnimation);
            postDelayed(this, mAnimInterval);
        }
    };


    public void animationEnd() {
        //1.角标+1
        mCurrentIndex++;
        //2.计算出正确的角标
        mCurrentIndex = mCurrentIndex < mDataSetAdapter.getItemCount() ? mCurrentIndex : mCurrentIndex % mDataSetAdapter.getItemCount();
        //3.计算下一个待显示文字角标
        confirmNextIndex();
        //3.位置复位
        mCurrentOffsetY = mOrgOffsetY;
        mAnimationEnded = true;
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        removeCallbacks(mRollingTask);
        if (isRunning()) {
            mAnimation.cancel();
        }
    }

    /**
     * 计算第二个角标
     */
    private void confirmNextIndex() {
        //3.计算第二个角标
        mNextIndex = mCurrentIndex + 1;
        //4.计算出正确的第二个角标
        mNextIndex = mNextIndex < mDataSetAdapter.getItemCount() ? mNextIndex : 0;
    }

    /**
     * float估值器
     *
     * @param fraction
     * @param startValue
     * @param endValue
     * @return
     */
    float evaluate(float fraction, float startValue, float endValue) {
        return startValue + fraction * (endValue - startValue);
    }

    @Override
    public void setOnClickListener(OnClickListener l) {

    }

    public void setOnItemClickListener(final OnItemClickListener onItemClickListener) {
        super.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                onItemClickListener.onItemClick(VerticalRollingTextView.this, mCurrentIndex);
            }
        });
    }

    public interface OnItemClickListener {
        void onItemClick(VerticalRollingTextView view, int index);
    }

    class InternalAnimation extends Animation {

        float startValue;
        float endValue;

        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            if (mAnimationEnded) return;

            mCurrentOffsetY = evaluate(interpolatedTime, startValue, endValue);
            if (mCurrentOffsetY == endValue) {
                animationEnd();
            }
            postInvalidate();
        }

        public void updateValue(float startValue, float endValue) {
            this.startValue = startValue;
            this.endValue = endValue;
        }

    }

}

然后在values文件夹下创建attrs,自定义属性

<resources>
    <declare-styleable name="VerticalRollingTextView">
        <!--文字颜色-->
        <attr name="android:textColor"/>
        <!--文字大小-->
        <attr name="android:textSize"/>
        <!--滚动动画时长-->
        <attr name="android:duration"/>
        <!--两次动画之间的间隔-->
        <attr name="animInterval" format="integer"/>
    </declare-styleable>
</resources>

最后在布局中调用

            <com.bawei.redchild.view.VerticalRollingTextView
                    android:id="@+id/home_rolling_tv"
                    android:layout_height="40dp"
                    android:layout_width="match_parent"
                    android:layout_alignParentLeft="true"
                    myattrs:animInterval="3000"
                    android:layout_marginLeft="75dp"
                    android:layout_marginTop="8dp"
                    android:textSize="18sp"
                />
                <!-- animInterval 滚动间隔时间 -->

在代码中获取控件,并给控件设置数据

mVerticalRollingView.setDataSetAdapter(new DataSetAdapter<String>(Arrays.asList(mStrs)) {

            @Override
            protected String text(String s) {
                return s;
            }
        });

可以设置点击监听

        mVerticalRollingView.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(VerticalRollingTextView view, int index) {
                Toast.makeText(MainActivity.this, mStrs[index], Toast.LENGTH_SHORT).show();

            }
        });

最后开始,或者停止这个滚动字幕

        if (mVerticalRollingView.isRunning()) {
            //停止滚动
            mVerticalRollingView.stop();
            button.setText("滚动");
        } else {
            //开始滚动
            mVerticalRollingView.run();
            button.setText("停止");
        }

相关文章推荐

自定义textview控件实现文字滚动效果

/** * 当触摸该控件是会滚动 */ public class ZDYMarqueeText extends TextView { private int speed = 3;...

Android自定义控件实现多行文字自动向上滚动轮播效果(伪文字轮播)

[TOC] 转载请注明出处:http://write.blog.csdn.net/mdeditor最近一个朋友有个需求,需要实现多行文字自动向上翻滚的效果,上网找了很多没有特别满意的,只有一个dem...
  • CHX_W
  • CHX_W
  • 2017年07月09日 00:13
  • 1043

自定义文字滚动控件,用于单行文本的显示,当文字过长的时候,就会自动的向左滚动

//-------------------------------------------------说明---------------------------------------------...
  • think12
  • think12
  • 2011年01月10日 21:20
  • 1403

自定义控件_滚动的TextView

  • 2016年04月20日 16:42
  • 2.48MB
  • 下载

自定义控件实现(淘宝头条/京东快报)垂直循环滚动栏目

1、通过继承LinearLayout的方式 ①自定义属性 xml version="1.0" encoding="utf-8"?> name="JDAdverView"> ...

自定义滚动导航控件

  • 2015年01月28日 16:31
  • 621KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:上下滚动文字自定义控件
举报原因:
原因补充:

(最多只允许输入30个字)