自动滚动的Textview



又到了写博博的时候了!大家还好吧!

开始做机顶盒了,所以这里就有很多的界面需要做成一个自动化的界面。因为遥控盒手机触摸毕竟不一样咯!这里而且要方便大众的视觉体验的话,我们必须要考虑到这些因素。当然,我觉着,这次的自动滚动效果一定对大家也很有帮助的哦!

我们只要写一个类来继承我布局文件里面写的一个TextView就ok啦。



package com.example.myscroltextview.view;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.widget.TextView;

/**
* 垂直滚动的textview
*
* @author Catherine.Brian.William
*
*/
public class VertailScrollTextView extends TextView {

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

public VertailScrollTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

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

Handler handler;

/**
* 是否在滚动
*/
boolean scrolling = false;

/**
* 当前的位移
*/
float currentY;
/**
* 每次滚动的距离
*/
float speed = 0.2f;

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

/**
* 真实宽度,在配置width="xxdp"里起作用
*/
private int exactlyWidth = -1;

/**
* 真实高度,在配置height="xxdip"里起作用
*/
private int exactlyHeight = -1;

/**
* 实际高度:所有字显示完全需要的高度
*/
float absloutHeight = 0;

/**
* handler发消息的时间间隔
*/
int delayTime = 50;

/**
* 每行的字符串
*/
ArrayList<String> lineStrings;

Paint mPaint;

private static final int DY = 20; // 每一行的间隔

/**
* 初始化
*/
private void init() {

// 非高亮部分
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(20);
mPaint.setColor(Color.WHITE);
mPaint.setTypeface(Typeface.SERIF);

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();
handler.sendEmptyMessageDelayed(0, delayTime);
break;
}
super.handleMessage(msg);
}

/**
* 重置currentY(当currentY超过absolutHeight时,让它重置为0)
*/
private void resetCurrentY() {
if (currentY >= absloutHeight || currentY <= -absloutHeight
|| getHeight() <= 0) {
currentY = 0;
}
}
};

}

@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() + DY) + getPaddingBottom()
+ getPaddingTop();
// 如果是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 MaxWidth
*/
public void generateTextList(int MaxWidth) {
lineStrings = new ArrayList<String>();

String remain = scrollText;

while (!remain.equals("")) {
String line = getLineText(MaxWidth, remain);
lineStrings.add(line);
remain = remain.substring(line.length(), remain.length());
}

}

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

// 真实行
StringBuffer trueStringBuffer = new StringBuffer();

// 临时行
StringBuffer tempStringBuffer = new StringBuffer();

for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
String add = "";
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 {
add = "" + c;
}
tempStringBuffer.append(add);
String temp = tempStringBuffer.toString();

float width = getPaint().measureText(temp.toString());

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 == ‘ ‘) {

return j;
}
}
return -1;
}

/**
* 是否为英文单词的首字母
*
* @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;
}

/**
* 设置textview的文字
*
* @param scrollText
*/
public void setScrollText(String scrollText) {
this.scrollText = scrollText;
// setText(scrollText);
reset();
}

public String getScrollText() {
return scrollText;
}

/**
* 重置
*/
private void reset() {
requestLayout();
invalidate();
currentY = 0;
}

/**
* 开始滚动
*/
public void play() {
if (!scrolling) {
handler.sendEmptyMessage(0);
scrolling = true;
}
}

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

/**
* 更改滚动状态
*/
public void updateScrollStatus() {
if (scrolling) {
stop();
} else {
play();
}
}

@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
float x = getPaddingLeft();
float y = getPaddingTop();

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

for (int i = 0; i < lineStrings.size(); i++) {
// currentY+=50;
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) {
// 如果最顶端的文字已经到达需要循环从下面滚出的时候
System.out.println("x:" + x + "y:" + y);
}
if (y >= absloutHeight) {
// 如果最底端的文字已经到达需要循环从上面滚出的时候
System.out.println("x:" + x + "y:" + y);
y = y - absloutHeight;
}

canvas.drawText(lineStrings.get(i), x, y, mPaint);
}

}

