实现技术主要用到1、多点触摸  2、matrix的矩阵,平移、缩放

根据手指的数量判断是进行的拖动、还是缩放动作

package com.bi.xintest;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ImageView; public class ScaleView extends ImageView { final public static int DRAG = 1;
final public static int ZOOM = 2; public int mode = 0; private Matrix matrix = new Matrix();
private Matrix matrix1 = new Matrix();
private Matrix saveMatrix = new Matrix(); private float x_down = 0;
private float y_down = 0; private Bitmap touchImg = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher); private PointF mid = new PointF(); private float initDis = 1f; private int screenWidth, screenHeight; private float[] x = new float[4];
private float[] y = new float[4]; private boolean flag = false; public ScaleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
} public ScaleView(Context context, AttributeSet attrs) {
super(context, attrs);
} public ScaleView(Context context) {
super(context);
touchImg = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
DisplayMetrics dm = getResources().getDisplayMetrics();
screenWidth = dm.widthPixels;
screenHeight = dm.heightPixels;
matrix = new Matrix();
// this.setScaleType(ScaleType.MATRIX);
} @Override
protected void onDraw(Canvas canvas) { canvas.save();
// 根据 matrix 来重绘新的view
canvas.drawBitmap(touchImg, matrix, null);
canvas.restore();
} @Override
public boolean onTouchEvent(MotionEvent event) { int action = event.getAction();
// 多点触摸的时候 必须加上MotionEvent.ACTION_MASK
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
saveMatrix.set(matrix);
x_down = event.getX();
y_down = event.getY();
// 初始为drag模式
mode = DRAG;
break; case MotionEvent.ACTION_POINTER_DOWN:
saveMatrix.set(matrix);
// 初始的两个触摸点间的距离
initDis = spacing(event);
// 设置为缩放模式
mode = ZOOM;
// 多点触摸的时候 计算出中间点的坐标
midPoint(mid, event);
break; case MotionEvent.ACTION_MOVE: // drag模式
if (mode == DRAG) {
// 设置当前的 matrix
matrix1.set(saveMatrix);
// 平移 当前坐标减去初始坐标 移动的距离
matrix1.postTranslate(event.getX() - x_down, event.getY()
- y_down);// 平移
// 判断达到移动标准
flag = checkMatrix(matrix1);
if (flag) {
// 设置matrix
matrix.set(matrix1); // 调用ondraw重绘
invalidate();
}
} else if (mode == ZOOM) {
matrix1.set(saveMatrix);
float newDis = spacing(event);
// 计算出缩放比例
float scale = newDis / initDis; // 以mid为中心进行缩放
matrix1.postScale(scale, scale, mid.x, mid.y);
flag = checkMatrix(matrix1);
if (flag) {
matrix.set(matrix1);
invalidate();
}
}
break; case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = 0;
break;
} return true; } //取两点的距离
private float spacing(MotionEvent event) {
try {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float)Math.sqrt(x * x + y * y);
} catch (IllegalArgumentException ex) {
Log.v("TAG", ex.getLocalizedMessage());
return 0;
}
} //取两点的中点
private void midPoint(PointF point, MotionEvent event) {
try {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
} catch (IllegalArgumentException ex) { //这个异常是android自带的,网上清一色的这么说。。。。
Log.v("TAG", ex.getLocalizedMessage());
}
} private boolean checkMatrix(Matrix m) { GetFour(m); // 出界判断
//view的右边缘x坐标小于屏幕宽度的1/3的时候,
// view左边缘大于屏幕款短的2/3的时候
//view的下边缘在屏幕1/3上的时候
//view的上边缘在屏幕2/3下的时候
if ((x[0] < screenWidth / 3 && x[1] < screenWidth / 3
&& x[2] < screenWidth / 3 && x[3] < screenWidth / 3)
|| (x[0] > screenWidth * 2 / 3 && x[1] > screenWidth * 2 / 3
&& x[2] > screenWidth * 2 / 3 && x[3] > screenWidth * 2 / 3)
|| (y[0] < screenHeight / 3 && y[1] < screenHeight / 3
&& y[2] < screenHeight / 3 && y[3] < screenHeight / 3)
|| (y[0] > screenHeight * 2 / 3 && y[1] > screenHeight * 2 / 3
&& y[2] > screenHeight * 2 / 3 && y[3] > screenHeight * 2 / 3)) {
return true;
}
// 图片现宽度
double width = Math.sqrt((x[0] - x[1]) * (x[0] - x[1]) + (y[0] - y[1])
* (y[0] - y[1]));
// 缩放比率判断 宽度打雨3倍屏宽,或者小于1/3屏宽
if (width < screenWidth / 3 || width > screenWidth * 3) {
return true;
}
return false; // if ((x[0] >= 0 && x[1] >= 0 && x[2] >= 0 && x[3] >= 0)
// && (x[0] <= screenWidth && x[1] <= screenWidth
// && x[2] <= screenWidth && x[3] <= screenWidth)
// && (y[0] >= 0 && y[1] >= 0 && y[2] >= 0 && y[3] >= 0) && (y[0] <=
// screenHeight
// && y[1] <= screenHeight && y[2] <= screenHeight && y[3] <=
// screenHeight)) {
//
// return true;
// }
//
// return false;
} private void GetFour(Matrix matrix) {
float[] f = new float[9];
matrix.getValues(f);
// StringBuffer sb = new StringBuffer();
// for(float ff : f)
// {
// sb.append(ff+" ");
// }
// 图片4个顶点的坐标
//矩阵 9 MSCALE_X 缩放的, MSKEW_X 倾斜的 。MTRANS_X 平移的
x[0] = f[Matrix.MSCALE_X] * 0 + f[Matrix.MSKEW_X] * 0
+ f[Matrix.MTRANS_X];
y[0] = f[Matrix.MSKEW_Y] * 0 + f[Matrix.MSCALE_Y] * 0
+ f[Matrix.MTRANS_Y];
x[1] = f[Matrix.MSCALE_X] * touchImg.getWidth() + f[Matrix.MSKEW_X] * 0
+ f[Matrix.MTRANS_X];
y[1] = f[Matrix.MSKEW_Y] * touchImg.getWidth() + f[Matrix.MSCALE_Y] * 0
+ f[Matrix.MTRANS_Y];
x[2] = f[Matrix.MSCALE_X] * 0 + f[Matrix.MSKEW_X]
* touchImg.getHeight() + f[Matrix.MTRANS_X];
y[2] = f[Matrix.MSKEW_Y] * 0 + f[Matrix.MSCALE_Y]
* touchImg.getHeight() + f[Matrix.MTRANS_Y];
x[3] = f[Matrix.MSCALE_X] * touchImg.getWidth() + f[Matrix.MSKEW_X]
* touchImg.getHeight() + f[Matrix.MTRANS_X];
y[3] = f[Matrix.MSKEW_Y] * touchImg.getWidth() + f[Matrix.MSCALE_Y]
* touchImg.getHeight() + f[Matrix.MTRANS_Y];
} }

