Android自由拖拽平移组件-自定义view系列(2)


功能简介

自由移动的组件,自由切换是否仅允许在屏幕内移动,可监听是否为点击事件

相关文章讲解:
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技术生活交流

微信


  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值