1. 程式人生 > >android實現垂直方向跑馬燈效果

android實現垂直方向跑馬燈效果

因為最近公司要做一個抽獎功能,裡面有一個模組就是中獎使用者,對中獎使用者實現垂直方向跑馬燈效果,最先的思想方式是類似歌詞,做了n久,發現刷屏時間會有問題,特自己寫了一個控制元件,希望能幫到大家

“`

package com.demo.xsl.text;

import java.util.ArrayList;

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

/**
* 文字垂直滾動
* @author eandroidhu
*
*/
public class ScrollTextView extends TextView {
/**
* 每行的字串
*/
ArrayList lineStrings;

/**
 * 當前的位移
 */
float currentY;

/**
 * 處理滾動訊息
 */
Handler handler;

/**
 * 要顯示的text
 */
String scrollText="";


/**
 * 真實寬度,在配置width="xxdp"裡起作用
 */
private int exactlyWidth = -1;

/**
 * 真實高度,在配置height="xxdip"裡起作用 
 */
private int exactlyHeight = -1;
private float index = 0;
public String getScrollText() {
    return scrollText;
}

public void setScrollText(String scrollText) {
    this.scrollText = scrollText;
    reset();
}

/**
 * 重置
 */
private void reset() {

    if(lineStrings!=null)
    lineStrings.clear();
    stop();
    currentY = 0;
    absloutHeight = 0;
    this.setText("");
    if(handler!=null){
        handler.removeMessages(0);
        handler.removeMessages(1);
        handler.removeMessages(2);
        handler.removeMessages(3);
    }

    requestLayout();
    invalidate();

}

public ScrollTextView(Context context, AttributeSet attrs) {
    super(context, attrs);

    init();
}

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

public ScrollTextView(Context context) {
    super(context);
    init();
}

/**
 * 是否在滾動
 */
boolean scrolling = false;

/**
 * 實際高度:所有字顯示完全需要的高度
 */
float absloutHeight = 0;

/**
 * handler發訊息的時間間隔
 */

private int delayTime = 10; //滾動時間
private int stopTime = 3000; //停休時間

public int getDelayTime() {
return delayTime;

}

public void setDelayTime(int delayTime) {
this.delayTime = delayTime;
}

public int getStopTime() {
return stopTime;
}

public void setStopTime(int stopTime) {
this.stopTime = stopTime;
}

/**
 * 每次滾動的距離
 */
float speed = 0.5f;

/**
 * 初始化
 */
void init() {
    handler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            if (absloutHeight <= getHeight()) {
                currentY = 0;
                stop();
                return;
            }
            switch (msg.what) {

                case 0: {
                    currentY = currentY - speed;

                    //resetCurrentY();
                    invalidate();
                    boolean flag = true;
                    if (currentY >= absloutHeight || currentY <= -absloutHeight) {
                        flag = false;
                        handler.sendEmptyMessageDelayed(3, stopTime);
                    }
                    if(flag){

                          if (currentY >=  index|| currentY <= -index || getHeight() <= 0) {

                              handler.sendEmptyMessageDelayed(2, stopTime);
                          }else{
                             handler.sendEmptyMessageDelayed(0, delayTime);
                          }
                    }


                    break;
                }
                case 1: {

                    currentY += msg.arg1;

                    resetCurrentY();
                    invalidate();

                }
                break;
                case 2:{
                    index = index+absloutHeight/lineStrings.size();
                     stop();
                     handler.sendEmptyMessageDelayed(0, delayTime);
                }
                break;
                case 3:{
                     currentY = 0;
                     index = absloutHeight/lineStrings.size();;
                     stop();
                     handler.sendEmptyMessageDelayed(0, delayTime);
                }
            }

        }

        /**
         * 重置currentY(當currentY超過absloutHeight時,讓它重置為0)
         */
        private void resetCurrentY() {
            if (currentY >= absloutHeight || currentY <= -absloutHeight || getHeight() <= 0) {
                currentY = 0;
            }

        }
    };

}

/**
 * 上次觸發事件的手指y座標
 */
float lastY = 0;

/**
 * 為true代表原來是滾動
 */
boolean needStop;

public void pause() {
    if (scrolling) {

        stop();
        needStop = true;
    }
}

public void goOn() {

    if (needStop) {
        play();
        needStop = false;
    }
}

/* @Override
public boolean onTouchEvent(MotionEvent event) {

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            distanceY = lastY = event.getY();
            distanceX = event.getX();
            pause();

            return true;
        case MotionEvent.ACTION_MOVE:
            float dy = event.getY() - lastY;
            lastY = event.getY();
            // currentY = currentY + dy;
            Message msg = Message.obtain();
            msg.what = 1;
            msg.arg1 = (int)dy;
            handler.sendMessage(msg);
            return true;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            goOn();
            float y = event.getY() - distanceY;
            float x = event.getX() - distanceX;

            if (Math.sqrt(y * y + x * x) < performUpScrollStateDistance) {
                updateScrollStatus();
            }
            return true;

    }
    return super.onTouchEvent(event);
}

*/
/**
* 當手指移動此大小的距離以內,被認為是滾動狀態改變的事件,大於該值代表是手指搬運
*/
public static final long performUpScrollStateDistance = 5;

public float distanceY = 0;

public float distanceX = 0;

/**
 * 更改滾動狀態
 */
public void updateScrollStatus() {

    if (scrolling) {
        stop();
    } else {
        play();
    }
}

/**
 * 開始滾動
 */
public void play() {

    if (!scrolling) {
        handler.sendEmptyMessage(0);
        scrolling = true;
    }
}

/**
 * 停止滾動
 */
public void stop() {
    if (scrolling) {
        handler.removeMessages(0);
        scrolling = false;
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int width = MeasureWidth(widthMeasureSpec);
    int height = MeasureHeight(width, heightMeasureSpec);
    setMeasuredDimension(width, height);
    currentY = 0;
    if (height < absloutHeight) {
        play();
    } else {
        stop();
    }

}

/**
 * 測量寬度
 * 
 * @param widthMeasureSpec
 * @return
 */
private int MeasureWidth(int widthMeasureSpec) {
    int mode = MeasureSpec.getMode(widthMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec);
    // 如果是wrap_content
    if (mode == MeasureSpec.AT_MOST) {

        double abwidth = getPaint().measureText(scrollText);

        width = Math.min((int)Math.rint(abwidth), width);
        exactlyWidth = -1;
    }
    if (mode == MeasureSpec.EXACTLY) {
        exactlyWidth = width;
    }
    return width;
}

/**
 * 測量高度
 * 
 * @param width:寬度
 * @param heightMeasureSpec
 * @return
 */
private int MeasureHeight(int width, int heightMeasureSpec) {
    int mode = MeasureSpec.getMode(heightMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    generateTextList(width);
    int lines = lineStrings.size();

    absloutHeight = lines * getLineHeight() + getPaddingBottom() + getPaddingTop();
    index = absloutHeight/lines;
    // 如果是wrap_content
    if (mode == MeasureSpec.AT_MOST) {

        height = (int)Math.min(absloutHeight, height);
        exactlyHeight = -1;

    } else if (mode == MeasureSpec.EXACTLY) {
        exactlyHeight = height;
    }
    return height;
}

/**
 * 是否為英文單詞的首字母
 * 
 * @param str
 * @param i
 * @return
 */
boolean isENWordStart(String str, int i) {

    if (i == 0) {
        return true;

    } else if (str.charAt(i - 1) == ' ') {
        return true;
    }
    return false;
}

/**
 * 獲取一行的字元
 * 
 * @param MaxWidth
 * @param str
 * @return
 */
private String getLineText(int MaxWidth, String str) {

    // 真實行
    StringBuffer trueStringBuffer = new StringBuffer();
    // 臨時行
    StringBuffer tempStringBuffer = new StringBuffer();
    boolean isLine;
    for (int i = 0; i < str.length(); i++) {
        isLine = false;
        char c = str.charAt(i);
        String add = "";
        // 如果c是字母需要考慮英文單詞換行功能
        if (!isChinese(c) && isENWordStart(str, i)) {

            int place = getNextSpecePlace(i, str);
            // 找到下一個空格
            if (place > -1) {
                add = str.substring(i, place) + " ";
                if (getPaint().measureText(add) > MaxWidth) {
                    add = "" + c;
                } else {
                    i = place;
                }
            } else {
                add = "" + c;
            }
        } else {
            if(c=='\n') { //判斷是否到了換行的標示符
                isLine = true;
                 add = "" + c;
            }else
            add = "" + c;
        }

        tempStringBuffer.append(add);
        String temp = tempStringBuffer.toString();
        float width = getPaint().measureText(temp.toString());
        if(isLine)
            break;
        if (width <= MaxWidth) {

            trueStringBuffer.append(add);
        } else {
            break;
        }

    }

    return trueStringBuffer.toString();

}

/**
 * 找到下一個空格的地方
 * 
 * @param i
 * @param str
 * @return
 */
int getNextSpecePlace(int i, String str) {

    for (int j = i; j < str.length(); j++) {
        char c = str.charAt(j);
        if (c == '\n') {

            return j;
        }
    }
    return -1;
}

/**
 * 生成多行字串列表
 * 
 * @param MaxWidth
 */
public void generateTextList(int MaxWidth) {
    lineStrings = new ArrayList<String>();
   // String remain = scrollText;

    String[] contenx = scrollText.split("k#");
    for (String string : contenx) {
           lineStrings.add(string);
    }
 /*   while (!remain.equals("")) {
        String line = getLineText(MaxWidth, remain);
        lineStrings.add(line);
        remain = remain.substring(line.length(), remain.length());

    }*/
};

@Override
protected void onDraw(Canvas canvas) {

    super.onDraw(canvas);
    float x = getPaddingLeft();
    float y = getPaddingTop();

    float lineHeight = getLineHeight();
    float textSize = getPaint().getTextSize();

    for (int i = 0; i < lineStrings.size(); i++) {
        y = lineHeight * i + textSize + currentY;

        float min = 0;
        if (exactlyHeight > -1) {
            min = Math.min(min, exactlyHeight - absloutHeight);
        }
        if (y < min) {

            y = y + absloutHeight;

        } else if (y >= min && y < textSize + min) {

            //如果最頂端的文字已經到達需要迴圈從下面滾出的時候
            canvas.drawText(lineStrings.get(i), x, y + absloutHeight, getPaint());
        }
        if (y >= absloutHeight) {
            //如果最底端的文字已經到達需要迴圈從上面滾出的時候
            canvas.drawText(lineStrings.get(i), x, y, getPaint());
            y = y - absloutHeight;
        }
        canvas.drawText(lineStrings.get(i), x, y, getPaint());
    }
}

/**
 * 判斷是否為中文
 * 
 * @param c
 * @return
 */
private static final boolean isChinese(char c) {
    Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
    if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
            || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
            || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
            || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION
            || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
            || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
        return true;
    }
    return false;
}

}
原始碼下載連結
也可以關注我的公眾號
這裡寫圖片描述