图+文上下滚动跑马灯实现

<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: rgb(255, 255, 255);">实现思路:</span>

跑马灯上下滚动,需要三部分:

1.当前显示的图文信息区域,用类ItemInfo对象currentItem表示,ItemInfo类包括Rect信息与绘制图文信息,并提供绘制方法。
2.紧挨着当前区域上方的区域,用类ItemInfo对象preItem,如果跑马灯向上滚,此对象表示滚动后的最终位置
3.着当前区域下方的区域,用类ItemInfo对象nextItem,如果跑马灯向上滚,此对象表示下一条图文信息,滚动到currentItem的位置

 class ItemInfo {
        private Rect srcRect;
        private Rect varyRect;
        private boolean isAchieve;
        private String content;
        private Drawable icon;
        private String time;

        public ItemInfo(Rect rect) {
            srcRect = rect;
            varyRect = new Rect(rect);
            isAchieve = true;
        }

        public void update(int recouseid, String content, String time) {
            this.content = content;
            this.time = time;
            icon = getResources().getDrawable(recouseid);
            varyRect = new Rect(srcRect);
            isAchieve = false;
        }

        public Rect getSrcRect() {
            return srcRect;
        }

        public void draw(Canvas canvas, Paint paint) {
            BitmapDrawable bd = (BitmapDrawable) icon;
            canvas.drawBitmap(bd.getBitmap(), getPaddingLeft(), varyRect.centerY() - icon.getIntrinsicHeight() / 2, paint);

            m_paint.setTextAlign(Paint.Align.LEFT);
            m_paint.setTextSize(getTextSize());
            Paint.FontMetricsInt fontMetricsContent = m_paint.getFontMetricsInt();
            int baselineContent = (varyRect.bottom + varyRect.top - fontMetricsContent.bottom - fontMetricsContent.top) / 2;
            canvas.drawText(content, (float) (getCompoundDrawablePadding() + icon.getIntrinsicWidth()), baselineContent, paint);

            m_paint.setTextAlign(Paint.Align.RIGHT);
            m_paint.setTextSize(timeTextSize);
            Paint.FontMetricsInt fontMetricsTime = m_paint.getFontMetricsInt();
            int baselineTime = (varyRect.bottom + varyRect.top - fontMetricsTime.bottom - fontMetricsTime.top) / 2;
            canvas.drawText(time, varyRect.width(), baselineTime, paint);
        }

        private Rect getStringRect(String strText) {
            Rect rect = new Rect();
            m_paint.getTextBounds(strText, 0, strText.length(), rect);
            return rect;
        }

        public void moveTo(Rect rect, int gapX, int gapY) {
            if (isAchieve) return;
            if (varyRect.equals(rect)) {
                isAchieve = true;
                return;
            }
            if (Math.abs(rect.left - varyRect.left) < gapX) {
                varyRect.left = rect.left;
                varyRect.right = rect.right;
            } else {
                varyRect.left += gapX;
                varyRect.right += gapX;
            }
            if (Math.abs(rect.top - varyRect.top) < gapY) {
                varyRect.top = rect.top;
                varyRect.bottom = rect.bottom;
            } else {
                varyRect.top += gapY;
                varyRect.bottom += gapY;
            }
        }

        public void reset() {
            isAchieve = true;
            varyRect = new Rect(srcRect);
        }

        public boolean isAchieve() {
            return isAchieve;
        }
    }

            Rect rect = new Rect(0, 0, getMeasuredWidth(), getMeasuredHeight());
            curItemInfo = new ItemInfo(rect);
            nextItemInfo = new ItemInfo(new Rect(0, rect.height(), rect.width(), rect.height() * 2));
            preItemInfo = new ItemInfo(new Rect(0, -rect.height(), rect.width(), 0));


实现向上滚动效果(向下同理):

以当前显示的currentItem移动preItem位置时,为终止条件,每隔一定时间,更新OnDraw,Rect的Y轴位置增加变化量,向上移动一小段距离,更新绘制currentItem的位置,到preItem位置时停止刷新OnDraw。(跑马灯,向上移出旧的图文信息)
nextItem做为下一条图文信息显示,跟着currentItem做相同的行为,以当前显示的currentItem移动到preItem位置时,为终止条件。(跑马灯,向上移入新的图文信息)
 @Override
        public boolean run() {
//            // TODO Auto-generated method stub
            if (curItemInfo == null) {
                sleep(200);
                return true;
            }
            if (!curItemInfo.isAchieve()) {
                nextItemInfo.moveTo(curItemInfo.getSrcRect(), 0, -GAP);
                curItemInfo.moveTo(preItemInfo.getSrcRect(), 0, -GAP);
                intervalDraw();
                return true;
            } else {
                if (SystemClock.uptimeMillis() - stopTime > showDuration) {
                    startIntervalDraw();
                    return true;
                }
                sleep(1000);
                return true;
            }
        }

        private void intervalDraw() {
            postInvalidate();
            sleep(50);
        }

        private void startIntervalDraw() {
            updateData();
        }


