基本說明
- 寫一個 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