Android缩放布局ZoomLayout

缩放布局

Java代码

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;

public class ZoomView extends FrameLayout {

    private static final String TAG = "ZoomView";
    private boolean isEnableZoom = true;
    private boolean isEnableGestureZoom = false;

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

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

    public ZoomView(final Context context) {
        super(context);
    }

    /**
     * Zooming view listener interface.
     */
    public interface ZoomViewListener {

        void onZoomStarted(float zoom, float zoomx, float zoomy);

        void onZooming(float zoom, float zoomx, float zoomy);

        void onZoomEnded(float zoom, float zoomx, float zoomy);
    }

    // zooming
    float zoom = 1.0f;
    float maxZoom = 2.0f;
    float smoothZoom = 1.0f;
    float zoomX, zoomY;
    float smoothZoomX, smoothZoomY;
    private boolean scrolling; // NOPMD by karooolek on 29.06.11 11:45

    // minimap variables
    private boolean showMinimap = false;
    private int miniMapColor = Color.WHITE;
    private int miniMapHeight = -1;
    private String miniMapCaption;
    private float miniMapCaptionSize = 10.0f;
    private int miniMapCaptionColor = Color.WHITE;

    // touching variables
    private long lastTapTime;
    private float touchStartX, touchStartY;
    private float touchLastX, touchLastY;
    private float startd;
    private boolean pinching;
    private float lastd;
    private float lastdx1, lastdy1;
    private float lastdx2, lastdy2;

    // drawing
    private final Matrix m = new Matrix();
    private final Paint p = new Paint();

    // listener
    ZoomViewListener listener;

    private Bitmap ch;

    public float getZoom() {
        return zoom;
    }

    public float getMaxZoom() {
        return maxZoom;
    }

    public void setMaxZoom(final float maxZoom) {
        if (maxZoom < 1.0f) {
            return;
        }

        this.maxZoom = maxZoom;
    }


    public void setMiniMapEnabled(final boolean showMiniMap) {
        this.showMinimap = showMiniMap;
    }

    public boolean isMiniMapEnabled() {
        return showMinimap;
    }

    public void setMiniMapHeight(final int miniMapHeight) {
        if (miniMapHeight < 0) {
            return;
        }
        this.miniMapHeight = miniMapHeight;
    }

    public int getMiniMapHeight() {
        return miniMapHeight;
    }

    public void setMiniMapColor(final int color) {
        miniMapColor = color;
    }

    public int getMiniMapColor() {
        return miniMapColor;
    }

    public String getMiniMapCaption() {
        return miniMapCaption;
    }

    public void setMiniMapCaption(final String miniMapCaption) {
        this.miniMapCaption = miniMapCaption;
    }

    public float getMiniMapCaptionSize() {
        return miniMapCaptionSize;
    }

    public void setMiniMapCaptionSize(final float size) {
        miniMapCaptionSize = size;
    }

    public int getMiniMapCaptionColor() {
        return miniMapCaptionColor;
    }

    public void setMiniMapCaptionColor(final int color) {
        miniMapCaptionColor = color;
    }

    public void zoomTo(final float zoom, final float x, final float y) {
        this.zoom = Math.min(zoom, maxZoom);
        zoomX = x;
        zoomY = y;
        smoothZoomTo(this.zoom, x, y);
    }

    public void smoothZoomTo(final float zoom, final float x, final float y) {
        smoothZoom = clamp(1.0f, zoom, maxZoom);
        smoothZoomX = x;
        smoothZoomY = y;
        if (listener != null) {
            listener.onZoomStarted(smoothZoom, x, y);
        }
    }

    public ZoomViewListener getListener() {
        return listener;
    }

    public void setListener(final ZoomViewListener listener) {
        this.listener = listener;
    }

    public float getZoomFocusX() {
        return zoomX * zoom;
    }

    public float getZoomFocusY() {
        return zoomY * zoom;
    }

    @Override
    public boolean dispatchTouchEvent(final MotionEvent ev) {
        if (!isEnableZoom) {
            return super.dispatchTouchEvent(ev);
        }
        // single touch
        if (ev.getPointerCount() == 1) {
            processSingleTouchEvent(ev);
        }
        // // double touch
        if (ev.getPointerCount() == 2) {
            processDoubleTouchEvent(ev);
        }

        // redraw
        getRootView().invalidate();
        invalidate();
        if (smoothZoom == 1F) {
            return super.dispatchTouchEvent(ev);
        }
        return true;
    }

