Как иметь виджеты вне приложения, используя флаттер и котлин?

Мне нужен способ сделать кнопку или контейнер, которые все еще будут видны, даже когда я закрываю приложение, вот так: https://i.stack.imgur.com/GTpOim.jpg. Но это просто невозможно во флаттере. Итак, я делал канал платформы в своем приложении и пытался создать контейнер и кнопку с нативными компонентами. Но я использую kotlin и не знаю много об этом языке программирования. Есть ли способ, чтобы мой код мог создавать такие виджеты? (Я был бы очень благодарен, если бы вы могли отредактировать мой полный код).

Полный код:

Детонация:

class FloatingContainer extends StatelessWidget {

  static const platform = const MethodChannel('flutter.App.com.channel');

  @override
  Widget build(BuildContext context) {
    return Container ();
  }
  Future<Null> _showNativeView() async {}

}

Котлин:

package com.example.swipe

import android.os.Bundle

import io.flutter.app.FlutterActivity
import io.flutter.plugins.GeneratedPluginRegistrant
import io.flutter.plugin.common.MethodChannel

class MainActivity() : FlutterActivity() {
    private val CHANNEL = "flutter.App.com.channel"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        GeneratedPluginRegistrant.registerWith(this)

        MethodChannel(flutterView, CHANNEL).setMethodCallHandler { call, result ->

        }
    }
}

Ответ 2

Я не знаю о флаттере, но это не сложно в родном Android (Java/Kotlin), вы можете легко сделать это с помощью службы, но вам нужно будет добавить

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

разрешение на ваш манифест. и вы можете запросить это конкретное разрешение, используя фрагмент ниже:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
            Uri.parse("package:" + getPackageName()));
    startActivityForResult(intent, DRAW_OVER_OTHER_APP_PERMISSION);
}

@Override
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
    if (requestCode == DRAW_OVER_OTHER_APP_PERMISSION) {
        //Check if the permission is granted or not.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(this)) {
            initService()
        } else {
            //Permission is not granted
        }
    } else {
        super.onActivityResult(requestCode, resultCode, data);
    }
}

после разрешения все, что вам нужно, - это создать класс обслуживания и использовать класс WindowManager чтобы вывести ваш вид (любой вид, который вам нравится) на экран.

Вы можете использовать этот класс обслуживания, чтобы получить представление:

class FloatingService : Service() {

private var mWindowManager: WindowManager? = null
private var floatView: View? = null

override fun onBind(intent: Intent): IBinder? {
    return null
}

@SuppressLint("ClickableViewAccessibility")
override fun onCreate() {
    super.onCreate()
    //Inflate the floating layout we created
    floatView = LayoutInflater.from(this).inflate(R.layout.layout_floating, null)

    //Add the view to the window.
    val params = WindowManager.LayoutParams(
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.TYPE_PHONE,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
            PixelFormat.TRANSLUCENT)

    //Specify the floating view position
    params.gravity = Gravity.TOP or Gravity.LEFT        //Initially view will be added to top-left corner
    params.x = 0
    params.y = 100

    //Add the view to the window
    mWindowManager = getSystemService(WINDOW_SERVICE) as WindowManager?
    mWindowManager!!.addView(floatView, params)

    //Set the close button.
    val closeButton = floatView!!.findViewById(R.id.close_btn) as ImageView
    closeButton.setOnClickListener {
        stopSelf()
    }

    //Drag and move floating view using user touch action.
    val floatingHeadView = floatView!!.findViewById<ImageView>(R.id.img_head_view)

    floatingHeadView.setOnTouchListener(object : View.OnTouchListener {
        private var lastAction: Int = 0
        private var initialX: Int = 0
        private var initialY: Int = 0
        private var initialTouchX: Float = 0.toFloat()
        private var initialTouchY: Float = 0.toFloat()

        override fun onTouch(v: View?, event: MotionEvent?): Boolean {
            when (event?.action) {
                MotionEvent.ACTION_DOWN -> {

                    //remember the initial position.
                    initialX = params.x
                    initialY = params.y

                    //get the touch location
                    initialTouchX = event.rawX
                    initialTouchY = event.rawY

                    lastAction = event.action
                    return true
                }
                MotionEvent.ACTION_UP -> {
                    //As we implemented on touch listener with ACTION_MOVE,
                    //we have to check if the previous action was ACTION_DOWN
                    //to identify if the user clicked the view or not.
                    if (lastAction == MotionEvent.ACTION_DOWN) {
                        //Open the floating view click.
                        val intent = Intent([email protected], FloatingActivity::class.java)
                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        startActivity(intent)

                        //close the service and remove the floating view 
                        stopSelf()
                    }
                    lastAction = event.action
                    return true
                }
                MotionEvent.ACTION_MOVE -> {
                    //Calculate the X and Y coordinates of the view.
                    params.x = initialX + (event.rawX - initialTouchX).toInt()
                    params.y = initialY + (event.rawY - initialTouchY).toInt()

                    //Update the layout with new X & Y coordinate
                    mWindowManager!!.updateViewLayout(floatView, params)
                    lastAction = event.action
                    return true
                }
            }
            return false
        }
    })
}

override fun onDestroy() {
    super.onDestroy()
    if (floatView != null) mWindowManager!!.removeView(floatView)
}
}

Ответ 3

Это встроенная функция Android, поэтому вы должны написать изначально для Android и IOS. вот ссылка для ответа Чата головы, как посыльный

Я надеюсь, что это поможет вам.

Ответ 4

Здравствуйте, в этом случае вы ищете PlatformChannels. Вы можете просмотреть документацию здесь: https://flutter.dev/docs/development/platform-integration/platform-channels или, если хотите, у меня есть небольшой пост об этом на моем веб-сайте: http://fjbatresv.com/flutter-tambien-habla-nativo/ (выберите свой язык в верхней части сообщения.)

Ответ 5

Это известно как рисовать поверх других приложений.

Эта функция недоступна в iOS, вероятно, причина, по которой флаттер не имеет этой функции или официального пакета для нее.

Но для достижения этой функции в вашем приложении вы можете написать несколько PlatformChannels.

Это разрешение позволит вам рисовать поверх всего.

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

Позволяет приложению открывать окна, используя тип TYPE_SYSTEM_ALERT, показанный поверх всех других приложений. Очень немногие приложения должны использовать это разрешение; Эти окна предназначены для взаимодействия на уровне системы с пользователем.

Постоянное значение: "android.permission.SYSTEM_ALERT_WINDOW"

Этот код также может помочь вам достичь этого.

Вы также можете проверить библиотеку упругих голов Flipkart-Incubator тоже.