Android自由拖拽平移组件
功能简介
自由移动的组件,自由切换是否仅允许在屏幕内移动,可监听是否为点击事件
相关文章讲解:
View.layout如何刷新控件位置?点击跳转
用layout方法刷新控件新位置后,为什么页面有新的组件添加后,会刷新页面,控件回到原来的位置 点击跳转
Gif演示
实现步骤
1.创建SimpleMovingView.java并继承一个view
2.我们可以通过onTouchEvent的方法来获取手势相关信息
3.MotionEvent.ACTION_DOWN
按压的时候记录一下手指相对于SimpleMovingView的位置event.getX() event.getY()
4.MotionEvent.ACTION_MOVE
移动的时候进行计算,当前手势移动的event.getX() event.getY()
减去按压时候记录的位置,则为SimpleMovingView移动的距离。
5.用layout(left,top,right,bottom)
去刷新控件位置即可。
6.用layout方法去刷新控件位置会有个问题,当根视图刷新时,会遍历刷新其所有子视图,那么SimpleMovingView就会回到移动前的位置了。如何解决这个问题可以看这篇文章. 点击跳转 。想了解layout为什么刷新位置看这篇 点击跳转
7.MotionEvent.ACTION_UP
手势抬起的时候,检测是否为点击事件,可以实现setOnMovingViewClickListener
接口用来监听点击事件。
8.如何视为点击事件?判断控件相对于屏幕的位置是否移动,this.getX() this.getY()
可以获取组件相对于屏幕中的位置。手势按下的时候记录一下,抬起的时候记录一下,再进行判断是否一致。一致则视为点击事件。
java代码
/**
* 简介:简单可移动View
* 作者:YFZ
* Android技术生活-QQ交流群:723592501
* 主要功能: 自由移动组件,并可反馈点击事件
* mIsLimitedInScreen 设置是否限制仅在屏幕内移动
* setOnMovingViewClickListener 实现接口,返回点击事件
*/
public class SimpleMovingView extends LinearLayout {
private Context mContext;
//是否限制仅在屏幕内移动
private boolean mIsLimitedInScreen =true;
//屏幕的长宽
private int mScreenHeight,mScreenWidth;
//记录手指按下时,手指相对于组件的X,Y位置.
private float mDownOnViewX =0,mDownOnViewY =0;
//记录手指按下时,组件相对于屏幕的X,Y绝对位置.
private float mDownOnScreenX =0,mDownOnScreenY =0;
//记录手指移动时与按下时的X,Y距离
private float mMoveOnViewXDistance =0,mMoveOnViewYDistance =0;
//记录新位置left top right bottom;
private int mNewLeft=0,mNewTop=0,mNewRight=0,mNewBottom=0;
//点击回调
private OnClickListener mOnClickListener;
public SimpleMovingView(Context context) {
super(context);
initial(context);
}
public SimpleMovingView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initial(context);
}
public SimpleMovingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initial(context);
}
private void initial(Context context){
mContext=context;
DisplayMetrics dm= new DisplayMetrics();
WindowManager wm=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getMetrics( dm );
mScreenHeight =dm.heightPixels;
mScreenWidth =dm.widthPixels;
}
//return true,截获触摸焦点,并处理不同的手势事件
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
mDownOnViewX = event.getX();
mDownOnViewY = event.getY();
mDownOnScreenX= this.getX();
mDownOnScreenY= this.getY();
break;
case MotionEvent.ACTION_MOVE:
mMoveOnViewXDistance =event.getX()- mDownOnViewX;
mMoveOnViewYDistance =event.getY()- mDownOnViewY;
mNewLeft=(int)(getLeft()+ mMoveOnViewXDistance);
mNewTop=(int)(getTop()+ mMoveOnViewYDistance);
mNewRight=(int)(getRight()+ mMoveOnViewXDistance);
mNewBottom=(int)(getBottom()+ mMoveOnViewYDistance);
if(mIsLimitedInScreen){ //如果开启了限制仅允许在屏幕内移动
checkIfOverBoundary();
}
refreshNewPosition();
break;
case MotionEvent.ACTION_UP:
if(null != mOnClickListener){ //如果添加了监听
if(mDownOnScreenX==this.getX() && mDownOnScreenY==this.getY()) { //且组件没有移动
mOnClickListener.isClick(true);
}
}
break;
default:
break;
}
return true;
}
//刷新位置UI
private void refreshNewPosition(){
layout(mNewLeft,mNewTop,mNewRight,mNewBottom); //刷新位置UI
}
//检测是否超出边界
private void checkIfOverBoundary(){
if(mNewLeft<0){ //左边朝边界
mNewLeft=0;
mNewRight=mNewLeft+getWidth();
}
if(mNewTop<0){ //上边朝边界
mNewTop=0;
mNewBottom=mNewTop+getHeight();
}
if(mNewRight>mScreenWidth){ //右边朝边界
mNewRight=mScreenWidth;
mNewLeft=mNewRight-getWidth();
}
if(mNewBottom>mScreenHeight){ //下边朝边界
mNewBottom=mScreenHeight;
mNewTop=mNewBottom-getHeight();
}
}
//向外提供监听接口
public void setOnMovingViewClickListener(OnClickListener onClickListener){
this.mOnClickListener=onClickListener;
}
//接口回调-点击
public interface OnClickListener{
void isClick(boolean isClick);
}
}
Android技术生活交流
微信
![]()