我的学习视频地址,一起来学习Android…
http://edu.csdn.net/course/detail/2741/43164?auto_start=1>
代码下载地址
代码一:自定义支持多点触摸的TextView
http://download.csdn.net/detail/zhiyuan0932/9513852
什么是多点触摸
允许计算机用户同时通过多个手指来控制图形界面的一种技术
多点触摸的应用场景
- 对图片、文字、网页进行放大或者缩小
- 多手指手势操作自定义控件和布局
触摸事件的重要方法
event.getActionMasked(); 获取事件类型
在只使用单手指操作的时候,这个方法我们一般使用的是event.getAction(),来获取事件类型,但是对于多个手指,我们使用event.getActionMasked()或者event.getAction() & MotionEvent.ACTION_MASK 来获取支持多个手指触摸的事件类型。MotionEvent.ACTION_POINTER_DOWN 手指按下事件
这个方法可以获取到多个手指按下的状态MotionEvent.ACTION_POINTER_UP 手指抬起事件
这个方法可以获取到多个手指抬起的状态MotionEvent.ACTION_MOVE 手指移动事件
event.getPointerCount() 获取手指个数
这个方法是获取当前手指的个数
案例一:通过两指触摸实现字体缩放
- 在这里直接贴代码,首先贴出布局代码
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent" ><com.example.scaletextview.ZoomTextViewandroid:id="@+id/textView"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_centerInParent="true"android:gravity="center"android:text="@string/hello_world"android:textSize="30sp" /></RelativeLayout>
- 贴出自定义支持多点触控的TextView代码
package com.example.scaletextview;import android.content.Context;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.TextView;public class ZoomTextView extends TextView {private static final String TAG = "ZoomTextView";private float textSize;private int mode;private float oldDist;public ZoomTextView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}public ZoomTextView(Context context, AttributeSet attrs) {super(context, attrs);}public ZoomTextView(Context context) {super(context);}/*** 处理TextView的触摸事件*/@Overridepublic boolean onTouchEvent(MotionEvent event) {//在一开始,计算当前字体的大小if (textSize == 0) {textSize = this.getTextSize();}// 获取触摸事件的类型,如果是单点是event.getAction(),当涉及到多点触控时,就使用getActionMasked来获取触摸事件类型switch (event.getActionMasked()) {case MotionEvent.ACTION_POINTER_DOWN:// 当手指按下的时候,就去获取当前手指的间距oldDist = spacing(event);break;case MotionEvent.ACTION_MOVE:// 获取当前触摸点的个数if (event.getPointerCount() >= 2) {// 如果触摸点>=2 获取当前两个手指的距离,然后进行缩放float newDist = spacing(event);zoom(newDist / oldDist);//重新置位oldDist = newDist;}break;}return true;}/*** 不断进行缩放* * @param f*/private void zoom(float f) {textSize *= f;this.setTextSize(px2sp(getContext(), textSize));}/*** 将px值转换为sp值,保证文字大小不变* * @param pxValue* @param fontScale* (DisplayMetrics类中属性scaledDensity)* @return*/public static int px2sp(Context context, float pxValue) {float fontScale = context.getResources().getDisplayMetrics().scaledDensity;return (int) (pxValue / fontScale + 0.5f);}/*** 计算两个手指的大小* * @param event* @return*/private float spacing(MotionEvent event) {//获取第一个点的x坐标和第二个点的x坐标float x = event.getX(0) - event.getX(1);//分别获取y坐标float y = event.getY(0) - event.getY(1);//使用勾股定理计算两点距离return FloatMath.sqrt(x * x + y * y);}
}
案例二:通过两指触摸实现图片缩放
- 第一步:写一个自定义控件继承自View,并计算控件宽高
public class ScaleImageView extends View//在onMeasure方法中计算出当前控件的宽和高@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);width = this.getWidth();height = this.getHeight();}
- 第二步:对外提供设置图片的方法
public void setImageResource(int resourceId) {Bitmap mbitmap = BitmapFactory.decodeResource(getResources(),resourceId);this.mBitmap = mbitmap;postInvalidate();}// 对外提供设置图片的方法public void setImageBitmap(Bitmap mBitmap) {this.mBitmap = mBitmap;// 当传递过图片来之后,对图片进行初始化操作postInvalidate();}
- 第三步:对图片进行初始化的处理(图片过大需要进行等比例缩放处理),然后将图片绘制到界面上
//进行图片的初始化public void initBitmap(Canvas canvas) {if (mBitmap != null) {matrix.reset();int bitmapWidth = mBitmap.getWidth();int bitmapHeight = mBitmap.getHeight();if (bitmapWidth > width || bitmapHeight > height) {if (bitmapWidth - width > bitmapHeight - height) {// 当图片宽度大于屏幕宽度时,将图片等比例压缩,使它可以完全显示出来float ratio = width / (bitmapWidth * 1.0f);matrix.postScale(ratio, ratio);float translateY = (height - (bitmapHeight * ratio)) / 2f;// 在纵坐标方向上进行偏移,以保证图片居中显示matrix.postTranslate(0, translateY);totalTranslateY = translateY;totalScaleRadio = initScaleRadio = ratio;} else {// 当图片高度大于屏幕高度时,将图片等比例压缩,使它可以完全显示出来float ratio = height / (bitmapHeight * 1.0f);matrix.postScale(ratio, ratio);float translateX = (width - (bitmapWidth * ratio)) / 2f;// 在横坐标方向上进行偏移,以保证图片居中显示matrix.postTranslate(translateX, 0);totalTranslateX = translateX;totalScaleRadio = initScaleRadio = ratio;}currentBitmapWidth = bitmapWidth * initScaleRadio;currentBitmapHeight = bitmapHeight * initScaleRadio;} else {// 当图片的宽高都小于屏幕宽高时,直接让图片居中显示float translateX = (width - mBitmap.getWidth()) / 2f;float translateY = (height - mBitmap.getHeight()) / 2f;matrix.postTranslate(translateX, translateY);totalTranslateX = translateX;totalTranslateY = translateY;totalScaleRadio = initScaleRadio = 1f;currentBitmapWidth = bitmapWidth;currentBitmapHeight = bitmapHeight;}canvas.drawBitmap(mBitmap, matrix, null);}}
在进行初始化处理的时候,需要对图片进行缩放和移动,这里将图片小于控件时的偏移量计算原理贴出,方便大家理解
* 第四步:处理onTouch事件
*
/*** 处理触摸事件*/@Overridepublic boolean onTouchEvent(MotionEvent event) {// 获取触摸事件的类型,如果是单点是event.getAction(),当涉及到多点触控时,就使用getActionMasked来获取触摸事件类型switch (event.getActionMasked()) {case MotionEvent.ACTION_POINTER_DOWN:if (event.getPointerCount() >= 2) {// 计算两个手指的距离oldDist = spacing(event);}break;case MotionEvent.ACTION_MOVE:// 获取当前触摸点的个数if (event.getPointerCount() >= 2) {centerPoniter(event);// 如果触摸点>=2 获取当前两个手指的距离,然后进行缩放// 重新置位float newDist = spacing(event);// 进行缩放currentState = STATE_ZOOM;// 计算出当前的缩放值scaleRatio = newDist / oldDist;// 调用onDraw方法,重新绘制界面postInvalidate();// 对手指间距离进行重新置位oldDist = newDist;}break;}return true;}
- 第五步 进行图片的缩放处理
private void zoom(Canvas canvas) {totalScaleRadio = totalScaleRadio * scaleRatio;//这里是对图片的放大和缩小进行一定的限制//最大不超过图片的4倍,最小不小于源图片的大小if (totalScaleRadio >= initScaleRadio * 4) {totalScaleRadio = initScaleRadio * 4;} else if (totalScaleRadio < initScaleRadio) {totalScaleRadio = initScaleRadio;}matrix.reset();// 将图片按总缩放比例进行缩放matrix.postScale(totalScaleRadio, totalScaleRadio);float scaledWidth = mBitmap.getWidth() * totalScaleRadio;float scaledHeight = mBitmap.getHeight() * totalScaleRadio;float translateX = 0f;float translateY = 0f;// 如果当前图片宽度小于屏幕宽度,则按屏幕中心的横坐标进行水平缩放。否则按两指的中心点的横坐标进行水平缩放if (currentBitmapWidth < width) {translateX = (width - currentBitmapWidth) / 2f;} else {//当图片大于控件的大小时,需要去计算出这个偏移量的大小,随后附加图片对这个计算原理做介绍translateX = mTranslateX * scaleRatio + fingerCenterX* (1 - scaleRatio);// 进行边界检查,保证图片缩放后在水平方向上不会偏移出屏幕// 当当前图片比屏幕大的时候,要保证不再往右偏,否则就会在右侧移除屏幕if (translateX > 0) {translateX = 0;// 保证当图片比屏幕大的时候,屏幕宽--左偏的一个大小,不得大于图片的实际大小} else if (width - translateX > scaledWidth) {translateX = width - scaledWidth;}}// 如果当前图片高度小于屏幕高度,则按屏幕中心的纵坐标进行垂直缩放。否则按两指的中心点的纵坐标进行垂直缩放if (currentBitmapHeight < height) {translateY = (height - currentBitmapHeight) / 2f;} else {//跟x轴上的偏移量是一个道理translateY = mTranslateY * scaleRatio + fingerCenterY* (1 - scaleRatio);// 进行边界检查,保证图片缩放后在垂直方向上不会偏移出屏幕if (translateY > 0) {translateY = 0;} else if (height - translateY > scaledHeight) {translateY = height - scaledHeight;}}// 缩放后对图片进行偏移,以保证缩放后中心点位置不变matrix.postTranslate(translateX, translateY);mTranslateX = translateX;mTranslateY = translateY;currentBitmapWidth = scaledWidth;currentBitmapHeight = scaledHeight;canvas.drawBitmap(mBitmap, matrix, null);}
下面贴出当图片 大于控件大小时,手指进行缩放时的X轴的偏移量计算原理,来方便大家的理解
计算手指距离和手指中心的方法
/*** 计算两个手指间的距离* @param event* @return*/private float spacing(MotionEvent event) {// 获取第一个点的x坐标和第二个点的x坐标float x = event.getX(0) - event.getX(1);// 分别获取y坐标float y = event.getY(0) - event.getY(1);// 使用勾股定理计算两点距离return FloatMath.sqrt(x * x + y * y);}/*** 计算手指的中心点* @param event*/private void centerPoniter(MotionEvent event) {float x0 = event.getX(0);float x1 = event.getX(1);float y0 = event.getY(0);float y1 = event.getY(1);fingerCenterX = (x0 + x1) / 2;fingerCenterY = (y0 + y1) / 2;}