【问题标题】:Pinch Zoom and Pan捏缩放和平移
【发布时间】:2013-12-12 01:54:19
【问题描述】:

我有一个以 LinearLayout 作为主要布局的活动。在该布局中,有一个按钮可将视图 (R.layout.motor_block) 添加到主布局 (R.id.layout):

    LayoutInflater inflater =
    (LayoutInflater)this.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
    View iv = inflater.inflate( R.layout.motor_block, null );
    RelativeLayout rl = (RelativeLayout) findViewById(R.id.layout);
    rl.addView(iv);

这很好用,但是当我添加更多视图时,屏幕会被它们填满,所以我需要一种通过添加平移来“扩展”大小的方法,这样我就可以浏览所有视图。 我也想添加缩放。

我尝试使用 WebView:

       RelativeLayout rl = (RelativeLayout) findViewById(R.id.layout);
   WebView wv = (WebView) findViewById(R.id.webView1);
   wv.getSettings().setSupportZoom(true);  
   wv.getSettings().setBuiltInZoomControls(true);
   wv.getSettings().setUseWideViewPort(true);
   wv.getSettings().setLoadWithOverviewMode(true);
   wv.getSettings().setDisplayZoomControls(false);
   wv.getSettings().setDefaultZoom(WebSettings.ZoomDensity.FAR);
   wv.addView(iv);

视图被添加到其中,并且平移工作。问题是当我缩放时,webView 会缩放背景,而视图不会改变大小。

我也尝试了一些自定义视图,但它们不支持带有子视图的视图。

最好的方法是什么?

【问题讨论】:

    标签: java android layout pinchzoom pan


    【解决方案1】:

    只是一个例子。在主容器视图上使用 setTranslationX/Y 和 setScaleX/Y。它的子节点将随之缩放和翻译。

    public class MainActivity extends Activity {
    
        private RelativeLayout mainLayout;
        private ScaleGestureDetector scaleGestureDetector;
        private float scale = 1;
        private PointF touchPoint;
        private PointF pan;
    
        private boolean isScaling;
        private boolean endScalingNextUp;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mainLayout = (RelativeLayout) findViewById(id.main_layout);
            scaleGestureDetector = new ScaleGestureDetector(this, new ExampleScaleGestureListener());
            Button b = ((Button) findViewById(id.btn_reset));
            b.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    reset();
                }
            });
            reset();
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            scaleGestureDetector.onTouchEvent(event);
    
            if (scale != 1 && !isScaling) {
                float x = event.getRawX();
                float y = event.getRawY();
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    touchPoint = new PointF(x, y);
                } else if (event.getAction() == MotionEvent.ACTION_MOVE && touchPoint != null) {
                    pan.x = x - touchPoint.x;
                    pan.y = y - touchPoint.y;
                    panView();
                }
            }
            if (isScaling && endScalingNextUp) {
                if (event.getAction() == MotionEvent.ACTION_POINTER_UP) {
                    endScalingNextUp = false;
                    isScaling = false;
                }
            }
    
            return true;
        }
    
        private void setPivot(float focusX, float focusY) {
            mainLayout.setPivotX(focusX);
            mainLayout.setPivotY(focusY);
        }
    
        private void scaleView() {
            mainLayout.setScaleX(scale);
            mainLayout.setScaleY(scale);
        }
    
        private void panView() {
            mainLayout.setTranslationX(pan.x);
            mainLayout.setTranslationY(pan.y);
        }
    
        private void reset() {
            setPivot(0, 0);
            scale = 1;
            scaleView();
            pan = new PointF(0, 0);
            panView();
            isScaling = false;
        }
    
        private class ExampleScaleGestureListener implements OnScaleGestureListener {
    
            private static final float SCALE_SPEED = .02f;
    
            @Override
            public void onScaleEnd(ScaleGestureDetector detector) {
                endScalingNextUp = true;
            }
    
            @Override
            public boolean onScaleBegin(ScaleGestureDetector detector) {
                float focusX = detector.getFocusX();
                float focusY = detector.getFocusY();
                setPivot(focusX, focusY);
                isScaling = true;
                endScalingNextUp = false;
                return true;
            }
    
            @Override
            public boolean onScale(ScaleGestureDetector detector) {
                isScaling = true;
                endScalingNextUp = false;
                if (detector.getScaleFactor() < 1) {
                    scale -= SCALE_SPEED;
                } else if (detector.getScaleFactor() > 1) {
                    scale += SCALE_SPEED;
                }
                scaleView();
                return true;
            }
        }
    }
    
    
        <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingBottom="@dimen/activity_vertical_margin"
            android:paddingLeft="@dimen/activity_horizontal_margin"
            android:paddingRight="@dimen/activity_horizontal_margin"
            android:paddingTop="@dimen/activity_vertical_margin"
            android:id="@+id/main_layout"
            tools:context=".MainActivity" >
    
            <TextView
                android:id="@+id/tv"
                android:layout_centerInParent="true"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/hello_world" />
    
            <ImageView
                android:id="@+id/imageView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_above="@+id/tv"
                android:layout_marginBottom="69dp"
                android:layout_marginRight="29dp"
                android:layout_toLeftOf="@+id/tv"
                android:src="@drawable/ic_launcher" />
    
            <Button
                android:id="@+id/btn_reset"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/tv"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="22dp"
                android:text="Reset" />
    
        </RelativeLayout>
    

    【讨论】:

      【解决方案2】:

      最简单的方法是将所有这些视图添加到 ScrollView 中。然后,您可以将 ScrollView 添加到 Horizo​​ntalScrollView 以双向滚动。有一个手势用于捏合和缩放手势,并为它们呼叫听众。对于缩放,您可以通过运行循环或可能使用 ScaleGestureDetector 来增加每个视图的大小。
      这种方法有点不稳定,但很有效。检查以下答案以获取更多信息- Implementing Pan and Zoom

      更新:-

      这里有更多 SO 答案 -
      How to implement zoom effect for image view in android?
      android pinch zoom

      【讨论】:

      • 当视图调整大小时,它们之间的距离是否保持不变?
      • 如果您手动缩放它们,是的,它们之间会保留相同的边距,但是我不确定 ScaleGestureDetector。
      • 这个答案可以应用于平移和缩放网格视图吗?
      猜你喜欢
      • 2023-03-27
      • 2013-01-17
      • 1970-01-01
      • 2012-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多