    private void processSingleTouchEvent(final MotionEvent ev) {

        final float x = ev.getX();
        final float y = ev.getY();

        final float w = miniMapHeight * (float) getWidth() / getHeight();
        final float h = miniMapHeight;
        final boolean touchingMiniMap = x >= 10.0f && x <= 10.0f + w
                && y >= 10.0f && y <= 10.0f + h;

        if (showMinimap && smoothZoom > 1.0f && touchingMiniMap) {
            processSingleTouchOnMinimap(ev);
        } else {
            processSingleTouchOutsideMinimap(ev);
        }
    }

    private void processSingleTouchOnMinimap(final MotionEvent ev) {
        final float x = ev.getX();
        final float y = ev.getY();

        final float w = miniMapHeight * (float) getWidth() / getHeight();
        final float h = miniMapHeight;
        final float zx = (x - 10.0f) / w * getWidth();
        final float zy = (y - 10.0f) / h * getHeight();
        smoothZoomTo(smoothZoom, zx, zy);
    }

    private void processSingleTouchOutsideMinimap(final MotionEvent ev) {
        final float x = ev.getX();
        final float y = ev.getY();
        float lx = x - touchStartX;
        float ly = y - touchStartY;
        final float l = (float) Math.hypot(lx, ly);
        float dx = x - touchLastX;
        float dy = y - touchLastY;
        touchLastX = x;
        touchLastY = y;

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                touchStartX = x;
                touchStartY = y;
                touchLastX = x;
                touchLastY = y;
                dx = 0;
                dy = 0;
                lx = 0;
                ly = 0;
                scrolling = false;
                break;

            case MotionEvent.ACTION_MOVE:
                if (scrolling || (smoothZoom > 1.0f && l > 30.0f)) {
                    if (!scrolling) {
                        scrolling = true;
                        ev.setAction(MotionEvent.ACTION_CANCEL);
                        super.dispatchTouchEvent(ev);
                    }
                    smoothZoomX -= dx / zoom;
                    smoothZoomY -= dy / zoom;
                    return;
                }
                break;

            case MotionEvent.ACTION_OUTSIDE:
            case MotionEvent.ACTION_UP:

                // tap
                if (l < 30.0f) {
                    // check double tap
                    if (System.currentTimeMillis() - lastTapTime < 500) {
                        if (smoothZoom == 1.0f) {
                            smoothZoomTo(maxZoom, x, y);
                        } else {
                            smoothZoomTo(1.0f, getWidth() / 2.0f,
                                    getHeight() / 2.0f);
                        }
                        lastTapTime = 0;
                        ev.setAction(MotionEvent.ACTION_CANCEL);
                        super.dispatchTouchEvent(ev);
                        return;
                    }

                    lastTapTime = System.currentTimeMillis();

                    performClick();
                }
                break;

            default:
                break;
        }

        ev.setLocation(zoomX + (x - 0.5f * getWidth()) / zoom, zoomY
                + (y - 0.5f * getHeight()) / zoom);

        ev.getX();
        ev.getY();

