美文网首页
Android跑马灯(实现不满一屏不进行滚动)

Android跑马灯(实现不满一屏不进行滚动)

作者: Steven_SHH | 来源:发表于2019-03-11 14:45 被阅读0次
public class MarqueeView extends AppCompatTextView implements Runnable {
    private static final String TAG = "MarqueeView";
    private String string;//最终绘制的文本
    private float speed = 1;//移动速度
    private int textColor = getResources().getColor(R.color.color_999999);//文字颜色,默认黑色
    private float textSize = 12;//文字颜色,默认黑色
    private int textdistance;//
    private int textDistance1 = 10;//item间距,dp单位
    private String black_count = "";//间距转化成空格距离

    private int repetType = REPET_INTERVAL;//滚动模式
    public static final int REPET_ONCETIME = 0;//一次结束
    public static final int REPET_INTERVAL = 1;//一次结束以后,再继续第二次
    public static final int REPET_CONTINUOUS = 2;//紧接着 滚动第二次

    private float startLocationDistance = 0f;//开始的位置选取,百分比来的,距离左边,0~1,0代表不间距,1的话代表,从右面,1/2代表中间。

    private boolean isClickStop = false;//点击是否暂停
    private boolean isResetLocation = true;//默认为true
    private float xLocation = 0;//文本的x坐标
    private int contentWidth;//内容的宽度

    private boolean isRoll = false;//是否继续滚动
    private float oneBlack_width;//空格的宽度

    private TextPaint paint;//画笔
    private Rect rect;

    private int repetCount = 0;//
    private boolean resetInit = true;

    private Thread thread;
    private String content = "";

    private float textHeight;


    public MarqueeView(Context context) {
        this(context, null);
    }

