android - 如何在 android 中缩放整个 RecyclerView

标签 android android-recyclerview zooming

我创建了一个缩放功能,它对 LinearLayoutFrameLayout 有效,但对 RecyclerView 无效。

XML 文件:

<com.nm.esign.entities.ZoomLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/zoom_main1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >


    <LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/fl_zoom"
    android:orientation="vertical"

    android:layout_width="match_parent"
    android:layout_height="match_parent">

      <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_view_template_img"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="30dp"

            android:scrollbars="vertical" />


    </LinearLayout>


     </com.nm.esign.entities.ZoomLayout>

主要 Activity :

  protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_view_template);

        //  prevBtn=(android.support.v7.widget.AppCompatButton)findViewById(R.id.btnDocumentPrev_temp);
        // nextBtn=(android.support.v7.widget.AppCompatButton)findViewById(R.id.btnDocumentNxt_temp);
    RecyclerView    recyclerView = (RecyclerView) findViewById(R.id.recycler_view_template_img);

    LinearLayout    fl_zoom=(LinearLayout)findViewById(R.id.fl_zoom)


        ZoomLayout myZoomView = new ZoomLayout(ViewTemplate.this);

      fl_zoom.addView(myZoomView); // working fine
// recyclerView.addView(myZoomView); // not working 

....................................

}

ZoomLayout 类:

/**
 * Created by Lenovo5 on 3/16/2017.
 */

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.FrameLayout;

/**
 * Layout that provides pinch-zooming of content. This view should have exactly one child
 * view containing the content.
 */
public class ZoomLayout extends FrameLayout implements ScaleGestureDetector.OnScaleGestureListener {

    private enum Mode {
        NONE,
        DRAG,
        ZOOM
    }

    private static final String TAG = "ZoomLayout";
    private static final float MIN_ZOOM = 1.0f;
    private static final float MAX_ZOOM = 4.0f;

    private Mode mode = Mode.NONE;
    private float scale = 1.0f;
    private float lastScaleFactor = 0f;

    // Where the finger first  touches the screen
    private float startX = 0f;
    private float startY = 0f;

    // How much to translate the canvas
    private float dx = 0f;
    private float dy = 0f;
    private float prevDx = 0f;
    private float prevDy = 0f;

    public ZoomLayout(Context context) {
        super(context);
        init(context);
    }

    public ZoomLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public ZoomLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    private void init(Context context) {
        final ScaleGestureDetector scaleDetector = new ScaleGestureDetector(context, this);
        this.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
                    case MotionEvent.ACTION_DOWN:
                        Log.i(TAG, "DOWN");
                        if (scale > MIN_ZOOM) {
                            mode = Mode.DRAG;
                            startX = motionEvent.getX() - prevDx;
                            startY = motionEvent.getY() - prevDy;
                        }
                        break;
                    case MotionEvent.ACTION_MOVE:
                        if (mode == Mode.DRAG) {
                            dx = motionEvent.getX() - startX;
                            dy = motionEvent.getY() - startY;
                        }
                        break;
                    case MotionEvent.ACTION_POINTER_DOWN:
                        mode = Mode.ZOOM;
                        break;
                    case MotionEvent.ACTION_POINTER_UP:
                        mode = Mode.DRAG;
                        break;
                    case MotionEvent.ACTION_UP:
                        Log.i(TAG, "UP");
                        mode = Mode.NONE;
                        prevDx = dx;
                        prevDy = dy;
                        break;
                }
                scaleDetector.onTouchEvent(motionEvent);

                if ((mode == Mode.DRAG && scale >= MIN_ZOOM) || mode == Mode.ZOOM) {
                    getParent().requestDisallowInterceptTouchEvent(true);
                    float maxDx = (child().getWidth() - (child().getWidth() / scale)) / 2 * scale;
                    float maxDy = (child().getHeight() - (child().getHeight() / scale))/ 2 * scale;
                    dx = Math.min(Math.max(dx, -maxDx), maxDx);
                    dy = Math.min(Math.max(dy, -maxDy), maxDy);
                    Log.i(TAG, "Width: " + child().getWidth() + ", scale " + scale + ", dx " + dx
                            + ", max " + maxDx);
                    applyScaleAndTranslation();
                }

                return true;
            }
        });
    }

    // ScaleGestureDetector

    @Override
    public boolean onScaleBegin(ScaleGestureDetector scaleDetector) {
        Log.i(TAG, "onScaleBegin");
        return true;
    }

    @Override
    public boolean onScale(ScaleGestureDetector scaleDetector) {
        float scaleFactor = scaleDetector.getScaleFactor();
        Log.i(TAG, "onScale" + scaleFactor);
        if (lastScaleFactor == 0 || (Math.signum(scaleFactor) == Math.signum(lastScaleFactor))) {
            scale *= scaleFactor;
            scale = Math.max(MIN_ZOOM, Math.min(scale, MAX_ZOOM));
            lastScaleFactor = scaleFactor;
        } else {
            lastScaleFactor = 0;
        }
        return true;
    }

    @Override
    public void onScaleEnd(ScaleGestureDetector scaleDetector) {
        Log.i(TAG, "onScaleEnd");
    }

    private void applyScaleAndTranslation() {
        child().setScaleX(scale);
        child().setScaleY(scale);
        child().setTranslationX(dx);
        child().setTranslationY(dy);
    }

    private View child() {
        return getChildAt(0);
    }
}

错误来了:-

  recyclerView.addView(myZoomView);

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.nm.esign, PID: 6028
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.nm.esign/com.nm.esign.activity.ViewTemplate}: java.lang.IllegalStateException: RecyclerView has no LayoutManager
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3319)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3415)
    at android.app.ActivityThread.access$1100(ActivityThread.java:229)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1821)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:7331)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
 Caused by: java.lang.IllegalStateException: RecyclerView has no LayoutManager
    at android.support.v7.widget.RecyclerView.generateDefaultLayoutParams(RecyclerView.java:3869)
    at android.view.ViewGroup.addView(ViewGroup.java:4431)
    at android.view.ViewGroup.addView(ViewGroup.java:4409)
    at com.nm.esign.activity.ViewTemplate.onCreate(ViewTemplate.java:112)
    at android.app.Activity.performCreate(Activity.java:6904)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1136)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3266)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3415) 
    at android.app.ActivityThread.access$1100(ActivityThread.java:229) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1821) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:148) 
    at android.app.ActivityThread.main(ActivityThread.java:7331) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 

最佳答案

你的代码中必须有这一行

LinearLayoutManager manager = new LinearLayoutManager(this);
manager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(manager);

关于android - 如何在 android 中缩放整个 RecyclerView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43084654/

相关文章:

Android - 为什么属性 TextAppearanceLarge 和 TextAppearanceMedium 定义不同的文本颜色

android - Play 商店中的 Ionic Cordova Build/Manifest 支持设备

javascript - 通过 javascript 禁用 Firefox 图像缩放

android - 如何删除 HTML5 Slider 视频 Controller

android - Sinch SDK - 如何注销用户?

android - ScrollView 中水平回收 View 的滚动问题

android - RecyclerView 之间的距离太远

android - 使用 RecyclerView 适配器更新数据的最佳方法

c# - 在 C# 中模拟 ImageLayout.Zoom

ios - 如何使用 Cocos2d 缩放圆形区域?