基本說明
- 寫一個 MarqueeText.java 之可控的跑馬燈,並於主頁面程式實作。
- 撰寫編譯軟體:Android Studio 1.4
- 版本:Android 5.1
- 繼承 TextView 功能,另外增加可調速度、方向、暫停、角度。
- 加入 SeekBar 拖動條來控制 Delay 量,達到即時改變跑馬燈的速度。
- 可做成一個 Palette-CustomView 選項,可以直接加到 activity_main.xml 佈局內。
Step 1. 以開新專案 MarqueeDemo
---Step 2. 新增一個 JAVA Class → MarqueeText.java
package com.example.lin.marqueedemo;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.TextView;
/**
* Created by lin on 2015/12/15.
* 自製可調式跑馬燈(包含:速度、方向、暫停及繼承其他同 TextView 之功能。
*/
public class MarqueeText extends TextView implements Runnable {
public enum MarqueeDirection {
LEFT, RIGHT
}
private volatile boolean m_isStop = false; // 跑馬燈是否 stop
private boolean m_isMeasure = false; // 跑馬燈初始值量測 flag (只做一次)
private int m_TextWidth = 0; // 內文長度
private int m_Distance = 3; // 跑馬燈每次跳動距離
private int m_Scroll_X = 0; // 跑馬燈 X 軸座標
private int m_Scroll_Y = 0; // 跑馬燈 Y 軸座標
public int m_Delay = 50; // 跑馬燈速度(Delay 越小越快)
public MarqueeDirection m_Direction = MarqueeDirection.LEFT; // 跑馬燈方向控制
public MarqueeText(Context context) {
super(context);
}
public MarqueeText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MarqueeText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
// 程式啟動做一次
protected void onDraw(Canvas canvas) {
if (!m_isMeasure) {
setEllipsize(TextUtils.TruncateAt.MARQUEE);
setSingleLine(true);
getTextWidth();
setScrollInit();
startScroll();
m_isMeasure = true;
}
super.onDraw(canvas);
}
// 量測 android:text 內文長度
private void getTextWidth() {
Paint paint = getPaint();
String str = getText().toString();
m_TextWidth = (int) paint.measureText(str);
}
// 跑馬燈起始位置 (RIGHT/LEFT 兩種不同)
protected void setScrollInit() {
// 從右向左滾動(跑馬燈方向 ←)
if (m_Direction == MarqueeDirection.RIGHT) {
m_Scroll_X = -getWidth();
} else {
// 從左向右滾動(跑馬燈方向 →)
m_Scroll_X = m_TextWidth;
}
// 設定 TextView 內文滾動座標
scrollTo(m_Scroll_X, m_Scroll_Y);
}
// 實作 Runnable 的 run() 方法,用做跑馬燈移動的座標累加/減
@Override
public void run() {
// 偵測到 m_isStop=true,就做 return 來結束 run() 方法。
if (m_isStop) {
return;
}
// 偵測方向 m_Direction,做座標的累加/累減
if (m_Direction == MarqueeDirection.RIGHT) {
// 方向 ←
m_Scroll_X += m_Distance;
if (getScrollX() >= m_TextWidth) {
setScrollInit();
}
} else {
// 方向 →
m_Scroll_X -= m_Distance;
if (getScrollX() <= -getWidth()) {
setScrollInit();
}
}
// 設定 TextView 內文滾動座標
scrollTo(m_Scroll_X, m_Scroll_Y);
// 做 Delay
postDelayed(this, m_Delay);
}
public void startScroll() {
m_isStop = false;
removeCallbacks(this); // 清除執行緒
post(this); // 更新執行緒
}
public void pauseScroll() {
m_isStop = true;
removeCallbacks(this); // 清除執行緒
post(this); // 更新執行緒
}
public void switchScroll() {
// 切換跑馬燈方向
if (m_Direction == MarqueeDirection.RIGHT) {
m_Direction = MarqueeDirection.LEFT;
} else {
m_Direction = MarqueeDirection.RIGHT;
}
}
public void setDelay(int d) {
m_Delay = d;
removeCallbacks(this); // 清除執行緒
post(this); // 更新執行緒
}
}
---Step 3. 將寫好的跑馬燈加入佈局檔 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="1"
android:background="#404040">
<com.example.lin.marqueedemo.MarqueeText
android:id="@+id/test"
android:rotation="180"
android:text="↖( ̄▽ ̄)↗ 聖誕節快樂 (ノ>▽<。)ノ"
android:textSize="30dp"
android:textColor="#ffffff"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"/>
<com.example.lin.marqueedemo.MarqueeText
android:id="@+id/test2"
android:text="d(`・∀・)b Merry Christmas 。:.゚ヽ(*′∀`)ノ゚.:。 "
android:textSize="30dp"
android:textColor="#e6da04"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"/>
<LinearLayout
android:orientation="vertical"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_gravity="center"
android:layout_centerInParent="true" >
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:weightSum="1">
<TextView
android:layout_width="60dp"
android:layout_height="wrap_content"
android:text="Delay 1:"
android:textColor="#FFFFFF"
android:textSize="15dp"
android:layout_gravity="left"
android:id="@+id/textView" />
<SeekBar
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/seekBar"
android:progress="@integer/seekbarValue"
android:max="100" />
</LinearLayout>
<TextView
android:layout_width="30dp"
android:layout_height="20dp"
android:text="@integer/seekbarValue"
android:textColor="#FFFFFF"
android:textSize="15dp"
android:layout_gravity="right"
android:id="@+id/textView2" />
<Button
android:onClick="btn_start"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Start"
android:id="@+id/button" />
<Button
android:onClick="btn_pause"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Pause"
android:id="@+id/button2" />
<Button
android:onClick="btn_init"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Init Setting"
android:id="@+id/button3" />
<Button
android:onClick="btn_switch"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Switch Direction"
android:id="@+id/button4" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:weightSum="1" >
<TextView
android:layout_width="60dp"
android:layout_height="wrap_content"
android:text="Delay 2:"
android:textColor="#FFFFFF"
android:textSize="15dp"
android:layout_gravity="left"
android:id="@+id/textView3" />
<SeekBar
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/seekBar2"
android:progress="@integer/seekbarValue"
android:max="100" />
</LinearLayout>
<TextView
android:layout_width="30dp"
android:layout_height="20dp"
android:text="@integer/seekbarValue"
android:textColor="#FFFFFF"
android:textSize="15dp"
android:layout_gravity="right"
android:id="@+id/textView4" />
</LinearLayout>
</RelativeLayout>
---Stop 4. 至 values 目錄新增一個 Values XML file → integers.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="seekbarValue">50</integer>
</resources>
Step 5. 撰寫頁面主程式 MainActivity.java
package com.example.lin.marqueedemo;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.SeekBar;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private MarqueeText test, test2;
private TextView t1, t2, t3, t4;
private SeekBar delayBar, delayBar2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initMarqueeText();
initSeekBar();
}
public void initSeekBar() {
delayBar = (SeekBar) findViewById(R.id.seekBar);
delayBar2 = (SeekBar) findViewById(R.id.seekBar2);
t1 = (TextView) findViewById(R.id.textView);
t2 = (TextView) findViewById(R.id.textView2);
t3 = (TextView) findViewById(R.id.textView3);
t4 = (TextView) findViewById(R.id.textView4);
delayBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
t2.setText(String.valueOf(progress));
test.setDelay(Integer.valueOf(progress));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
delayBar2.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
t4.setText(String.valueOf(progress));
test2.setDelay(Integer.valueOf(progress));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
public void initMarqueeText() {
test = (MarqueeText) findViewById(R.id.test);
test2 = (MarqueeText) findViewById(R.id.test2);
test.m_Direction = MarqueeText.MarqueeDirection.RIGHT;
test2.m_Direction = MarqueeText.MarqueeDirection.RIGHT;
}
public void btn_start(View view1) {
test.startScroll();
test2.startScroll();
}
public void btn_pause(View view2) {
test.pauseScroll();
test2.pauseScroll();
}
public void btn_init(View view3) {
test.setScrollInit();
test2.setScrollInit();
delayBar.setProgress(getResources().getInteger(R.integer.seekbarValue));
delayBar2.setProgress(getResources().getInteger(R.integer.seekbarValue));
}
public void btn_switch(View view4) {
test.switchScroll();
test2.switchScroll();
}
}
---
原始檔 GitLab 備份(限校內):http://120.117.72.71/fate615030/androidProject.MarqueeDemo.git
Reference:
http://www.inote.tw/android-marquee-example
http://www.cnblogs.com/nuliniaoboke/archive/2013/01/10/2854707.html
