本文实例为大家分享了Android实现橡皮筋回弹和平移缩放的具体代码,供大家参考,具体内容如下
前言由于最近在做一个view的平移缩放功能以及橡皮筋效果,不过网上查到的大多数都是分开实现的,所以我这里把这两种功能整合到了一起
代码实现这里我写把效果分开来写,最后再合并
平移、缩放
mLayout.java
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.FrameLayout;
import android.widget.Scroller;
/**
* Created by ChenZehao
* on 2019/8/4
*/
public class mLayout extends FrameLayout{
// 属性变量
private float translationX; // 移动X
private float translationY; // 移动Y
private float scale = 1; // 伸缩比例
// 移动过程中临时变量
private float actionX;
private float actionY;
private float spacing;
private int moveType; // 0=未选择,1=拖动,2=缩放
private float firstX;
private float firstY;
public mLayout(Context context) {
this(context, null);
}
public mLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public mLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
moveType = 1;
actionX = event.getRawX();
actionY = event.getRawY();
firstX = actionX;
firstY = actionY;
break;
case MotionEvent.ACTION_POINTER_DOWN:
moveType = 2;
spacing = getSpacing(event);
break;
case MotionEvent.ACTION_MOVE:
if (moveType == 1) {
translationX = translationX + event.getRawX() - actionX;
translationY = translationY + event.getRawY() - actionY;
System.out.println();
setTranslationX(translationX);
setTranslationY(translationY);
actionX = event.getRawX();
actionY = event.getRawY();
}
else if (moveType == 2) {
scale = scale * getSpacing(event) / spacing;
if(scale >= 1){
setScaleX(scale);
setScaleY(scale);
}else{
scale = 1;
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
moveType = 0;
break;
}
return true;
}
// 触碰两点间距离
private float getSpacing(MotionEvent event) {
//通过三角函数得到两点间的距离
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
}
橡皮筋回弹
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.FrameLayout;
import android.widget.Scroller;
/**
* Created by ChenZehao
* on 2019/8/4
*/
public class mLayout extends FrameLayout{
//系数可自己更改
private static final float DEFAULT_FATOR = 0.4f;
/**
* 阻尼因子
*/
private float mFator = DEFAULT_FATOR;
private Scroller mScroller;
/**
* 记录上一次触摸事件
*/
private MotionEvent mLastMotionEvent;
public mLayout(Context context) {
this(context, null);
}
public mLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public mLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mScroller = new Scroller(context);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastMotionEvent = MotionEvent.obtain(event);
break;
case MotionEvent.ACTION_MOVE:
int dx = (int) (event.getRawX() - mLastMotionEvent.getRawX());
int dy = (int) (event.getRawY() - mLastMotionEvent.getRawY());
//如果不想对四个方向增加阻尼效果,直接删除即可
//向上平移
if ((Math.abs(dx) < Math.abs(dy)) && dy < 0){
smoothScrollBy(0, -(int) (dy * mFator));
}
//向下平移
else if (Math.abs(dx) < Math.abs(dy) && dy > 0) {
smoothScrollBy(0, -(int) (dy * mFator));
}
//向左平移
else if (Math.abs(dx) > Math.abs(dy) && dx < 0){
smoothScrollBy(-(int) (dx * mFator), 0);
}
//向右平移
else if (Math.abs(dx) > Math.abs(dy) && dx > 0){
smoothScrollBy(-(int) (dx * mFator), 0);
}
mLastMotionEvent = MotionEvent.obtain(event);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
smoothScrollTo(0, 0);
break;
}
return true;
}
private void smoothScrollBy(int dx, int dy) {
mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy);
invalidate();
}
private void smoothScrollTo(int fx, int fy) {
int dx = fx - mScroller.getFinalX();
int dy = fx - mScroller.getFinalY();
smoothScrollBy(dx, dy);
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
super.computeScroll();
}
}
平移、缩放、阻尼效果合并
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.FrameLayout;
import android.widget.Scroller;
/**
* Created by ChenZehao
* on 2019/8/4
*/
public class mLayout extends FrameLayout{
private float scale = 1; // 伸缩比例
// 移动过程中临时变量
private float actionX;
private float actionY;
private float spacing;
private int moveType; // 0=未选择,1=拖动,2=缩放
private float firstX;
private float firstY;
//系数可自己更改
private static final float DEFAULT_FATOR = 0.4f;
/**
* 阻尼因子
*/
private float mFator = DEFAULT_FATOR;
private Scroller mScroller;
/**
* 记录上一次触摸事件
*/
private MotionEvent mLastMotionEvent;
public mLayout(Context context) {
this(context, null);
}
public mLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public mLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mScroller = new Scroller(context);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mLastMotionEvent = MotionEvent.obtain(event);
moveType = 1;
actionX = event.getRawX();
actionY = event.getRawY();
firstX = actionX;
firstY = actionY;
break;
case MotionEvent.ACTION_POINTER_DOWN:
moveType = 2;
spacing = getSpacing(event);
break;
case MotionEvent.ACTION_MOVE:
if (moveType == 1) {
int dx = (int) (event.getRawX() - mLastMotionEvent.getRawX());
int dy = (int) (event.getRawY() - mLastMotionEvent.getRawY());
//如果不想对四个方向增加阻尼效果,直接删除即可
//向上平移
if ((Math.abs(dx) < Math.abs(dy)) && dy < 0){
smoothScrollBy(0, -(int) (dy * mFator));
}
//向下平移
else if (Math.abs(dx) < Math.abs(dy) && dy > 0) {
smoothScrollBy(0, -(int) (dy * mFator));
}
//向左平移
else if (Math.abs(dx) > Math.abs(dy) && dx < 0){
smoothScrollBy(-(int) (dx * mFator), 0);
}
//向右平移
else if (Math.abs(dx) > Math.abs(dy) && dx > 0){
smoothScrollBy(-(int) (dx * mFator), 0);
}
mLastMotionEvent = MotionEvent.obtain(event);
}
else if (moveType == 2) {
scale = scale * getSpacing(event) / spacing;
if(scale >= 1){
setScaleX(scale);
setScaleY(scale);
}else{
scale = 1;
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL:
moveType = 0;
if(scale == 1)
smoothScrollTo(0, 0);
break;
}
return true;
}
private void smoothScrollBy(int dx, int dy) {
mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy);
invalidate();
}
private void smoothScrollTo(int fx, int fy) {
int dx = fx - mScroller.getFinalX();
int dy = fx - mScroller.getFinalY();
smoothScrollBy(dx, dy);
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
super.computeScroll();
}
// 触碰两点间距离
private float getSpacing(MotionEvent event) {
//通过三角函数得到两点间的距离
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
}
使用方法
在xml文件中添加mLayout布局,便可对mLayout里面的控件和布局进行平移、缩放、阻尼效果的操作
功能扩展——在布局中添加button
如果我们在mLayout布局中添加button,那么会出现获取焦点冲突的问题,导致触摸到按钮时无法进行平移等操作,因此我们需要重写button的dispatchTouchEvent函数,因此要创建一个类mButton来继承Button
点击时事件被button获取,因此要将事件通过dispatchTouchEvent回传给父view,再调用父view的onInterceptTouchEvent函数对拦截到的事件进行处理。
代码如下:
mButton.java
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
public class mButton extends android.support.v7.widget.AppCompatButton {
public mButton(Context context) {
super(context);
}
public mButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public mButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(false);
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
break;
}
return super.dispatchTouchEvent(ev);
}
}
mLayout.java
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.FrameLayout;
import android.widget.Scroller;
/**
* Created by ChenZehao
* on 2019/8/4
*/
public class mLayout extends FrameLayout{
private float scale = 1; // 伸缩比例
// 移动过程中临时变量
private float actionX;
private float actionY;
private float spacing;
private int moveType; // 0=未选择,1=拖动,2=缩放
private float firstX;
private float firstY;
//系数可自己更改
private static final float DEFAULT_FATOR = 0.4f;
/**
* 阻尼因子
*/
private float mFator = DEFAULT_FATOR;
private Scroller mScroller;
/**
* 记录上一次触摸事件
*/
private MotionEvent mLastMotionEvent;
public mLayout(Context context) {
this(context, null);
}
public mLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public mLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mScroller = new Scroller(context);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mLastMotionEvent = MotionEvent.obtain(event);
moveType = 1;
actionX = event.getRawX();
actionY = event.getRawY();
firstX = actionX;
firstY = actionY;
break;
case MotionEvent.ACTION_POINTER_DOWN:
moveType = 2;
spacing = getSpacing(event);
break;
case MotionEvent.ACTION_MOVE:
if (moveType == 1) {
int dx = (int) (event.getRawX() - mLastMotionEvent.getRawX());
int dy = (int) (event.getRawY() - mLastMotionEvent.getRawY());
//如果不想对四个方向增加阻尼效果,直接删除即可
//向上平移
if ((Math.abs(dx) < Math.abs(dy)) && dy < 0){
smoothScrollBy(0, -(int) (dy * mFator));
}
//向下平移
else if (Math.abs(dx) < Math.abs(dy) && dy > 0) {
smoothScrollBy(0, -(int) (dy * mFator));
}
//向左平移
else if (Math.abs(dx) > Math.abs(dy) && dx < 0){
smoothScrollBy(-(int) (dx * mFator), 0);
}
//向右平移
else if (Math.abs(dx) > Math.abs(dy) && dx > 0){
smoothScrollBy(-(int) (dx * mFator), 0);
}
mLastMotionEvent = MotionEvent.obtain(event);
}
else if (moveType == 2) {
scale = scale * getSpacing(event) / spacing;
if(scale >= 1){
setScaleX(scale);
setScaleY(scale);
}else{
scale = 1;
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL:
moveType = 0;
if(scale == 1)
smoothScrollTo(0, 0);
break;
}
return true;
}
//拦截子button的事件
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_DOWN:
mLastMotionEvent = MotionEvent.obtain(event);
moveType = 1;
actionX = event.getRawX();
actionY = event.getRawY();
firstX = actionX;
firstY = actionY;
break;
case MotionEvent.ACTION_POINTER_DOWN:
moveType = 2;
spacing = getSpacing(event);
break;
case MotionEvent.ACTION_MOVE:
if (moveType == 1) {
int dx = (int) (event.getRawX() - mLastMotionEvent.getRawX());
int dy = (int) (event.getRawY() - mLastMotionEvent.getRawY());
//如果不想对四个方向增加阻尼效果,直接删除即可
//向上平移
if ((Math.abs(dx) < Math.abs(dy)) && dy < 0){
smoothScrollBy(0, -(int) (dy * mFator));
}
//向下平移
else if (Math.abs(dx) < Math.abs(dy) && dy > 0) {
smoothScrollBy(0, -(int) (dy * mFator));
}
//向左平移
else if (Math.abs(dx) > Math.abs(dy) && dx < 0){
smoothScrollBy(-(int) (dx * mFator), 0);
}
//向右平移
else if (Math.abs(dx) > Math.abs(dy) && dx > 0){
smoothScrollBy(-(int) (dx * mFator), 0);
}
mLastMotionEvent = MotionEvent.obtain(event);
}
else if (moveType == 2) {
scale = scale * getSpacing(event) / spacing;
if(scale >= 1){
setScaleX(scale);
setScaleY(scale);
}else{
scale = 1;
}
}
break;
case MotionEvent.ACTION_UP:
moveType = 0;
if(scale == 1)
smoothScrollTo(0, 0);
if(firstX != event.getRawX() || firstY != event.getRawY())
return true;
break;
case MotionEvent.ACTION_POINTER_UP:
moveType = 0;
if(scale == 1)
smoothScrollTo(0, 0);
break;
case MotionEvent.ACTION_CANCEL:
moveType = 0;
if(scale == 1)
smoothScrollTo(0, 0);
break;
}
return super.onInterceptTouchEvent(event);
}
private void smoothScrollBy(int dx, int dy) {
mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy);
invalidate();
}
private void smoothScrollTo(int fx, int fy) {
int dx = fx - mScroller.getFinalX();
int dy = fx - mScroller.getFinalY();
smoothScrollBy(dx, dy);
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
super.computeScroll();
}
// 触碰两点间距离
private float getSpacing(MotionEvent event) {
//通过三角函数得到两点间的距离
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
}