创建 Xamarin 应用程序并覆盖其他应用程序

Posted

技术标签:

【中文标题】创建 Xamarin 应用程序并覆盖其他应用程序【英文标题】:Creating Xamarin App with overlay over other Applications 【发布时间】:2020-11-26 10:42:08 【问题描述】:

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

很遗憾,我没有找到任何示例代码或文档。

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

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

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

有人知道如何做到这一点吗?

最好的问候,

朱利安

【问题讨论】:

您可以尝试使用浮动窗口。 【参考方案1】:

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

创建一个FloatingService

[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_
   android:layout_>

  <ImageView
    android:id="@+id/iv1"
    android:src="@android:drawable/ic_media_play"
    android:layout_
    android:layout_/>

  <ImageView
    android:id="@+id/iv2"
    android:src="@android:drawable/star_on"
    android:layout_marginLeft="10dp"
    android:layout_
    android:layout_/>
  <ImageView
    android:id="@+id/iv3"
    android:src="@android:drawable/ic_menu_more"
    android:layout_marginLeft="10dp"
    android:layout_
    android:layout_/>
</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)));
            
        
    

并在您的Manifest.xml 中添加&lt;uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /&gt;

效果如下:

【讨论】:

以上是关于创建 Xamarin 应用程序并覆盖其他应用程序的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin 中的 Android ParsePushBroadcastReceiver

覆盖或禁用设置菜单

我们可以覆盖 Xamarin.forms 中的 NAVIGATION BACK BUTTON 按下吗?

Xamarin - 编写一个简单的覆盖/布局

xamarin 错误:NSInternalInconsistencyException 原因:应用程序窗口应在应用程序结束时具有根视图控制器

如何使用 Xamarin Essentials Share 将应用程序链接共享给其他用户并在他们单击后打开应用程序?