码迷,mamicode.com
首页 > 其他好文 > 详细

图片缩放和多点触控

时间:2015-08-21 21:23:33      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:

实现图片的缩放并不难,主要需要一些计算和对图片的平移及缩放操作

主布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.zoomimageview.MainActivity" >

    <com.view.ZoomImageView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scaleType="matrix"
        android:src="@drawable/m3" />

</LinearLayout>

上面使用自定义View 

如下:

package com.view;

import android.content.Context;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.ImageView;
import android.widget.SectionIndexer;

public class ZoomImageView extends ImageView implements OnGlobalLayoutListener,
        OnScaleGestureListener, OnTouchListener {
    private boolean once;
    // 缩放得最小值
    private float minScale;
    // 双击放大值
    private float doubleTouch;
    // 缩放最大值
    private float maxScale;

    private Matrix matrix;
    // 控件的宽高
    private float width;
    private float height;

    private ScaleGestureDetector scaleGestureDetector;

    public ZoomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        matrix = new Matrix();
        setScaleType(ScaleType.MATRIX);
        scaleGestureDetector = new ScaleGestureDetector(context, this);
        setOnTouchListener(this);
    }

    public ZoomImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ZoomImageView(Context context) {
        this(context, null);
    }

    public void onGlobalLayout() {
        if (!once) {
            // 得到控件的宽和高
            width = getWidth();
            height = getHeight();
            // 得到资源的宽和高
            Drawable drawable = getDrawable();
            int imgWidth = drawable.getIntrinsicWidth();
            int imgHeight = drawable.getIntrinsicHeight();

            float scale = 1.0f;

            if (imgWidth > width && imgHeight < height) {
                scale = width * 1.0f / imgWidth;
            }

            if (imgWidth < width && imgHeight > height) {
                scale = height * 1.0f / imgHeight;
            }

            if ((imgWidth > width && imgHeight > height)
                    || (imgWidth < width && imgHeight < height)) {
                scale = Math.min(width * 1.0f / imgWidth, height * 1.0f
                        / imgHeight);
            }
            minScale = scale;
            maxScale = scale * 4;
// 偏移量
            float dx = width * 1 / 2 - imgWidth * 1 / 2;
            float dy = height * 1 / 2- imgHeight * 1 / 2;
            // 将图片移动到控件的中心
            matrix.postTranslate(dx, dy);
            // 缩放
            matrix.postScale(minScale, minScale, width * 1 / 2, height * 1 / 2);
            setImageMatrix(matrix);

            once = true;

        }

    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        getViewTreeObserver().addOnGlobalLayoutListener(this);

    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        getViewTreeObserver().removeGlobalOnLayoutListener(this);
    }

    // 取得缩放值
    private float getScale() {
        float values[] = new float[9];
        matrix.getValues(values);
        return values[Matrix.MSCALE_X];
    }

    // 将缩放的图片放到矩形中 来获得缩放之后图片的宽高
    private RectF getMatrixRectF() {
        Matrix newmMatrix = matrix;
        RectF rectf = new RectF();
        Drawable drawable = getDrawable();
        if (drawable != null) {
            rectf.set(0, 0, drawable.getIntrinsicWidth(),
                    drawable.getIntrinsicHeight());
            newmMatrix.mapRect(rectf);
        }
        return rectf;
    }

    // 对缩放的位置及边界控制
    private void controlScaleImgState() {
        // 边界空白消除:
        RectF rectf = getMatrixRectF();
        float transX = 0;
        float transY = 0;
        if (width <= rectf.width()) {
            if (rectf.left > 0) {
                transX = -rectf.left;
            }
            if (rectf.right < width) {
                transX = width - rectf.right;
            }
        }
        if (height <= rectf.height()) {
            if (rectf.top > 0) {
                transY = rectf.top;
            }
            if (rectf.bottom < height) {
                transY = height - rectf.bottom;
            }

        }
        
        // 控制居中 当图片小于屏幕
        if (width > rectf.width()) {
            transX = width * 1 / 2 - rectf.right + rectf.width() * 1 / 2;
        }
        if (height > rectf.height()) {
            transY = height * 1 / 2 - rectf.bottom + rectf.height() * 1 / 2;
        }
//设置平移
        matrix.postTranslate(transX, transY);

    }

    // onScaleGestureListener 需要复写的方法
    public boolean onScale(ScaleGestureDetector detector) {
        // 取得当前缩放值
        float scale = getScale();
        // 取得根据手指判断的缩放值
        float scaleFactor = detector.getScaleFactor();
        if (getDrawable() == null) {
            return true;
        }
        // 如果在放大 当前缩放值不大于最大缩放值 或者 如果在缩小 当前缩放值不小于最小缩放值
        if ((scale < maxScale && scaleFactor > 1.0f)
                || (scale > minScale && scaleFactor < 1.0f)) {
            // 如果乘积大于最大值 则设为最大值
            if (scale * scaleFactor > maxScale) {
                scaleFactor = maxScale / scale;
            }
            // 如果乘积小于最小值 则设为最小值
            if (scale * scaleFactor < minScale) {
                scaleFactor = minScale / scale;
            }

            controlScaleImgState();

            matrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(),
                    detector.getFocusX());
            setImageMatrix(matrix);

        }

        return true;
    }

    public boolean onScaleBegin(ScaleGestureDetector detector) {
        return true;
    }

    public void onScaleEnd(ScaleGestureDetector detector) {

    }

    // onTouchListener 复写的方法
    public boolean onTouch(View v, MotionEvent event) {
        scaleGestureDetector.onTouchEvent(event);
        return true;
    }

}

说一下上面实现的大致过程:

1、首先继承了ImageView   实现了 OnGlobalLayoutListener 接口

  为什么要实现OnGlobalLayoutListener:

     当一个视图树的布局发生改变时,可以被ViewTreeObserver监听到, 这是一个注册监听视图树的观察者(observer),在视图树的全局事件改变时得到通知。ViewTreeObserver不能直接实例化,而是通过 getViewTreeObserver()获得。 在oncreate中View.getWidth和View.getHeight无法获得一个view的高度和宽度,这是因为View组件布局要 在onResume回调后完成。所以现在需要使用getViewTreeObserver().addOnGlobalLayoutListener() 来获得宽度或者高度。这是获得一个view的宽度和高度的方法之一。

2、之后又实现了 OnScaleGestureListener 和 OnTouchListener 接口

  说一下它们的作用:

   为View创建scaleGestureDetector,它会提供多点触摸在的手势变化信息,实例化它时需要OnScaleGestureListener 作为参数。callback方法ScaleGestureDetector.OnScaleGestureListener 会在特定手势事件时发出通知。而该类需要和Touch事件引发的MotionEvent配合使用。所以需要实现OnTouchListener 接口,来侦测多点触控。

  因此,需要在public boolean onTouch(View v, MotionEvent event) 方法中

  调用scaleGestureDetector.onTouchEvent(event) 将MotionEvent 传出;

3、onGlobalLayout() 

 实现OnTouchListener 接口时,需要复写onGlobalLayout() ,在这个方法中计算了缩放值和平移值

来保证初始化视图的大小及位置

4、onAttachedToWindow()和onDetachedFromWindow()

  用来添加和移除OnGlobalLayoutListener(this)

5、onScale(ScaleGestureDetector detector)  

  onScaleonScaleBegin 、onScaleEnd是实现OnScaleGestureListener接口需要复写的

  根据detector.getScaleFactor()所返回的值来进行缩放。

 

 

 

 

 

 

 

 

图片缩放和多点触控

标签:

原文地址:http://www.cnblogs.com/mydomainlistentome/p/4748812.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!