Android中实现双指缩放的功能
16lz
2021-12-27
Android中实现双指缩放的功能
安卓中实现将图片缩放的功能提供了一个很好的类:ScaleGestureDetector,本章就介绍使用canvas和ScaleGestureDetector类实现缩放的功能,如果要想详细了解ScaleGestureDetector请参考博文Android的ScaleGestureDetector缩放类详解
1. 先初始化缩放比和图片居中绘制的坐标点
float posX, posY;//图片的坐标 int viewWidth, viewHeight;//屏幕的宽高 float widthScale, heightScale;//宽高缩放比 boolean hasInitViewSize;//是否已经初始化视图 public void initSize() { viewWidth = getWidth();//得到屏幕宽度 viewHeight = getHeight();//得到屏幕高度 if (viewWidth < 0 && viewHeight < 0) { return; } hasInitViewSize = true; widthScale = viewWidth / imgWidth;//宽高缩放比=屏幕的宽高/屏幕的宽高 heightScale = viewHeight / imgHeight; scaleFactor = Math.min(widthScale, heightScale);//总缩放比取宽高缩放比中最小的 posX = viewWidth / 2 - imgWidth / 2;//使图片居中绘制 posY = viewHeight / 2 - imgHeight / 2; }
2. 创建两个内部类分别继承SimpleOnScaleGestureListener和SimpleOnGestureListener来动态获取缩放比和坐标
class MySimpleOnGestureDetector extends GestureDetector.SimpleOnGestureListener { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { posX -= distanceX;//X轴的坐标=X轴的坐标-在X轴方向的移动距离 posY -= distanceY;//y轴的坐标=y轴的坐标-在y轴方向的移动距离 invalidate();//刷新view return true; } } class MySimpleScaleOnGestureDetector extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { scaleFactor *= detector.getScaleFactor();//缩放比=缩放比*动态获取的缩放比 scaleFactor = scaleFactor < 0.75 ? (float) 0.75 : scaleFactor > 3 ? 3 : scaleFactor;//控制缩放倍率在0.75-3之间 invalidate();//刷新view return true; } }
3. 为了移动图片时不超出屏幕,还得进行控制,原则是:图片较小时任意一条边都不能出了边界,图片较大任意一条边都不能进入边界。宽度和高度分别独立计算。
public void checkBounds() { if (scaleFactor > widthScale) {//宽度方向已经填满 posX = Math.min(posX, (scaleFactor - 1) * (imgWidth / 2)); posX = Math.max(posX, viewWidth - imgWidth - (scaleFactor - 1) * (imgWidth / 2)); } else { posX = Math.max(posX, (scaleFactor - 1) * (imgWidth / 2)); posX = Math.min(posX, viewWidth - imgWidth - (scaleFactor - 1) * (imgWidth / 2)); } if (scaleFactor > heightScale) {//高度方向已经填满 posY = Math.min(posY, (scaleFactor - 1) * (imgHeight / 2)); posY = Math.max(posY, viewHeight - imgHeight - (scaleFactor - 1) * (imgHeight / 2)); } else { posY = Math.max(posY, (scaleFactor - 1) * (imgHeight / 2)); posY = Math.min(posY, viewHeight - imgHeight - (scaleFactor - 1) * (imgHeight / 2)); } }
4. 在类中实现onDraw方法进行绘制缩放
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (bitmap == null) { return; } if (!hasInitViewSize) { initSize(); } canvas.save();//画布保存 checkBounds();//检查边界,使图片不能超出屏幕 canvas.scale(scaleFactor, scaleFactor, posX + imgWidth / 2, posY + imgHeight / 2);///以图片的中心为基点进行缩放 canvas.drawBitmap(bitmap, posX, posY, paint);//绘制图片 canvas.restore();//画布重绘 }
5. 关键点已经差不多写完了,现在将完整的类写上
package com.example.mygesture;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Paint;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.ScaleGestureDetector;import android.view.View;public class MyScaleView extends View { ScaleGestureDetector scaleGestureDetector; float scaleFactor; float posX, posY; int viewWidth, viewHeight; float widthScale, heightScale; boolean hasInitViewSize; Paint paint = new Paint(); Bitmap bitmap; float imgWidth, imgHeight; GestureDetector gestureDetector; public MyScaleView(Context context, @Nullable AttributeSet attrs) {//注意:得在有两个参数的构造函数中实例化ScaleGestureDetector 和GestureDetector super(context, attrs); init(context); } private void init(Context context) { scaleGestureDetector = new ScaleGestureDetector(context, new MySimpleScaleOnGestureDetector()); gestureDetector = new GestureDetector(context, new MySimpleOnGestureDetector()); } class MySimpleOnGestureDetector extends GestureDetector.SimpleOnGestureListener { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { posX -= distanceX; posY -= distanceY; invalidate(); return true; } } class MySimpleScaleOnGestureDetector extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { scaleFactor *= detector.getScaleFactor(); scaleFactor = scaleFactor < 0.75 ? (float) 0.75 : scaleFactor > 3 ? 3 : scaleFactor; invalidate(); return true; } } public void initSize() { viewWidth = getWidth(); viewHeight = getHeight(); if (viewWidth < 0 && viewHeight < 0) { return; } hasInitViewSize = true; widthScale = viewWidth / imgWidth; heightScale = viewHeight / imgHeight; scaleFactor = Math.min(widthScale, heightScale); posX = viewWidth / 2 - imgWidth / 2; posY = viewHeight / 2 - imgHeight / 2; } public void checkBounds() {//检查边界 if (scaleFactor > widthScale) { posX = Math.min(posX, (scaleFactor - 1) * (imgWidth / 2)); posX = Math.max(posX, viewWidth - imgWidth - (scaleFactor - 1) * (imgWidth / 2)); } else { posX = Math.max(posX, (scaleFactor - 1) * (imgWidth / 2)); posX = Math.min(posX, viewWidth - imgWidth - (scaleFactor - 1) * (imgWidth / 2)); } if (scaleFactor > heightScale) { posY = Math.min(posY, (scaleFactor - 1) * (imgHeight / 2)); posY = Math.max(posY, viewHeight - imgHeight - (scaleFactor - 1) * (imgHeight / 2)); } else { posY = Math.max(posY, (scaleFactor - 1) * (imgHeight / 2)); posY = Math.min(posY, viewHeight - imgHeight - (scaleFactor - 1) * (imgHeight / 2)); } } @Override public boolean onTouchEvent(MotionEvent event) { scaleGestureDetector.onTouchEvent(event);//双指缩放 gestureDetector.onTouchEvent(event);//单指移动 return true; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (bitmap == null) { return; } if (!hasInitViewSize) { initSize(); } canvas.save(); checkBounds(); canvas.scale(scaleFactor, scaleFactor, posX + imgWidth / 2, posY + imgHeight / 2); canvas.drawBitmap(bitmap, posX, posY, paint); canvas.restore(); } public void setImageResouse(int resID) {//设置图片 bitmap = BitmapFactory.decodeResource(getResources(), resID); imgWidth = bitmap.getWidth(); imgHeight = bitmap.getHeight(); initSize(); invalidate(); }}
6. 类已经写好了,现在对其使用,创建一个新的Activity
6.1 构造布局文件
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".text.Main8Activity"> <com.example.mygesture.MyScaleView android:id="@+id/activity_main8_myScaleView" android:layout_width="match_parent" android:layout_height="match_parent" /></LinearLayout>
6.2 对应的类中
package com.example.mygesture.text;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import com.example.mygesture.MyScaleView;import com.example.mygesture.R;public class Main8Activity extends AppCompatActivity { MyScaleView myScaleView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main8); myScaleView = findViewById(R.id.activity_main8_myScaleView); myScaleView.setImageResouse(R.drawable.q4); }}
7. 所以使用还是很简单的,因为缩放操作模拟器上不好演示,效果图就省略了。
Tip: 小白,写得不好请见谅。若有不对的地方请留言。
关于手势方面的功能点还可以参考Android中实现自定义手势和识别手势的功能,Android中简单实现页面翻转和自动翻转的功能
更多相关文章
- Android的selector,背景选择器
- 浅谈android的selector背景选择器
- 浅谈android的selector背景选择器
- 【腾讯Bugly干货分享】Android动态布局入门及NinePatchChunk解密
- Android(安卓)上传头像(文件)到服务器
- Android的图像处理
- android的selector背景选择器
- Android开机动画bootanimation.zip
- React Native嵌入到Android原生应用中、组件的生命周期、颜色、