仿Launcher文件夹效果的距离算法

仿Launcher文件夹效果的距离算法

需求背景是要实现类似于桌面的图标合并的文件夹需求,但是参考谷歌桌面实现差异过大移植成本很高。github上找到了一个类似的实现库,比较简单,成本较低:https://github.com/AlphaBoom/ClassifyView。但是判断合并还是移动的方法在小屏幕下体验不佳,极易误操作。

一、原方法包括网上一些文档的做法都是通过移动速度和重合的距离判断,如果移动速度较小且距离小于图标一半则判断是移动。如果距离小于1/3则判断是合并。但是从一个图标移向另外一个图标距离一定是先到一半,然后再1/3。如果要达到合并效果,则必须是比较大的速度达到1/2距离,跳过判断移动,然后再达到1/3的距离。这样就有一定概率导致误判,在小屏幕上,这个速度一直都会比较小,阈值更不好取。体验不佳。

(小米早期桌面以及目前发现的华为部分机型桌面也是这种做法)
在这里插入图片描述

二、体验了一些上述之外的机型,总结出了下面这种方法。

假设A在B的左上方,将A拖动到B,如下图,其实是达到1/3的重合距离才触发合并,之前都不需要任何操作,其次是远离,直到1/2才开始触发移动。因为A在B的左上方的时候,其实第一次达到1/2距离时是不需要移动的。所以我们只要结合拖动的图标和目标的图标的相对位置 加上 重合距离判断也可以达到效果。

在这里插入图片描述

距离判断的部分代码如下:

 public int getCurrentState(View selectedView, View targetView, int x, int y,
                               VelocityTracker velocityTracker, int selectedPosition,
                               int targetPosition) {
        if (velocityTracker == null) return ClassifyView.MOVE_STATE_NONE;
        int left = x;
        int top = y;
        int selectX= left + selectedView.getWidth()/2;
        int selectY= top + selectedView.getHeight()/2;
        int targetX= targetView.getLeft() + targetView.getWidth()/2;
        int targetY= targetView.getTop() + targetView.getHeight()/2;
        /**
         * 距离算法:
         * 屏幕太小 速度很难控制
         * 假设一个正方形A从左到右依次靠近并离开另一个正方形B。
         * 状态依次是 None>merge>move>None
         */
        boolean canMerge = canMergeItem(selectedPosition, targetPosition);
        int distance = getDistance(selectX, selectY, targetX, targetY);
        //距离小于1/3宽度
        if(canMerge && distance < targetView.getWidth()/3){
            return ClassifyView.MOVE_STATE_MERGE;
        }
        //距离大于1/3宽度小于1/2宽度
        if(distance < targetView.getWidth()/2){
            if(selectedPosition <= targetPosition){
            	//select原位置在target左上方
                if(canMerge && (targetX-selectX+targetY-selectY) > 0){
                	//select目前在target左上方
                    return ClassifyView.MOVE_STATE_NONE;
                }else {
                    return ClassifyView.MOVE_STATE_MOVE;
                }
            }else {
            	//selectet原位置在target右下方
                if(canMerge && (targetX-selectX+targetY-selectY) < 0){
                	//select目前在target右下方
                    return ClassifyView.MOVE_STATE_NONE;
                }else {
                    return ClassifyView.MOVE_STATE_MOVE;
                }
            }
        }
        //距离大于1/2宽度小于宽度
        if(distance < targetView.getWidth()){
            if(selectedPosition <= targetPosition){
                if((selectX-targetX+selectY-targetY) > 0){
                    //select原位置在target左上方,目前在target右下方
                    return ClassifyView.MOVE_STATE_MOVE;
                }
            }else {
                if((targetX-selectX+targetY-selectY) > 0){
                    //select原位置在target右下方,目前在target左上方
                    return ClassifyView.MOVE_STATE_MOVE;
                }
            }
        }
        return ClassifyView.MOVE_STATE_NONE;
    }
    private int getDistance(int selectX,int selectY,int targetX,int targetY){
        return (int) Math.hypot(selectX-targetX,selectY-targetY);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值