众所周知,当TextView需要文字进入走马灯状态的时候,需要设置属性
android:ellipsize="marquee"
但是有时候并不能启动走马灯效果,这是因为失去了焦点导致的,这时候可以通过强制设置焦点,从而促使不会不启动走马灯,同时如果没有启动走马灯,设置setSelected(true)也会开启走马灯效果,
当然我们也可以重写Textview强制开启走马灯。
以下是我自定义的一个强制开启走马灯的TextView , MarqueeFocusedTextView
package com.bluewindtalker.weight;
/**
*
*/
import android.content.Context;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.TextView;
/**
* @author bluewindtalker
* @description 防止由于焦点问题而不能自动启动的走马灯textview,这里建议加上以下属性。
* android:singleLine="true"
* android:focusableInTouchMode="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:focusable="true"
代码效果相同。(另:正常的textview如果没有自动启动,可以通过设置setSelected(true)开启走马灯)
如需要高级使用,请查看MarqueeManualView
* @data Jun 22, 2016 -- 2:56:11 PM
* @reference http://m15031966454.blog.163.com/blog/static/201261060201222043240815/
*/
public class MarqueeFocusedTextView extends TextView {
/**
* @param context
*/
public MarqueeFocusedTextView(Context context) {
this(context, null);
}
/**
* @param context
* @param attrs
*/
public MarqueeFocusedTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initMarquee();
}
/**
* @param context
* @param attrs
* @param defStyleAttr
*/
public MarqueeFocusedTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initMarquee();
}
@Override
public boolean isFocused() {
//跑马灯, 只有当焦点在它上面时才有效。
return true;
}
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
// 关于MarqueeText类中为什么要复写onFocusChanged()方法,那是因为如果不写,在Textview 获得焦点后,再失
//去焦点时 字就会停止“跑”了,所以如果想让它一直跑下去就复写onFocusChanged(),并且里面什么也不做(主要是不能调用父类的方法)
//http://m15031966454.blog.163.com/blog/static/201261060201222043240815/
// super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
/**
* 初始化,设置必要的属性
*/
private void initMarquee(){
setFocusable(true);
setSingleLine();
setFocusableInTouchMode(true);
setEllipsize(TextUtils.TruncateAt.MARQUEE);
setMarqueeRepeatLimit(-1);
}
}
无法设置走马灯文字之间间隔;
无法设置走马灯速度;
无法设置走马灯启动、关闭时机;
无法设置走马灯暂停的时间长短;
这些都是在TextView中设置好的,例如间距以下是TextView源码
void start(int repeatLimit) {
if (repeatLimit == 0) {
stop();
return;
}
mRepeatLimit = repeatLimit;
final TextView textView = mView.get();
if (textView != null && textView.mLayout != null) {
mStatus = MARQUEE_STARTING;
mScroll = 0.0f;
final int textWidth = textView.getWidth() - textView.getCompoundPaddingLeft() -
textView.getCompoundPaddingRight();
final float lineWidth = textView.mLayout.getLineWidth(0);
final float gap = textWidth / 3.0f;//这里将间距设固定了,没法通过反射等方式更改
mGhostStart = lineWidth - textWidth + gap;
mMaxScroll = mGhostStart + textWidth;
mGhostOffset = lineWidth + gap;
mFadeStop = lineWidth + textWidth / 6.0f;
mMaxFadeScroll = mGhostStart + lineWidth + lineWidth;
textView.invalidate();
mChoreographer.postFrameCallback(mStartCallback);
}
}
另外走马灯的启动时间、间隔时间、速度都是固定的,有兴趣的童鞋可以去查看下TextView源码
private static final int MARQUEE_DELAY = 1200;
private static final int MARQUEE_RESTART_DELAY = 1200;
private static final int MARQUEE_DP_PER_SECOND = 30;
这个控件名字是MarqueeManualView
主要思想就是通过一个FrameLayout循环调用两个内容一样的TextView实现循环调用。
这个mMoveTextOut是当前展示的TextView从屏幕显示的区域移动到看不见的区域
mMoveTextOut = new TranslateAnimation(0, -mTextDifference, 0, 0);
mMoveTextOut.setDuration(marqueeDuration);
mMoveTextOut.setInterpolator(mInterpolator);
mMoveTextOut.setFillAfter(true);
mMoveTextOut.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if (isStop) {
return;
}
postDelayed(mMarqueeRunnable, mPauseTime);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
这个mMoveTextIn是TextView从屏幕外,移动到屏幕中view的起点的动画
mMoveTextIn = new TranslateAnimation(mTextDifference, 0, 0, 0);
mMoveTextIn.setDuration(marqueeDuration);
mMoveTextIn.setInterpolator(mInterpolator);
mMoveTextIn.setFillAfter(true);
通过以上两个TextView走的动画进行循环,
具体步骤:
1.mTextView使用动画mMoveTextOut,而mGhostTextView使用动画mMoveTextIn,
2.当mGhostTextView到达mTextView初始位置的时候,则停顿下,交替两个控件的动画,mGHostTextView使用动画mMoveTextOut,而mTextView使用动画mMoveTextIn.
重复上面1,2.
运行效果:
控件全部代码及对应示例代码如下:
https://github.com/bluewindtalker/MarqueeManualView