记录一个Android中简单实现垂直跑马灯功能的方法:实现了垂直跑马灯的功能。记录一下以便日后查看:
首先在MainActivity下新建一个名为
ScrollTextView的.java 文件
ScrollTextView.java代码如下:
其中判断分行结束符以 "\n" 为准。。。
package com.example.chenhy.pmd;
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 HeJx
*
*/
public class ScrollTextView extends TextView {
/**
* ??е??????
*/
ArrayList<String> 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 = 0; //??????
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("\n"); //这里的"\n" 是标志
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;
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.chenhy.pmd.MainActivity">
<com.example.chenhy.pmd.ScrollTextView
android:id="@+id/marqueeview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="10sp"
>
</com.example.chenhy.pmd.ScrollTextView>
</LinearLayout>
最后是mainactivity中的代码
package com.example.chenhy.pmd;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ScrollTextView marqueeView = (ScrollTextView) findViewById(R.id.marqueeview);
marqueeView.setScrollText("塞纳河畔 左岸的咖啡\n" +
"我手一杯 品尝你的美\n" +
"留下唇印的嘴\n" +
"花店玫瑰 名字写错谁\n" +
"告白气球 风吹到对街\n" +
"微笑在天上飞\n" +
"你说你有点难追 想让我知难而退\n" +
"礼物不需挑最贵 只要香榭的落叶\n" +
"喔 营造浪漫的约会 不害怕搞砸一切\n" +
"拥有你就拥有 全世界\n" +
"亲爱的 爱上你 从那天起\n" +
"甜蜜的很轻易\n" +
"亲爱的 别任性 你的眼睛\n" +
"在说我愿意\n" +
"塞纳河畔 左岸的咖啡\n" +
"我手一杯 品尝你的美\n" +
"留下唇印的嘴\n" +
"花店玫瑰 名字写错谁\n" +
"告白气球 风吹到对街\n" +
"微笑在天上飞\n" +
"你说你有点难追 想让我知难而退\n" +
"礼物不需挑最贵 只要香榭的落叶\n" +
"喔 营造浪漫的约会 不害怕搞砸一切\n" +
"拥有你就拥有 全世界\n" +
"亲爱的 爱上你 从那天起\n" +
"甜蜜的很轻易\n" +
"亲爱的 别任性 你的眼睛\n" +
"在说我愿意\n" +
"亲爱的 爱上你 恋爱日记\n" +
"飘香水的回忆\n" +
"一整瓶 的梦境 全都有你\n" +
"搅拌在一起\n" +
"亲爱的别任性 你的眼睛\n" +
"在说我愿意"+"塞纳河畔 左岸的咖啡\n" +
"我手一杯 品尝你的美\n" +
"留下唇印的嘴\n" +
"花店玫瑰 名字写错谁\n" +
"告白气球 风吹到对街\n" +
"微笑在天上飞\n" +
"你说你有点难追 想让我知难而退\n" +
"礼物不需挑最贵 只要香榭的落叶\n" +
"喔 营造浪漫的约会 不害怕搞砸一切\n" +
"拥有你就拥有 全世界\n" +
"亲爱的 爱上你 从那天起\n" +
"甜蜜的很轻易\n" +
"亲爱的 别任性 你的眼睛\n" +
"在说我愿意\n" +
"塞纳河畔 左岸的咖啡\n" +
"我手一杯 品尝你的美\n" +
"留下唇印的嘴\n" +
"花店玫瑰 名字写错谁\n" +
"告白气球 风吹到对街\n" +
"微笑在天上飞\n" +
"你说你有点难追 想让我知难而退\n" +
"礼物不需挑最贵 只要香榭的落叶\n" +
"喔 营造浪漫的约会 不害怕搞砸一切\n" +
"拥有你就拥有 全世界\n" +
"亲爱的 爱上你 从那天起\n" +
"甜蜜的很轻易\n" +
"亲爱的 别任性 你的眼睛\n" +
"在说我愿意\n" +
"亲爱的 爱上你 恋爱日记\n" +
"飘香水的回忆\n" +
"一整瓶 的梦境 全都有你\n" +
"搅拌在一起\n" +
"亲爱的别任性 你的眼睛\n" +
"在说我愿意");
}
}
最后,上一张效果图