自定义View(三)实现简单的可拖动、可缩放的ImageView的更多相关文章

  1. 自定义View(三)--实现一个简单地流式布局

    Android中的流式布局也就是常说的瀑布流很是常见,不仅在很多项目中都能见到,而且面试中也有很多面试官问道,那么什么是流式布局呢?简单来说就是如果当前行的剩余宽度不足以摆放下一个控件的时候,则自动将 ...

  2. 自定义View其实很简单系列1-12

    作者: AigeStudio  http://blog.csdn.net/aigestudio 说明:文中的1/12表示12篇中的第1篇, 1/6=2/12表示12篇中的第2篇,其它类似. 自定义控件 ...

  3. Android 自定义View (三) 圆环交替 等待效果

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24500107 一个朋友今天有这么个需求(下图),我觉得那自定义View来做还是很 ...

  4. 自定义View(三),仿支付宝芝麻信用自定义控件

    仿支付宝的芝麻信用仪表盘 实现的效果 实现的功能: 指针和数字动态改变 背景动态变化 没了... 代码如下 MyCustomView.java package com.example.testcust ...

  5. 自定义View实现图片的绘制、旋转、缩放

    1.图片 把一张JPG图片改名为image.jpg,然后拷贝到项目的res-drawable中. 2.activity_main.xml <LinearLayout xmlns:android= ...

  6. Android自定义View之上拉、下拉列表 头部元素跟随 缩放、平移效果的实现

    滑动ListView列表然后 listView上边的视图 跟随着上拉或者下拉的距离 自动放大或者缩小  视图里边元素自动平移的效果 思路很简单 根据listView 的滑动距离去计算图片和文字应该平移 ...

  7. [转]Android自定义控件三部曲系列完全解析(动画, 绘图, 自定义View)

    来源:http://blog.csdn.net/harvic880925/article/details/50995268 一.自定义控件三部曲之动画篇 1.<自定义控件三部曲之动画篇(一)—— ...

  8. Android自定义View(一、初体验自定义TextView)

    转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51454685 本文出自:[openXu的博客] 目录: 继承View重写onDraw方法 自 ...

  9. wing带你玩转自定义view系列(2) 简单模仿qq未读消息去除效果

    上一篇介绍了贝塞尔曲线的简单应用 仿360内存清理效果 这一篇带来一个  两条贝塞尔曲线的应用 : 仿qq未读消息去除效果. 转载请注明出处:http://blog.csdn.net/wingicho ...

  10. Android 自定义 view(三)—— onDraw 方法理解

    前言: 上一篇已经介绍了用自己定义的属性怎么简单定义一个view<Android 自定义view(二) -- attr 使用>,那么接下来我们继续深究自定义view,下一步将要去简单理解自 ...

