Android 如何覆盖自定义视图(surfaceview)
我有一个自定义的SurfaceView,它由工作线程管理。我正在使用与以下博文中的代码非常相似的代码来管理SurfaceView: 我的自定义SurfaceView是可滚动的,因为我监听触摸事件,将它们发送到手势检测器,并实现onScroll。我在一些成员变量(x轴和y轴)中跟踪滚动距离,并在绘制到画布时按适当的量转换任何坐标。我还夹紧滚动距离,可以轻松计算和存储夹紧时的任何过滚动量 这一切都很好 问题是我想在我的自定义SurfaceView上显示标准的Android overscroll效果。我尝试手动调用overScrollBy,但它不起作用,我最好的猜测是因为我正在从辅助线程绘制视图,这意味着永远不会调用视图的onDraw 我发现了以下关于自定义overscroll效果的stackoverflow帖子:Android 如何覆盖自定义视图(surfaceview),android,Android,我有一个自定义的SurfaceView,它由工作线程管理。我正在使用与以下博文中的代码非常相似的代码来管理SurfaceView: 我的自定义SurfaceView是可滚动的,因为我监听触摸事件,将它们发送到手势检测器,并实现onScroll。我在一些成员变量(x轴和y轴)中跟踪滚动距离,并在绘制到画布时按适当的量转换任何坐标。我还夹紧滚动距离,可以轻松计算和存储夹紧时的任何过滚动量 这一切都很好 问题是我想在我的自定义SurfaceView上显示标准的Android overscroll效果
这篇文章不是写给SurfaceView的,但我可能会修改代码。也就是说,有更好的办法吗?我想展示与其他地方展示的完全相同的overscroll效果。复制overscroll可绘制文件并尝试复制overscroll逻辑似乎。。。难看。嗯,我也有同样的问题 我查看了android视图的实现,在“onOverScrolled”中只有“故意清空”的注释 查看ListView实现,我可以看到他们已经通过获取不能从外部使用的drawables'com.android.internal.R.styleable.ListView_overScrollHeader'和'com.android.internal.R.styleable.ListView_overScrollFooter'手动实现了它。不幸的是,我无法在源代码中找到这些资源
似乎我们必须手动进行overscroll…好吧,我使用OverScroller在simple View中创建了一个简单的overscroll示例:
package net.project.experimental;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.OverScroller;
public class WorksheetView extends View
{
protected static final int OVERSCROLL_DISTANCE = 10;
protected static final int INVALID_POINTER_ID = -1;
private int fWorksheetWidth = 2000;
private int fWorksheetHeight = 2000;
private OverScroller fScroller;
private VelocityTracker fVelocityTracker = null;
private int fMinimumVelocity;
// The ‘active pointer’ is the one currently moving our object.
private int fTranslatePointerId = INVALID_POINTER_ID;
private PointF fTranslateLastTouch = new PointF( );
private boolean fInteracting = false;
public WorksheetView(Context context, AttributeSet attrs)
{
super( context, attrs );
this.initView( context, attrs );
}
public WorksheetView(Context context, AttributeSet attrs, int defStyle)
{
super( context, attrs, defStyle );
this.initView( context, attrs );
}
protected void initView(Context context, AttributeSet attrs)
{
fScroller = new OverScroller( this.getContext( ) );
this.setOverScrollMode( OVER_SCROLL_ALWAYS );
final ViewConfiguration configuration = ViewConfiguration.get( getContext( ) );
//fTouchSlop = configuration.getScaledTouchSlop( );
fMinimumVelocity = configuration.getScaledMinimumFlingVelocity( );
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
if ( fVelocityTracker == null )
{
fVelocityTracker = VelocityTracker.obtain( );
}
fVelocityTracker.addMovement( event );
final int action = event.getAction( );
switch ( action & MotionEvent.ACTION_MASK )
{
case MotionEvent.ACTION_DOWN:
{
if ( !fScroller.isFinished( ) )
fScroller.abortAnimation( );
final float x = event.getX( );
final float y = event.getY( );
fTranslateLastTouch.set( x, y );
fTranslatePointerId = event.getPointerId( 0 );
this.startInteracting( );
break;
}
case MotionEvent.ACTION_MOVE:
{
final int pointerIndexTranslate = event.findPointerIndex( fTranslatePointerId );
if ( pointerIndexTranslate >= 0 )
{
float translateX = event.getX( pointerIndexTranslate );
float translateY = event.getY( pointerIndexTranslate );
this.overScrollBy(
(int) (fTranslateLastTouch.x - translateX),
(int) (fTranslateLastTouch.y - translateY),
this.getScrollX( ),
this.getScrollY( ),
fWorksheetWidth - this.getWidth( ),
fWorksheetHeight - this.getHeight( ),
OVERSCROLL_DISTANCE,
OVERSCROLL_DISTANCE,
true );
fTranslateLastTouch.set( translateX, translateY );
this.invalidate( );
}
break;
}
case MotionEvent.ACTION_UP:
{
final VelocityTracker velocityTracker = fVelocityTracker;
velocityTracker.computeCurrentVelocity( 1000 );
//velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int initialXVelocity = (int) velocityTracker.getXVelocity( );
int initialYVelocity = (int) velocityTracker.getYVelocity( );
if ( (Math.abs( initialXVelocity ) + Math.abs( initialYVelocity ) > fMinimumVelocity) )
{
this.fling( -initialXVelocity, -initialYVelocity );
}
else
{
if ( fScroller.springBack( this.getScrollX( ), this.getScrollY( ), 0, fWorksheetWidth - this.getWidth( ), 0, fWorksheetHeight - this.getHeight( ) ) )
this.invalidate( );
this.stopInteracting( );
}
if ( fVelocityTracker != null )
{
fVelocityTracker.recycle( );
fVelocityTracker = null;
}
fTranslatePointerId = INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_DOWN:
{
break;
}
case MotionEvent.ACTION_POINTER_UP:
{
final int pointerIndex = (event.getAction( ) & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = event.getPointerId( pointerIndex );
if ( pointerId == fTranslatePointerId )
{
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
fTranslateLastTouch.set( event.getX( newPointerIndex ), event.getY( newPointerIndex ) );
fTranslatePointerId = event.getPointerId( newPointerIndex );
}
break;
}
case MotionEvent.ACTION_CANCEL:
{
if ( fScroller.springBack( this.getScrollX( ), this.getScrollY( ), 0, fWorksheetWidth - this.getWidth( ), 0, fWorksheetHeight - this.getHeight( ) ) )
this.invalidate( );
fTranslatePointerId = INVALID_POINTER_ID;
break;
}
}
return true;
}
private void fling(int velocityX, int velocityY)
{
int x = this.getScrollX( );
int y = this.getScrollY( );
this.startInteracting( );
//fScroller.setFriction( ViewConfiguration.getScrollFriction( ) );
fScroller.fling( x, y, velocityX, velocityY, 0, fWorksheetWidth - this.getWidth( ), 0, fWorksheetHeight - this.getHeight( ) );
this.invalidate( );
}
private void startInteracting()
{
fInteracting = true;
}
private void stopInteracting()
{
fInteracting = false;
}
@Override
public void computeScroll()
{
if ( fScroller != null && fScroller.computeScrollOffset( ) )
{
int oldX = this.getScrollX( );
int oldY = this.getScrollY( );
int x = fScroller.getCurrX( );
int y = fScroller.getCurrY( );
if ( oldX != x || oldY != y )
{
this.overScrollBy(
x - oldX,
y - oldY,
oldX,
oldY,
fWorksheetWidth - this.getWidth( ),
fWorksheetHeight - this.getHeight( ),
OVERSCROLL_DISTANCE,
OVERSCROLL_DISTANCE,
false );
}
if ( fScroller.isFinished( ) )
this.stopInteracting( );
this.postInvalidate( );
}
}
@Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY)
{
// Treat animating scrolls differently; see #computeScroll() for why.
if ( !fScroller.isFinished( ) )
{
super.scrollTo( scrollX, scrollY );
if ( clampedX || clampedY )
{
fScroller.springBack( this.getScrollX( ), this.getScrollY( ), 0, fWorksheetWidth - this.getWidth( ), 0, fWorksheetHeight - this.getHeight( ) );
}
}
else
{
super.scrollTo( scrollX, scrollY );
}
awakenScrollBars( );
}
@Override
protected int computeHorizontalScrollExtent()
{
return this.getWidth( );
}
@Override
protected int computeHorizontalScrollRange()
{
return fWorksheetWidth;
}
@Override
protected int computeHorizontalScrollOffset()
{
return this.getScrollX( );
}
@Override
protected int computeVerticalScrollExtent()
{
return this.getHeight( );
}
@Override
protected int computeVerticalScrollRange()
{
return fWorksheetHeight;
}
@Override
protected int computeVerticalScrollOffset()
{
return this.getScrollY( );
}
@Override
protected void onDraw(Canvas canvas)
{
canvas.drawColor( Color.BLACK );
Paint paint = new Paint( );
if ( fInteracting )
;
paint.setColor( Color.WHITE );
canvas.drawRect( 0, 0, fWorksheetWidth, fWorksheetHeight, paint );
paint.setColor( Color.RED );
for (int i = 0; i < 1500; i += 10)
{
canvas.drawLine( i, 0, i + 100, 500, paint );
}
canvas.drawRect( fWorksheetWidth - 50, 0, fWorksheetWidth, fWorksheetHeight, paint );
canvas.drawRect( 0, fWorksheetHeight - 50, fWorksheetWidth, fWorksheetHeight, paint );
}
}
package net.project.experimental;
导入android.content.Context;
导入android.graphics.Canvas;
导入android.graphics.Color;
导入android.graphics.Paint;
导入android.graphics.PointF;
导入android.util.AttributeSet;
导入android.view.MotionEvent;
导入android.view.VelocityTracker;
导入android.view.view;
导入android.view.ViewConfiguration;
导入android.widget.OverScroller;
公共类工作表视图扩展视图
{
受保护的静态最终int过卷距离=10;
受保护的静态final int无效\u指针\u ID=-1;
私有int fWorksheetWidth=2000;
私人int fWorksheetHeight=2000;
私人超级市场;
私有VelocityTracker fVelocityTracker=null;
私有整数速度;
//“活动指针”是当前正在移动对象的指针。
private int FTRATEPOINTERID=无效的\u指针\u ID;
私有点f ftTranslateLastTouch=新点f();
私有布尔fInteracting=false;
公共工作表视图(上下文、属性集属性)
{
超级(上下文,attrs);
this.initView(context,attrs);
}
公共工作表视图(上下文、属性集属性、int-defStyle)
{
超级(上下文、属性、定义样式);
this.initView(context,attrs);
}
受保护的void initView(上下文、属性集属性)
{
fScroller=newoverscroller(this.getContext());
此.setOverScrollMode(始终滚动);
final ViewConfiguration=ViewConfiguration.get(getContext());
//fTouchSlop=configuration.getScaledTouchSlop();
fMinimumVelocity=configuration.getScaledMinimumFlingVelocity();
}
@凌驾
公共布尔onTouchEvent(运动事件)
{
if(fVelocityTracker==null)
{
fVelocityTracker=VelocityTracker.get();
}
fVelocityTracker.addMovement(事件);
final int action=event.getAction();
开关(动作和动作事件.action\u掩码)
{
case MotionEvent.ACTION\u DOWN:
{
如果(!fScroller.isFinished())
abortAnimation();
final float x=event.getX();
最终浮点y=event.getY();
ftTranslateLastTouch.set(x,y);
ftTranslatePointerId=event.getPointerId(0);
这是startInteracting();
打破
}
case MotionEvent.ACTION\u移动:
{
final int pointerIndexTranslate=event.findPointerIndex(fTranslatePointerId);
if(pointerIndexTranslate>=0)
{
float translateX=event.getX(pointerIndexTranslate);
float translateY=event.getY(pointerIndexTranslate);
这是overScrollBy(
(int)(fTranslateLastTouch.x-translateX),
(int)(fTranslateLastTouch.y-translateY),
这个.getScrollX(),
这个.getScrollY(),
fWorksheetWidth-this.getWidth(),
fWorksheetHeight-this.getHeight(),
过滚距离,
过滚距离,
正确的);
ftTranslateLastTouch.set(translateX、translateY);
这个。使()无效;
}
打破
}
case MotionEvent.ACTION\u UP:
{
最终速度追踪器速度追踪器=fVelocityTracker;
计算当前速度(1000);
//velocityTracker.computeCurr
private void compensateForOverscroll(Canvas canvas)
{
int x = this.getScrollX( );
int y = this.getScrollY( );
Matrix matrix = canvas.getMatrix( );
int maxX = fWorksheetWidth - this.getWidth( );
int maxY = fWorksheetHeight - this.getHeight( );
if ( x < 0 || x > maxX || y < 0 || y > maxY )
{
if ( x < 0 )
matrix.postTranslate( x, 0 );
else if ( x > maxX )
matrix.postTranslate( (x - maxX), 0 );
if ( y < 0 )
matrix.postTranslate( 0, y );
else if ( y > maxY )
matrix.postTranslate( 0, (y - maxY) );
canvas.setMatrix( matrix );
}
}
@Override
protected void dispatchDraw(Canvas canvas)
{
int width = this.getWidth( );
int height = this.getHeight( );
int maxX = fWorksheetWidth - width;
int maxY = fWorksheetHeight - height;
int x = this.getScrollX( );
int y = this.getScrollY( );
if ( x < 0 || x > maxX )
{
canvas.save( );
Matrix canvasMatrix = canvas.getMatrix( );
if ( x < 0 )
{
fOverScrollDrawable.setBounds( 0, x, height, x - x );
canvasMatrix.preRotate( -90 );
canvasMatrix.preTranslate( - y - height, 0 );
}
else if ( x > maxX )
{
fOverScrollDrawable.setBounds( 0, maxX, height, x );
canvasMatrix.preRotate( 90 );
canvasMatrix.preTranslate( y, - x - fWorksheetWidth );
}
canvas.setMatrix( canvasMatrix );
fOverScrollDrawable.draw( canvas );
canvas.restore( );
}
if ( y < 0 || y > maxY )
{
canvas.save( );
Matrix canvasMatrix = canvas.getMatrix( );
if ( y < 0 )
{
fOverScrollDrawable.setBounds( x, y, x + width, y - y );
}
else if ( y > maxY )
{
fOverScrollDrawable.setBounds( 0, maxY, width, y );
canvasMatrix.preRotate( 180 );
canvasMatrix.preTranslate( - x - width, - y - fWorksheetHeight );
}
canvas.setMatrix( canvasMatrix );
fOverScrollDrawable.draw( canvas );
canvas.restore( );
}
}
@Override
protected void onDraw(Canvas canvas)
{
canvas.save( );
this.compensateForOverscroll( canvas );
canvas.drawColor( Color.BLACK );
Paint paint = new Paint( );
if ( fInteracting )
;
paint.setColor( Color.WHITE );
canvas.drawRect( 0, 0, fWorksheetWidth, fWorksheetHeight, paint );
paint.setColor( Color.RED );
for (int i = 0; i < 1500; i += 10)
{
canvas.drawLine( i, 0, i + 100, 500, paint );
}
canvas.drawRect( fWorksheetWidth - 50, 0, fWorksheetWidth, fWorksheetHeight, paint );
canvas.drawRect( 0, fWorksheetHeight - 50, fWorksheetWidth, fWorksheetHeight, paint );
canvas.restore( );
}
Drawable fOverScrollDrawable;
...
Resources rsr = context.getResources( );
fOverScrollDrawable = rsr.getDrawable( R.drawable.overscroll_glow );