天天看點

Android自定義控件--1(TextView跑馬燈效果)

N久沒有跟新了,最近做的銀行項目中的一個自定義控件(用于狀态欄歡迎語句+櫃員資訊的滾動,簡單點說就是TextView跑馬燈效果)

package com.hacheng.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import android.view.animation.DecelerateInterpolator;
import android.widget.Scroller;
import android.widget.TextView;

public class ScrollTextView extends TextView {
	private Scroller mScroller;
	private int mTouchSlop;
	private int mMinimumVelocity;
	private int mMaximumVelocity;

	private float mLastMotionY;
	private boolean mIsBeingDragged;
	private VelocityTracker mVelocityTracker;
	private int mActivePointerId = INVALID_POINTER;

	private static final int INVALID_POINTER = -1;

	public ScrollTextView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initView();
	}

	public ScrollTextView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initView();
	}

	public ScrollTextView(Context context) {
		super(context);
		initView();
	}

	private void initView() {
		final Context cx = getContext();
		// 設定滾動減速器,在fling中會用到
		mScroller = new Scroller(cx, new DecelerateInterpolator(0.5f));
		final ViewConfiguration configuration = ViewConfiguration.get(cx);
		mTouchSlop = configuration.getScaledTouchSlop();
		mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
		mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();

	}

	/**
	 * 此方法為最後機會來修改mScrollX,mScrollY. 這方法後将根據mScrollX,mScrollY來偏移Canvas已實作内容滾動
	 */
	@Override
	public void computeScroll() {
		super.computeScroll();

		final Scroller scroller = mScroller;
		if (scroller.computeScrollOffset()) { // 正在滾動,讓view滾動到目前位置
			int scrollY = scroller.getCurrY();
			final int maxY = (getLineCount() * getLineHeight()
					+ getPaddingTop() + getPaddingBottom())
					- getHeight();
			boolean toEdge = scrollY < 0 || scrollY > maxY;
			if (scrollY < 0)
				scrollY = 0;
			else if (scrollY > maxY)
				scrollY = maxY;

			/*
			 * 下面等同于: mScrollY = scrollY; awakenScrollBars(); //顯示滾動條,必須在xml中配置。
			 * postInvalidate();
			 */
			scrollTo(0, scrollY);
			if (toEdge) // 移到兩端,由于位置沒有發生變化,導緻滾動條不顯示
				awakenScrollBars();
		}
	}

	public void fling(int velocityY) {
		final int maxY = (getLineCount() * getLineHeight() + getPaddingTop() + getPaddingBottom())
				- getHeight();

		mScroller.fling(getScrollX(), getScrollY(), 0, velocityY, 0, 0, 0,
				Math.max(0, maxY));

		// 重新整理,讓父控件調用computeScroll()
		invalidate();
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		/*
		 * 事件處理方式:先自己處理後交給父類處理。 PS:方式不同,可能導緻效果不同。請根據需求自行修改。
		 */
		boolean handled = false;
		final int contentHeight = getLineCount() * getLineHeight();
		if (contentHeight > getHeight()) {
			handled = processScroll(ev);
		}

		return handled | super.onTouchEvent(ev);
	}

	private boolean processScroll(MotionEvent ev) {
		boolean handled = false;
		if (mVelocityTracker == null) {
			mVelocityTracker = VelocityTracker.obtain();
		}
		mVelocityTracker.addMovement(ev); // 幫助類,用來在fling時計算移動初速度

		final int action = ev.getAction();

		switch (action) {
		case MotionEvent.ACTION_DOWN: {
			if (!mScroller.isFinished()) {
				mScroller.forceFinished(true);
			}

			mLastMotionY = ev.getY();
			mActivePointerId = ev.getPointerId(0);
			mIsBeingDragged = true;
			handled = true;
			break;
		}
		case MotionEvent.ACTION_MOVE: {
			final int pointerId = mActivePointerId;
			if (mIsBeingDragged && INVALID_POINTER != pointerId) {
				final int pointerIndex = ev.findPointerIndex(pointerId);
				final float y = ev.getY(pointerIndex);
				int deltaY = (int) (mLastMotionY - y);

				if (Math.abs(deltaY) > mTouchSlop) { // 移動距離(正負代表方向)必須大于ViewConfiguration設定的預設值
					mLastMotionY = y;

					/*
					 * 預設滾動時間為250ms,建議立即滾動,否則滾動效果不明顯 或者直接使用scrollBy(0, deltaY);
					 */
					mScroller.startScroll(getScrollX(), getScrollY(), 0,
							deltaY, 0);
					invalidate();
					handled = true;
				}
			}
			break;
		}
		case MotionEvent.ACTION_UP: {
			final int pointerId = mActivePointerId;
			if (mIsBeingDragged && INVALID_POINTER != pointerId) {
				final VelocityTracker velocityTracker = mVelocityTracker;
				velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
				int initialVelocity = (int) velocityTracker
						.getYVelocity(pointerId);

				if (Math.abs(initialVelocity) > mMinimumVelocity) {
					fling(-initialVelocity);
				}

				mActivePointerId = INVALID_POINTER;
				mIsBeingDragged = false;

				if (mVelocityTracker != null) {
					mVelocityTracker.recycle();
					mVelocityTracker = null;
				}

				handled = true;
			}
			break;
		}
		}
		return handled;
	}
}
           

layout中引用:

<com.hacheng.view.ScrollTextView
            android:id="@+id/scrollview"
            android:layout_width="750px"
            android:layout_height="48px"
            android:ellipsize="marquee"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:lines="1"
            android:marqueeRepeatLimit="marquee_forever"
            android:scrollHorizontally="true"
            android:singleLine="true"
            android:text="歡迎光臨中國某某銀行!櫃員号:25645 地區号:658978"
            android:textSize="38dp" >
        </com.hacheng.view.ScrollTextView>           

源碼下載下傳請戳這裡: