我正在使用一个字幕来显示我的一个活动中的文本。我的问题是,是否可以加快字幕的速度,使其在屏幕上滚动得更快。下面是我的XML和Java。
TextView et2 = (TextView) findViewById(R.id.noneednum);
et2.setEllipsize(TruncateAt.MARQUEE);
et2.setText("");
if (num.size() > 0) {
for (String str : num) {
et2.append(str + " ");
}
}
et2.setSelected(true);
}
和XML:
<TextView
android:id="@+id/noneednum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:gravity="center_vertical|center_horizontal"
android:lines="1"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:text="Large Text"
android:textColor="#fff"
android:textSize="140dp" />
您必须创建一个自定义类来滚动文本:
滚动文本视图.java
public class ScrollTextView extends TextView {
// scrolling feature
private Scroller mSlr;
// milliseconds for a round of scrolling
private int mRndDuration = 10000;
// the X offset when paused
private int mXPaused = 0;
// whether it's being paused
private boolean mPaused = true;
/*
* constructor
*/
public ScrollTextView(Context context) {
this(context, null);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(INVISIBLE);
}
/*
* constructor
*/
public ScrollTextView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(INVISIBLE);
}
/*
* constructor
*/
public ScrollTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(INVISIBLE);
}
/**
* begin to scroll the text from the original position
*/
public void startScroll() {
// begin from the very right side
mXPaused = -1 * getWidth();
// assume it's paused
mPaused = true;
resumeScroll();
}
/**
* resume the scroll from the pausing point
*/
public void resumeScroll() {
if (!mPaused) return;
// Do not know why it would not scroll sometimes
// if setHorizontallyScrolling is called in constructor.
setHorizontallyScrolling(true);
// use LinearInterpolator for steady scrolling
mSlr = new Scroller(this.getContext(), new LinearInterpolator());
setScroller(mSlr);
int scrollingLen = calculateScrollingLen();
int distance = scrollingLen - (getWidth() + mXPaused);
int duration = (new Double(mRndDuration * distance * 1.00000
/ scrollingLen)).intValue();
setVisibility(VISIBLE);
mSlr.startScroll(mXPaused, 0, distance, 0, duration);
invalidate();
mPaused = false;
}
/**
* calculate the scrolling length of the text in pixel
*
* @return the scrolling length in pixels
*/
private int calculateScrollingLen() {
TextPaint tp = getPaint();
Rect rect = new Rect();
String strTxt = getText().toString();
tp.getTextBounds(strTxt, 0, strTxt.length(), rect);
int scrollingLen = rect.width() + getWidth();
rect = null;
return scrollingLen;
}
/**
* pause scrolling the text
*/
public void pauseScroll() {
if (null == mSlr) return;
if (mPaused)
return;
mPaused = true;
// abortAnimation sets the current X to be the final X,
// and sets isFinished to be true
// so current position shall be saved
mXPaused = mSlr.getCurrX();
mSlr.abortAnimation();
}
@Override
/*
* override the computeScroll to restart scrolling when finished so as that
* the text is scrolled forever
*/
public void computeScroll() {
super.computeScroll();
if (null == mSlr) return;
if (mSlr.isFinished() && (!mPaused)) {
this.startScroll();
}
}
public int getRndDuration() {
return mRndDuration;
}
public void setRndDuration(int duration) {
this.mRndDuration = duration;
}
public boolean isPaused() {
return mPaused;
}
}
在你的布局中这样写:
<yourpackagename.ScrollTextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/scrolltext" />
在你的活动中这样写:
ScrollTextView scrolltext=(ScrollTextView) findViewById(R.id.scrolltext);
scrolltext.setText(yourscrollingtext);
scrolltext.setTextColor(Color.BLACK);
scrolltext.startScroll();
如果你想提高滚动速度,那么降低的值
private int mRndDuration = 10000;//reduce the value of mRndDuration to increase scrolling speed
如果TextView是AppCompatTextView的实例,则上面的代码将失败。下面的代码是AppCompatTextView。在棉花糖中测试。
public static void setMarqueeSpeed(TextView tv, float speed) {
if (tv != null) {
try {
Field f = null;
if (tv instanceof AppCompatTextView) {
f = tv.getClass().getSuperclass().getDeclaredField("mMarquee");
} else {
f = tv.getClass().getDeclaredField("mMarquee");
}
if (f != null) {
f.setAccessible(true);
Object marquee = f.get(tv);
if (marquee != null) {
String scrollSpeedFieldName = "mScrollUnit";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
scrollSpeedFieldName = "mPixelsPerSecond";
}
Field mf = marquee.getClass().getDeclaredField(scrollSpeedFieldName);
mf.setAccessible(true);
mf.setFloat(marquee, speed);
}
} else {
Logger.e("Marquee", "mMarquee object is null.");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
这对我有效。如果f.get(tv)返回null,请在调用setMarqueSpeed()之前尝试调用mTextView.setSelected(true)。最初的答案:Android和一个TextView';s水平字幕滚动速率
private void setMarqueeSpeed(TextView tv, float speed, boolean speedIsMultiplier) {
try {
Field f = tv.getClass().getDeclaredField("mMarquee");
f.setAccessible(true);
Object marquee = f.get(tv);
if (marquee != null) {
String scrollSpeedFieldName = "mScrollUnit";
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.L)
scrollSpeedFieldName = "mPixelsPerSecond";
Field mf = marquee.getClass().getDeclaredField(scrollSpeedFieldName);
mf.setAccessible(true);
float newSpeed = speed;
if (speedIsMultiplier)
newSpeed = mf.getFloat(marquee) * speed;
mf.setFloat(marquee, newSpeed);
}
} catch (Exception e) {
e.printStackTrace();
}
}
我在运行Android 7.1的设备上解决了以上滚动问题,从这里和其他地方的多篇文章中提取
- 解决了速度问题
- 仅在需要时滚动/文本长于TextView的宽度
- 适用于扩展TextView或AppCompatTextView
package com.myclass.classes;
import android.content.Context;
import android.graphics.Rect;
import android.text.Layout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.LinearInterpolator;
import android.widget.Scroller;
import android.widget.TextView;
public class ScrollTextView extends TextView {
// scrolling feature
private Scroller mSlr;
// the X offset when paused
private int mXPaused = 0;
// whether it's being paused
private boolean mPaused = true;
private float mScrollSpeed = 250f; //Added speed for same scrolling speed regardless of text
/*
* constructor
*/
public ScrollTextView(Context context) {
this(context, null);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(VISIBLE);
getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener); //added listener check
}
/*
* constructor
*/
public ScrollTextView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(VISIBLE);
getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener); //added listener check
}
/*
* constructor
*/
public ScrollTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(VISIBLE);
getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener); //added listener check
}
@Override
protected void onDetachedFromWindow() {
removeGlobalListener();
super.onDetachedFromWindow();
}
/**
* begin to scroll the text from the original position
*/
private void startScroll() {
boolean needsScrolling = checkIfNeedsScrolling();
// begin from the middle
mXPaused = -1 * (getWidth() / 2);
// assume it's paused
mPaused = true;
if (needsScrolling) {
resumeScroll();
} else {
pauseScroll();
}
removeGlobalListener();
}
/**
* Removing global listener
**/
private synchronized void removeGlobalListener() {
try {
if (onGlobalLayoutListener != null)
getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayoutListener);
onGlobalLayoutListener = null;
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Waiting for layout to initiate
*/
private OnGlobalLayoutListener onGlobalLayoutListener = () -> {
startScroll();
};
/**
* Checking if we need scrolling
*/
private boolean checkIfNeedsScrolling() {
measure(0, 0);
int textViewWidth = getWidth();
if (textViewWidth == 0)
return false;
float textWidth = getTextLength();
return textWidth > textViewWidth;
}
/**
* resume the scroll from the pausing point
*/
public void resumeScroll() {
if (!mPaused) return;
// Do not know why it would not scroll sometimes
// if setHorizontallyScrolling is called in constructor.
setHorizontallyScrolling(true);
// use LinearInterpolator for steady scrolling
mSlr = new Scroller(this.getContext(), new LinearInterpolator());
setScroller(mSlr);
int scrollingLen = calculateScrollingLen();
int distance = scrollingLen - (getWidth() + mXPaused);
int duration = (int) (1000f * distance / mScrollSpeed);
setVisibility(VISIBLE);
mSlr.startScroll(mXPaused, 0, distance, 0, duration);
invalidate();
mPaused = false;
}
/**
* calculate the scrolling length of the text in pixel
*
* @return the scrolling length in pixels
*/
private int calculateScrollingLen() {
int length = getTextLength();
return length + getWidth();
}
private int getTextLength() {
TextPaint tp = getPaint();
Rect rect = new Rect();
String strTxt = getText().toString();
tp.getTextBounds(strTxt, 0, strTxt.length(), rect);
int length = rect.width();
rect = null;
return length;
}
/**
* pause scrolling the text
*/
public void pauseScroll() {
if (null == mSlr) return;
if (mPaused)
return;
mPaused = true;
// abortAnimation sets the current X to be the final X,
// and sets isFinished to be true
// so current position shall be saved
mXPaused = mSlr.getCurrX();
mSlr.abortAnimation();
}
@Override
/*
* override the computeScroll to restart scrolling when finished so as that
* the text is scrolled forever
*/
public void computeScroll() {
super.computeScroll();
if (null == mSlr) return;
if (mSlr.isFinished() && (!mPaused)) {
this.startScroll();
}
}
public boolean isPaused() {
return mPaused;
}
}
借助已接受的答案&有些更改,您现在甚至可以在运行时使用此库设置Speed()。
https://github.com/RohanPatil1/SpeedMarquee
使用XML
<com.rohan.speed_marquee.SpeedMarquee
android:id="@+id/marqueeTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/dummy_text"
android:maxLines="1"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:marquee_speed="180.0" />
使用方法
findViewById<Button>(R.id.speedButton).setOnClickListener {
//Increment Text3's speed by 100.0
marqueeTextView3.setSpeed(marqueeTextView3.getSpeed() + 100.0f)
}
}