From:http://orgcent.com/android-custom-vertical-scroll-textview/

其实要让TextView能够滚动,可以使用ScrollView/HorizontalScrollView或者设置ScrollingMovementMethod来实现。
点击查看:android实现TextView垂直或水平滚动

下面自定义垂直滚动的TextView,主要是用来学习Scroller的使用。关于ScrollTextView的实现,可以看下面的介绍和源码。

packagecom.orgcent.demo.view;

importandroid.content.Context;
importandroid.util.AttributeSet;
importandroid.view.MotionEvent;
importandroid.view.VelocityTracker;
importandroid.view.ViewConfiguration;
importandroid.view.animation.DecelerateInterpolator;
importandroid.widget.Scroller;
importandroid.widget.TextView;
/**
* 配置android:scrollbars="vertical",启用垂直滚动条
*
* 实现水平滚动就是修改mScrollX,可参考HorizontalScrollView
*
* 滚动原理: 在绘制前对画布进行偏移操作
*
* 下面是View的绘制机制:
* |- view.computeScroll() --用来对mScrollX/Y进行修改。由于在绘制前调用,可调用invalite()来触发
* |- canvas.translate(-mScrollX,-mScrollY) --偏移画布
* |- view.draw() --绘制
*
* 上述内容可以在View.buildDrawingCache()或ViewGroup.dispatchDraw()->drawChild()中找到.直接查看方法名即可
*
* 滚动帮助类:
* Scroller --用来计算滚动后的偏移值.具体请参考ScrollView和HorizontalScrollView
* VelocityTracker --速度计算类。根据fling时的按下、抬起动作,计算滚动初速度
*
* ScrollTextView--流程解析:
* 1、onTouchEvent() --使用Scroller来计算滚动偏移值
* 2、重写computeScroll() --对View的mScrollY进行修改, 此处控制滚动范围
*
* 滚动范围:
* 最小值:0
* 最大值:所有文本高度+内边距-View高度。也就是超出屏幕的文本高度
*/

publicclassScrollTextViewextendsTextView{
privateScroller mScroller;
privateintmTouchSlop;
privateintmMinimumVelocity;
privateintmMaximumVelocity;

privatefloatmLastMotionY;
privatebooleanmIsBeingDragged;
privateVelocityTracker mVelocityTracker;
privateintmActivePointerId=INVALID_POINTER;


privatestaticfinalintINVALID_POINTER=-1;

publicScrollTextView(Contextcontext,AttributeSetattrs,intdefStyle){
super(context, attrs, defStyle);
initView();
}

publicScrollTextView(Contextcontext,AttributeSetattrs){
super(context, attrs);
initView();
}

publicScrollTextView(Contextcontext){
super(context);
initView();
}

privatevoidinitView(){
finalContextcx=getContext();
//设置滚动减速器,在fling中会用到
mScroller=newScroller(cx,newDecelerateInterpolator(0.5f));
finalViewConfiguration configuration=ViewConfiguration.get(cx);
mTouchSlop=configuration.getScaledTouchSlop();
mMinimumVelocity=configuration.getScaledMinimumFlingVelocity();
mMaximumVelocity=configuration.getScaledMaximumFlingVelocity();

}

/**
* 此方法为最后机会来修改mScrollX,mScrollY.
* 这方法后将根据mScrollX,mScrollY来偏移Canvas已实现内容滚动
*/

@Override
publicvoidcomputeScroll(){
super.computeScroll();

finalScroller scroller=mScroller;
if(scroller.computeScrollOffset()){//正在滚动,让view滚动到当前位置
intscrollY=scroller.getCurrY();
finalintmaxY=(getLineCount()*getLineHeight()+getPaddingTop()+getPaddingBottom())-getHeight();
booleantoEdge=scrollY<0||scrollY>maxY;
if(scrollY<0)
scrollY=0;
elseif(scrollY>maxY)
scrollY=maxY;

/*
*下面等同于:
* mScrollY = scrollY;
* awakenScrollBars(); //显示滚动条,必须在xml中配置。
* postInvalidate();
*/

scrollTo(0, scrollY);
if(toEdge)//移到两端,由于位置没有发生变化,导致滚动条不显示
awakenScrollBars();
}
}

publicvoidfling(intvelocityY){
finalintmaxY=(getLineCount()*getLineHeight()+getPaddingTop()+getPaddingBottom())-getHeight();

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

//刷新,让父控件调用computeScroll()
invalidate();
}


@Override
publicbooleanonTouchEvent(MotionEvent ev){
/*
* 事件处理方式:先自己处理后交给父类处理。
* PS:方式不同,可能导致效果不同。请根据需求自行修改。
*/

booleanhandled=false;
finalintcontentHeight=getLineCount()*getLineHeight();
if(contentHeight>getHeight()){
handled=processScroll(ev);
}

returnhandled|super.onTouchEvent(ev);
}

privatebooleanprocessScroll(MotionEvent ev){
booleanhandled=false;
if(mVelocityTracker==null){
mVelocityTracker=VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);//帮助类,用来在fling时计算移动初速度

finalintaction=ev.getAction();

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

mLastMotionY=ev.getY();
mActivePointerId=ev.getPointerId(0);
mIsBeingDragged=true;
handled=true;
break;
}
caseMotionEvent.ACTION_MOVE:{
finalintpointerId=mActivePointerId;
if(mIsBeingDragged&&INVALID_POINTER!=pointerId){
finalintpointerIndex=ev.findPointerIndex(pointerId);
finalfloaty=ev.getY(pointerIndex);
intdeltaY=(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;
}
caseMotionEvent.ACTION_UP:{
finalintpointerId=mActivePointerId;
if(mIsBeingDragged&&INVALID_POINTER!=pointerId){
finalVelocityTracker velocityTracker=mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
intinitialVelocity=(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;
}
}
returnhandled;
}
}


更多相关文章

  1. Android麦克风录音带音量大小动态显示的圆形自定义View
  2. PopupWindow简单实现
  3. Android(安卓)OpenGL 文本显示 LabelMaker
  4. Android(安卓)Studio中TextView文本过长滚动显示方法
  5. Android实现图片 高斯模糊,以及图片镜像 翻转。
  6. android开发之修改ListView默认滑动条样式
  7. android源码中常用的Rect方法
  8. Android(安卓)列表使用(ListView GridView Gallery图片计时滚动)
  9. FrameLayout布局绘制流程解析

随机推荐

  1. android 图片轮播框架banner
  2. ContentProvider共享数据和ContentResolv
  3. ZZ android am命令
  4. android fragment 使用name关联Fragment
  5. android屏幕的那些事之一!
  6. android跳转到手机系统默认应用市场的方
  7. Android(安卓)  Fragmnet的使用新体会
  8. android 常见死机问题--log分析
  9. android图片上传
  10. Android如何调试程序(一)