jp.co.ipublishing.esnavi.views.MarqueeView.java Source code

Java tutorial

Introduction

Here is the source code for jp.co.ipublishing.esnavi.views.MarqueeView.java

Source

/*
 * Copyright 2015 iPublishing Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package jp.co.ipublishing.esnavi.views;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;

import org.apache.commons.lang3.exception.ExceptionUtils;

import jp.co.ipublishing.esnavi.R;

/**
 * ??
 */
public class MarqueeView extends View {
    private static final String TAG = "MarqueeView";

    @NonNull
    private final Paint mTextPaint = new Paint();

    @NonNull
    private String mText = "";

    private boolean mRunning = true;

    private int mLastX;

    /**
     * ??
     */
    private int mRepeatCount = 0;

    /**
     * 
     */
    private int mRepeatLimit = 1;

    /**
     * ????
     */
    private int mCurrentX;

    /**
     * 1????
     */
    private int mTextMoveSpeed = 5;

    /**
     * ?(?)
     */
    private final Runnable runnable = new Runnable() {
        public void run() {
            // ??X
            mLastX = getLastX();

            while (mRepeatCount < mRepeatLimit || mRepeatLimit < 0) {
                mCurrentX = getMarqueeStartX(); // ??

                final int fps = 30;
                final long frameTime = 1000 / fps;

                long beforeTime = System.currentTimeMillis();
                long afterTime;

                // 1??
                while (mRunning) {
                    // ?????1???
                    if (mCurrentX <= mLastX) {
                        mRepeatCount += 1;
                        break;
                    }

                    mCurrentX -= mTextMoveSpeed;
                    postInvalidate();

                    afterTime = System.currentTimeMillis();
                    final long pastTime = afterTime - beforeTime;
                    final long sleepTime = frameTime - pastTime;

                    if (sleepTime > 0) {
                        try {
                            Thread.sleep(sleepTime);
                        } catch (Exception e) {
                            Log.e(TAG, ExceptionUtils.getStackTrace(e));
                        }
                    }
                    beforeTime = System.currentTimeMillis();
                }
            }
        }
    };

    /**
     * ??
     */
    @Nullable
    private Thread mThread;

    /**
     * (XML????)
     *
     * @param context 
     */
    public MarqueeView(Context context) {
        super(context);

        initMarqueeView();
    }

    /**
     * (XML??)
     *
     * @param context 
     * @param attrs   XML???
     */
    public MarqueeView(Context context, AttributeSet attrs) {
        super(context, attrs);

        initMarqueeView();

        // XML??
        final TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.MarqueeView);

        final String marqueeText = attributes.getString(R.styleable.MarqueeView_marquee_text);
        if (marqueeText != null) {
            setText(marqueeText);
        }

        final int textSize = attributes.getDimensionPixelOffset(R.styleable.MarqueeView_marquee_textSize, 0);
        if (textSize > 0) {
            setTextSize(textSize);
        }

        final int padding = attributes.getDimensionPixelOffset(R.styleable.MarqueeView_marquee_padding, 0);
        if (padding > 0) {
            setPadding(padding, padding, padding, padding);
        }

        setTextColor(attributes.getColor(R.styleable.MarqueeView_marquee_textColor, 0xFFFFFFFF));
        setBackgroundColor(attributes.getColor(R.styleable.MarqueeView_marquee_background, 0xFF000000));
        setRepeatLimit(attributes.getInteger(R.styleable.MarqueeView_marquee_repeatLimit, 1));
        setTextMoveSpeed(attributes.getInteger(R.styleable.MarqueeView_marquee_textMoveSpeed, 5));

        attributes.recycle();
    }

    /**
     * ??
     * ??????????
     */
    private void initMarqueeView() {
        mTextPaint.setAntiAlias(true);
        mTextPaint.setTextSize(25);
        mTextPaint.setColor(0xFFFFFFFF);

        setPadding(0, 0, 0, 0);
        setBackgroundColor(0xFF000000);

        requestLayout();
        invalidate();
    }

    /**
     * ???
     */
    public void clearMarquee() {
        mCurrentX = getMarqueeStartX();
        mRepeatCount = 0;
        mRunning = false;
    }

    /**
     * ??
     */
    public void startMarquee() {
        clearMarquee();

        mRunning = true;

        if (mThread == null) {
            mThread = new Thread(runnable);
            mThread.start();
        } else {
            mLastX = getLastX();
            mCurrentX = getMarqueeStartX();
        }
    }

    /**
     * ?
     *
     * @param repeatLimit ???
     */
    public void setRepeatLimit(int repeatLimit) {
        this.mRepeatLimit = repeatLimit;
    }

    /**
     * ?(px)?
     *
     * @param speed (?)
     */
    public void setTextMoveSpeed(int speed) {
        if (speed > 0) {
            mTextMoveSpeed = speed;
        }
    }

    /**
     * ?
     *
     * @param text ?
     */
    public void setText(@NonNull String text) {
        this.mText = text;

        requestLayout();
        invalidate();
    }

    /**
     * ?
     *
     * @param size 
     */
    public void setTextSize(int size) {
        mTextPaint.setTextSize(size);

        requestLayout();
        invalidate();
    }

    /**
     * ?
     *
     * @param color
     */
    public void setTextColor(int color) {
        mTextPaint.setColor(color);

        invalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
    }

    /**
     * ??
     *
     * @param measureSpec
     * @return
     */
    private int measureWidth(int measureSpec) {
        final int result;
        final int specMode = MeasureSpec.getMode(measureSpec);
        final int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            // We were told how big to be
            result = specSize;
        } else {
            final WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
            final Display display = wm.getDefaultDisplay();
            result = display.getWidth();
        }

        return result;
    }

    /**
     * ???
     *
     * @param measureSpec
     * @return
     */
    private int measureHeight(int measureSpec) {
        final int result;

        final int specMode = MeasureSpec.getMode(measureSpec);
        final int specSize = MeasureSpec.getSize(measureSpec);
        final int ascent = (int) mTextPaint.ascent();

        if (specMode == MeasureSpec.EXACTLY) {
            // We were told how big to be
            result = specSize;
        } else {
            // Measure the mText (beware: ascent is a negative number)
            final int tmpResult = (int) (-ascent + mTextPaint.descent()) + getPaddingTop() + getPaddingBottom();
            if (specMode == MeasureSpec.AT_MOST) {
                // Respect AT_MOST value if that was what is called for by measureSpec
                result = Math.min(tmpResult, specSize);
            } else {
                result = tmpResult;
            }
        }

        return result;
    }

    /**
     * ???X?
     *
     * @return
     */
    private int getMarqueeStartX() {
        final WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        final Display display = wm.getDefaultDisplay();
        final Point size = new Point();
        display.getSize(size);

        final int measureText = (int) mTextPaint.measureText(mText);
        final int measureWidth = getMeasuredWidth();

        if (size.x == measureWidth) {
            return measureWidth;
        } else if (measureText > size.x) {
            // ????
            return size.x;
        } else if (measureWidth > measureText) {
            return measureWidth;
        } else {
            return measureText;
        }
    }

    /**
     * ??X
     *
     * @return
     */
    private int getLastX() {
        final WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        final Display display = wm.getDefaultDisplay();
        final Point size = new Point();
        display.getSize(size);

        final int measureText = (int) mTextPaint.measureText(mText);

        if (measureText >= size.x) {
            // ????
            return -measureText;
        } else {
            return -measureText;
        }
    }

    /**
     * ???
     *
     * @param canvas ?
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        final int ascent = (int) mTextPaint.ascent();

        final int x = getPaddingLeft() + mCurrentX;
        final int y = getPaddingTop() - ascent;

        canvas.drawText(mText, x, y, mTextPaint);
    }
}