在android中两个手指的中点缩放

时间:2014-04-29 07:21:21

标签: java android android-layout android-canvas horizontalscrollview

我有一个HorizontalScrollView,里面有多个视图。我已经实现了pinch zoom gesture,其中缩放了我的两个手指之间的多个视图。

但我面临一个小故障。当我进行捏缩放时,捏缩放的中点正在移动但是为了用户体验,我希望这个点保持固定,其他东西应该在缩放时自行调整,以使中点保持静止。

有人可以告诉我该怎么做。

自定义视图的

onDraw()方法是

                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 
        }
在requestLayout

上调用

onMeasure方法

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

上述自定义视图由HorizontalScrollView的子类调用12次。因此,HorizontalScrollview有12个子视图。

在本课程中,我正在做以下事情

  1. 检测两根手指的触摸坐标。

  2. 计算触摸第一根手指的子视图的索引。

  3. 计算触摸第二根手指的子视图的索引。

  4. 将捏拉缩放的比例因子传递给start和last之间的所有子视图。 这两个指数是在前两个步骤中计算出来的。

  5. 最后在子视图上调用invalidate()。因此,孩子可以根据父视图传递的比例因子进行缩放。

  6. 但这里有一个问题。两个手指的中点应该保持静止,其他东西应该在缩放期间调整。但我的中点是随着扩展而变化。

    有人可以帮我这么做吗?请告诉我代码的任何部分是否需要。

    HorizontalScrollview的手势监听器代码

          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;
                }
    

    我的示例应用程序 enter image description here

    根据评论中的建议编辑:

            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;
            } 
    

    这是onDraw方法的自定义视图

           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's width in requestLayout()
    
            canvas.save();
    
            canvas.scale(sf,1,pivotx,pivoty);  //pivotX and pivotY are also set by parent's onScale method of gestureListener
            canvas.drawRect(r, paint);
            requestLayout();
            canvas.restore();
    
            } 
    

    enter image description here

1 个答案:

答案 0 :(得分:0)

对于您正在缩放的​​视图,您可以设置&#34;不变&#34;不应使用setPivotX()setPivotY()移动的点。当我使用ScaleGestureDetector时,我会使用focus点。例如:

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

在您的情况下,我不确定您是否要与所有孩子或父视图一起执行此操作,但通常您只需要对单个&#34;父母进行此操作&#34 ;视图,它将适用于该视图的孩子。

与此相关,我并不完全理解为什么在缩放父视图时将比例因子传递给每个孩子也会扩展其所有子项。也许您只需要在托管孩子的FrameLayout中添加一个ViewGroup(或其他HorizontalScrollView后代),然后只需缩放(在适当设置其轴后)?


更新了评论

鉴于您只想在手指之间的缩小区域缩放视图,我相信您有几个选项,具体取决于您的应用:

1)将这些视图动态添加到中间FrameLayout,后者得到缩放并设置其轴心,将非缩放视图保留为HorizontalScrollView的直接子视图;或

2)在首先调整孩子的位置后,将焦点向下传递到每个缩放的子视图。例如,假设您的DrawView直接或间接地从android.view.View继承,我强烈推荐,那么您可以执行以下操作:

    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();
    }