java - 在android中围绕两个手指的中点缩放

标签 java android android-layout android-canvas horizontalscrollview

我有一个 Horizo​​ntalScrollView,其中有多个 View 。我已经实现了 pinch zoom gesture,其中我的两个手指之间的多个 View 被缩放。

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

谁能告诉我怎么做。

onDraw() 自定义 View 的方法是

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

上面的自定义 View 被 Horizo​​ntalScrollView 的子类调用了 12 次。所以 Horizo​​ntalScrollview 有 12 个 subview 。

在这门课上我做了以下事情

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

  2. 计算第一个手指触摸的 subview 的索引。

  3. 计算中指触摸的 subview 的索引。

  4. 将缩放比例因子传递给开始和最后之间的所有 subview 。 这两个指标是前两步计算得到的。

  5. 最后在 subview 上调用 invalidate()。所以 child 可以根据父 View 传递的比例因子缩放自己。

但是这里有一个问题。两个手指的中点应该保持静止,其他东西应该在缩放过程中调整。但我的中点是随着缩放而移动。

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

Horizo​​ntalScrollview的手势监听代码为

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

这是自定义view的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

最佳答案

对于要缩放的 View ,您可以使用 setPivotX()setPivotY() 设置不应移动的“不变”点。当我使用 ScaleGestureDetector 时,我为此使用了 focus 点。例如:

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

我不确定你是想对所有 subview 执行此操作,还是只对父 View 执行此操作,但通常你只需要对单个“父” View 执行此操作即可正常工作对于该 View 的子项。

与此相关,我不太明白为什么在缩放父 View 时将缩放因子向下传递给每个 subview 也会缩放其所有 subview 。也许您只需要将一个 FrameLayout(或其他一些 ViewGroup 后代)添加到托 pipe 项的 Horizo​​ntalScrollView 中,然后缩放它(在适本地设置它的枢轴之后)?


更新评论

鉴于您只想缩放手指之间捏合区域的 View ,我相信您有几个选择,具体取决于您的应用:

1) 动态地将这些 View 添加到一个中间 FrameLayout 中,它会缩放并设置其轴心,将非缩放 View 保留为 Horizo​​ntalScrollView 的直接 subview ;或

2) 在第一次调整 child 的位置后,将焦点向下传递到每个缩放的 subview 。例如,假设您的 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();
    }

关于java - 在android中围绕两个手指的中点缩放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23358112/

相关文章:

java - 在Android中以编程方式查找数据库的路径

android - ListView 的自定义滚动发光/边缘颜色?

java - 在 linux 中运行时出现 NoClassDefFoundError

java - 以编程方式向 TextView 添加边框

java - 无法显示超出最大字符数

Android:仅当我立即启动 App 时,Boot Complete 才有效

Java进程 Swing InputStream和OutputStream操作

android - 获取状态栏颜色

android - 如何在单个 Activity 中使用单选组和复选框?

android-layout - 动态设置 View 样式 : Android