[安卓]!新人首贴!安卓开发实现在任何Activity下更新悬浮窗内容

首先感谢多位CSDN大神的指导!如果本文有任何不对的地方,欢迎指出。
个人查了很多资料,都没有相关的指导,大部分的教程都只是实现了悬浮窗,并没有涉及悬浮窗内容的更新问题。

我的这个demo实现了在一个Activity生成悬浮窗后,在其他任何Activity或者是Serivce或者是线程中,都可以对悬浮窗的内容进行更新。

实现思路

通过发送系统广播的方法,通知悬浮窗类对其自身的内容进行更新

实现过程

1,新建一个类,继承Service,在这个类中实现一个可拖动的悬浮窗,并注册一个广播接收器,在其中读取特定的广播,并依据广播内容更新悬浮窗。
2,在其他需要更新悬浮窗的地方,发送一个特定的广播。

demo说明

1,按下相应按钮可以打开/关闭悬浮窗。
2,按下测试,会新建一个线程,在线程中延时发送广播,更新悬浮窗内容。
3,实际测试在别的Activity中发送相应广播,也可以更新悬浮窗。

源代码

  • 悬浮窗的实现类:FxService.java
package com.application.mac.floating_test4;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

public class FxService extends Service
{

    static final String receive_show = "Float_window_show";

    //注册广播
    private MsgReceiver msgReceiver;

    //定义浮动窗口布局
    LinearLayout mFloatLayout;
    WindowManager.LayoutParams wmParams;
    //创建浮动窗口设置布局参数的对象
    WindowManager mWindowManager;

    Button mFloatView_Button;
    TextView mFloatView_textView;

    private static final String TAG = "FxService";

    /**
     * 广播接收器
     *
     */
    public class MsgReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            //此处从广播中取出数据,并写入你想要的函数
            String string = intent.getStringExtra(receive_show);
            mFloatView_textView.setText(string);
        }

    }

    @Override
    public void onCreate()
    {
        // TODO Auto-generated method stub
        super.onCreate();
        Log.i(TAG, "on_create");
        createFloatView();

        //动态注册广播接收器
        msgReceiver = new MsgReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.application.mac.RECEIVER");
        registerReceiver(msgReceiver, intentFilter);
    }

    @Override
    public IBinder onBind(Intent intent)
    {
        // TODO Auto-generated method stub
        return null;
    }

    private void createFloatView()
    {
        wmParams = new WindowManager.LayoutParams();
        //获取的是WindowManagerImpl.CompatModeWrapper
        mWindowManager = (WindowManager)getApplication().getSystemService(getApplication().WINDOW_SERVICE);
        Log.i(TAG, "mWindowManager--->" + mWindowManager);
        //设置window type
        wmParams.type = WindowManager.LayoutParams.TYPE_PHONE;
        //设置图片格式,效果为背景透明
        wmParams.format = PixelFormat.RGBA_8888;
        //设置浮动窗口不可聚焦(实现操作除浮动窗口外的其他可见窗口的操作)
        wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        //调整悬浮窗显示的停靠位置为左侧置顶
        wmParams.gravity = Gravity.LEFT | Gravity.TOP;
        // 以屏幕左上角为原点,设置x、y初始值,相对于gravity
        wmParams.x = 0;
        wmParams.y = 0;

        //设置悬浮窗口长宽数据
        wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
        wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;

         /*// 设置悬浮窗口长宽数据
        wmParams.width = 200;
        wmParams.height = 80;*/

        LayoutInflater inflater = LayoutInflater.from(getApplication());
        //获取浮动窗口视图所在布局
        mFloatLayout = (LinearLayout) inflater.inflate(R.layout.float_layout, null);
        //添加mFloatLayout
        mWindowManager.addView(mFloatLayout, wmParams);
        //浮动窗口按钮
        mFloatView_Button = (Button)mFloatLayout.findViewById(R.id.float_id);
        mFloatView_textView = (TextView)mFloatLayout.findViewById(R.id.float_text);
        mFloatView_textView.setText("我是悬浮窗");

        mFloatLayout.measure(View.MeasureSpec.makeMeasureSpec(0,
                View.MeasureSpec.UNSPECIFIED), View.MeasureSpec
                .makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
        Log.i(TAG, "Width/2--->" + mFloatView_Button.getMeasuredWidth()/2);
        Log.i(TAG, "Height/2--->" + mFloatView_Button.getMeasuredHeight()/2);
        //设置监听浮动窗口的触摸移动
        mFloatView_Button.setOnTouchListener(new View.OnTouchListener()
        {

            @Override
            public boolean onTouch(View v, MotionEvent event)
            {
                // TODO Auto-generated method stub
                //getRawX是触摸位置相对于屏幕的坐标,getX是相对于按钮的坐标
                wmParams.x = (int) event.getRawX() - mFloatView_Button.getMeasuredWidth()/2;
                Log.i(TAG, "RawX" + event.getRawX());
                Log.i(TAG, "X" + event.getX());
                //减25为状态栏的高度
                wmParams.y = (int) event.getRawY() - mFloatView_Button.getMeasuredHeight()/2 - 25;
                Log.i(TAG, "RawY" + event.getRawY());
                Log.i(TAG, "Y" + event.getY());
                //刷新
                mWindowManager.updateViewLayout(mFloatLayout, wmParams);
                return false;  //此处必须返回false,否则OnClickListener获取不到监听
            }
        });

        mFloatView_Button.setOnClickListener(new OnClickListener()
        {

            @Override
            public void onClick(View v)
            {
                // TODO Auto-generated method stub
                Toast.makeText(FxService.this, "onClick", Toast.LENGTH_SHORT).show();
                mFloatView_textView.setText("我很丑\n但我很聪明");
            }
        });
    }

    @Override
    public void onDestroy()
    {
        // TODO Auto-generated method stub
        super.onDestroy();
        //注销广播
        unregisterReceiver(msgReceiver);

        if(mFloatLayout != null)
        {
            //移除悬浮窗口
            mWindowManager.removeView(mFloatLayout);
        }
    }
}

