zoukankan      html  css  js  c++  java
  • 【Android】不依赖焦点和选中的TextView跑马灯



    前言

    继承TextView,并仿照源码修改而来,主要是取消了焦点和选中了判断,也不依赖文本的宽度。

    声明
    欢迎转载,但请保留文章原始出处:)
    博客园:http://www.cnblogs.com

    农民伯伯: http://over140.cnblogs.com 

    正文

    import java.lang.ref.WeakReference;

    import android.content.Context;
    import android.graphics.Canvas;
    import android.os.Handler;
    import android.os.Message;
    import android.util.AttributeSet;
    import android.widget.TextView;

    public class MarqueeTextView extends TextView {

        private Marquee mMarquee;

        public MarqueeTextView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }

        public MarqueeTextView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }

        public MarqueeTextView(Context context) {
            super(context);
        }

        public void startMarquee() {
            startMarquee(-1);
        }

        public void startMarquee(int repeatLimit) {
            if (mMarquee == null)
                mMarquee = new Marquee(this);
            mMarquee.start(repeatLimit);
        }

        public void stopMarquee() {
            if (mMarquee != null && !mMarquee.isStopped()) {
                mMarquee.stop();
            }
        }

        public void toggleMarquee() {
            if (mMarquee == null || mMarquee.isStopped())
                startMarquee();
            else
                stopMarquee();
        }

        @Override
        protected void onDraw(Canvas canvas) {
            if (mMarquee != null && mMarquee.isRunning()) {
                final float dx = -mMarquee.getScroll();
                canvas.translate(getLayoutDirection() == LAYOUT_DIRECTION_RTL ? -dx
                        : +dx, 0.0f);
            }
            super.onDraw(canvas);
        }

        @SuppressWarnings("unused")
        private static final class Marquee extends Handler {
            // TODO: Add an option to configure this
            private static final float MARQUEE_DELTA_MAX = 0.07f;
            private static final int MARQUEE_DELAY = 0;// 1200;
            private static final int MARQUEE_RESTART_DELAY = 1200;
            private static final int MARQUEE_RESOLUTION = 1000 / 30;
            private static final int MARQUEE_PIXELS_PER_SECOND = 30;

            private static final byte MARQUEE_STOPPED = 0x0;
            private static final byte MARQUEE_STARTING = 0x1;
            private static final byte MARQUEE_RUNNING = 0x2;

            private static final int MESSAGE_START = 0x1;
            private static final int MESSAGE_TICK = 0x2;
            private static final int MESSAGE_RESTART = 0x3;

            private final WeakReference<TextView> mView;

            private byte mStatus = MARQUEE_STOPPED;
            private final float mScrollUnit;
            private float mMaxScroll;
            private float mMaxFadeScroll;
            private float mGhostStart;
            private float mGhostOffset;
            private float mFadeStop;
            private int mRepeatLimit;

            private float mScroll;

            Marquee(TextView v) {
                final float density = v.getContext().getResources()
                        .getDisplayMetrics().density;
                mScrollUnit = (MARQUEE_PIXELS_PER_SECOND * density)
                        / MARQUEE_RESOLUTION;
                mView = new WeakReference<TextView>(v);
            }

            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                case MESSAGE_START:
                    mStatus = MARQUEE_RUNNING;
                    tick();
                    break;
                case MESSAGE_TICK:
                    tick();
                    break;
                case MESSAGE_RESTART:
                    if (mStatus == MARQUEE_RUNNING) {
                        if (mRepeatLimit >= 0) {
                            mRepeatLimit--;
                        }
                        start(mRepeatLimit);
                    }
                    break;
                }
            }

            void tick() {
                if (mStatus != MARQUEE_RUNNING) {
                    return;
                }

                removeMessages(MESSAGE_TICK);

                final TextView textView = mView.get();
                // && (textView.isFocused() || textView.isSelected())
                if (textView != null) {
                    mScroll += mScrollUnit;
                    if (mScroll > mMaxScroll) {
                        mScroll = mMaxScroll;
                        sendEmptyMessageDelayed(MESSAGE_RESTART,
                                MARQUEE_RESTART_DELAY);
                    } else {
                        sendEmptyMessageDelayed(MESSAGE_TICK, MARQUEE_RESOLUTION);
                    }
                    textView.invalidate();
                }
            }

            void stop() {
                mStatus = MARQUEE_STOPPED;
                removeMessages(MESSAGE_START);
                removeMessages(MESSAGE_RESTART);
                removeMessages(MESSAGE_TICK);
                resetScroll();
            }

            private void resetScroll() {
                mScroll = 0.0f;
                final TextView textView = mView.get();
                if (textView != null) {
                    textView.invalidate();
                }
            }

            void start(int repeatLimit) {
                if (repeatLimit == 0) {
                    stop();
                    return;
                }
                mRepeatLimit = repeatLimit;
                final TextView textView = mView.get();
                if (textView != null && textView.getLayout() != null) {
                    mStatus = MARQUEE_STARTING;
                    mScroll = 0.0f;
                    final int textWidth = textView.getWidth()
                            - textView.getCompoundPaddingLeft()
                            - textView.getCompoundPaddingRight();
                    final float lineWidth = textView.getLayout().getLineWidth(0);
                    final float gap = textWidth / 3.0f;
                    mGhostStart = lineWidth - textWidth + gap;
                    mMaxScroll = mGhostStart + textWidth;
                    mGhostOffset = lineWidth + gap;
                    mFadeStop = lineWidth + textWidth / 6.0f;
                    mMaxFadeScroll = mGhostStart + lineWidth + lineWidth;

                    textView.invalidate();
                    sendEmptyMessageDelayed(MESSAGE_START, MARQUEE_DELAY);
                }
            }

            float getGhostOffset() {
                return mGhostOffset;
            }

            float getScroll() {
                return mScroll;
            }

            float getMaxFadeScroll() {
                return mMaxFadeScroll;
            }

            boolean shouldDrawLeftFade() {
                return mScroll <= mFadeStop;
            }

            boolean shouldDrawGhost() {
                return mStatus == MARQUEE_RUNNING && mScroll > mGhostStart;
            }

            boolean isRunning() {
                return mStatus == MARQUEE_RUNNING;
            }

            boolean isStopped() {
                return mStatus == MARQUEE_STOPPED;
            }
        }
    }

    代码说明: 

    1、取消了焦点和选中的判断

    2、将延迟1200改为0,立即执行跑马灯效果。

    3、核心代码都是直接从TextView拷贝出来。

     

    2014-04-25 更新

    强烈建议参考本文的最新版本:【Android】不依赖焦点和选中的TextView跑马灯【2】 

    结束 

    这里主要是提供一种解决问题的思路,实际使用还需要进行相应的修改。
  • 相关阅读:
    poj-1273(最大流)
    SPOJ
    Gym
    (转)博弈 SG函数
    《STL详解》解题报告
    《STL详解》读书笔记
    LightOJ
    hdu1286 找新朋友 欧拉函数模板
    (转)数位dp
    (转)约瑟夫环问题
  • 原文地址:https://www.cnblogs.com/over140/p/3164712.html
Copyright © 2011-2022 走看看