Zoom around the middle of two fingers in android

I have a HorizontalScrollView in which there are several views inside it. I implemented a pinch zoom gesture in which several views that are between two fingers are scaled.

But I faced one failure. When I do the scaling, the mid-point of the scaling increases, but for the convenience of the user, I want this point to remain fixed, and other things should be adjusted during scaling, so that the mid-point remains stationary.

Can someone tell me how to do this.

onDraw() custom view method

  Rect r =new Rect(0, 0, 700, 40); public void onDraw(Canvas canvas) { float kk=mScaleFactor; //this variable will be set by pinch zoom event and represent how much to scale sf*=kk; // this view must scale according to previous scaling canvas.save(); canvas.scale(sf , 1); paint.setStyle(Paint.Style.FILL); paint.setColor(Color.BLUE); canvas.drawRect(r, paint); width=sf*700; canvas.restore(); requestLayout(); //this will change view width to fit the expanded rectangle } 

onMeasure method called on requestLayout

  @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension((int)width, 340); } 

The above custom view is called 12 times a subclass of HorizontalScrollView . Thus, there are 12 child views of the HorizontalScrollView .

In this class I do the following things

  • Detection of touch coordinates of two fingers.

  • Calculation of the index of the child's view, which touched the first finger.

  • Calculation of the index of the child's view, which touched the second finger.

  • Transmission of the scale factor for all child views between the beginning and the last. These two indexes are calculated in the previous two steps.

  • And finally, invalidate () is called in the child view. Thus, the child can scale itself in accordance with the scaling factor transmitted by the parent representation.

But there is one problem. The midpoint of two fingers should remain motionless, and other things should be adjusted during scaling. But my midpoint moves with scaling.

Can someone help me with this. Please tell me if any part of the code is needed.

HorizontalScrollView Listening Code -

  private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { mScaleFactor *= detector.getScaleFactor(); mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f)); ViewGroup pp=takeparent(); //give object of this class for(int i=start;i<=last;i++) { LinearLayout ll=(LinearLayout)pp.getChildAt(i); DrawView view=(DrawView)ll.findViewById(R.id.drawview); view.mScaleFactor=mScaleFactor; view.invalidate(); view.donesf=true; } 

Example of my application enter image description here

Editing as indicated in the comments:

  private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { mScaleFactor *= detector.getScaleFactor(); mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f)); ViewGroup pp=takeparent(); pp contains all the custom child views //start and last are indices of range of child for which we have to apply gesture for(int i=start;i<=last;i++) { LinearLayout ll=(LinearLayout)pp.getChildAt(i); DrawView view=(DrawView)ll.findViewById(R.id.drawview); view.mScaleFactor=mScaleFactor; view.pivotx=detector.getFocusX()+view.getLeft(); view.pivoty=detector.getFocusY()+view.getTop(); view.invalidate(); } return true; } 

This is a custom onDraw method.

  public void onDraw(Canvas canvas) { sf=mScaleFactor //this scale factor is set by parent view width=sf*700; //this width will be use to rescale the view width in requestLayout() canvas.save(); canvas.scale(sf,1,pivotx,pivoty); //pivotX and pivotY are also set by parent onScale method of gestureListener canvas.drawRect(r, paint); requestLayout(); canvas.restore(); } 

enter image description here

+2
java android android-layout android-canvas horizontalscrollview
Apr 29 '14 at 7:21
source share
1 answer

For a scalable view, you can set an “invariant” point that should not be moved using setPivotX() and setPivotY() . When I use the ScaleGestureDetector , I use the focus point for this. For example:

  @Override public boolean onScaleBegin(ScaleGestureDetector detector) { ... mScaledView.setPivotX(detector.getFocusX()); mScaledView.setPivotY(detector.getFocusY()); ... 

I'm not sure if you want to do this with all the children, or only with the parent view in your case, but usually you just need to do this with a single "parent" view, and it will work correctly for children from this point of view.

In this regard, I did not quite understand why you pass the scaling factor for each child, when the scaling of the parent view also scales all its children. Maybe you just need to add one FrameLayout (or some other ViewGroup descendant) to your HorizontalScrollView that accepts children, and then just scale that (after setting its rod accordingly)?




Updated re comment

Given that you only want to scale the views in the area of ​​pinching between the fingers, I believe that you have a couple of options, depending on your application:

1) Dynamically add only those views to the intermediate FrameLayout , which receives scaling and has its own reference set, leaving unscaled views as direct children of the HorizontalScrollView ; or

2) Passing the focus point for each scaled child view after the first setup for the child position. For example, if your DrawView directly or indirectly inherited from android.view.View , which I would highly recommend, you can do something like:

  for (int i = start; i <= last; i++) { LinearLayout ll = (LinearLayout)pp.getChildAt(i); DrawView view = (DrawView)ll.findViewById(R.id.drawview); view.setScaleX(mScaleFactor); view.setScaleY(mScaleFactor); view.setPivotX(detector.getFocusX() - view.getLeft()); // Note: minus, not plus... view.setPivotY(detector.getFocusY() - view.getTop()); view.invalidate(); } 
0
Apr 29 '14 at 8:08
source share



All Articles