我们在项目里经常会用到需要使用ImageView的地方,这时候有些产品经理可能会提出需要让这个ImageView玩出花样旋起来,原来的那个只能显示图片的就不好使了,需要考虑去实现一个功能更强大的ImageView了。
一、 准备工作
由于我们要实现的是一个可自由变换的ImageView,那么首先要想到的是如何通过手势的方式对特定的操作进行区分,这里使用了Github中封装手势操作的组件库Almeros/android-gesture-detectors,其对移动、旋转和缩放都进行了很好的封装,可以帮助我们减少很多麻烦。
repositories {
//添加jitpack仓库
maven { url 'https://jitpack.io' }
}
implementation 'com.github.Almeros:android-gesture-detectors:v1.0.1'
二、实现旋转
效果
实现思路
- 声明RotateGestureDetector对象,初始化并设置监听器等;
- 为ImageView设置setOnTouchListener事件,在其回调中让RotateGestureDetector实例对象接手触摸事件;
- 在RotateGestureDetector的监听器回调中,获取对应的变化值,并设置给ImageView。
代码实例
public class DemoRotateImageView extends AppCompatImageView implements ViewTreeObserver.OnGlobalLayoutListener{
//操作对象
private Matrix mMatrix;
//旋转手势监听器
private RotateGestureDetector mRotateGestureDetector ;
//当前焦点
private float mFocusX, mFocusY;
public DemoRotateImageView(Context context) {
this(context, null);
}
public DemoRotateImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DemoRotateImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//记住,一定要把ScaleType设置成ScaleType.MATRIX,否则无法缩放
setScaleType(ScaleType.MATRIX);
mMatrix = new Matrix();
//手势旋转
mRotateGestureDetector = new RotateGestureDetector(context, new RotateGestureDetector.OnRotateGestureListener() {
@Override
public boolean onRotate(RotateGestureDetector detector) {
float rotationDegrees = -detector.getRotationDegreesDelta();
mMatrix.postRotate(rotationDegrees,mFocusX,mFocusY);
setImageMatrix(mMatrix);
return true;
}
@Override
public boolean onRotateBegin(RotateGestureDetector detector) {
return true;
}
@Override
public void onRotateEnd(RotateGestureDetector detector) {
}
});
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mRotateGestureDetector.onTouchEvent(event);
return true ;
}
public boolean mIsOneLoad = true;
@Override
public void onGlobalLayout() {
if (mIsOneLoad) {
//获取图片,如果没有图片则直接退出
Drawable d = getDrawable();
if (d == null){
return;
}
//获取图片的宽和高
int dw = d.getIntrinsicWidth();
int dh = d.getIntrinsicHeight();
//将其中图片中心点作为焦点
mFocusX = dw * 1.0f / 2 ;
mFocusY = dh * 1.0f / 2 ;
mIsOneLoad = false;
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
//修改窗口事件中对视图变化进行监听
getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
三、实现缩放
实现思路
- 声明ScaleGestureDetector对象,初始化并设置监听器等;
- 为ImageView设置setOnTouchListener事件,在其回调中让ScaleGestureDetector实例对象接手触摸事件;
- 在onGlobalLayout中设置初始、最大、最小缩放值;
- 在ScaleGestureDetector的监听器回调中,获取焦点并对缩放进行处理后设置ImageView;
- 当缩放值大于最大和最小缩放值后不允许其继续缩放。
代码实例
public class DemoScaleImageView extends AppCompatImageView implements ViewTreeObserver.OnGlobalLayoutListener{
//操作对象
private Matrix mMatrix;
//缩放手势监听器
private ScaleGestureDetector mScaleGestureDetector ;
//图片宽高
private float mFocusX, mFocusY;
//初始化的比例,也就是最小比例
private float mInitScale;
//图片最大比例
private float mMaxScale;
//图片最小比例
private float mMinScale ;
public DemoScaleImageView(Context context) {
this(context, null);
}
public DemoScaleImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DemoScaleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//记住,一定要把ScaleType设置成ScaleType.MATRIX,否则无法缩放
setScaleType(ScaleType.MATRIX);
mMatrix = new Matrix();
//手势旋转
mScaleGestureDetector = new ScaleGestureDetector(context,new ScaleGestureDetector.SimpleOnScaleGestureListener(){
@Override
public boolean onScale(ScaleGestureDetector detector) {
//开始缩放
float scaleFactor = detector.getScaleFactor();
Log.i("缩放操作值",scaleFactor+"");
float scale = getCurrentScale();
//缩放操作需要在mMinScale和mMaxScale中进行 范围外的话就拦截
if(scale < mMaxScale && scale > mMinScale){
mMatrix.postScale(scaleFactor, scaleFactor, mFocusX, mFocusY);
setImageMatrix(mMatrix);
return true;
}else{
return false;
}
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
//开始缩放并获取焦点
mFocusX = detector.getFocusX();
mFocusY = detector.getFocusY();
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
super.onScaleEnd(detector);
}
});
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mScaleGestureDetector.onTouchEvent(event);
return true ;
}
public boolean mIsOneLoad = true;
@Override
public void onGlobalLayout() {
if (mIsOneLoad) {
//获取图片,如果没有图片则直接退出
Drawable d = getDrawable();
if (d == null){
return;
}
//获取图片的宽和高
int dw = d.getIntrinsicWidth();
int dh = d.getIntrinsicHeight();
//使其图片中点作为焦点
mFocusX = dw * 1.0f / 2 ;
mFocusY = dh * 1.0f / 2 ;
//初始化缩放比例
mInitScale = getCurrentScale();
//手势放大时最大比例
mMaxScale = mInitScale * 2;
//手势缩小时的最小比例
mMinScale = mInitScale * 0.8f ;
mIsOneLoad = false;
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
/**
* 获取当前图片的缩放值
* @return 缩放值
*/
private float getCurrentScale() {
float[] values = new float[9];
mMatrix.getValues(values);
return values[Matrix.MSCALE_X];
}
}












网友评论