图片缩放和多点触控

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

主布局:

<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)

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

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

时间: 2024-08-07 00:03:15

图片缩放和多点触控的相关文章

Android实现多点触控,自由缩放图片

Android多点触控涉及到的知识点 1.ScaleGestureDetector 2.OnScaleGestureListener 3.Matrix 4.OnTouchListener 四个知识点需要了解一下,需要注意的是Matrix在内存中是一个一维数组,操控图片的Matrxi是一个3X3的矩阵,在内存中也就是一个大小为9的一维数组. 实现多点触控,自由变化图片 1. ImageView的基础上继承 2.因为要在图片加载完成就获取到相关的属性,所以实现OnGlobalLayoutListen

(三)多点触控之自由移动缩放后的图片

在上一篇文章中,将图片的自由缩放功能基本上完成了.效果还不错.如果你还没读过,可以点击下面的链接:http://www.cnblogs.com/fuly550871915/p/4939954.html 接下来这个项目要往前走,在自由缩放的基础上实现自由移动.要用的知识点就是OnTouchListener对移动手势的监控.在写代码之前我们应该考虑下面的几个问题: (1)什么时候可以移动?当图片比屏幕大时才需要移动,如果图片在屏幕内显示,没必要移动.(2)当移动的距离达到多少时才触发移动效果?在这里

Android多点触控(图片的缩放Demo)

本文主要介绍Android的多点触控,使用了一个图片缩放的实例,来更好的说明其原理.需要实现OnTouchListener接口,重写其中的onTouch方法. 实现效果图: 源代码: 布局文件: activity_main: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools&quo

Android多点触控技术实战,自由地对图片进行缩放和移动

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11100327 在上一篇文章中我带着大家一起实现了Android瀑布流照片墙的效果,虽然这种效果很炫很酷,但其实还只能算是一个半成品,因为照片墙中所有的图片都是只能看不能点的.因此本篇文章中,我们就来对这一功能进行完善,加入点击图片就能浏览大图的功能,并且在浏览大图的时候还可以通过多点触控的方式对图片进行缩放. 如果你还没有看过 Android瀑布流照片墙实现,体验不规则排列的美感

Android实现图片多点触控自由伸缩

简介 作为Android开发者,我们经常需要自定义控件,比如下面我们说的实现图片的多点触控和伸缩释放,这也是由于用户已经有这样的常识了,那就是看见有图片的地方就可以点击查看大图,并且可以通过手指对图片进行伸缩和移动,如果应用没有实现这一点,那么对用户来说将会是很糟糕的体验,用户很"愤怒".所以作为Android开发者,我们的任务就是让用户"爽".哈哈哈....下面我们将通过自定义ImageView实现以上功能. 涉及技术 一.Matrix(矩阵),Android是通

MultiTouch————多点触控,伸缩图片,变换图片位置

前言:当今的手机都支持多点触控功能(可以进行图片伸缩,变换位置),但是我们程序员要怎样结合硬件去实现这个功能呢? 跟随我一起,来学习这个功能 国际惯例:先上DEMO免费下载地址:http://download.csdn.net/detail/cnwutianhao/9443667 示例图片: 我是用Genymotion录制的,没有真机上多点触控显示的效果那么好,大家在真机上跑程序,会体会到多点触控功能.(注:Genymotion多点触控快捷键是 ctrl+鼠标指针上下拖动) 具体代码实现: 布局

Android多点触控技术,实现对图片的放大缩小平移,惯性滑动等功能

首先推荐一下鸿洋大大的打造个性的图片预览与多点触控视频教程,这套教程教我们一步一步实现了多点触控实现对图片的平移和缩放的功能,这篇文章我将在鸿洋大大的基础之上做了一些扩展功能: 1.图片的惯性滑动 2.图片缩放小于正常比例时,松手会自动回弹成正常比例 3.图片缩放大于最大比例时,松手会自动回弹成最大比例 实现图片的缩放,平移,双击缩放等基本功能的代码如下,每一行代码我都做了详细的注释 public class ZoomImageView extends ImageView implements

unity3d 触屏多点触控(旋转与缩放)

unity3d 触屏多点触控(旋转与缩放) /*Touch OrbitProgrammed by: Randal J. Phillips (Caliber Mengsk)Original Creation Date: 12/16/2011Last Updated:                   12/16/2011Desctiption: Simple orbit by one touch and drag, as well as pinch to zoom with two finger

多点触控 地图缩放

使用地图App中,我们经常需要对界面进行缩放操作来更加便利的查看位置.那么在Appium中怎样去模拟这类操作呢? MultiAction MultiAction 是多点触控的类,可以模拟用户多点操作.主要包含 add() 和 perform() 两个方法, MultiAction可以结合前面所学的 ActionTouch可以模拟出用户的多个手指滑动的操作效果: from appium.webdriver.common.multi_action import MultiAction from ap