        super.dispatchTouchEvent(ev);
    }

    private void processDoubleTouchEvent(final MotionEvent ev) {
        final float x1 = ev.getX(0);
        final float dx1 = x1 - lastdx1;
        lastdx1 = x1;
        final float y1 = ev.getY(0);
        final float dy1 = y1 - lastdy1;
        lastdy1 = y1;
        final float x2 = ev.getX(1);
        final float dx2 = x2 - lastdx2;
        lastdx2 = x2;
        final float y2 = ev.getY(1);
        final float dy2 = y2 - lastdy2;
        lastdy2 = y2;

        // pointers distance
        final float d = (float) Math.hypot(x2 - x1, y2 - y1);
        final float dd = d - lastd;
        lastd = d;
        final float ld = Math.abs(d - startd);

        Math.atan2(y2 - y1, x2 - x1);
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startd = d;
                pinching = false;
                break;

            case MotionEvent.ACTION_MOVE:
                if (isEnableGestureZoom) {
                    if (pinching || ld > 30.0f) {
                        pinching = true;
                        final float dxk = 0.5f * (dx1 + dx2);
                        final float dyk = 0.5f * (dy1 + dy2);
                        smoothZoomTo(Math.max(1.0f, zoom * d / (d - dd)), zoomX - dxk
                                / zoom, zoomY - dyk / zoom);
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
            default:
                pinching = false;
                break;
        }

        ev.setAction(MotionEvent.ACTION_CANCEL);
        super.dispatchTouchEvent(ev);
    }

    private float clamp(final float min, final float value, final float max) {
        return Math.max(min, Math.min(value, max));
    }

    private float lerp(final float a, final float b, final float k) {
        return a + (b - a) * k;
    }

    private float bias(final float a, final float b, final float k) {
        return Math.abs(b - a) >= k ? a + k * Math.signum(b - a) : b;
    }

    @Override
    protected void dispatchDraw(final Canvas canvas) {
        // do zoom
        zoom = lerp(bias(zoom, smoothZoom, 0.05f), smoothZoom, 0.2f);
        smoothZoomX = clamp(0.5f * getWidth() / smoothZoom, smoothZoomX,
                getWidth() - 0.5f * getWidth() / smoothZoom);
        smoothZoomY = clamp(0.5f * getHeight() / smoothZoom, smoothZoomY,
                getHeight() - 0.5f * getHeight() / smoothZoom);

        zoomX = lerp(bias(zoomX, smoothZoomX, 0.1f), smoothZoomX, 0.35f);
        zoomY = lerp(bias(zoomY, smoothZoomY, 0.1f), smoothZoomY, 0.35f);
        if (zoom != smoothZoom && listener != null) {
            listener.onZooming(zoom, zoomX, zoomY);
        }

        final boolean animating = Math.abs(zoom - smoothZoom) > 0.0000001f
                || Math.abs(zoomX - smoothZoomX) > 0.0000001f
                || Math.abs(zoomY - smoothZoomY) > 0.0000001f;

        // nothing to draw
        if (getChildCount() == 0) {
            return;
        }
        // prepare matrix
        m.setTranslate(0.5f * getWidth(), 0.5f * getHeight());
        m.preScale(zoom, zoom);
        m.preTranslate(
                -clamp(0.5f * getWidth() / zoom, zoomX, getWidth() - 0.5f
                        * getWidth() / zoom),
                -clamp(0.5f * getHeight() / zoom, zoomY, getHeight() - 0.5f
                        * getHeight() / zoom));

        // get view
        final View v = getChildAt(0);
        m.preTranslate(v.getLeft(), v.getTop());

        // get drawing cache if available
        if (animating && ch == null && isAnimationCacheEnabled()) {
            v.setDrawingCacheEnabled(true);
            ch = v.getDrawingCache();
        }

        // draw using cache while animating
        if (animating && isAnimationCacheEnabled() && ch != null) {
            p.setColor(0xffffffff);
            canvas.drawBitmap(ch, m, p);
        } else { // zoomed or cache unavailable
            ch = null;
            canvas.save();
            canvas.concat(m);
            v.draw(canvas);
            canvas.restore();
        }

        // draw minimap
        if (showMinimap) {
            if (miniMapHeight < 0) {
                miniMapHeight = getHeight() / 4;
            }

            canvas.translate(10.0f, 10.0f);

            p.setColor(0x80000000 | 0x00ffffff & miniMapColor);
            final float w = miniMapHeight * (float) getWidth() / getHeight();
            final float h = miniMapHeight;
            canvas.drawRect(0.0f, 0.0f, w, h, p);

            if (miniMapCaption != null && miniMapCaption.length() > 0) {
                p.setTextSize(miniMapCaptionSize);
                p.setColor(miniMapCaptionColor);
                p.setAntiAlias(true);
                canvas.drawText(miniMapCaption, 10.0f,
                        10.0f + miniMapCaptionSize, p);
                p.setAntiAlias(false);
            }

            p.setColor(0x80000000 | 0x00ffffff & miniMapColor);
            final float dx = w * zoomX / getWidth();
            final float dy = h * zoomY / getHeight();
            canvas.drawRect(dx - 0.5f * w / zoom, dy - 0.5f * h / zoom, dx
                    + 0.5f * w / zoom, dy + 0.5f * h / zoom, p);

            canvas.translate(-10.0f, -10.0f);
        }

        // redraw
        getRootView().postInvalidate();
        postInvalidate();
    }

    /**
     * 开启手势 缩放
     *
     * @param isEnableGestureZoom false 关闭手势缩放 true 开启手势缩放 默认 false
     */
    public void isEnableGestureZoom(boolean isEnableGestureZoom) {
        this.isEnableGestureZoom = isEnableGestureZoom;
    }

    /**
     * 设置 false 时不拦截事件
     *
     * @param isEnableZoom true 开启缩放功能 false 关闭缩放功能,默认开启缩放
     */
    public void isEnableZoom(boolean isEnableZoom) {
        this.isEnableZoom = isEnableZoom;
    }

    /**
     * 恢复原来状态
     */
    public void setDefaultZoomSize() {
        smoothZoomTo(1.0f, getWidth() / 2.0f,
                getHeight() / 2.0f);
    }
}