    public MarqueeView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MarqueeView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initattrs(attrs);
        initpaint();
        initClick();


    }

    private void initClick() {
        setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {

                if (isClickStop) {
                    if (isRoll) {
                        stopRoll();
                    } else {
                        continueRoll();
                    }
                }
            }
        });
    }

    @SuppressLint("RestrictedApi")
    private void initattrs(AttributeSet attrs) {
        TintTypedArray tta = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
                R.styleable.MarqueeView);

        textColor = tta.getColor(R.styleable.MarqueeView_marqueeview_text_color, textColor);
        isClickStop = tta.getBoolean(R.styleable.MarqueeView_marqueeview_isclickalbe_stop, isClickStop);
        isResetLocation = tta.getBoolean(R.styleable.MarqueeView_marqueeview_is_resetLocation, isResetLocation);
        speed = tta.getFloat(R.styleable.MarqueeView_marqueeview_text_speed, speed);
        textSize = tta.getFloat(R.styleable.MarqueeView_marqueeview_text_size, textSize);
        textDistance1 = tta.getInteger(R.styleable.MarqueeView_marqueeview_text_distance, textDistance1);
        startLocationDistance = tta.getFloat(R.styleable.MarqueeView_marqueeview_text_startlocationdistance, startLocationDistance);
        repetType = tta.getInt(R.styleable.MarqueeView_marqueeview_repet_type, repetType);
        tta.recycle();
    }


    /**
     * 刻字机修改
     */
    private void initpaint() {

        rect = new Rect();
        paint = new TextPaint(Paint.ANTI_ALIAS_FLAG);//初始化文本画笔
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(textColor);//文字颜色值,可以不设定
        paint.setTextSize(dp2px(textSize));//文字大小

    }

    public int dp2px(float dpValue) {
        final float scale = getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (resetInit) {
            setTextDistance(textDistance1);

            if (startLocationDistance < 0) {
                startLocationDistance = 0;
            } else if (startLocationDistance > 1) {
                startLocationDistance = 1;
            }
            xLocation = getWidth() * startLocationDistance;
//            Log.e(TAG, "onMeasure: --- " + xLocation);
            resetInit = false;
        }


        //需要判断滚动模式的
        switch (repetType) {
            case REPET_ONCETIME:

                if (contentWidth < (-xLocation)) {
                    //也就是说文字已经到头了
//                    此时停止线程就可以了
                    stopRoll();
                }
                break;
            case REPET_INTERVAL:
                if (contentWidth <= (-xLocation)) {
                    //也就是说文字已经到头了
                    xLocation = getWidth();
                }
                break;

            case REPET_CONTINUOUS:


                if (xLocation < 0) {
                    int beAppend = (int) ((-xLocation) / contentWidth);

                    Log.e(TAG, "onDraw: ---" + contentWidth + "--------" + (-xLocation) + "------" + beAppend);

                    if (beAppend >= repetCount) {
                        repetCount++;
                        //也就是说文字已经到头了
//                    xLocation = speed;//这个方法有问题,所以采取了追加字符串的 方法
                        string = string + content;
                    }
                }
                //此处需要判断的xLocation需要加上相应的宽度
                break;

            default:
                //默认一次到头好了
                if (contentWidth < (-xLocation)) {
                    //也就是说文字已经到头了
//                    此时停止线程就可以了
                    stopRoll();
                }
                break;
        }


        //把文字画出来
        if (string != null) {
            canvas.drawText(string, xLocation, getHeight() / 2 + textHeight / 2, paint);

        }

    }

    public void setRepetType(int repetType) {
        this.repetType = repetType;
        resetInit = true;
        setContent(content);
    }


    @Override
    public void run() {
        while (isRoll && !TextUtils.isEmpty(content)) {
            try {
                Thread.sleep(10);
                xLocation = xLocation - speed;
                postInvalidate();//每隔10毫秒重绘视图
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


    }

    /**
     * 继续滚动
     */
    public void continueRoll() {
        if (!isRoll) {
            if (thread != null) {
                thread.interrupt();

                thread = null;
            }

            isRoll = true;
            thread = new Thread(this);
            thread.start();//开启死循环线程让文字动起来

        }
    }

    /**
     * 停止滚动
     */
    public void stopRoll() {
        isRoll = false;
        if (thread != null) {
            thread.interrupt();
            thread = null;
        }

    }

    /**
     * 点击是否暂停,默认是不
     *
     * @param isClickStop
     */
    private void setClickStop(boolean isClickStop) {
        this.isClickStop = isClickStop;
    }


    /**
     * 是否循环滚动
     *
     * @param isContinuable
     */
    private void setContinueble(int isContinuable) {
        this.repetType = isContinuable;
    }

    /**
     * 设置文字间距  不过如果内容是List形式的,该方法不适用 ,list的数据源,必须在设置setContent之前调用此方法。
     *
     * @param textdistance2
     */
    public void setTextDistance(int textdistance2) {


        //设置之后就需要初始化了

        String black = " ";
        oneBlack_width = getBlacktWidth();//空格的宽度
        textdistance2 = dp2px(textdistance2);
        int count = (int) (textdistance2 / oneBlack_width);//空格个数,有点粗略,有兴趣的朋友可以精细

        if (count == 0) {
            count = 1;
        }

        textdistance = (int) (oneBlack_width * count);
        black_count = "";
        for (int i = 0; i <= count; i++) {
            black_count = black_count + black;//间隔字符串
        }
        setContent(content);//设置间距以后要重新刷新内容距离,不过如果内容是List形式的,该方法不适用
    }

    /**
     * 计算出一个空格的宽度
     *
     * @return
     */
    private float getBlacktWidth() {
        String text1 = "en en";
        String text2 = "enen";
        return getContentWidth(text1) - getContentWidth(text2);

    }

    private float getContentWidth(String black) {
        if (black == null || black == "") {
            return 0;
        }

        if (rect == null) {
            rect = new Rect();
        }
        paint.getTextBounds(black, 0, black.length(), rect);
        textHeight = getContentHeight();

        return rect.width();
    }

    /**
     *获取内容高度
     */
    private float getContentHeight() {

        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        return Math.abs((fontMetrics.bottom - fontMetrics.top)) / 2;
    }

    /**
     * 设置文字颜色
     *
     * @param textColor
     */
    public void setTextColor(int textColor) {
        if (textColor != 0) {
            this.textColor = textColor;
            paint.setColor(getResources().getColor(textColor));//文字颜色值,可以不设定
        }
    }

    /**
     * 设置文字大小
     *
     * @param textSize
     */
    public void setTextSize(float textSize) {
        if (textSize > 0) {
            this.textSize = textSize;
            paint.setTextSize(dp2px(textSize));//文字颜色值,可以不设定
            contentWidth = (int) (getContentWidth(content) + textdistance);//大小改变,需要重新计算宽高
        }
    }

    /**
     * 设置滚动速度
     *
     * @param speed
     */
    public void setTextSpeed(float speed) {
        this.speed = speed;
    }


    /**
     * |设置滚动的条目内容 , 集合形式的
     *
     * @param strings
     */
    public void setContent(List<String> strings) {
        setTextDistance(textDistance1);
        String temString = "";

        if (strings != null && strings.size() != 0) {

            for (int i = 0; i < strings.size(); i++) {

                temString = temString + strings.get(i) + black_count;
            }

        }
        setContent(temString);
    }


    /**
     * 设置滚动的条目内容  字符串形式的
     *
     * @parambt_control00
     */
    public void setContent(String content2) {
        if (TextUtils.isEmpty(content2)) {
            return;
        }
        if (isResetLocation) {//控制重新设置文本内容的时候,是否初始化xLocation。
            xLocation = getWidth() * startLocationDistance;
        }

        if (!content2.endsWith(black_count)) {
            content2 = content2 + black_count;//避免没有后缀
        }
        this.content = content2;

        //这里需要计算宽度啦,当然要根据模式来搞
        if (repetType == REPET_CONTINUOUS) {
        //如果说是循环的话,则需要计算 文本的宽度 ,然后再根据屏幕宽度 , 看能一个屏幕能盛得下几个文本

            contentWidth = (int) (getContentWidth(content) + textdistance);//可以理解为一个单元内容的长度
            //从0 开始计算重复次数了, 否则到最后 会跨不过这个坎而消失。
            repetCount = 0;
            int contentCount = (getWidth() / contentWidth) + 2;
            this.string = "";
            for (int i = 0; i <= contentCount; i++) {
                this.string = this.string + this.content;//根据重复次数去叠加。
            }

        } else {
            if (xLocation < 0 && repetType == REPET_ONCETIME) {
                if (-xLocation > contentWidth) {
                    xLocation = getWidth() * startLocationDistance;
                }
            }
            contentWidth = (int) getContentWidth(content);

            this.string = content2;
        }

        // 如果内容小于一屏的话,就不进行滚动
        if (contentWidth < getScreenWidth(JinrApp.getInstance())) {
            stopRoll();
            postInvalidate();
            return;
        }


        if (!isRoll) {//如果没有在滚动的话,重新开启线程滚动
            continueRoll();
        }

    }

    /**
     * 从新添加内容的时候,是否初始化位置
     *
     * @param isReset
     */
    private void setResetLocation(boolean isReset) {
        isResetLocation = isReset;
    }

   /**
     * 获取屏幕宽度
     *
     */
  public int getScreenWidth(Context context) {
        WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = manager.getDefaultDisplay();
        return display.getWidth();
    }
}

相关文章

网友评论

      本文标题:Android跑马灯(实现不满一屏不进行滚动)

      本文链接:https://www.haomeiwen.com/subject/gnfbpqtx.html