2

I have a LinearLayout in my Android app and I would like to make it scrollable in all directions. I simply implemented this with a HorizontalScrollView and ScrollView under which I placed my layout.

This works great, but I would like to implement pinch-zoom as well. So I was inspired by this question: Android - zoom in/out RelativeLayout with spread/pinch

and I came up with the following layout:

<com.example.ZoomableScrollView
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_weight="0.2"
    android:scrollbars="none"
    android:background="@android:color/black">

    <HorizontalScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="none">
        <LinearLayout
            android:id="@+id/sheet_layout"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="vertical"
            tools:context=".MainActivity">
        </LinearLayout>
    </HorizontalScrollView>
</com.example.ZoomableScrollView>

The children of the inner LinearLayout are dynamically added (they are simple TextViews inside horizontal LinearLayouts to make a simple table).

The ZoomableScrollView is quite simple and looks like this:

public class ZoomableScrollView extends ScrollView {
    float mScaleFactor = 1.f;
    private final ScaleGestureDetector mScaleDetector;

    static final float MIN_SCALE = 1f;
    static final float MAX_SCALE = 4f;

    public ZoomableScrollView(Context context) {
        this(context, null, 0);
    }

    public ZoomableScrollView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ZoomableScrollView(Context context, AttributeSet attrs,
                              int defStyle) {
        super(context, attrs, defStyle);
        mScaleDetector = new ScaleGestureDetector(context, new OnScaleListener());
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.w("DEBUG", "On touch event");
        boolean retVal = mScaleDetector.onTouchEvent(event);
        return super.onTouchEvent(event) || retVal;
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        Log.w("DEBUG", String.format("Scaling with scale factor %f", mScaleFactor));
        canvas.save(Canvas.MATRIX_SAVE_FLAG);
        canvas.scale(mScaleFactor, mScaleFactor);
        super.dispatchDraw(canvas);
        canvas.restore();
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    private class OnScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener
    {
        @Override
        public boolean onScale(ScaleGestureDetector detector)
        {
            mScaleFactor *= detector.getScaleFactor();

            // Don't let the object get too small or too large.
            mScaleFactor = Math.max(MIN_SCALE, Math.min(mScaleFactor, MAX_SCALE));
            Log.w("DEBUG", "OnScale: scale factor: " + mScaleFactor);
            invalidate();
            return true;
        }
    }
}

I have 2 issues with this:

  1. The zooming is not very smooth, sometimes the View will scroll when it should zoom. That's not such a big deal atm.
  2. When zooming, the LinearLayout becomes smaller and you can't scroll everywhere anymore. I think I understand why this is the case, but I don't know how to change that and I'm thinking that I went into the wrong direction here.

I don't mind changing the layout completely. In the end, I would like to have it behave a bit like a browser, where you can zoom and scroll everywhere (not as complex though). Is there a simple solution for this ?

Community
  • 1
  • 1
Matt Ko
  • 969
  • 7
  • 14

1 Answers1

-1

As for two dimensional scrollView I had used this one. Maybe you should try to add pinch for it.

Stan
  • 6,511
  • 8
  • 55
  • 87
  • Thanks for the tip. I would guess that it's easier to control the various touch events if you do everything in a single layout. So maybe that's the way to go. But it still seems quite complex, I was hoping for a simpler solution. I'll look into it. – Matt Ko Apr 07 '15 at 10:24
  • At least its a really good 2D-ScrollView. However u r right, adding a pinch for it is not a simple task. – Stan Apr 07 '15 at 10:27