android实现垂直方向跑马灯效果
2016-02-29 10:30
381 查看
因为最近公司要做一个抽奖功能,里面有一个模块就是中奖用户,对中奖用户实现垂直方向跑马灯效果,最先的思想方式是类似歌词,做了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;
private int delayTime = 10; //滚动时间
private int stopTime = 3000; //停休时间
}
public void setDelayTime(int delayTime) {
this.delayTime = delayTime;
}
public int getStopTime() {
return stopTime;
}
public void setStopTime(int stopTime) {
this.stopTime = stopTime;
}
/* @Override
public boolean onTouchEvent(MotionEvent event) {
*/
/**
* 当手指移动此大小的距离以内,被认为是滚动状态改变的事件,大于该值代表是手指搬运
*/
public static final long performUpScrollStateDistance = 5;
}
源码下载链接
“`
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; }
}
源码下载链接
相关文章推荐
- Android自定义控件
- android_ScrollView 监听滚动到某个位置的方法
- Android Studio 加快编译速度
- android 一个手机可以打开 另一个手机打开就崩溃
- Android解耦库EventBus的使用和源码分析
- There is no ic_menu_refresh icon in android:drawable?
- 如何「偷」Android 的内存?
- Android布局— — —帧布局
- Android 反编译
- Android绚丽加载效果视图(loading)控件
- Android开发笔记(七十二)数据加密算法
- Android的Style的使用
- android sqlite查询方式
- android在进行创建项目gen下没有自动生成R.java
- Android Service和Thread的区别
- Android Media相关标准接口
- android studio gradle介绍
- android学习之RadioButton
- 深入理解LayoutInflater.inflate()
- Android布局— — —表格布局