随机推荐

  1. 剑指offer-二叉树的深度

    题目: 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. 链接: http://www.nowcoder.com/practic ...

  2. html5设计原理(转)

    转自:   http://www.cn-cuckoo.com/2010/10/21/the-design-of-html5-2151.html 今天我想跟大家谈一谈HTML5的设计.主要分两个方面:一 ...

  3. oracle的over函数应用(转载)

    摘自: http://www.poluoluo.com/jzxy/201004/81921.html 百度文库也记载了Oracle中over()分析函数的用法 在泡坛子的时候中无意中发现了这个函数,才 ...

  4. MYSQL 中 update set from where 问题

    MySQL 和 SQLSERVER不一样,update set from 一张表的时候 应该改为 UPDATE TABLE_AA INNER JOIN TABLE_BB ON TABLE_AA.ID ...

  5. python几个重要的模块备忘

    一:模块使用方法 二:时间模块time 三:系统接口模块os和sys 四:数据保存的几个模块json,pickle,xml,configparse 五:数据复制移动模块shutil 六:日志模块log ...

  6. tp框架总结(四)

    一 ajax的返回 调用实例: $this->ajaxReturn(返回数据,提示信息,操作状态); $this->ajaxReturn(返回数据,‘json’); js: <scr ...

  7. PHP常用函数大全

    usleep() 函数延迟代码执行若干微秒.unpack() 函数从二进制字符串对数据进行解包.uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID.time_sleep_until() ...

  8. Datatable 列查询,统计值

    Column 列查询,如下: var dt = CommonUtil.ToDataTable(dataJson); //判断是否有当前日期数据 var systemDateTime = new Com ...

  9. BeanUtils.populate的作用

    它是在org.apache.commons.beanutils.BeanUtils包中的一个方法. 方法的作用:将一些 key-value 的值(例如 hashmap)映射到 bean 中的属性.   ...

  10. 如何在属性面板中增加一个属性-UI界面编辑器(XproerUI)教程

    版权所有 2009-2015 荆门泽优软件有限公司 保留所有权利 产品首页:http://www.ncmem.com/apps/xproerui/index.asp 开发文档(SkinStudio): ...