安卓自动吸附,可拖动悬浮窗

博客围绕安卓自动吸附、可拖动悬浮窗展开,虽未给出具体内容,但可知聚焦于安卓系统下悬浮窗的自动吸附与可拖动功能,这在移动开发领域有一定应用价值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import com.huiyingdai.apptest.view.explode.Utils;

import org.kymjs.kjframe.utils.DensityUtils;

/**
 *hx
 */
public abstract class AbastractDragFloatActionButton extends RelativeLayout {
    private int parentHeight;//悬浮的父布局高度
    private int parentWidth;

    public AbastractDragFloatActionButton(Context context) {
        this(context, null, 0);
    }

    public AbastractDragFloatActionButton(Context context, AttributeSet attrs) {
        this(context, attrs, 0);

    }

    public abstract int getLayoutId();

    public abstract void renderView(View view);

    public AbastractDragFloatActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        View view= LayoutInflater.from(context).inflate(getLayoutId(), this);
        renderView(view);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }



    @Override
    protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
        View view = getChildAt(0);
        view.layout(0,0,view.getMeasuredWidth(),view.getMeasuredHeight());
    }

    private int lastX;
    private int lastY;

    private boolean isDrag;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int rawX = (int) event.getRawX();
        int rawY = (int) event.getRawY();
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                setPressed(true);//默认是点击事件
                isDrag=false;//默认是非拖动而是点击事件
                getParent().requestDisallowInterceptTouchEvent(true);//父布局不要拦截子布局的监听
                lastX=rawX;
                lastY=rawY;
                ViewGroup parent;
                if(getParent()!=null){
                    parent= (ViewGroup) getParent();
                    parentHeight=parent.getHeight();
                    parentWidth=parent.getWidth();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                isDrag = (parentHeight > 0 && parentWidth > 0);//只有父布局存在你才可以拖动
                if(!isDrag) break;

                int dx=rawX-lastX;
                int dy=rawY-lastY;
                //这里修复一些华为手机无法触发点击事件
                int distance= (int) Math.sqrt(dx*dx+dy*dy);
                isDrag = distance>0;//只有位移大于0说明拖动了
                if(!isDrag) break;

                float x=getX()+dx;
                float y=getY()+dy;
                //检测是否到达边缘 左上右下
                x=x<0?0:x>parentWidth-getWidth()?parentWidth-getWidth():x;
                y=y<0?0:y>parentHeight-getHeight()?parentHeight-getHeight():y;
                setX(x);
                setY(y);
                lastX=rawX;
                lastY=rawY;
                break;
            case MotionEvent.ACTION_UP:
                //如果是拖动状态下即非点击按压事件
                setPressed(isDrag);
                moveHide(rawX, rawY);
                break;
        }

        //如果不是拖拽,那么就不消费这个事件,以免影响点击事件的处理
        //拖拽事件要自己消费
        return isDrag || super.onTouchEvent(event);
    }


    private void moveHide(int rawX,int rawY) {
        if (rawX >= parentWidth / 2) {
            //靠右吸附
            animate().setInterpolator(new DecelerateInterpolator())
                    .setDuration(500)
                    //.xBy(parentWidth - getWidth() - getX())
                    .xBy(parentWidth - getWidth() - getX() - Utils.dp2Px(15))
                    .start();
        } else {
            //靠左吸附
            //ObjectAnimator oa = ObjectAnimator.ofFloat(this, "x", getX(), 0);
            ObjectAnimator oa = ObjectAnimator.ofFloat(this, "x", getX(),
                    Utils.dp2Px(15));
            oa.setInterpolator(new DecelerateInterpolator());
            oa.setDuration(500);
            oa.start();

        }
        if(rawY>=parentHeight-Utils.dp2Px(50)){ //这里的50是距顶部的距离加上控件一半的高
            animate().setInterpolator(new DecelerateInterpolator())
                    .setDuration(500)
                    //.xBy(parentWidth - getWidth() - getX())
                    .yBy(parentHeight - getHeight() - getY() - Utils.dp2Px(20))
                    .start();
        }else if(rawY<=Utils.dp2Px(112)){//这里的112是距底部的距离加上控件一半的高
            ObjectAnimator oa = ObjectAnimator.ofFloat(this, "y", getY(),
                    Utils.dp2Px(82));
            oa.setInterpolator(new DecelerateInterpolator());
            oa.setDuration(500);
            oa.start();
        }
    }

}


使用



import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;

import com.huiyingdai.apptest.R;
import com.huiyingdai.apptest.application.HydApplication;
import com.hyjf.ui.library.util.MediaUtil;

public class MyButton extends AbastractDragFloatActionButton {
    public MyButton(Context context) {
        super(context);
    }

    public MyButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public int getLayoutId() {
        return R.layout.custom_button;//拿到你自己定义的悬浮布局
    }

    ImageView iv;

    @Override
    public void renderView(View view) {
        //初始化那些布局
        iv= view.findViewById(R.id.iv_event);

    }

    public void setData(String url){
        //MediaUtil.displayImage(HydApplication.getInstance(), url, iv, R.drawable.shape_loading_image, false);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值