Android自定義TextView實現文字自動滾動
阿新 • • 發佈:2019-02-01
效果:迴圈滾動,類似廣告條
思路:
開啟定時器重新整理繪製文字的位置即可達到效果。
步驟1:新建ScrollTextView類繼承自TextView。程式碼如下:
public class ScrollTextView extends TextView { private static final String TAG = "ScrollTextView"; private String mText = "蒹葭蒼蒼,白露為霜。所謂伊人,在水一方。"; private int mOffsetX = 0; private Rect mRect; private Timer mTimer; private TimerTask mTimerTask; /** * 速度,負數左移,正數右移。 */ private int mSpeed = -10; private static final int PFS = 24; public ScrollTextView(Context context) { this(context, null); } public ScrollTextView(Context context, AttributeSet attrs) { super(context, attrs); mRect = new Rect(); mTimer = new Timer(); mTimerTask = new MyTimerTask(); mTimer.schedule(mTimerTask, 0, 1000 / 24); } private class MyTimerTask extends TimerTask { @Override public void run() { //如果View能容下所有文字,直接返回 if (mRect.right < getWidth()){ return; } if (mOffsetX < - mRect.right - getPaddingEnd()){ //左移時的情況 mOffsetX = getPaddingStart(); } else if (mOffsetX > getPaddingStart()){ //右移時的情況 mOffsetX = - mRect.right; } mOffsetX += mSpeed; postInvalidate(); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //獲取文字區域大小,儲存在mRect中。 getPaint().getTextBounds(mText, 0, mText.length(), mRect); if (mRect.right < getWidth()){ canvas.drawText(mText, 0, getHeight() / 2, getPaint()); }else { canvas.drawText(mText, mOffsetX, getHeight() / 2, getPaint()); } } /** * 檢視移除時銷燬任務和定時器 */ @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); Log.e(TAG, "killTimer"); if (mTimerTask != null){ mTimerTask.cancel(); mTimerTask = null; } if (mTimer != null){ mTimer.cancel(); mTimer = null; } } }
完成上面程式碼可以的到如下效果:
以上是硬編碼文字,如果嘗試在XML佈局或程式碼設定文字,將會顯示的一塌糊塗:
<com.fanhongfei.scrolltext.ScrollTextView android:id="@+id/scrollTextView" android:layout_width="150dp" android:layout_height="60dp" android:background="#EE4000" android:text="開關磁阻電機的優缺點及使用" android:textColor="#FFFF" />
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ScrollTextView textView = findViewById(R.id.scrollTextView);
textView.setText("開關磁阻電機的優缺點及使用");
}
步驟2:需要對onDraw()做一些更改,如下:
@Override
protected void onDraw(Canvas canvas) {
//此處去掉了super.onDraw(Canvas canvas);
mText = getText().toString();
TextPaint textPaint = getPaint();
textPaint.setColor(getCurrentTextColor());
//獲取文字區域大小,儲存在mRect中。
textPaint.getTextBounds(mText, 0, mText.length(), mRect);
if (mRect.right < getWidth()){
canvas.drawText(mText, 0, getHeight() / 2, textPaint);
}else {
canvas.drawText(mText, mOffsetX, getHeight() / 2, textPaint);
}
}
一切都很正常,把字型調大再看看,發現並沒有居中顯示,而是稍稍偏上。
問題就在於:
canvas.drawText(mText, mOffsetX, getHeight() / 2, textPaint);
第三個引數,垂直方向的中點和文字的基準點並不重合。
需做如下計算:
float mTextCenterVerticalToBaseLine =
( - textPaint.ascent() + textPaint.descent()) / 2 - textPaint.descent();
這樣就能文字居中了:
canvas.drawText(mText, mOffsetX, getHeight() / 2 + mTextCenterVerticalToBaseLine, textPaint);
別忘了在佈局XML中設定單行顯示,因為沒有重寫測量方法,佈局使用wrap_content時得到的並不是我們想要的尺寸。
android:maxLines="1"
到此就完成了。
最後附上完整程式碼:
自定義的ScrollTextView類:
public class ScrollTextView extends TextView {
private static final String TAG = "ScrollTextView";
private String mText = "蒹葭蒼蒼,白露為霜。所謂伊人,在水一方。";
private int mOffsetX = 0;
private Rect mRect;
private Timer mTimer;
private TimerTask mTimerTask;
/**
* 速度,負數左移,正數右移。
*/
private int mSpeed = -10;
private static final int PFS = 24;
public ScrollTextView(Context context) {
this(context, null);
}
public ScrollTextView(Context context, AttributeSet attrs) {
super(context, attrs);
mRect = new Rect();
mTimer = new Timer();
mTimerTask = new MyTimerTask();
//更新幀率24
mTimer.schedule(mTimerTask, 0, 1000 / PFS);
}
private class MyTimerTask extends TimerTask {
@Override
public void run() {
//如果View能容下所有文字,直接返回
if (mRect.right < getWidth()){
return;
}
if (mOffsetX < - mRect.right - getPaddingEnd()){
//左移時的情況
mOffsetX = getPaddingStart();
} else if (mOffsetX > getPaddingStart()){
//右移時的情況
mOffsetX = - mRect.right;
}
mOffsetX += mSpeed;
postInvalidate();
}
}
@Override
protected void onDraw(Canvas canvas) {
//此處去掉了super.onDraw(Canvas canvas);
mText = getText().toString();
TextPaint textPaint = getPaint();
textPaint.setColor(getCurrentTextColor());
//獲取文字區域大小,儲存在mRect中。
textPaint.getTextBounds(mText, 0, mText.length(), mRect);
float mTextCenterVerticalToBaseLine =
( - textPaint.ascent() + textPaint.descent()) / 2 - textPaint.descent();
if (mRect.right < getWidth()){
canvas.drawText(mText, 0, getHeight() / 2 + mTextCenterVerticalToBaseLine, textPaint);
}else {
canvas.drawText(mText, mOffsetX, getHeight() / 2 + mTextCenterVerticalToBaseLine, textPaint);
}
}
/**
* 檢視移除時銷燬任務和定時器
*/
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Log.e(TAG, "killTimer");
if (mTimerTask != null){
mTimerTask.cancel();
mTimerTask = null;
}
if (mTimer != null){
mTimer.cancel();
mTimer = null;
}
}
public void setSpeed(int speed){
this.mSpeed = speed;
}
}
MainActivity:
public class MainActivity extends Activity {
String text1 = "桑之未落,其葉沃若。于嗟鳩兮,無食桑葚;\n" +
"于嗟女兮,無與士耽。士之耽兮,猶可說也;\n" +
"女之耽兮,不可說也。";
String text2 = "桑之落矣,其黃而隕。自我徂爾,三歲食貧。\n" +
"淇水湯湯,漸車帷裳。女也不爽,士貳其行。\n" +
"士也罔極,二三其德。";
String text3 = "三歲為婦,靡室勞矣;夙興夜寐,靡有朝矣。\n" +
"言既遂矣,至於暴矣。兄弟不知,咥其笑矣。\n" +
"靜言思之,躬自悼矣。";
String text4 = "及爾偕老,老使我怨。淇則有岸,隰則有泮。\n" +
"總角之宴,言笑晏晏。信誓旦旦,不思其反。\n" +
"反是不思,亦已焉哉!";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ScrollTextView textView1 = findViewById(R.id.scrollTextView1);
textView1.setText(text1);
textView1.setSpeed(-5);
ScrollTextView textView2 = findViewById(R.id.scrollTextView2);
textView2.setText(text2);
textView2.setSpeed(10);
ScrollTextView textView3 = findViewById(R.id.scrollTextView3);
textView3.setText(text3);
textView3.setSpeed(-15);
ScrollTextView textView4 = findViewById(R.id.scrollTextView4);
textView4.setText(text4);
textView4.setSpeed(20);
}
}
佈局檔案activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:gravity="center"
android:orientation="vertical"
tools:context="com.fanhongfei.scrolltext.MainActivity">
<com.fanhongfei.scrolltext.ScrollTextView
android:id="@+id/scrollTextView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#EE4000"
android:maxLines="1"
android:textColor="#FFFF"
android:textSize="14sp" />
<com.fanhongfei.scrolltext.ScrollTextView
android:id="@+id/scrollTextView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:background="#EE4000"
android:maxLines="1"
android:textColor="#DAA520"
android:textSize="24sp" />
<com.fanhongfei.scrolltext.ScrollTextView
android:id="@+id/scrollTextView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:background="#EE4000"
android:maxLines="1"
android:textColor="#FFFF"
android:textSize="28sp" />
<com.fanhongfei.scrolltext.ScrollTextView
android:id="@+id/scrollTextView4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:background="#EE4000"
android:maxLines="1"
android:textColor="#CDCD00"
android:textSize="32sp" />
</LinearLayout>
工程檔案: