Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android--最強跑馬燈

Android--最強跑馬燈

編輯:關於Android編程

Android 跑馬燈已經有很多版本,從最基本的TextView,到重寫TextView使TextView取消焦點限制,還有重寫TextView利用ScrollTo方法寫的,基本都能滿足一般需要。然而在使用過程中,發現一些意外---有時會不播放,刷新線程還在繼續但就是不播放,最後在github上找到一個用動畫實現跑馬燈的項目(項目地址:https://github.com/ened/Android-MarqueeView,再次對作者表示感謝),改造了一番,總算ok了。以後再也不用為跑馬燈煩惱了。


特點:

1. 文字長短都有跑馬燈效果。

2. 可以控制速度



代碼:

package com.example.test_marquee;

import android.content.Context;
import android.graphics.Paint;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;

/**
 * LinearLayout作為父View,必須有一個子TextView
 * 
 * 利用動畫實現
 */
public class MarqueeView extends LinearLayout {

	private static final int TEXTVIEW_VIRTUAL_WIDTH = 2000;/* TextView默認寬度 */
	private static final int DEFAULT_SPEED = 35;/* 默認滾動速度 越大滾動越慢 */
	private static final int DEFAULT_ANIMATION_PAUSE = 0;/* 出去動畫與進入動畫的時間間隔 */
	private static final String TAG = MarqueeView.class.getSimpleName();

	private TextView mTextField;/* 該跑馬燈的孫子View之TextView */
	private ScrollView mScrollView;/* 該跑馬燈的子View之mScrollView */

	private Animation mMoveTextOut = null;/* 作用於TextView的動畫 --出去 */
	private Animation mMoveTextIn = null;/* 作用於TextView的動畫 --進入 */

	private Paint mPaint;
	private int mSpeed = DEFAULT_SPEED;
	private int mAnimationPause = DEFAULT_ANIMATION_PAUSE;
	private Interpolator mInterpolator = new LinearInterpolator();

	private Runnable mAnimationStartRunnable;

	/** 字符串之間的間隔 */
	private String interval = "     ";
	private String stringOfItem = "";
	/** str+interval的長度 */
	private float widthOfItem = 0;
	private float widthOfTextView;
	private String stringOfTextView = "";
	private float startXOfOut = 0;
	private float endXOfOut = 0;
	private float startXOfIn = 0;
	private float endXOfIn = 0;

	public MarqueeView(Context context) {
		super(context);
		init(context);
	}

	public MarqueeView(Context context, AttributeSet attrs) {
		super(context, attrs);

		init(context);
	}

	public MarqueeView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		init(context);
	}

	private void init(Context context) {
		// init helper
		mPaint = new Paint();
		mPaint.setAntiAlias(true);
		mPaint.setStrokeWidth(1);
		mPaint.setStrokeCap(Paint.Cap.ROUND);
		mInterpolator = new LinearInterpolator();
	}

	// 當給子View分配位置和尺寸時調用。
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		Logcat.d(TAG, "onLayout called!" + "changed: " + changed);
		if (getChildCount() == 0 || getChildCount() > 1) {
			throw new RuntimeException(
					"MarqueeView must have exactly one child element.");
		}

		//
		if (changed) {
			View v = getChildAt(0);
			if (!(v instanceof TextView)) {
				throw new RuntimeException(
						"The child view of this MarqueeView must be a TextView instance.");
			}
			initView(getContext());
			mTextField.setText(mTextField.getText());
		}
	}

	/** Starts the configured marquee effect. */
	public void startMarquee() {
		Logcat.d(TAG, "startMarquee called");
		startTextFieldAnimation();
	}

	// 一旦開始動畫,動畫結束開始由監聽器負責。
	private void startTextFieldAnimation() {
		mAnimationStartRunnable = new Runnable() {
			public void run() {
				mTextField.startAnimation(mMoveTextOut);
			}
		};
		postDelayed(mAnimationStartRunnable, mAnimationPause);
	}

	/**
	 * Disables the animations.
	 */
	public void reset() {

		if (mAnimationStartRunnable == null)
			return;
		removeCallbacks(mAnimationStartRunnable);
		mTextField.clearAnimation();
		mMoveTextOut.reset();
		mMoveTextIn.reset();
		invalidate();
	}

	private void prepareAnimation() {
		// Measure
		mPaint.setTextSize(mTextField.getTextSize());
		mPaint.setTypeface(mTextField.getTypeface());
		float mTextWidth = mPaint.measureText(mTextField.getText().toString());

		float width = getMeasuredWidth();
		startXOfOut = -(mTextWidth - width) % widthOfItem;
		endXOfOut = -mTextWidth + width;
		startXOfIn = -(mTextWidth - width) % widthOfItem;
		endXOfIn = -mTextWidth + width;

		final int duration = ((int) Math.abs(startXOfOut - endXOfOut) * mSpeed);

		if (BuildConfig.DEBUG) {
			Log.d(TAG, "(int) Math.abs(startXOfOut - endXOfOut)       : "
					+ (int) Math.abs(startXOfOut - endXOfOut));
			Log.d(TAG, "mSpeed       : " + mSpeed);
			Log.d(TAG, "startXOfOut       : " + startXOfOut);
			Log.d(TAG, "endXOfOut         : " + endXOfOut);
			Log.d(TAG, "startXOfIn        : " + startXOfIn);
			Log.d(TAG, "endXOfIn  		  : " + endXOfIn);
			Log.d(TAG, "duration  		  : " + duration);
		}
		mMoveTextOut = new TranslateAnimation(startXOfOut, endXOfOut, 0, 0);
		mMoveTextOut.setDuration(duration);
		mMoveTextOut.setInterpolator(mInterpolator);
		mMoveTextOut.setFillAfter(true);

		mMoveTextIn = new TranslateAnimation(startXOfIn, endXOfIn, 0, 0);
		mMoveTextIn.setDuration(duration);
		mMoveTextIn.setStartOffset(mAnimationPause);
		mMoveTextIn.setInterpolator(mInterpolator);
		mMoveTextIn.setFillAfter(true);

		mMoveTextOut.setAnimationListener(new Animation.AnimationListener() {
			public void onAnimationStart(Animation animation) {
			}

			public void onAnimationEnd(Animation animation) {
				mTextField.startAnimation(mMoveTextIn);
			}

			public void onAnimationRepeat(Animation animation) {
			}
		});

		mMoveTextIn.setAnimationListener(new Animation.AnimationListener() {
			public void onAnimationStart(Animation animation) {
			}

			public void onAnimationEnd(Animation animation) {
				startTextFieldAnimation();
			}

			public void onAnimationRepeat(Animation animation) {
			}
		});
	}

	/** 初始化子View */
	private void initView(Context context) {

		// Scroll View
		LayoutParams sv1lp = new LayoutParams(LayoutParams.MATCH_PARENT,
				LayoutParams.WRAP_CONTENT);
		sv1lp.gravity = Gravity.CENTER_HORIZONTAL;
		mScrollView = new ScrollView(context);

		// Scroll View 1 - Text Field
		mTextField = (TextView) getChildAt(0);
		removeView(mTextField);

		mScrollView.addView(mTextField, new ScrollView.LayoutParams(
				TEXTVIEW_VIRTUAL_WIDTH, LayoutParams.WRAP_CONTENT));

		mTextField.addTextChangedListener(new TextWatcher() {
			@Override
			public void beforeTextChanged(CharSequence charSequence, int i,
					int i2, int i3) {
			}

			@Override
			public void onTextChanged(CharSequence charSequence, int i, int i2,
					int i3) {
			}

			@Override
			public void afterTextChanged(Editable editable) {

				Logcat.d(TAG, "afterTextChanged called");

				// 如果提供的字符串未被加工過,就先加工,否則就開始動畫
				if (!stringOfTextView.equals(editable.toString())) {

					String str = editable.toString();
					mPaint.setTextSize(mTextField.getTextSize());
					mPaint.setTypeface(mTextField.getTypeface());

					stringOfItem = str + interval;
					widthOfItem = mPaint.measureText(stringOfItem);
					stringOfTextView = stringOfItem;
					widthOfTextView = widthOfItem;

					while (widthOfTextView <= 2 * getMeasuredWidth()) {
						stringOfTextView += stringOfItem;
						widthOfTextView = mPaint.measureText(stringOfTextView);
					}
					Logcat.d(TAG, "string of TextView deal ok!###");
					Logcat.d(TAG, "lengthOfll: " + getMeasuredWidth() + "###");
					Logcat.d(TAG, "lengthOfTextView: " + widthOfTextView
							+ "###");
					Logcat.d(TAG, "CONTENT: " + stringOfTextView + "###");
					// 設置起始
					mTextField.setText(stringOfTextView);
					return;
				}
				reset();
				prepareAnimation();
				expandTextView();
				post(new Runnable() {
					@Override
					public void run() {
						startMarquee();
					}
				});
			}
		});

		addView(mScrollView, sv1lp);
	}

	private void expandTextView() {
		ViewGroup.LayoutParams lp = mTextField.getLayoutParams();
		lp.width = (int) widthOfTextView + 5;
		mTextField.setLayoutParams(lp);
	}
}

使用:




    

        
    

Demo下載地址:

http://download.csdn.net/detail/u012587637/8219987




  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved