web-dev-qa-db-ja.com

ズーム可能なスクロールビューを作成するにはどうすればよいですか?

私のAndroidアプリケーションでは、ズーム可能なアクティビティを作成する必要があります。線形レイアウトをズームするための便利なコードを見つけました ここ 。しかし、私のアプリケーションでは、いくつかのアクティビティはスクロールビューで始まります。コードがscrollviewを認識しません。スクロール可能なアクティビティのピンチズームを作成するにはどうすればよいですか?これは私のレイアウトの1つです。

<ScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
Android:id="@+id/scrollViewZoom"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_centerHorizontal="true"
Android:layout_centerVertical="true" >

<LinearLayout
    Android:id="@+id/wd_content"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:layout_marginTop="10dp"
    Android:orientation="vertical" >

    <!-- Start Circle -->

    <TableRow
        Android:id="@+id/row_circl1"
        Android:layout_width="wrap_content"
        Android:layout_height="match_parent"
        Android:layout_gravity="center"
        Android:layout_marginTop="30dp"
        Android:background="@color/purple_color" >

        <RelativeLayout
            Android:id="@+id/circle_layout1"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:background="@color/white_color" >

            <ImageView
                Android:id="@+id/img_engin_circle1"
                Android:layout_width="wrap_content"
                Android:layout_height="wrap_content"
                Android:layout_centerHorizontal="true"
                Android:background="@drawable/circle_engin_bg"
                Android:contentDescription="TODO" />
        </RelativeLayout>

        <RelativeLayout
            Android:id="@+id/circle_layout2"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:background="@color/white_color" >

            <ImageView
                Android:id="@+id/img_engin_circle2"
                Android:layout_width="wrap_content"
                Android:layout_height="wrap_content"
                Android:layout_centerHorizontal="true"
                Android:background="@drawable/circle_engin_bg"
                Android:contentDescription="TODO" />
        </RelativeLayout>
    </TableRow>

    <TableRow
        Android:id="@+id/row_name_circle"
        Android:layout_width="wrap_content"
        Android:layout_height="match_parent"
        Android:layout_gravity="center"
        Android:layout_marginTop="30dp" >

        <RelativeLayout
            Android:id="@+id/circle_name_layout1"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_marginTop="-15dp"
            Android:background="@color/white_color" >

            <ImageView
                Android:id="@+id/img_name_circle1"
                Android:layout_width="wrap_content"
                Android:layout_height="wrap_content"
                Android:layout_centerHorizontal="true"
                Android:background="@drawable/circle_gauge_name"
                Android:contentDescription="TODO" />
        </RelativeLayout>

        <RelativeLayout
            Android:id="@+id/circle_name_layout2"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_marginTop="-15dp"
            Android:background="@color/white_color" >

            <ImageView
                Android:id="@+id/img_name_circle2"
                Android:layout_width="wrap_content"
                Android:layout_height="wrap_content"
                Android:layout_centerHorizontal="true"
                Android:background="@drawable/circle_gauge_name"
                Android:contentDescription="TODO" />
        </RelativeLayout>
    </TableRow>

    <!-- End Circle -->

</LinearLayout>

</ScrollView>

どんなアイデアでも私を助けてくれるでしょう。ありがとう。

17
IndieBoy

OK。ネットを耕した後、ついに私の答えを見つけました。 scrollviewのonTouchEvent()が機能しないことがわかったので、dispatchTouchEvent()の代わりにonTouchEvent()を使用する必要があります。上部に私のxmlコード(私の質問)が表示されます。これはもちろんコメント付きの私のアクティビティコードです。

    // step 1: add some instance
private float mScale = 1f;
private ScaleGestureDetector mScaleDetector;
GestureDetector gestureDetector;

//step 2: create instance from GestureDetector(this step sholude be place into onCreate())
gestureDetector = new GestureDetector(this, new GestureListener());

// animation for scalling
mScaleDetector = new ScaleGestureDetector(this, new ScaleGestureDetector.SimpleOnScaleGestureListener() 
    {                                   
        @Override
        public boolean onScale(ScaleGestureDetector detector) 
        {
            float scale = 1 - detector.getScaleFactor();

            float prevScale = mScale;
            mScale += scale;

            if (mScale < 0.1f) // Minimum scale condition:
                mScale = 0.1f;

            if (mScale > 10f) // Maximum scale condition:
                mScale = 10f;
            ScaleAnimation scaleAnimation = new ScaleAnimation(1f / prevScale, 1f / mScale, 1f / prevScale, 1f / mScale, detector.getFocusX(), detector.getFocusY());
            scaleAnimation.setDuration(0);
            scaleAnimation.setFillAfter(true);
            ScrollView layout =(ScrollView) findViewById(R.id.scrollViewZoom);
            layout.startAnimation(scaleAnimation);
            return true;
        }
    });


// step 3: override dispatchTouchEvent()
 @Override
 public boolean dispatchTouchEvent(MotionEvent event) {
    super.dispatchTouchEvent(event);
    mScaleDetector.onTouchEvent(event);
    gestureDetector.onTouchEvent(event);
    return gestureDetector.onTouchEvent(event);
 }

//step 4: add private class GestureListener

private class GestureListener extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }
    // event when double tap occurs
    @Override
    public boolean onDoubleTap(MotionEvent e) {
        // double tap fired.
        return true;
    }
}

どうもありがとう。

24
IndieBoy

ソリューションのおかげで、スクロールビューがアクティビティではなくフラグメント内にあるため、少し異なる実装を行いました。すべてのロジックをビューに委任するには、同じカスタムスクロールビューにdispatchTouchEventを追加することをお勧めします。

package com.your.package;

import Android.content.Context;
import Android.util.AttributeSet;
import Android.view.GestureDetector;
import Android.view.MotionEvent;
import Android.view.ScaleGestureDetector;
import Android.view.animation.ScaleAnimation;
import Android.widget.ScrollView;

import com.your.package.R;

public class CustomZoomScrollView extends ScrollView {


    // step 1: add some instance
    private float mScale = 1f;
    private ScaleGestureDetector mScaleDetector;
    GestureDetector gestureDetector;


    public CustomZoomScrollView(Context context) {
        super(context);
    }

    public CustomZoomScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //step 2: create instance from GestureDetector(this step should be place into onCreate())
        gestureDetector = new GestureDetector(getContext(), new GestureListener());

        mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleGestureDetector.SimpleOnScaleGestureListener()
        {
            @Override
            public boolean onScale(ScaleGestureDetector detector)
            {
                float scale = 1 - detector.getScaleFactor();

                float prevScale = mScale;
                mScale += scale;

                if (mScale < 0.1f) // Minimum scale condition:
                    mScale = 0.1f;

                if (mScale > 10f) // Maximum scale condition:
                    mScale = 10f;
                ScaleAnimation scaleAnimation = new ScaleAnimation(1f / prevScale, 1f / mScale, 1f / prevScale, 1f / mScale, detector.getFocusX(), detector.getFocusY());
                scaleAnimation.setDuration(0);
                scaleAnimation.setFillAfter(true);
                getRootView().findViewById(R.id.svSeats).startAnimation(scaleAnimation);
                return true;
            }
        });
    }

    // step 3: override dispatchTouchEvent()
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        super.dispatchTouchEvent(event);
        mScaleDetector.onTouchEvent(event);
        gestureDetector.onTouchEvent(event);
        return gestureDetector.onTouchEvent(event);
    }

//step 4: add private class GestureListener

    private class GestureListener extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }
        // event when double tap occurs
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            // double tap fired.
            return true;
        }
    }
}