Kotlin 代码

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.MotionEvent
import android.widget.FrameLayout

class ZoomView : FrameLayout {
    private var isEnableZoom = true
    private var isEnableGestureZoom = false

    constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(context!!, attrs, defStyle) {}
    constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs) {}
    constructor(context: Context?) : super(context!!) {}

    /**
     * Zooming view listener interface.
     */
    interface ZoomViewListener {
        fun onZoomStarted(zoom: Float, zoomx: Float, zoomy: Float)
        fun onZooming(zoom: Float, zoomx: Float, zoomy: Float)
        fun onZoomEnded(zoom: Float, zoomx: Float, zoomy: Float)
    }

    // zooming
    private var zoom = 1.0f
    private var maxZoom = 2.0f
    private var smoothZoom = 1.0f
    private var zoomX = 0f
    private var zoomY = 0f
    private var smoothZoomX = 0f
    private var smoothZoomY = 0f
    private var scrolling // NOPMD by karooolek on 29.06.11 11:45
            = false

    // minimap variables
    var isMiniMapEnabled = false
    var miniMapColor = Color.WHITE
    private var miniMapHeight = -1
    var miniMapCaption: String? = null
    var miniMapCaptionSize = 10.0f
    var miniMapCaptionColor = Color.WHITE

    // touching variables
    private var lastTapTime: Long = 0
    private var touchStartX = 0f
    private var touchStartY = 0f
    private var touchLastX = 0f
    private var touchLastY = 0f
    private var startd = 0f
    private var pinching = false
    private var lastd = 0f
    private var lastdx1 = 0f
    private var lastdy1 = 0f
    private var lastdx2 = 0f
    private var lastdy2 = 0f

    // drawing
    private val m = Matrix()
    private val p = Paint()

    // listener
    var listener: ZoomViewListener? = null
    private var ch: Bitmap? = null
    fun getMaxZoom(): Float {
        return maxZoom
    }

    fun setMaxZoom(maxZoom: Float) {
        if (maxZoom < 1.0f) {
            return
        }
        this.maxZoom = maxZoom
    }

    fun setMiniMapHeight(miniMapHeight: Int) {
        if (miniMapHeight < 0) {
            return
        }
        this.miniMapHeight = miniMapHeight
    }

    fun getMiniMapHeight(): Int {
        return miniMapHeight
    }

    fun zoomTo(zoom: Float, x: Float, y: Float) {
        this.zoom = Math.min(zoom, maxZoom)
        zoomX = x
        zoomY = y
        smoothZoomTo(this.zoom, x, y)
    }

    private fun smoothZoomTo(zoom: Float, x: Float, y: Float) {
        smoothZoom = clamp(1.0f, zoom, maxZoom)
        smoothZoomX = x
        smoothZoomY = y
        if (listener != null) {
            listener!!.onZoomStarted(smoothZoom, x, y)
        }
    }

    val zoomFocusX: Float
        get() = zoomX * zoom
    val zoomFocusY: Float
        get() = zoomY * zoom

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        if (!isEnableZoom) {
            return super.dispatchTouchEvent(ev)
        }
        // single touch
        if (ev.pointerCount == 1) {
            processSingleTouchEvent(ev)
        }
        // // double touch
        if (ev.pointerCount == 2) {
            processDoubleTouchEvent(ev)
        }

        // redraw
        rootView.invalidate()
        invalidate()
        return if (smoothZoom == 1f) {
            super.dispatchTouchEvent(ev)
        } else true
    }

    private fun processSingleTouchEvent(ev: MotionEvent) {
        val x = ev.x
        val y = ev.y
        val w = miniMapHeight * width.toFloat() / height
        val h = miniMapHeight.toFloat()
        val touchingMiniMap = x >= 10.0f && x <= 10.0f + w && y >= 10.0f && y <= 10.0f + h
        if (isMiniMapEnabled && smoothZoom > 1.0f && touchingMiniMap) {
            processSingleTouchOnMinimap(ev)
        } else {
            processSingleTouchOutsideMinimap(ev)
        }
    }

    private fun processSingleTouchOnMinimap(ev: MotionEvent) {
        val x = ev.x
        val y = ev.y
        val w = miniMapHeight * width.toFloat() / height
        val h = miniMapHeight.toFloat()
        val zx = (x - 10.0f) / w * width
        val zy = (y - 10.0f) / h * height
        smoothZoomTo(smoothZoom, zx, zy)
    }

    private fun processSingleTouchOutsideMinimap(ev: MotionEvent) {
        val x = ev.x
        val y = ev.y
        var lx = x - touchStartX
        var ly = y - touchStartY
        val l = Math.hypot(lx.toDouble(), ly.toDouble()).toFloat()
        var dx = x - touchLastX
        var dy = y - touchLastY
        touchLastX = x
        touchLastY = y
        when (ev.action) {
            MotionEvent.ACTION_DOWN -> {
                touchStartX = x
                touchStartY = y
                touchLastX = x
                touchLastY = y
                dx = 0f
                dy = 0f
                lx = 0f
                ly = 0f
                scrolling = false
            }
            MotionEvent.ACTION_MOVE -> if (scrolling || smoothZoom > 1.0f && l > 30.0f) {
                if (!scrolling) {
                    scrolling = true
                    ev.action = MotionEvent.ACTION_CANCEL
                    super.dispatchTouchEvent(ev)
                }
                smoothZoomX -= dx / zoom
                smoothZoomY -= dy / zoom
                return
            }
            MotionEvent.ACTION_OUTSIDE, MotionEvent.ACTION_UP ->
                // tap
                if (l < 30.0f) {
                    // check double tap
                    if (System.currentTimeMillis() - lastTapTime < 500) {
                        if (smoothZoom == 1.0f) {
                            smoothZoomTo(maxZoom, x, y)
                        } else {
                            smoothZoomTo(1.0f, width / 2.0f,
                                    height / 2.0f)
                        }
                        lastTapTime = 0
                        ev.action = MotionEvent.ACTION_CANCEL
                        super.dispatchTouchEvent(ev)
                        return
                    }
                    lastTapTime = System.currentTimeMillis()
                    performClick()
                }
            else -> {
            }
        }
        ev.setLocation(zoomX + (x - 0.5f * width) / zoom, zoomY
                + (y - 0.5f * height) / zoom)
        ev.x
        ev.y
        super.dispatchTouchEvent(ev)
    }

    private fun processDoubleTouchEvent(ev: MotionEvent) {
        val x1 = ev.getX(0)
        val dx1 = x1 - lastdx1
        lastdx1 = x1
        val y1 = ev.getY(0)
        val dy1 = y1 - lastdy1
        lastdy1 = y1
        val x2 = ev.getX(1)
        val dx2 = x2 - lastdx2
        lastdx2 = x2
        val y2 = ev.getY(1)
        val dy2 = y2 - lastdy2
        lastdy2 = y2

        // pointers distance
        val d = Math.hypot(x2 - x1.toDouble(), y2 - y1.toDouble()).toFloat()
        val dd = d - lastd
        lastd = d
        val ld = Math.abs(d - startd)
        Math.atan2(y2 - y1.toDouble(), x2 - x1.toDouble())
        when (ev.action) {
            MotionEvent.ACTION_DOWN -> {
                startd = d
                pinching = false
            }
            MotionEvent.ACTION_MOVE -> if (isEnableGestureZoom) {
                if (pinching || ld > 30.0f) {
                    pinching = true
                    val dxk = 0.5f * (dx1 + dx2)
                    val dyk = 0.5f * (dy1 + dy2)
                    smoothZoomTo(Math.max(1.0f, zoom * d / (d - dd)), zoomX - dxk
                            / zoom, zoomY - dyk / zoom)
                }
            }
            MotionEvent.ACTION_UP -> pinching = false
            else -> pinching = false
        }
        ev.action = MotionEvent.ACTION_CANCEL
        super.dispatchTouchEvent(ev)
    }

    private fun clamp(min: Float, value: Float, max: Float): Float {
        return Math.max(min, Math.min(value, max))
    }

    private fun lerp(a: Float, b: Float, k: Float): Float {
        return a + (b - a) * k
    }

    private fun bias(a: Float, b: Float, k: Float): Float {
        return if (Math.abs(b - a) >= k) a + k * Math.signum(b - a) else b
    }

    override fun dispatchDraw(canvas: Canvas) {
        // do zoom
        zoom = lerp(bias(zoom, smoothZoom, 0.05f), smoothZoom, 0.2f)
        smoothZoomX = clamp(0.5f * width / smoothZoom, smoothZoomX,
                width - 0.5f * width / smoothZoom)
        smoothZoomY = clamp(0.5f * height / smoothZoom, smoothZoomY,
                height - 0.5f * height / smoothZoom)
        zoomX = lerp(bias(zoomX, smoothZoomX, 0.1f), smoothZoomX, 0.35f)
        zoomY = lerp(bias(zoomY, smoothZoomY, 0.1f), smoothZoomY, 0.35f)
        if (zoom != smoothZoom && listener != null) {
            listener!!.onZooming(zoom, zoomX, zoomY)
        }
        val animating = Math.abs(zoom - smoothZoom) > 0.0000001f || Math.abs(zoomX - smoothZoomX) > 0.0000001f || Math.abs(zoomY - smoothZoomY) > 0.0000001f

        // nothing to draw
        if (childCount == 0) {
            return
        }
        // prepare matrix
        m.setTranslate(0.5f * width, 0.5f * height)
        m.preScale(zoom, zoom)
        m.preTranslate(
                -clamp(0.5f * width / zoom, zoomX, width - 0.5f
                        * width / zoom),
                -clamp(0.5f * height / zoom, zoomY, height - 0.5f
                        * height / zoom))

        // get view
        val v = getChildAt(0)
        m.preTranslate(v.left.toFloat(), v.top.toFloat())

        // get drawing cache if available
        if (animating && ch == null && isAnimationCacheEnabled) {
            v.isDrawingCacheEnabled = true
            ch = v.drawingCache
        }

        // draw using cache while animating
        if (animating && isAnimationCacheEnabled && ch != null) {
            p.color = -0x1
            canvas.drawBitmap(ch!!, m, p)
        } else { // zoomed or cache unavailable
            ch = null
            canvas.save()
            canvas.concat(m)
            v.draw(canvas)
            canvas.restore()
        }

        // draw minimap
        if (isMiniMapEnabled) {
            if (miniMapHeight < 0) {
                miniMapHeight = height / 4
            }
            canvas.translate(10.0f, 10.0f)
            p.color = -0x80000000 or 0x00ffffff and miniMapColor
            val w = miniMapHeight * width.toFloat() / height
            val h = miniMapHeight.toFloat()
            canvas.drawRect(0.0f, 0.0f, w, h, p)
            if (miniMapCaption != null && miniMapCaption!!.length > 0) {
                p.textSize = miniMapCaptionSize
                p.color = miniMapCaptionColor
                p.isAntiAlias = true
                canvas.drawText(miniMapCaption!!, 10.0f,
                        10.0f + miniMapCaptionSize, p)
                p.isAntiAlias = false
            }
            p.color = -0x80000000 or 0x00ffffff and miniMapColor
            val dx = w * zoomX / width
            val dy = h * zoomY / height
            canvas.drawRect(dx - 0.5f * w / zoom, dy - 0.5f * h / zoom, dx
                    + 0.5f * w / zoom, dy + 0.5f * h / zoom, p)
            canvas.translate(-10.0f, -10.0f)
        }

        // redraw
        rootView.postInvalidate()
        postInvalidate()
    }

    /**
     * 开启手势 缩放
     *
     * @param isEnableGestureZoom false 关闭手势缩放 true 开启手势缩放 默认 false
     */
    fun isEnableGestureZoom(isEnableGestureZoom: Boolean) {
        this.isEnableGestureZoom = isEnableGestureZoom
    }

    /**
     * 设置 false 时不拦截事件
     *
     * @param isEnableZoom true 开启缩放功能 false 关闭缩放功能,默认开启缩放
     */
    fun isEnableZoom(isEnableZoom: Boolean) {
        this.isEnableZoom = isEnableZoom
    }

    /**
     * 恢复原来状态
     */
    fun setDefaultZoomSize() {
        smoothZoomTo(1.0f, width / 2.0f,
                height / 2.0f)
    }

    companion object {
        private const val TAG = "ZoomView"
    }
}

如何使用?
ZoomView仅支持直接包住一个子View若多个View请用FrameLayout等布局包住使用

<com.xxx.common.views.ZoomView
        android:id="@+id/wpViewRoom"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center">

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

            <com.xxx.pdflib.PDfViewPager2
                android:id="@+id/pdfViewPager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="center" />

            <com.xxx.live.ui.course.view.WhitePanView
                android:id="@+id/wpView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="center"
                android:visibility="visible" />
        </FrameLayout>
</com.xxx.common.views.ZoomView>

若侵权留言删

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值