Android 中一個簡單垂直跑馬燈的實現
阿新 • • 發佈:2018-11-15
記錄一個Android中簡單實現垂直跑馬燈功能的方法:實現了垂直跑馬燈的功能。記錄一下以便日後檢視:
首先在MainActivity下新建一個名為 ScrollTextView的.java 檔案
ScrollTextView.java程式碼如下:
其中判斷分行結束符以 "\n" 為準。。。
package com.example.chenhy.pmd; import java.util.ArrayList; import android.content.Context; import android.graphics.Canvas; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.TextView; /** * ?????????? * @author HeJx * */ public class ScrollTextView extends TextView { /** * ??е?????? */ ArrayList<String> lineStrings; /** * ?????λ?? */ float currentY; /** * ?????????? */ Handler handler; /** * ??????text */ String scrollText=""; /** * ??????,??????width="xxdp"???????? */ private int exactlyWidth = -1; /** * ??????,??????height="xxdip"???????? */ private int exactlyHeight = -1; private float index = 0; public String getScrollText() { return scrollText; } public void setScrollText(String scrollText) { this.scrollText = scrollText; reset(); } /** * ???? */ private void reset() { if(lineStrings!=null) lineStrings.clear(); stop(); currentY = 0; absloutHeight = 0; this.setText(""); if(handler!=null){ handler.removeMessages(0); handler.removeMessages(1); handler.removeMessages(2); handler.removeMessages(3); } requestLayout(); invalidate(); } public ScrollTextView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public ScrollTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public ScrollTextView(Context context) { super(context); init(); } /** * ???????? */ boolean scrolling = false; /** * ????????????????????????? */ float absloutHeight = 0; /** * handler???????????? */ private int delayTime = 10; //??????? private int stopTime = 0; //?????? public int getDelayTime() { return delayTime; } public void setDelayTime(int delayTime) { this.delayTime = delayTime; } public int getStopTime() { return stopTime; } public void setStopTime(int stopTime) { this.stopTime = stopTime; } /** * ??ι???????? */ float speed = 0.5f; /** * ????? */ void init() { handler = new Handler() { @Override public void handleMessage(Message msg) { if (absloutHeight <= getHeight()) { currentY = 0; stop(); return; } switch (msg.what) { case 0: { currentY = currentY - speed; //resetCurrentY(); invalidate(); boolean flag = true; if (currentY >= absloutHeight || currentY <= -absloutHeight) { flag = false; handler.sendEmptyMessageDelayed(3, stopTime); } if(flag){ if (currentY >= index|| currentY <= -index || getHeight() <= 0) { handler.sendEmptyMessageDelayed(2, stopTime); }else{ handler.sendEmptyMessageDelayed(0, delayTime); } } break; } case 1: { currentY += msg.arg1; resetCurrentY(); invalidate(); } break; case 2:{ index = index+absloutHeight/lineStrings.size(); stop(); handler.sendEmptyMessageDelayed(0, delayTime); } break; case 3:{ currentY = 0; index = absloutHeight/lineStrings.size();; stop(); handler.sendEmptyMessageDelayed(0, delayTime); } } } /** * ????currentY????currentY????absloutHeight????????????0?? */ private void resetCurrentY() { if (currentY >= absloutHeight || currentY <= -absloutHeight || getHeight() <= 0) { currentY = 0; } } }; } /** * ??δ???????????y???? */ float lastY = 0; /** * ?true???????????? */ boolean needStop; public void pause() { if (scrolling) { stop(); needStop = true; } } public void goOn() { if (needStop) { play(); needStop = false; } } /* @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: distanceY = lastY = event.getY(); distanceX = event.getX(); pause(); return true; case MotionEvent.ACTION_MOVE: float dy = event.getY() - lastY; lastY = event.getY(); // currentY = currentY + dy; Message msg = Message.obtain(); msg.what = 1; msg.arg1 = (int)dy; handler.sendMessage(msg); return true; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: goOn(); float y = event.getY() - distanceY; float x = event.getX() - distanceX; if (Math.sqrt(y * y + x * x) < performUpScrollStateDistance) { updateScrollStatus(); } return true; } return super.onTouchEvent(event); } */ /** * ???????????С?????????????????????????????????????????????????? */ public static final long performUpScrollStateDistance = 5; public float distanceY = 0; public float distanceX = 0; /** * ????????? */ public void updateScrollStatus() { if (scrolling) { stop(); } else { play(); } } /** * ??????? */ public void play() { if (!scrolling) { handler.sendEmptyMessage(0); scrolling = true; } } /** * ?????? */ public void stop() { if (scrolling) { handler.removeMessages(0); scrolling = false; } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureWidth(widthMeasureSpec); int height = MeasureHeight(width, heightMeasureSpec); setMeasuredDimension(width, height); currentY = 0; if (height < absloutHeight) { play(); } else { stop(); } } /** * ??????? * * @param widthMeasureSpec * @return */ private int MeasureWidth(int widthMeasureSpec) { int mode = MeasureSpec.getMode(widthMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); // ?????wrap_content if (mode == MeasureSpec.AT_MOST) { double abwidth = getPaint().measureText(scrollText); width = Math.min((int)Math.rint(abwidth), width); exactlyWidth = -1; } if (mode == MeasureSpec.EXACTLY) { exactlyWidth = width; } return width; } /** * ??????? * * @param width:??? * @param heightMeasureSpec * @return */ private int MeasureHeight(int width, int heightMeasureSpec) { int mode = MeasureSpec.getMode(heightMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); generateTextList(width); int lines = lineStrings.size(); absloutHeight = lines * getLineHeight() + getPaddingBottom() + getPaddingTop(); index = absloutHeight/lines; // ?????wrap_content if (mode == MeasureSpec.AT_MOST) { height = (int)Math.min(absloutHeight, height); exactlyHeight = -1; } else if (mode == MeasureSpec.EXACTLY) { exactlyHeight = height; } return height; } /** * ???????????????? * * @param str * @param i * @return */ boolean isENWordStart(String str, int i) { if (i == 0) { return true; } else if (str.charAt(i - 1) == ' ') { return true; } return false; } /** * ?????е???? * * @param MaxWidth * @param str * @return */ private String getLineText(int MaxWidth, String str) { // ????? StringBuffer trueStringBuffer = new StringBuffer(); // ????? StringBuffer tempStringBuffer = new StringBuffer(); boolean isLine; for (int i = 0; i < str.length(); i++) { isLine = false; char c = str.charAt(i); String add = ""; // ???c????????????????????й??? if (!isChinese(c) && isENWordStart(str, i)) { int place = getNextSpecePlace(i, str); // ??????????? if (place > -1) { add = str.substring(i, place) + " "; if (getPaint().measureText(add) > MaxWidth) { add = "" + c; } else { i = place; } } else { add = "" + c; } } else { if(c=='\n') { //?ж????????е????? isLine = true; add = "" + c; }else add = "" + c; } tempStringBuffer.append(add); String temp = tempStringBuffer.toString(); float width = getPaint().measureText(temp.toString()); if(isLine) break; if (width <= MaxWidth) { trueStringBuffer.append(add); } else { break; } } return trueStringBuffer.toString(); } /** * ?????????????? * * @param i * @param str * @return */ int getNextSpecePlace(int i, String str) { for (int j = i; j < str.length(); j++) { char c = str.charAt(j); if (c == '\n') { return j; } } return -1; } /** * ?????????????б? * * @param MaxWidth */ public void generateTextList(int MaxWidth) { lineStrings = new ArrayList<String>(); // String remain = scrollText; String[] contenx = scrollText.split("\n"); //這裡的"\n" 是標誌 for (String string : contenx) { lineStrings.add(string); } /* while (!remain.equals("")) { String line = getLineText(MaxWidth, remain); lineStrings.add(line); remain = remain.substring(line.length(), remain.length()); }*/ }; @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); float x = getPaddingLeft(); float y = getPaddingTop(); float lineHeight = getLineHeight(); float textSize = getPaint().getTextSize(); for (int i = 0; i < lineStrings.size(); i++) { y = lineHeight * i + textSize + currentY; float min = 0; if (exactlyHeight > -1) { min = Math.min(min, exactlyHeight - absloutHeight); } if (y < min) { y = y + absloutHeight; } else if (y >= min && y < textSize + min) { //??????????????????????????????????????? canvas.drawText(lineStrings.get(i), x, y + absloutHeight, getPaint()); } if (y >= absloutHeight) { //??????????????????????????????????????? canvas.drawText(lineStrings.get(i), x, y, getPaint()); y = y - absloutHeight; } canvas.drawText(lineStrings.get(i), x, y, getPaint()); } } /** * ?ж????????? * * @param c * @return */ private static final boolean isChinese(char c) { Character.UnicodeBlock ub = Character.UnicodeBlock.of(c); if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) { return true; } return false; } }
佈局檔案
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.chenhy.pmd.MainActivity"> <com.example.chenhy.pmd.ScrollTextView android:id="@+id/marqueeview" android:layout_width="match_parent" android:layout_height="match_parent" android:textSize="10sp" > </com.example.chenhy.pmd.ScrollTextView> </LinearLayout>
最後是mainactivity中的程式碼
package com.example.chenhy.pmd; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ScrollTextView marqueeView = (ScrollTextView) findViewById(R.id.marqueeview); marqueeView.setScrollText("塞納河畔 左岸的咖啡\n" + "我手一杯 品嚐你的美\n" + "留下脣印的嘴\n" + "花店玫瑰 名字寫錯誰\n" + "告白氣球 風吹到對街\n" + "微笑在天上飛\n" + "你說你有點難追 想讓我知難而退\n" + "禮物不需挑最貴 只要香榭的落葉\n" + "喔 營造浪漫的約會 不害怕搞砸一切\n" + "擁有你就擁有 全世界\n" + "親愛的 愛上你 從那天起\n" + "甜蜜的很輕易\n" + "親愛的 別任性 你的眼睛\n" + "在說我願意\n" + "塞納河畔 左岸的咖啡\n" + "我手一杯 品嚐你的美\n" + "留下脣印的嘴\n" + "花店玫瑰 名字寫錯誰\n" + "告白氣球 風吹到對街\n" + "微笑在天上飛\n" + "你說你有點難追 想讓我知難而退\n" + "禮物不需挑最貴 只要香榭的落葉\n" + "喔 營造浪漫的約會 不害怕搞砸一切\n" + "擁有你就擁有 全世界\n" + "親愛的 愛上你 從那天起\n" + "甜蜜的很輕易\n" + "親愛的 別任性 你的眼睛\n" + "在說我願意\n" + "親愛的 愛上你 戀愛日記\n" + "飄香水的回憶\n" + "一整瓶 的夢境 全都有你\n" + "攪拌在一起\n" + "親愛的別任性 你的眼睛\n" + "在說我願意"+"塞納河畔 左岸的咖啡\n" + "我手一杯 品嚐你的美\n" + "留下脣印的嘴\n" + "花店玫瑰 名字寫錯誰\n" + "告白氣球 風吹到對街\n" + "微笑在天上飛\n" + "你說你有點難追 想讓我知難而退\n" + "禮物不需挑最貴 只要香榭的落葉\n" + "喔 營造浪漫的約會 不害怕搞砸一切\n" + "擁有你就擁有 全世界\n" + "親愛的 愛上你 從那天起\n" + "甜蜜的很輕易\n" + "親愛的 別任性 你的眼睛\n" + "在說我願意\n" + "塞納河畔 左岸的咖啡\n" + "我手一杯 品嚐你的美\n" + "留下脣印的嘴\n" + "花店玫瑰 名字寫錯誰\n" + "告白氣球 風吹到對街\n" + "微笑在天上飛\n" + "你說你有點難追 想讓我知難而退\n" + "禮物不需挑最貴 只要香榭的落葉\n" + "喔 營造浪漫的約會 不害怕搞砸一切\n" + "擁有你就擁有 全世界\n" + "親愛的 愛上你 從那天起\n" + "甜蜜的很輕易\n" + "親愛的 別任性 你的眼睛\n" + "在說我願意\n" + "親愛的 愛上你 戀愛日記\n" + "飄香水的回憶\n" + "一整瓶 的夢境 全都有你\n" + "攪拌在一起\n" + "親愛的別任性 你的眼睛\n" + "在說我願意"); } }
最後,上一張效果圖