http://www.cnblogs.com/over140/p/3164712.html
【Android】不依赖焦点和选中的TextView跑马灯
前言
继承TextView,并仿照源码修改而来,主要是取消了焦点和选中了判断,也不依赖文本的宽度。
声明欢迎转载,但请保留文章原始出处:)
博客园:http://www.cnblogs.com
农民伯伯: http://over140.cnblogs.com
正文
importjava.lang.ref.WeakReference;
importandroid.content.Context;
importandroid.graphics.Canvas;
importandroid.os.Handler;
importandroid.os.Message;
importandroid.util.AttributeSet;
importandroid.widget.TextView;
public classMarqueeTextView extendsTextView{
privateMarqueemMarquee;
publicMarqueeTextView(Contextcontext,AttributeSetattrs){
super(context,attrs);
}
intdefStyle){
publicMarqueeTextView(Contextcontext){
super(context);
}
voidstartMarquee(){
startMarquee(-1);
}
voidstartMarquee( intrepeatLimit){
if(mMarquee== null)
mMarquee= newMarquee( this);
mMarquee.start(repeatLimit);
}
voidstopMarquee(){
if(mMarquee!= null&&!mMarquee.isStopped()){
mMarquee.stop();
}
}
voidtoggleMarquee(){
null||mMarquee.isStopped())
startMarquee();
else
stopMarquee();
}
@Override
protected voidonDraw(Canvascanvas){
null&&mMarquee.isRunning()){
final floatdx=-mMarquee.getScroll();
canvas.translate(getLayoutDirection()==LAYOUT_DIRECTION_RTL?-dx
:+dx,0.0f);
}
super.onDraw(canvas);
}
@SuppressWarnings("unused")
private static classMarquee extendsHandler{
// TODO:Addanoptiontoconfigurethis
floatMARQUEE_DELTA_MAX=0.07f;
intMARQUEE_DELAY=0; 1200; intMARQUEE_RESTART_DELAY=1200;
intMARQUEE_RESOLUTION=1000/30;
intMARQUEE_PIXELS_PER_SECOND=30;
byteMARQUEE_STOPPED=0x0;
byteMARQUEE_STARTING=0x1;
byteMARQUEE_RUNNING=0x2;
intMESSAGE_START=0x1;
intMESSAGE_TICK=0x2;
intMESSAGE_RESTART=0x3;
finalWeakReference<TextView>mView;
bytemStatus=MARQUEE_STOPPED;
floatmScrollUnit;
floatmMaxScroll;
floatmMaxFadeScroll;
floatmGhostStart;
floatmGhostOffset;
floatmFadeStop;
intmRepeatLimit;
floatmScroll;
Marquee(TextViewv){
floatdensity=v.getContext().getResources()
.getDisplayMetrics().density;
mScrollUnit=(MARQUEE_PIXELS_PER_SECOND*density)
/MARQUEE_RESOLUTION;
mView= newWeakReference<TextView>(v);
}
@Override
voidhandleMessage(Messagemsg){
switch(msg.what){
caseMESSAGE_START:
mStatus=MARQUEE_RUNNING;
tick();
break;
caseMESSAGE_TICK:
tick();
caseMESSAGE_RESTART:
if(mStatus==MARQUEE_RUNNING){
if(mRepeatLimit>=0){
mRepeatLimit--;
}
start(mRepeatLimit);
}
break;
}
}
voidtick(){
if(mStatus!=MARQUEE_RUNNING){
return;
}
removeMessages(MESSAGE_TICK);
finalTextViewtextView=mView.get();
&&(textView.isFocused()||textView.isSelected()) if(textView!= null){
mScroll+=mScrollUnit;
if(mScroll>mMaxScroll){
mScroll=mMaxScroll;
sendEmptyMessageDelayed(MESSAGE_RESTART,
MARQUEE_RESTART_DELAY);
} else{
sendEmptyMessageDelayed(MESSAGE_TICK,MARQUEE_RESOLUTION);
}
textView.invalidate();
}
}
voidstop(){
mStatus=MARQUEE_STOPPED;
removeMessages(MESSAGE_START);
removeMessages(MESSAGE_RESTART);
removeMessages(MESSAGE_TICK);
resetScroll();
}
voidresetScroll(){
mScroll=0.0f;
null){
textView.invalidate();
}
}
voidstart( if(repeatLimit==0){
stop();
return;
}
mRepeatLimit=repeatLimit;
null&&textView.getLayout()!= null){
mStatus=MARQUEE_STARTING;
mScroll=0.0f;
inttextWidth=textView.getWidth()
-textView.getCompoundPaddingLeft()
-textView.getCompoundPaddingRight();
floatlineWidth=textView.getLayout().getLineWidth(0);
floatgap=textWidth/3.0f;
mGhostStart=lineWidth-textWidth+gap;
mMaxScroll=mGhostStart+textWidth;
mGhostOffset=lineWidth+gap;
mFadeStop=lineWidth+textWidth/6.0f;
mMaxFadeScroll=mGhostStart+lineWidth+lineWidth;
textView.invalidate();
sendEmptyMessageDelayed(MESSAGE_START,MARQUEE_DELAY);
}
}
floatgetGhostOffset(){
returnmGhostOffset;
}
floatgetScroll(){
returnmScroll;
}
floatgetMaxFadeScroll(){
returnmMaxFadeScroll;
}
booleanshouldDrawLeftFade(){
returnmScroll<=mFadeStop;
}
booleanshouldDrawGhost(){
returnmStatus==MARQUEE_RUNNING&&mScroll>mGhostStart;
}
booleanisRunning(){
returnmStatus==MARQUEE_RUNNING;
}
booleanisStopped(){
returnmStatus==MARQUEE_STOPPED;
}
}
}
importandroid.content.Context;
importandroid.graphics.Canvas;
importandroid.os.Handler;
importandroid.os.Message;
importandroid.util.AttributeSet;
importandroid.widget.TextView;
public classMarqueeTextView extendsTextView{
privateMarqueemMarquee;
publicMarqueeTextView(Contextcontext,AttributeSetattrs){
super(context,attrs);
}
intdefStyle){
publicMarqueeTextView(Contextcontext){
super(context);
}
voidstartMarquee(){
startMarquee(-1);
}
voidstartMarquee( intrepeatLimit){
if(mMarquee== null)
mMarquee= newMarquee( this);
mMarquee.start(repeatLimit);
}
voidstopMarquee(){
if(mMarquee!= null&&!mMarquee.isStopped()){
mMarquee.stop();
}
}
voidtoggleMarquee(){
null||mMarquee.isStopped())
startMarquee();
else
stopMarquee();
}
@Override
protected voidonDraw(Canvascanvas){
null&&mMarquee.isRunning()){
final floatdx=-mMarquee.getScroll();
canvas.translate(getLayoutDirection()==LAYOUT_DIRECTION_RTL?-dx
:+dx,0.0f);
}
super.onDraw(canvas);
}
@SuppressWarnings("unused")
private static classMarquee extendsHandler{
// TODO:Addanoptiontoconfigurethis
floatMARQUEE_DELTA_MAX=0.07f;
intMARQUEE_DELAY=0; 1200; intMARQUEE_RESTART_DELAY=1200;
intMARQUEE_RESOLUTION=1000/30;
intMARQUEE_PIXELS_PER_SECOND=30;
byteMARQUEE_STOPPED=0x0;
byteMARQUEE_STARTING=0x1;
byteMARQUEE_RUNNING=0x2;
intMESSAGE_START=0x1;
intMESSAGE_TICK=0x2;
intMESSAGE_RESTART=0x3;
finalWeakReference<TextView>mView;
bytemStatus=MARQUEE_STOPPED;
floatmScrollUnit;
floatmMaxScroll;
floatmMaxFadeScroll;
floatmGhostStart;
floatmGhostOffset;
floatmFadeStop;
intmRepeatLimit;
floatmScroll;
Marquee(TextViewv){
floatdensity=v.getContext().getResources()
.getDisplayMetrics().density;
mScrollUnit=(MARQUEE_PIXELS_PER_SECOND*density)
/MARQUEE_RESOLUTION;
mView= newWeakReference<TextView>(v);
}
@Override
voidhandleMessage(Messagemsg){
switch(msg.what){
caseMESSAGE_START:
mStatus=MARQUEE_RUNNING;
tick();
break;
caseMESSAGE_TICK:
tick();
caseMESSAGE_RESTART:
if(mStatus==MARQUEE_RUNNING){
if(mRepeatLimit>=0){
mRepeatLimit--;
}
start(mRepeatLimit);
}
break;
}
}
voidtick(){
if(mStatus!=MARQUEE_RUNNING){
return;
}
removeMessages(MESSAGE_TICK);
finalTextViewtextView=mView.get();
&&(textView.isFocused()||textView.isSelected()) if(textView!= null){
mScroll+=mScrollUnit;
if(mScroll>mMaxScroll){
mScroll=mMaxScroll;
sendEmptyMessageDelayed(MESSAGE_RESTART,
MARQUEE_RESTART_DELAY);
} else{
sendEmptyMessageDelayed(MESSAGE_TICK,MARQUEE_RESOLUTION);
}
textView.invalidate();
}
}
voidstop(){
mStatus=MARQUEE_STOPPED;
removeMessages(MESSAGE_START);
removeMessages(MESSAGE_RESTART);
removeMessages(MESSAGE_TICK);
resetScroll();
}
voidresetScroll(){
mScroll=0.0f;
null){
textView.invalidate();
}
}
voidstart( if(repeatLimit==0){
stop();
return;
}
mRepeatLimit=repeatLimit;
null&&textView.getLayout()!= null){
mStatus=MARQUEE_STARTING;
mScroll=0.0f;
inttextWidth=textView.getWidth()
-textView.getCompoundPaddingLeft()
-textView.getCompoundPaddingRight();
floatlineWidth=textView.getLayout().getLineWidth(0);
floatgap=textWidth/3.0f;
mGhostStart=lineWidth-textWidth+gap;
mMaxScroll=mGhostStart+textWidth;
mGhostOffset=lineWidth+gap;
mFadeStop=lineWidth+textWidth/6.0f;
mMaxFadeScroll=mGhostStart+lineWidth+lineWidth;
textView.invalidate();
sendEmptyMessageDelayed(MESSAGE_START,MARQUEE_DELAY);
}
}
floatgetGhostOffset(){
returnmGhostOffset;
}
floatgetScroll(){
returnmScroll;
}
floatgetMaxFadeScroll(){
returnmMaxFadeScroll;
}
booleanshouldDrawLeftFade(){
returnmScroll<=mFadeStop;
}
booleanshouldDrawGhost(){
returnmStatus==MARQUEE_RUNNING&&mScroll>mGhostStart;
}
booleanisRunning(){
returnmStatus==MARQUEE_RUNNING;
}
booleanisStopped(){
returnmStatus==MARQUEE_STOPPED;
}
}
}
代码说明:
1、取消了焦点和选中的判断
2、将延迟1200改为0,立即执行跑马灯效果。
3、核心代码都是直接从TextView拷贝出来。
结束
这里主要是提供一种解决问题的思路,实际使用还需要进行相应的修改。