前言
作为一个Android开发,当系统控件满足不了业务需求的时候,就需要程序猿自己自定义控件或者容器。所以自定义控件、自定义容器,是我们必须掌握的技术。本次,程序猿小钟就为大家介绍一下自定义的放大缩小容器,并粗略的介绍一下容器中用到的GestureDetector和ScaleGestureDetector,如果大家想要更加深入了解这两个类的话,可以自己阅读一下源码。
手势工具类GestureDetector
GestureDetector类主要是用于识别一些特定的动作手势,例如单击、双击、长按等。只需要在容器中初始化并且在onTouchEvent事件中调用GestureDetector.onTouchEvent(motionEvent),并通过GestureDetector中的接口SimpleOnGestureListener监听到各种手势的回调。
SimpleOnGestureListener是GestureDetector的内部类,主要的方法有:
缩放手势工具类ScaleGestureDetector
ScaleGestureDetector类主要是用于识别缩放手势的工具。使用方式也是只需要在容器初始化并且在onTouchEvent事件中调用ScaleGestureDetector.onTouchEvent(motionEvent),并通过ScaleGestureDetector中的接口SimpleOnScaleGestureListener监听到缩放手势的回调。
SimpleOnScaleGestureListener是ScaleGestureDetector的内部类,方法有【监听缩放手势开始回调】、【监听缩放手势回调】、【监听缩放手势结束回调】:
放大缩小容器ScalableViewContainer
/**
* 放大缩小容器(Android7以上适用)
*/
public class ScalableViewContainer extends FrameLayout {
//常量定义
private final float MIN_SCALE =1.0f;
private final float MID_SCALE =1.75f;
private final float MAX_SCALE =3.0f;
//手势
private GestureDetector gestureDetector;
//缩放手势
private ScaleGestureDetector scaleDetector;
private int width; // 原始宽度
private int height; // 原始高度
private float curScale =1.0f; // 当前缩放比例
private float translateX; // 当前X偏移
private float translateY; // 当前Y偏移
private float minTransX; // 最小X偏移
private float maxTransX; // 最大X偏移
private float minTransY; // 最小Y偏移
private float maxTransY; // 最大Y偏移
public ScalableViewContainer(@NonNull Context context) {
this(context, null);
}
public ScalableViewContainer(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ScalableViewContainer(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//初始化手势工具类,自定义监听
gestureDetector =new GestureDetector(context, new CustomOnGestureListener());
scaleDetector =new ScaleGestureDetector(context, new CustomOnScaleGestureListener());
}
/**
* 重置
*/
public void resetScale() {
setScale(0);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
}
/**
* 触摸事件
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
scaleDetector.onTouchEvent(ev);
gestureDetector.onTouchEvent(ev);
return true;
}
/**
* 设置缩放
*/
private void setScale(float scale) {
float oldScale =curScale;
if (scale < MIN_SCALE) {
curScale =MIN_SCALE;
}else if (scale >MAX_SCALE) {
curScale =MAX_SCALE;
}else {
curScale = scale;
}
if (oldScale !=curScale) {
getChild().setScaleX(curScale);
getChild().setScaleY(curScale);
updateTrans();
}
}
/**
* 缩放后调整偏移
*/
private void updateTrans() {
minTransX = -width * (curScale -1) /2;
maxTransX =width * (curScale -1) /2;
minTransY = -height * (curScale -1) /2;
maxTransY =height * (curScale -1) /2;
setTrans(translateX, translateY);
}
/**
* 避免缩放时出现黑边
*/
private void setTrans(float transX, float transY) {
if (transX < minTransX) {
translateX =minTransX;
}else if (transX >maxTransX) {
translateX =maxTransX;
}else {
translateX = transX;
}
if (transY < minTransY) {
translateY =minTransY;
}else if (transY >maxTransY) {
translateY =maxTransY;
}else {
translateY = transY;
}
getChild().setTranslationX(translateX);
getChild().setTranslationY(translateY);
}
/**
* 获取容器中首个控件
*/
private View getChild() {
return getChildAt(0);
}
/**
* 缩放手势监听
*/
private class CustomOnScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
float tempScale =curScale * detector.getScaleFactor();
setScale(tempScale);
return true;
}else{
return false;
}
}
}
/**
* 手势监听
*/
private class CustomOnGestureListener extends GestureDetector.SimpleOnGestureListener {
/**
* 用户按下触摸屏,并拖动
*/
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
float transX =translateX -= distanceX;
float transY =translateY -= distanceY;
setTrans(transX, transY);
return true;
}else{
return false;
}
}
/**
* 用户双击屏幕
*/
@Override
public boolean onDoubleTap(MotionEvent e) {
//因Android7以下的手机缩放方法异常,把缩放功能控制在Android7以上的手机才能使用
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
float tempScale;
if (curScale >=MIN_SCALE && curScale < MID_SCALE){
tempScale =MID_SCALE;
}else if (curScale >=MID_SCALE && curScale < MAX_SCALE){
tempScale =MAX_SCALE;
}else {
tempScale =MIN_SCALE;
}
setScale(tempScale);
return true;
}else{
return false;
}
}
}
}
使用方式
2021年1月15日程序猿小钟带着ScalableViewContainer到此一游~
网友评论