There are many questions like this, but most of them are asking on HOW to set GestureDetector to a View. I have done that already, and now I'm wondering, that android has provided nothing to let an image fling. The problem I have is that I don't know what to do with the velocityX/Y provided in that method. My last try looks like this:
public class TouchableImage extends SizeableImage 
    implements GestureDetector.OnGestureListener, 
    GestureDetector.OnDoubleTapListener,
    OnTouchListener{
    protected GestureDetector mDetector;
    protected Matrix mCurrentMatrix;
    public TouchableImage(Context context) {
        super(context);
        init();
    }
    public TouchableImage(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    protected void init() {
        mCurrentMatrix = new Matrix();
        mDetector = new GestureDetector(getContext(), this);
        mDetector.setOnDoubleTapListener(this);
        if (hasImage()){
            onNewImage();
        }
    }
    private void onNewImage() {
        setOnTouchListener(this);
        setScaleType(ScaleType.MATRIX);
        setImageMatrix(mCurrentMatrix);
    }
    @Override
    public void setImageDrawable(Drawable d){
        super.setImageDrawable(d);
        onNewImage();
    }
    @Override
    public void setImageBitmap(Bitmap bm) {
        super.setImageBitmap(bm);
        onNewImage();
    }
    public boolean hasImage(){
        return getDrawable() != null;
    }
    /*GestureDetector.OnGestureListener */
    @Override
    public boolean onDown(MotionEvent e) {
        // do nothing on one finger down
        return true;
    }
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
            float velocityY) {
        LogCat.d("ZoomableImage_FLING", "x:" + velocityX + " y:" + velocityY);
        float distanceX = velocityX / 1000;
        float distanceY = velocityY/ 1000;
        long end = System.currentTimeMillis() + (long)(Math.abs(velocityX)> Math   .abs(velocityY) ? Math.abs(velocityX) / 8: Math.abs(velocityY)/8);
            long now = System.currentTimeMillis();
        while (now < end){
            FlingRunnable fr = new FlingRunnable(e1, e2, distanceX, distanceY);
            postDelayed(fr, 10);
            distanceX -= distanceX / 100;
            distanceY -= distanceY / 100;
            now = System.currentTimeMillis();
        }
        return true;
    }
    @Override
    public void onLongPress(MotionEvent e) {
        // do nothing onLongPress       
    }
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
            float distanceY) {
        LogCat.d("ZoomableImage_SCROLL", "x:" + distanceX + " y:" + distanceY);
        mCurrentMatrix.postTranslate(distanceX * -1, distanceY *-1);
        setImageMatrix(mCurrentMatrix);
        return true;
    }
    @Override
    public void onShowPress(MotionEvent e) {
        // do nothing onShowPress
    }
    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        // do nothing onSingleTapUp
        return true;
    }
    /*GestureDetector.OnDoubleTapListener*/
    @Override
    public boolean onDoubleTap(MotionEvent e) {
        // TODO Auto-generated method stub
        return false;
    }
    @Override
    public boolean onDoubleTapEvent(MotionEvent e) {
        // TODO Auto-generated method stub
        return false;
    }
    @Override
    public boolean onSingleTapConfirmed(MotionEvent e) {
        // TODO Auto-generated method stub
        return false;
    }
    /* Images onTouchListener */
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        /* simply dispatch the motion Events to our GestureDetector */
        return mDetector.onTouchEvent(event);
    }
    /* sizeable Image*/
    @Override
    public Matrix getCurrentMatrix() {
        return mCurrentMatrix;
    }
    @Override
    public void setImageBounds(PointF point) {
    }
    public class FlingRunnable implements Runnable{
        public MotionEvent e1;
        public MotionEvent e2;
        public float distanceX;
        public float distanceY;
        public FlingRunnable(MotionEvent e1, MotionEvent e2, float distanceX, floa t distanceY){
                this.e1 = e1;
            this.e2 = e2;
            this.distanceX = distanceX;
            this.distanceY = distanceY;
        }
        @Override
        public void run() {
            onScroll(e1, e2, distanceX, distanceY);
        }
    }
}    
One problem that I have is to find reasonable values for distanceX/Y  and for end.
Another problem that I have is that even if I have some values, the fling() seems to appear "at once" so like all onScroll() calls are added and applied at the same time.
NOTE: My build-target is 2.1 (Eclair) so I cannot use better detectors invented in 2.2 (Froyo)
 
     
     
    