/**
* 判断是否为中文
*
* @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;
}

}

自动滚动的Textview

时间: 2024-10-05 16:50:05

自动滚动的Textview的相关文章

Android:TextView 自动滚动(跑马灯) (转)

Android:TextView 自动滚动(跑马灯) TextView实现文字滚动需要以下几个要点: 1.文字长度长于可显示范围:android:singleLine="true" 2.设置可滚到,或显示样式:android:ellipsize="marquee" 3.TextView只有在获取焦点后才会滚动显示隐藏文字,因此需要在包中新建一个类,继承TextView.重写isFocused方法,这个方法默认行为是,如果TextView获得焦点,方法返回true,失

Android文字跑马灯控件(文本自动滚动控件)

最近在开发一个应用,需要用到文本的跑马灯效果,图省事,在网上找,但老半天都找不到,后来自己写了一个,很简单,代码如下: import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; impor

垂直自动滚动问题(第一行固定,其他行自动滚动)有人知道怎么实现吗?

============问题描述============ 大家好,小弟想做一个公告牌的Android程序,想实现如下效果:第一行(标题行)固定,其他行(详细内容)自动垂直滚动,应该怎么做呢?网上搜了相关资料,都没有这方面的完整例子 网上找到一个可以垂直滚动的代码如附件AutoScroll(下载地址:http://download.csdn.net/detail/tc310/7887641),这个可以垂直滚动,但是确实所有内容都滚动,无法把第一行(标题)固定显示. 我把布局文件改成如下,发现运行报

Android开发之实现图片自动滚动显示标签的ViewPager

Android中实现图片自动滚动的效果非常的常见,我们可以自己动画去实现功能.但是在Android中提供了一个ViewPager类,实现了滚动效果,在Android的extras目录下android-support-vx.jar中,x代表版本4,7等等.使用时我们需要android.support.v4.view.ViewPager的viewPager标签. 博客来源:http://blog.csdn.net/fengshizty 代码非常的简单,不用解释: xml布局文件如下: <Relati

Creating Dialogbased Win32 Application (4) / 创建基于对话框的Win32应用程序(四)Edit Control的应用、Unicode转ANSI、自动滚动 / Win32, VC++, Windows

创建基于对话框的Win32应用程序(四)——Edit Control的应用.Unicode转ANSI.自动滚动 之前的介绍中,我们用到了Button.Static Text.Checkbox这三个控件.这一节中我们将学习使用Edit Control(编辑框)控件,其中还包括Unicode转ANSI的方法.文本框自动滚动的功能等. 24.首先切换到Reasource View(Ctrl+Shift+E),找到待修改的主窗体,并从Toolbox(Ctrl+Atl+X)中添加Edit Control控

自动轮播,类似字幕或图片自动滚动播放

功能:ListView没隔一段时间自动滚动一段距离,当滚动到底部时,又从头开始显示,类似于原始数据为0123,而滚动起来则是012301230123...一直重复显示,这样就达到了信息轮播的功能. 本功能采用扩展ListView来实现的, public class AutoCircleScrollListview extends ListView implements OnScrollListener{ public final static int REFRESH_TIMES=1000;//滚

Android 文字自动滚动(跑马灯)效果的两种实现方法[特别好使]

有时候在xml中写的跑马灯效果不滚动:原因有以下 Android系统中TextView实现跑马灯效果,必须具备以下几个条件: 1.android:ellipsize=”marquee” 2.TextView必须单行显示,即内容必须超出TextView大小 3.TextView要获得焦点才能滚动(如果还不行,就要用自定义的TextView控件中重写isFocused()返回true就行[方法代码在下面的AlwaysMarqueeTextView 类],但是遇到新问题就是界面有多个这样的控件显示时当

RecyclerView常见问题解决方案,RecyclerView嵌套自动滚动,RecyclerView 高度设置wrap_content 无作用等问题

1,ScrollView或者RecyclerView1 嵌套RecyclerView2  进入页面自动跳转到recyclerView2上面页面会自动滚动 貌似是RecyclerView 自动获得了焦点两种解决办法一,recyclerview去除焦点recyclerview.setFocusableInTouchMode(false);recyclerview.requestFocus();二,在代码里面 让处于ScrollView或者RecyclerView1 顶端的某个控件获得焦点即可比如顶部

怎么停止LogCat的自动滚动?

============问题描述============ 真机调试时,想看看所有的调试消息,但是Logcat老是自动滚动,就是有新的调试消息时,就会自动向上滚动,把我现在看的滚没了,真是不胜其烦,但是又找不到关闭自动滚动的方法,啊啊啊,烦死了... ============解决方案1============ 在LogCat窗口右侧有一个+符号,新建Log Filter,设置好by Log Tag的值,这个值要与Log输出的Tag值一样,这样这个新建的窗口里面就只会显示你的Log了 =======