Extending Relativelayout, and Overriding Dispatchdraw() to Create a Zoomable Viewgroup

Extending RelativeLayout, and overriding dispatchDraw() to create a zoomable ViewGroup

If you are applying a scale factor to the drawing of your children, you also need to apply the appropriate scale factor to all of the other interactions with them -- dispatching touch events, invalidates, etc.

So in addition to dispatchDraw(), you will need to override and appropriate adjust the behavior of at least these other methods. To take care of invalidates, you will need to override this method to adjust the child coordinates appropriately:

http://developer.android.com/reference/android/view/ViewGroup.html#invalidateChildInParent(int[], android.graphics.Rect)

If you want the user to be able to interact with the child views you will also need to override this to adjust touch coordinates appropriately before they are dispatched to the children:

http://developer.android.com/reference/android/view/ViewGroup.html#dispatchTouchEvent(android.view.MotionEvent)

Also I would strongly recommend you implement this all inside of a simple ViewGroup subclass that has a single child view it manages. This will get rid of any complexity of behavior that RelativeLayout is introducing in its own ViewGroup, simplifying what you need to deal with and debug in your own code. Put the RelativeLayout as a child of your special zooming ViewGroup.

Finally, one improvement to your code -- in dispatchDraw() you want to save the canvas state after applying the scaling factor. This ensures that the child can't modify the transformation you have set.

Android - zoom in/out RelativeLayout with spread/pinch

So I created a subclass of RelativeLayout as described in the above mentioned topics. It looks like this:

public class ZoomableRelativeLayout extends RelativeLayout {
float mScaleFactor = 1;
float mPivotX;
float mPivotY;

public ZoomableRelativeLayout(Context context) {
super(context);
// TODO Auto-generated constructor stub
}

public ZoomableRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}

public ZoomableRelativeLayout(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}

protected void dispatchDraw(Canvas canvas) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(mScaleFactor, mScaleFactor, mPivotX, mPivotY);
super.dispatchDraw(canvas);
canvas.restore();
}

public void scale(float scaleFactor, float pivotX, float pivotY) {
mScaleFactor = scaleFactor;
mPivotX = pivotX;
mPivotY = pivotY;
this.invalidate();
}

public void restore() {
mScaleFactor = 1;
this.invalidate();
}

}

My implementation of the SimpleOnScaleGestureListener looks like this:

private class OnPinchListener extends SimpleOnScaleGestureListener {

float startingSpan;
float endSpan;
float startFocusX;
float startFocusY;

public boolean onScaleBegin(ScaleGestureDetector detector) {
startingSpan = detector.getCurrentSpan();
startFocusX = detector.getFocusX();
startFocusY = detector.getFocusY();
return true;
}

public boolean onScale(ScaleGestureDetector detector) {
mZoomableRelativeLayout.scale(detector.getCurrentSpan()/startingSpan, startFocusX, startFocusY);
return true;
}

public void onScaleEnd(ScaleGestureDetector detector) {
mZoomableRelativeLayout.restore();
}
}

Hope this helps!

Update:

You can integrate OnPinchListener for your ZoomableRelativelayout by using ScaleGestureDetector:

ScaleGestureDetector scaleGestureDetector = new ScaleGestureDetector(this, new OnPinchListener());

And you are required to bind touch listener of Zoomable layout with the touch listener of ScaleGestureDetector:

mZoomableLayout.setOnTouchListener(new OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
scaleGestureDetector.onTouchEvent(event);
return true;
}
});

How to zoom ViewGroup?

To zoom view group you need to extend ScrollView and override dispatchTouchEvent and dispatchDraw.

Zooming a layout (Relative Layout) in android

Since no one came up with solution, I kind of sort it out myself and thought it might be helpful for some one else who is stuck in this problem. The basic guidance came from here, where author implemented the zoom in and out for a single image, we just have to add images and handle other initialization as described in that tutorial.

ImageViewWithZoomClass:

private Drawable imageOne, imageTwo;
imageOne = context.getResources().getDrawable(R.drawable.icon1);
imageTwo = context.getResources().getDrawable(R.drawable.icon2);
.
.
imageOne.setBounds(0, 0, imageOne.getIntrinsicWidth(), imageOne.getIntrinsicHeight());
imageTwo.setBounds(0, 0, imageTwo.getIntrinsicWidth(), imageTwo.getIntrinsicHeight());
.
.
imageOne.draw(canvas);
imageTwo.draw(canvas);

and since I am using relative layout, I just used onClickListener in my MainActivity like this

relativeLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setContentView(new ImageViewWithZoom(getApplicationContext()));
}
});

and XML for the relative layout looks like this:

<RelativeLayout
android:id="@+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="130dp"
android:layout_marginRight="130dp"
android:background="@drawable/abc"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
>

<ImageView
android:id="@+id/img_1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/roadandrailways"
android:visibility="invisible"/>

<ImageView
android:id="@+id/img_2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/capital"
android:visibility="invisible"/>
</RelativeLayout>

You can add multiple images in layout.
Thats it, hope it helps.

Create a layout larger then screen

Android already comes with a view container that is dedicated to all that scrolling business: ScrollView.



Related Topics



Leave a reply



Submit