接下来是主页面的逻辑

  • MainActivity.java
package com.application.mac.floating_test4;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

import static com.application.mac.floating_test4.FxService.receive_show;

/**
 * 本项目实现了悬浮窗的外部更新
 * 原理:使用了安卓的广播系统,向FxService发送系统广播,从而实现
 * 内容的更新
 */
public class MainActivity extends AppCompatActivity {

    final static String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.text_floating).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(){
                    @Override
                    public void run() {
                        for(int i = 0;i < 60;i++){
                            Intent intent_Receiver = new Intent("com.application.mac.RECEIVER");
                            intent_Receiver.putExtra(receive_show,"现在数到" + i);
                            sendBroadcast(intent_Receiver);
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }.start();
            }
        });

        findViewById(R.id.open_Floating).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,FxService.class);
                startService(intent);
            }
        });
        findViewById(R.id.stop_Floating).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,FxService.class);
                stopService(intent);
            }
        });

    }

    @Override
    protected void onDestroy() {
        Intent intent = new Intent(MainActivity.this,FxService.class);
        stopService(intent);
        super.onDestroy();
    }
}

然后是悬浮窗的布局文件

  • float_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:orientation="vertical"
    android:layout_height="wrap_content">

    <Button
        android:id="@+id/float_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="拖拽"/>

    <TextView
        android:text="default text"
        android:id="@+id/float_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
</LinearLayout>

还有主页面的布局文件

  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
        <Button
            android:id="@+id/text_floating"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:text="测试"/>

        <Button
            android:id="@+id/open_Floating"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_toRightOf="@+id/text_floating"
            android:text="开悬浮窗"/>

        <Button
            android:id="@+id/stop_Floating"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toRightOf="@+id/open_Floating"
            android:layout_alignParentBottom="true"
            android:text="关悬浮窗" />

    </RelativeLayout>
</android.support.constraint.ConstraintLayout>

最后切记在AndroidManiFest.xml中声明相关权限

  • AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.application.mac.floating_test4">

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW"/>
    <uses-permission android:name="android.provider.Settings.ACTION_MANAGE_OVERLAY_PERMISSION"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <service
            android:name=".FxService" >
        </service>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

注意:此demo没有写动态申请权限的逻辑,烦请各位按需要自行实现。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值