美文网首页Android
关于android 浮动窗口的使用浅解

关于android 浮动窗口的使用浅解

作者: 从心开始的我 | 来源:发表于2017-06-02 18:33 被阅读172次

    最近项目在搞音频的小窗口播放(不是类似于音乐播放器的那种高端大气上档次的货),经过一系列的挣扎和努力算是搞出和设计师要求的效果了


    效果如下(不要在意图片的名字)


    搜狗截图_看图王.png

    就是这么个小东西,在app内外来回跑的那种(原谅我不能用gift,不知道公司让不让,相信这么浅白的东西,应该都能懂吧...)


    看也看了,那就开撸吧

    1,写一个小窗口的布局

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout android:id="@+id/ll_layout"
                  xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
        >
    
        <LinearLayout
            android:id="@+id/ll_container"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/float_window_back"//.9 图片
            android:gravity="center_vertical"
            android:orientation="horizontal"
            android:paddingLeft="10dp"
            android:paddingRight="10dp">
    
            <FrameLayout
                android:layout_width="40dp"
                android:layout_height="40dp"
                >
    
    
                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_gravity="center"
                    android:scaleType="centerCrop"
                    android:src="@drawable/float_window_img"/>
    
                <ProgressBar
                    android:layout_width="25dp"
                    android:layout_height="25dp"
                    android:layout_gravity="center"
                    android:indeterminateDrawable="@drawable/float_window_anim"/>//动画
            </FrameLayout>
    
    
            <TextView
                android:id="@+id/text_room_id"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_marginLeft="8dp"
                android:layout_weight="1"
                android:ellipsize="end"
                android:gravity="center"
                android:singleLine="true"
                android:textColor="#E6E6E6"
                android:textSize="14sp"/>
    
            <ImageButton
                android:id="@+id/bt_close"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:background="@color/transparent"
                android:paddingLeft="10dp"
                android:paddingRight="10dp"
                android:src="@drawable/float_window_close"
                />
        </LinearLayout>
    
    
    </LinearLayout>
    
    float_window_anim
    
    <?xml version="1.0" encoding="utf-8"?>
    <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false" >
        <item android:drawable="@drawable/float_window_animate_01" android:duration="300"></item>
        <item android:drawable="@drawable/float_window_animate_02" android:duration="300"></item>
        <item android:drawable="@drawable/float_window_animate_03" android:duration="300"></item>
    </animation-list>
    
    

    2,撸一个小窗口的自定义View

    public class FloatWindowView extends LinearLayout implements View.OnClickListener {
        private final TextView text_room_id;
        public final ImageButton bt_close;
        private WindowManager mManager;
        private Context mContext;
        private WindowManager.LayoutParams mParams;
    
        public FloatWindowView(Context context) {
            super(context);
            mContext = context;
            mManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            LayoutInflater.from(context).inflate(R.layout.dialog_video_play, this);
            text_room_id = (TextView) findViewById(R.id.text_room_id);
            bt_close = (ImageButton) findViewById(R.id.bt_close);
            bt_close.setOnClickListener(this);
        }
        
    //外部传入LayoutParams 
        public void setParams(WindowManager.LayoutParams params) {
            this.mParams = params;
        }
    
        int lastX, lastY;
        int paramX, paramY;
        boolean isMove;
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
    
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    lastX = (int) event.getRawX();
                    lastY = (int) event.getRawY();
                    paramX = mParams.x;
                    paramY = mParams.y;
                    break;
                case MotionEvent.ACTION_MOVE:
    
                    int dx = (int) event.getRawX() - lastX;
                    int dy = (int) event.getRawY() - lastY;
                    if (Math.abs(dx) >= 50 || Math.abs(dy) >= 50) {
                        isMove = true;
                    }
                    mParams.x = paramX + dx;
                    mParams.y = paramY + dy;
                    mManager.updateViewLayout(this, mParams);
                    break;
                case MotionEvent.ACTION_UP:
                    if (!isMove) {
                        int x = (int) event.getRawX() - lastX;
                        int y = (int) event.getRawY() - lastY;
                        if (Math.abs(x) <= 50 || Math.abs(y) <= 50) {
                            //模拟点击事件
                          doClick();
                        }
                    }
                    isMove = false;
                    break;
            }
            return true;
    
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.bt_close:
                   //关闭窗口,服务之类的东东
                    break;
            }
        }
        
    }
    
    这里有个插曲,我们不能给整个小窗口的根布局设置点击事件,这样的话 mManager.updateViewLayout(this, mParams);更新小窗口位置的事件就会被拦截,导致小窗口不能跟着手指滑动,因此用了个粗鄙的办法模拟点击事件了
    ```基于我们项目的实现方式,我就直接说我们的方式了
    

    3,在Application中创建,显示并记录小窗口的显示状态

    //显示状态表示
     public boolean inWindowShowing = false;
     private FloatWindowView mFloatWindowView;
    
        public void createFloatView(Context context) {
            if (null == mFloatWindowView) {
                mFloatWindowView = new FloatWindowView(context);
    //获取窗体服务
                WindowManager wm = (WindowManager) getSystemService(
                        Context.WINDOW_SERVICE);
    //创建一个窗体布局参数
                WindowManager.LayoutParams params = new WindowManager.LayoutParams();
    //保证背景无色
                params.format = PixelFormat.TRANSPARENT;
    //设置窗体初始化的位置(这个很纠结,下文再讲)
                params.gravity = Gravity.CENTER_VERTICAL;
                params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                params.width =WindowManager.LayoutParams.WRAP_CONTENT;
                params.height =WindowManager.LayoutParams.WRAP_CONTENT;
    //x坐标的位置(这个是在gravity的基础上的)
                params.x= wm.getDefaultDisplay().getWidth()/2;
    //y坐标位置
                params.y=wm.getDefaultDisplay().getHeight()/2- UIUtils.dip2px(100);
    //这个标识的优先级低于下拉通知栏
                    params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
    //这个就高于了  不推荐使用
    //                params.type = WindowManager.LayoutParams.TYPE_PHONE;
    
    
            /*
             * 下面的flags属性的效果形同“锁定”。 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应。
             * wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL |
             * LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCHABLE;
             */
    //先给浮窗view设置参数,方便滑动时动态改变小窗口位置
                mFloatWindowView.setParams(params);
               //添加到窗体上
                wm.addView(mFloatWindowView, params);
    //显示标识
                inWindowShowing = true;
            }
    
        }
    //这个很简单,从窗体上移除
        public void reMoveFloatView() {
            if (null != mFloatWindowView) {
                WindowManager wm = (WindowManager) getSystemService(
                        Context.WINDOW_SERVICE);
                wm.removeView(mFloatWindowView);
                mFloatWindowView = null;
                inWindowShowing = false;
            }
        }
    
    #然而然而然而,这个小窗口的初始化位置可把我整的够呛,只要把gravity设置成TOP和LEFT,
    #好的可以就是在屏幕的左上角了(当然设置成CENTER就会居中),但是呢  我们的设计说要在界面的右下角
    #并且距离底部导航栏高个20px,那么问题就来了  我把gravity设置成RIGHT|BOTTOM不就行了?NONONO,
    #TOO羊TOO新坡,设置成Bottom  只能在底部移动了就,  设置成Right和Bottom那么就直接不能动了,
    #所以才有了设置成CENTER_VERTICAL,这个位置的的X和Y都是相对于屏幕的中间的,
    #所以让浮窗显示在右边就把X设置成屏幕的一半,下边就把Y设置成高度的一半加上导航栏的高度再加个20px,好吧 位置终于OK 了
    

    这样的话就差不多实现了小窗口了

    关于那些个FLOG的什么意思的直接看这个 传送门--TP


    到此我们可以安安静静的写写文章泡泡X了,可是.....................

    TMD的一些国产ROM默认是把浮窗的权限是关着的...........我曹.....

    不过不要慌 还好前辈们帮我们解决了这个问题(至少90%吧)

    4,浮窗权限的适配

    具体做法传送门--TP

    再次向前辈们致敬...........

    这个实现方式目前是有缺陷的,最好能在service中创建,这样不容易被系统回收,反正问题还是有得,欢迎大家在评论区点评!

    相关文章

      网友评论

        本文标题:关于android 浮动窗口的使用浅解

        本文链接:https://www.haomeiwen.com/subject/altyfxtx.html