每一次移动到目标位置后,会停止显示当前图文几秒,并更新下一轮显示的图文信息。

        private void updateData() {
            stopTime = SystemClock.uptimeMillis();
            setTag(index);
            curItemInfo.update(R.drawable.publisher_sign_official, listStrings.get(index), "2016.6.14");
            if (index >= listStrings.size() - 1) {
                index = 0;
            } else {
                index++;
            }
            nextItemInfo.update(R.drawable.publisher_sign_official, listStrings.get(index), "2016.6.14");
        }

绘制
       @Override
        public void draw(Canvas canvas) {
            if (nextItemInfo == null) {
                return;
            }
            nextItemInfo.draw(canvas, m_paint);
            curItemInfo.draw(canvas, m_paint);
        }

全部代码:
package mktech.community.view.component;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;

import com.mktech.utils.LogUtils;

import java.util.List;

import mktech.community.R;
import mktech.community.UIContant;
import mktech.community.view.MyApplication;

public class MarqueeTextView extends TextView implements Runnable {
    private Paint m_paint;
    private Action mAction;
    private int timeTextSize = 18;
    private boolean isStopThread = true;

    public void setList(List<String> list) {
        if (list.size() == 0) return;
        mAction = new Loop(list);
        mAction.init();
        if (isStopThread) {
            isStopThread = false;
            new Thread(this).start();
        }
    }

