首页 > 解决方案 > 创建 Xamarin 应用程序并覆盖其他应用程序

问题描述

我正在尝试创建一个 xamarin android 应用程序,它应该有一个显示在其他应用程序上方的小覆盖窗口。

不幸的是,我还没有找到示例代码或文档。

我想要实现的是类似于 Apple 控制点、Facebook 聊天点或谷歌地图导航覆盖的东西。

我的手机上还安装了一个简单的 makro 记录器应用程序,只要启用了“在其他应用程序之上绘制”的可访问性权限,它就可以做到这一点。 示例叠加窗口

在上面的屏幕截图中,您可以看到右侧的小录制控件。控制覆盖可以在屏幕上拖动,打开设置等。

任何人都知道如何做到这一点?

最好的祝福,

朱利安

标签: androidxamarinoverlayandroid-picture-in-picture

解决方案


这是一个您可以参考的简单示例。

创建一个浮动服务

[Service]
class FloatingService : Service,Android.Views.View.IOnTouchListener
{
    WindowManagerLayoutParams layoutParams;
    IWindowManager windowManager;
    View floatView;
    public override void OnCreate()
    {
        base.OnCreate();
    }

    [return: GeneratedEnum]
    public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
    {
        showFloatingWindow();
        return StartCommandResult.NotSticky;
    }
    public override IBinder OnBind(Intent intent)
    {
        return null;
    }

    private void showFloatingWindow()
    {
        windowManager = GetSystemService(WindowService).JavaCast<IWindowManager>();
        LayoutInflater mLayoutInflater = LayoutInflater.From(ApplicationContext);
        floatView = mLayoutInflater.Inflate(Resource.Layout.floatview, null);
        floatView.SetBackgroundColor(Android.Graphics.Color.Transparent);
        floatView.SetOnTouchListener(this);
        ImageView iv1 = floatView.FindViewById<ImageView>(Resource.Id.iv1);
        ImageView iv2 = floatView.FindViewById<ImageView>(Resource.Id.iv2);
        ImageView iv3 = floatView.FindViewById<ImageView>(Resource.Id.iv3);
        iv1.Click += delegate { Toast.MakeText(ApplicationContext, "The first Image Click", ToastLength.Short).Show(); };
        iv2.Click += delegate { Toast.MakeText(ApplicationContext, "The second Image Click", ToastLength.Short).Show(); };
        iv3.Click += delegate { Toast.MakeText(ApplicationContext, "The third Image Click", ToastLength.Short).Show(); };
        
        // set LayoutParam
        layoutParams = new WindowManagerLayoutParams();
            if (Build.VERSION.SdkInt >= Build.VERSION_CODES.O)
            {
                layoutParams.Type = WindowManagerTypes.ApplicationOverlay;
            }
            else
            {
                layoutParams.Type = WindowManagerTypes.Phone;
            }
            layoutParams.Flags = WindowManagerFlags.NotTouchModal;
            layoutParams.Flags = WindowManagerFlags.NotFocusable;

            layoutParams.Width = 400;
            layoutParams.Height = 100;
            layoutParams.X = 300;
            layoutParams.Y = 300;
            windowManager.AddView(floatView, layoutParams);
            
        }
    private int x;
    private int y;
    public bool OnTouch(View v, MotionEvent e)
    {
        switch (e.Action)
        {
        
            case MotionEventActions.Down:
                x = (int)e.RawX;
                y = (int)e.RawY;
                break;

            case MotionEventActions.Move:
                int nowX = (int) e.RawX;
                int nowY = (int) e.RawY;
                int movedX = nowX - x;
                int movedY = nowY - y;
                x = nowX;
                y = nowY;
                layoutParams.X = layoutParams.X+ movedX;
                layoutParams.Y = layoutParams.Y + movedY;

        
            windowManager.UpdateViewLayout(floatView, layoutParams);
                break;

            default:
                break;
        }
        return false;
    }
}

floatview.xml:

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

  <ImageView
    android:id="@+id/iv1"
    android:src="@android:drawable/ic_media_play"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

  <ImageView
    android:id="@+id/iv2"
    android:src="@android:drawable/star_on"
    android:layout_marginLeft="10dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
  <ImageView
    android:id="@+id/iv3"
    android:src="@android:drawable/ic_menu_more"
    android:layout_marginLeft="10dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
</LinearLayout>

然后在您的 Activity 中启动 FloatingService :

 button.Click += async delegate
      {
         if (!Settings.CanDrawOverlays(this))
          {
            StartActivityForResult(new Intent(Settings.ActionManageOverlayPermission, Android.Net.Uri.Parse("package:" + PackageName)), 0);
          }
         else
          {
            StartService(new Intent(this, typeof(FloatingService)));

          }
      }

 protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
    {
        if (requestCode == 0)
        {
            if (!Settings.CanDrawOverlays(this))
            {

            }
            else
            {
                StartService(new Intent(this, typeof(FloatingService)));
            }
        }
    }

并添加<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />您的Manifest.xml.

效果如下:

在此处输入图像描述


推荐阅读