自定义图形拖动是在scene中拖动吗_Android加上一个在所有页面都可以自由拖动的导航键(拒绝浮窗)

一、内容概述

今天突然碰到这么一个需求:用户可以在任意页面点击某个东西回到首页。拿到这个需求的时候我首先想到的是做一个浮动窗口,这样逻辑不用管在每个页面都可见且可点击。但是突然又想到这该死的机型适配,7.0以上的系统需要开启浮窗权限,且不同的机型有不同的权限控制,且这个权限需要用户手动开启,因为这个功能非常重要,业务部提出来的,而且使用频率相当高,果断放弃了这个方案。考虑来考虑去,还是决定自定义一个ViewGroup,然后控制这个ViewGroup可以在屏幕范围内拖动,通过把这个自定义View放到BaseActivity和BaseFragment的布局中,来实现每个页面都可以触达的这么一个功能,虽然方案上有些瑕疵(每个页面的按钮虽然初始位置相同,但是经过拖动后再到下一个页面按钮就和前一个页面的有所不同了),但是好在需要屏幕适配的东西不多,且比较稳定。下面看看如何来实现这个需求。

ff0b8f6ac5744ee26df7b958d74e8c97.png

二、代码实战

自定义View的实现:package com.source.weight;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.widget.LinearLayout;import com.source.utils.PxUtils;import androidx.annotation.Nullable;/** * 自定义一个可以全屏拖动的LinearLayout * create by yangwei * on 2020/8/6 14:11 * @author yangwei */public class DragLinearLayout extends LinearLayout {    /**     * LinearLayout本身的宽度     */    private int width;    /**     * LinearLayout本身的高度     */    private int height;    /**     * 屏幕的宽度     */    private int screenWidth;    /**     * 屏幕的高度     */    private int screenHeight;    /**     * 手指点击屏幕时的x坐标     */    private float downX;    /**     * 手指点击屏幕时的y坐标     */    private float downY;    public DragLinearLayout(Context context) {        super(context);        initScreenWH();    }    public DragLinearLayout(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        initScreenWH();    }    /**     * 初始化屏幕的宽高     */    private void initScreenWH() {        screenWidth = PxUtils.getScreenWidth(getContext());        screenHeight = PxUtils.getScreenHeight(getContext());    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        width = getMeasuredWidth();        height = getMeasuredHeight();    }    @Override    public boolean onTouchEvent(MotionEvent event) {        super.onTouchEvent(event);        if (this.isEnabled()) {            switch (event.getAction()) {                case MotionEvent.ACTION_DOWN:                    downX = event.getX();                    downY = event.getY();                    break;                case MotionEvent.ACTION_MOVE:                    final float xDistance = event.getX() - downX;                    final float yDistance = event.getY() - downY;                    /**                     * 如果水平拖动距离或者横向拖动距离大于15的时候才会执行拖动                     */                    if (Math.abs(xDistance) > 15 || Math.abs(yDistance) > 15) {                        //左上右下位置                        int l, t, r, b;                        l = (int) (getLeft() + xDistance);                        r = l + width;                        t = (int) (getTop() + yDistance);                        b = t + height;                        //如果左边超出屏幕                        if (l <= 0) {                            l = 0;                            r = l + width;                            //如果右边超出屏幕                        } else if (r >= screenWidth) {                            r = screenWidth;                            l = r - width;                        }                        //如果上面超出屏幕                        if (t <= 0) {                            t = 0;                            b = t + height;                            //如果下面超出屏幕                        } else if (b >= screenHeight) {                            b = screenHeight;                            t = b - height;                        }                        this.layout(l, t, r, b);                    }                    break;                case MotionEvent.ACTION_UP:                case MotionEvent.ACTION_CANCEL:                    setPressed(false);                    break;                default:                    Log.e("DragLinearLayout", "执行了未知Action");                    break;            }            return true;        }        return super.onTouchEvent(event);    }}
在BaseActivity中的调用过程: @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.base_layout);        LinearLayout view = findViewById(R.id.linear_continer);        view.addView(LayoutInflater.from(this).inflate(getLayoutId(), null));        initViews();        findViewById(R.id.btn_window).setOnClickListener(v -> {            Toast.makeText(BaseActivity.this, "我点击了", Toast.LENGTH_SHORT).show();        });    }
布局部分:base_layout.xml<?xml version="1.0" encoding="utf-8"?>
229fd0e1054be28efe4a99ba5622ca13.png

三、总结

这样算下来一个简单的可在所有页面全屏拖动的布局就形成了,在布局中还可以放置其他控件,用户可以在其内部实现自己的自定义功能。有些时候在追求绚丽的时候也需要考虑下稳定性,如果没有稳定性,再好的功能也会被用户舍弃。

2f0b57cf79441863f10932c15706b917.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值