    public void setOnClickListener(final OnClickListener listener) {
        super.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (listener != null) {
                    listener.onClick(v);
                }
            }
        });
    }

    @Override
    public void run() {
        while (!isStopThread && !Thread.currentThread().isInterrupted()) {
            if (mAction != null) {
                if (!mAction.run()) {
                    break;
                }
            } else {
                sleep(200);
            }
        }
        isStopThread = true;
    }

    public void setText(final int icon, final String text) {
        mAction = new One(icon, text);
        if (isStopThread) {
            isStopThread = false;
            new Thread(this).start();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }


    public MarqueeTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        m_paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        m_paint.setStrokeWidth(3);
        m_paint.setColor(getTextColors().getDefaultColor());
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MarqueeTextView);
        timeTextSize = typedArray.getDimensionPixelSize(R.styleable.MarqueeTextView_TimeTextSize, 18);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);
        if (mAction != null) {
            mAction.draw(canvas);
        }
    }


    interface Action {
        void init();

        void draw(Canvas canvas);

        /**
         * @return true不跳出循环,false不再循环。
         */
        boolean run();
    }

    class ItemInfo {
        private Rect srcRect;
        private Rect varyRect;
        private boolean isAchieve;
        private String content;
        private Drawable icon;
        private String time;

        public ItemInfo(Rect rect) {
            srcRect = rect;
            varyRect = new Rect(rect);
            isAchieve = true;
        }

        public void update(int recouseid, String content, String time) {
            this.content = content;
            this.time = time;
            icon = getResources().getDrawable(recouseid);
            varyRect = new Rect(srcRect);
            isAchieve = false;
        }

        public Rect getSrcRect() {
            return srcRect;
        }

        public void draw(Canvas canvas, Paint paint) {
            BitmapDrawable bd = (BitmapDrawable) icon;
            canvas.drawBitmap(bd.getBitmap(), getPaddingLeft(), varyRect.centerY() - icon.getIntrinsicHeight() / 2, paint);

            m_paint.setTextAlign(Paint.Align.LEFT);
            m_paint.setTextSize(getTextSize());
            Paint.FontMetricsInt fontMetricsContent = m_paint.getFontMetricsInt();
            int baselineContent = (varyRect.bottom + varyRect.top - fontMetricsContent.bottom - fontMetricsContent.top) / 2;
            canvas.drawText(content, (float) (getCompoundDrawablePadding() + icon.getIntrinsicWidth()), baselineContent, paint);

            m_paint.setTextAlign(Paint.Align.RIGHT);
            m_paint.setTextSize(timeTextSize);
            Paint.FontMetricsInt fontMetricsTime = m_paint.getFontMetricsInt();
            int baselineTime = (varyRect.bottom + varyRect.top - fontMetricsTime.bottom - fontMetricsTime.top) / 2;
            canvas.drawText(time, varyRect.width(), baselineTime, paint);
        }

        private Rect getStringRect(String strText) {
            Rect rect = new Rect();
            m_paint.getTextBounds(strText, 0, strText.length(), rect);
            return rect;
        }

        public void moveTo(Rect rect, int gapX, int gapY) {
            if (isAchieve) return;
            if (varyRect.equals(rect)) {
                isAchieve = true;
                return;
            }
            if (Math.abs(rect.left - varyRect.left) < gapX) {
                varyRect.left = rect.left;
                varyRect.right = rect.right;
            } else {
                varyRect.left += gapX;
                varyRect.right += gapX;
            }
            if (Math.abs(rect.top - varyRect.top) < gapY) {
                varyRect.top = rect.top;
                varyRect.bottom = rect.bottom;
            } else {
                varyRect.top += gapY;
                varyRect.bottom += gapY;
            }
        }

        public void reset() {
            isAchieve = true;
            varyRect = new Rect(srcRect);
        }

        public boolean isAchieve() {
            return isAchieve;
        }
    }

    class Loop implements Action {
        private static final int GAP = 10;
        private static final int showDuration = 3000;
        private List<String> listStrings;
        private int index;
        private long stopTime = 0;
        private ItemInfo curItemInfo;
        private ItemInfo nextItemInfo;
        private ItemInfo preItemInfo;

        public Loop(List<String> listStrings) {
            this.listStrings = listStrings;
        }


        private void startDraw() {
            if (listStrings == null && listStrings.size() == 0) return;
            Rect rect = new Rect(0, 0, getMeasuredWidth(), getMeasuredHeight());
            curItemInfo = new ItemInfo(rect);
            nextItemInfo = new ItemInfo(new Rect(0, rect.height(), rect.width(), rect.height() * 2));
            preItemInfo = new ItemInfo(new Rect(0, -rect.height(), rect.width(), 0));
            index = 0;
            updateData();
        }

        @Override
        public void init() {
            startDraw();
        }

        private void updateData() {
            stopTime = SystemClock.uptimeMillis();
            setTag(index);
            curItemInfo.update(R.drawable.publisher_sign_official, listStrings.get(index), "2016.6.14");
            if (index >= listStrings.size() - 1) {
                index = 0;
            } else {
                index++;
            }
            nextItemInfo.update(R.drawable.publisher_sign_official, listStrings.get(index), "2016.6.14");
        }

        @Override
        public void draw(Canvas canvas) {
            if (nextItemInfo == null) {
                return;
            }
            nextItemInfo.draw(canvas, m_paint);
            curItemInfo.draw(canvas, m_paint);
        }

        @Override
        public boolean run() {
//            // TODO Auto-generated method stub
            if (curItemInfo == null) {
                sleep(200);
                return true;
            }
            if (!curItemInfo.isAchieve()) {
                nextItemInfo.moveTo(curItemInfo.getSrcRect(), 0, -GAP);
                curItemInfo.moveTo(preItemInfo.getSrcRect(), 0, -GAP);
                intervalDraw();
                return true;
            } else {
                if (SystemClock.uptimeMillis() - stopTime > showDuration) {
                    startIntervalDraw();
                    return true;
                }
                sleep(1000);
                return true;
            }
        }

        private void intervalDraw() {
            postInvalidate();
            sleep(50);
        }

        private void startIntervalDraw() {
            updateData();
        }

    }

    private void sleep(int time) {
        try {
            Thread.sleep(time);
        } catch (Exception e) {
            // TODO: handle exception
            Thread.currentThread().interrupt();
        }
    }

    class One implements Action {
        private int icon;
        private String text;
        private ItemInfo curItemInfo;

        public One(int icon, String text) {
            this.icon = icon;
            this.text = text;
        }

        @Override
        public boolean run() {
            while (getMeasuredWidth() == 0) {
                sleep(100);
                mAction.init();
            }
            return false;
        }

        @Override
        public void init() {
            Rect rect = new Rect(0, 0, getMeasuredWidth(), getMeasuredHeight());
            curItemInfo = new ItemInfo(rect);
            postInvalidate();
        }

        @Override
        public void draw(Canvas canvas) {
            if (curItemInfo == null) return;
            curItemInfo.update(icon, text, "2016.6.14");
            curItemInfo.draw(canvas, m_paint);
        }
    }

}


 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值