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>
源碼下載下傳請戳這裡: