Можете ли вы использовать Flutter MethodChannel для возврата нативной карты от Java - PullRequest
0 голосов
/ 10 апреля 2020

Я пытаюсь создать виджет из карты навигации собственного вида, используя методы каналов и AndroidViews, но продолжаю сталкиваться с этой проблемой:

E/MethodChannel#flutter/platform_views( 2258): Failed to handle method call
E/MethodChannel#flutter/platform_views( 2258): java.lang.IllegalArgumentException: Cannot add a null child view to a ViewGroup.

Вот код флаттера:

Main.dart

import 'navigation_view.dart';
import 'package:expandable_bottom_sheet/expandable_bottom_sheet.dart';
import 'package:flutter/material.dart';
import 'customButton1.dart';
import 'Constantes.dart';

void main() => runApp(MaterialApp(home: TextViewExample()));

class TextViewExample extends StatefulWidget {
  @override
  _TextViewExampleState createState() => _TextViewExampleState();
}

class _TextViewExampleState extends State<TextViewExample>
    with SingleTickerProviderStateMixin {
  @override
  void initState() {
    super.initState();
  }

  Widget build(BuildContext context) {
//    var s = NavigationView(
//      onNavigationViewCreated: _onNavigationViewCreated,
//    );
    double screenWidth, screenHeight;
    Size size = MediaQuery.of(context).size;
    screenHeight = size.height;
    screenWidth = size.width;
    print("FLUTTER INIT");
    return Scaffold(
        body: SafeArea(
      child: Stack(children: [
        Positioned(
          width: screenWidth,
          height: screenHeight - 220,
          child: Container(
            child: NavigationView(
              onNavigationViewCreated: _onNavigationViewCreated,
            ),
          ),
        ),
        Positioned(
          bottom: 75,
          child: Container(
            height: screenHeight,
            width: screenWidth,


  void _onNavigationViewCreated(NavigationViewController controller) {}
}   

Вот навигационный_двиг_dart

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

typedef void NavigationViewCreatedCallback(NavigationViewController controller);

class NavigationView extends StatefulWidget {
  const NavigationView({
    Key key,
    this.onNavigationViewCreated,
  }) : super(key: key);

  final NavigationViewCreatedCallback onNavigationViewCreated;

  @override
  State<StatefulWidget> createState() => _NavigationViewState();
}

class _NavigationViewState extends State<NavigationView> {
  @override
  Widget build(BuildContext context) {
    if (defaultTargetPlatform == TargetPlatform.android) {
      return AndroidView(
        viewType: 'com.Mavic.Cabinn/navigationview',
        onPlatformViewCreated: _onPlatformViewCreated,
      );
    }
    return Text(
        '$defaultTargetPlatform is not yet supported by the navigation_view plugin');
  }

  void _onPlatformViewCreated(int id) {
    if (widget.onNavigationViewCreated == null) {
      return;
    }
    widget.onNavigationViewCreated(new NavigationViewController._(id));
  }
}

class NavigationViewController {
  NavigationViewController._(int id)
      : _channel = new MethodChannel(
            'com.Mavic.Cabinn/navigationview$id');

  final MethodChannel _channel;

//  Future<void> setNavigation() async {
//    try {
//      Future.delayed(const Duration(seconds: 1), () async {
//        await _channel.invokeMethod('EmpezarNavegacion');
//
//        return;
//      });
//    } on PlatformException catch (e) {
//      print(e);
//    }
//  Future<void> setNavigation() async {
//    assert(AndroidView != null);
//    return _channel.invokeMethod('EmpezarNavegacion');
//  }
//}

  Future<dynamic> setNavigation() async {
    String message;
    try {
      final String result = await _channel.invokeMethod('EmpezarNagevacion');
      message = result;
    } on PlatformException catch (e) {
      print(message);
    }
  }
}

И, наконец, Java Код

package com.example.embeded_java_test;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.location.Location;
import android.os.Bundle;
import android.preference.PreferenceManager;


import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.AbsoluteSizeSpan;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.mapbox.api.directions.v5.DirectionsCriteria;
import com.mapbox.api.directions.v5.models.BannerInstructions;
import com.mapbox.api.directions.v5.models.DirectionsResponse;
import com.mapbox.api.directions.v5.models.DirectionsRoute;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.services.android.navigation.ui.v5.route.NavigationMapRoute;
import com.example.embeded_java_test.R;
import com.mapbox.services.android.navigation.ui.v5.NavigationView;
import com.mapbox.services.android.navigation.ui.v5.NavigationViewOptions;
import com.mapbox.services.android.navigation.ui.v5.OnNavigationReadyCallback;
//import com.mapbox.services.android.navigation.ui.v5.listeners.BannerInstructionsListener;
//import com.mapbox.services.android.navigation.ui.v5.listeners.InstructionListListener;
import com.mapbox.services.android.navigation.ui.v5.listeners.BannerInstructionsListener;
import com.mapbox.services.android.navigation.ui.v5.listeners.InstructionListListener;
import com.mapbox.services.android.navigation.ui.v5.listeners.NavigationListener;
//import com.mapbox.services.android.navigation.ui.v5.listeners.SpeechAnnouncementListener;
//import com.mapbox.services.android.navigation.ui.v5.voice.SpeechAnnouncement;
import com.mapbox.services.android.navigation.ui.v5.listeners.SpeechAnnouncementListener;
import com.mapbox.services.android.navigation.ui.v5.voice.SpeechAnnouncement;
import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute;
import com.mapbox.services.android.navigation.v5.routeprogress.ProgressChangeListener;
import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress;

import java.util.Locale;
import java.util.concurrent.Future;

import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import androidx.appcompat.app.AppCompatDelegate;
import androidx.coordinatorlayout.widget.CoordinatorLayout;

import org.jetbrains.annotations.NotNull;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.platform.PlatformView;
import com.example.embeded_java_test.MainActivity;

public class EmbeddedNavigationActivity extends AppCompatActivity implements OnNavigationReadyCallback,
        NavigationListener, ProgressChangeListener, InstructionListListener, SpeechAnnouncementListener,
        BannerInstructionsListener,PlatformView, MethodCallHandler {

    private  Point ORIGIN = Point.fromLngLat(-77.03194990754128, 38.909664963450105);
    private  Point DESTINATION = Point.fromLngLat(-77.0270025730133, 38.91057077063121);
    private  final int INITIAL_ZOOM = 16;

    private NavigationView navigationView;
    private View spacer;
    private TextView speedWidget;
    private final MethodChannel methodChannel;

    private boolean bottomSheetVisible = true;
    private boolean instructionListShown = false;
    private NavigationMapRoute navigationMapRoute;
//    @Override
//    public void onCreate(@Nullable Bundle savedInstanceState) {
//        super.onCreate(savedInstanceState);
//        navigationView = findViewById(R.id.navigationView);
//        navigationView.onCreate(savedInstanceState);
//        setTheme(R.style.Theme_AppCompat_Light_NoActionBar);
//        //initNightMode();

    @Override
    public void dispose() {}

    private Context context;
    private Activity activity;
    private Bundle savedInstance;


    public EmbeddedNavigationActivity(Context currentContext, Activity currentActivity, Bundle currentBundle,BinaryMessenger messenger, int id)
    {

        new MainActivity();
        MainActivity newMain = new MainActivity();
        this.activity=this;
        System.out.println(activity + "Activity");
        this.context=this;
        System.out.println(context + "Context");


        System.out.println(activity);
        Log.i("Here", "Constructor!!!");

        System.out.println(activity + " This Activity");
        this.savedInstance=currentBundle;
        System.out.println(currentContext + "Context");
//
        methodChannel = new MethodChannel(messenger, "com.Mavic.Cabinn/navigationview_" + id);
        methodChannel.setMethodCallHandler(this);
    }


    @Override
    public View getView() {
        Log.i("Here", "GETVIEW");
        return navigationView;
    }




    public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
        Log.i("MSG", "CALLING SET TEXT");
                switch (methodCall.method) {
            case "EmpezarNavegacion":
                EmpezarNavegacion(methodCall, result);
                    result.success(null);
                break;
            default:
                result.notImplemented();
        }

 }


    public void EmpezarNavegacion(MethodCall methodCall, Result result)
    {
        double LtLang = (double) methodCall.arguments;
        result.success(null);


        Mapbox.getInstance(context, activity.getString(R.string.access_token));
        activity.setContentView(R.layout.cabinn_nav);

        navigationView =activity.findViewById(R.id.navigationView);
        //super.onCreate(savedInstanceState);
        //Mapbox.getInstance(this,getString(R.string.access_token));
        //navigationView =(NavigationView)findViewById(R.id.navigationView);
        if(navigationView==null)
        {
            Log.e("ERROR NAVEGACION","NAVIGATION VIEW ES NULL, NO ESTA SETEADO EL CONTENT");
            return;
        }
        //fabNightModeToggle = findViewById(R.id.fabToggleNightMode);
        //speedWidget = findViewById(R.id.speed_limit);
        //spacer = findViewById(R.id.spacer);
        //setSpeedWidgetAnchor(R.id.summaryBottomSheet);
//        ORIGIN=ORIGEN;
//        DESTINATION=DESTINO;
        CameraPosition initialPosition = new CameraPosition.Builder()
                .target(new LatLng(ORIGIN.latitude(), ORIGIN.longitude()))
                .zoom(INITIAL_ZOOM)
                .build();
        //navigationView.onCreate(savedInstanceState);
        navigationView.onCreate(this.savedInstance);
        navigationView.initialize(this, initialPosition);
    }
    @Override
    public void onNavigationReady(boolean isRunning) {
        //navigationView.findViewById(R.id.instructionLayoutText).setVisibility(View.INVISIBLE);

        navigationView.findViewById(R.id.instructionListLayout).setVisibility(View.INVISIBLE);
        //navigationView.findViewById(R.id.maneuverView).setVisibility(View.INVISIBLE);
        navigationView.findViewById(R.id.summaryBottomSheet).setVisibility(View.INVISIBLE);
        navigationView.findViewById(R.id.feedbackFab).setVisibility(View.INVISIBLE);
        navigationView.findViewById(R.id.subStepText).setVisibility(View.INVISIBLE);
        navigationView.findViewById(R.id.subStepLayout).setVisibility(View.INVISIBLE);
        navigationView.findViewById(R.id.summaryContentLayout).setVisibility(View.INVISIBLE);
        //navigationView.findViewById(R.id.subManeuverView).setVisibility(View.INVISIBLE);
        //navigationView.findViewById(R.id.stepDistanceText).setVisibility(View.INVISIBLE);
        //navigationView.findViewById(R.id.stepPrimaryText).setVisibility(View.INVISIBLE);
        //navigationView.findViewById(R.id.stepSecondaryText).setVisibility(View.INVISIBLE);

        fetchRoute();
    }

    public void onStart_() {
        Log.i("NAV","NAVIGATION START");
        navigationView.onStart();
    }

    public void onResume_() {
        navigationView.onResume();
    }

    public void onLowMemory_() {
        navigationView.onLowMemory();
    }

    public void onBackPressed_() {
// If the navigation view didn't need to do anything, call super
        if (!navigationView.onBackPressed()) {
            super.onBackPressed();
        }
    }

    protected void onSaveInstanceState_(Bundle outState) {
        navigationView.onSaveInstanceState(outState);
    }

    protected void onRestoreInstanceState_(Bundle savedInstanceState) {
        navigationView.onRestoreInstanceState(savedInstanceState);
    }

    public void onPause_() {
        navigationView.onPause();
    }

    public void onStop_() {
        navigationView.onStop();
    }

    protected void onDestroy_() {
        navigationView.onDestroy();
        if (isFinishing()) {
            saveNightModeToPreferences(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
        }
    }
    @Override
    public void onCancelNavigation() {
// Navigation canceled, finish the activity
        finish();
    }
    @Override

    public void onNavigationFinished() {
// Intentionally empty
    }
    @Override

    public void onNavigationRunning() {
// Intentionally empty
    }
    @Override

    public void onProgressChange(Location location, RouteProgress routeProgress) {
        setSpeed(location);
    }
    @Override

    public void onInstructionListVisibilityChanged(boolean shown) {
        instructionListShown = shown;
        speedWidget.setVisibility(shown ? View.GONE : View.VISIBLE);
        if (instructionListShown) {
           // fabNightModeToggle.hide();
        } else if (bottomSheetVisible) {
            //fabNightModeToggle.show();
        }
    }

    @Override
    public SpeechAnnouncement willVoice(SpeechAnnouncement announcement) {
        return SpeechAnnouncement.builder().announcement("All announcements will be the same.").build();
    }

    @Override
    public BannerInstructions willDisplay(BannerInstructions instructions) {
        return instructions;
    }

    private void startNavigation(DirectionsRoute directionsRoute) {
        NavigationViewOptions.Builder options =
                NavigationViewOptions.builder()
                        .navigationListener(this)
                        .directionsRoute(directionsRoute)
                        .shouldSimulateRoute(true)
                        .progressChangeListener(this);
                        //.instructionListListener(this)
                        //.speechAnnouncementListener(this)
                       // .bannerInstructionsListener(this);
        setBottomSheetCallback(options);
        //setupNightModeFab();

        navigationView.startNavigation(options.build());
    }

    private void fetchRoute() {
        NavigationRoute.builder(this.context)
                .accessToken(this.activity.getString(R.string.access_token))
                .origin(ORIGIN)
                .voiceUnits(DirectionsCriteria.METRIC)
                .destination(DESTINATION)
                .alternatives(true)
                .build()
                .getRoute(new Callback<DirectionsResponse>() {
                    @Override
                    public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
                        if(response.body() == null)
                        {
                            Log.e("ERROR RUTA","NO RUTA ENCONTRADA");
                            return;
                        }else if(response.body().routes().size()==0)
                        {
                            Log.e("ERROR RUTA","SIN RUTA ENCONTRADA");
                            return;
                        }
                        DirectionsRoute currentRoute = response.body().routes().get(0);

                        //navigationMapRoute.addRoute(currentRoute);
                        startNavigation(currentRoute);
                    }

                    @Override
                    public void onFailure(Call<DirectionsResponse> call, Throwable t) {

                    }
                });
    }
    void simpleCallBack(Call<DirectionsResponse> call, Response<DirectionsResponse> response)
    {
        DirectionsRoute directionsRoute = response.body().routes().get(0);
        startNavigation(directionsRoute);
    }

    private void setSpeedWidgetAnchor(@IdRes int res) {
        //CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) spacer.getLayoutParams();
        //layoutParams.setAnchorId(res);
        //spacer.setLayoutParams(layoutParams);
    }

    private void setBottomSheetCallback(NavigationViewOptions.Builder options) {
        options.bottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
            @Override
            public void onStateChanged(@NonNull View bottomSheet, int newState) {
                switch (newState) {
                    case BottomSheetBehavior.STATE_HIDDEN:
                        bottomSheetVisible = false;
                        //fabNightModeToggle.hide();
                        setSpeedWidgetAnchor(R.id.recenterBtn);
                        break;
                    case BottomSheetBehavior.STATE_EXPANDED:
                        bottomSheetVisible = true;
                        break;
                    case BottomSheetBehavior.STATE_SETTLING:
                        if (!bottomSheetVisible) {
// View needs to be anchored to the bottom sheet before it is finished expanding
// because of the animation
                            //fabNightModeToggle.show();
                            setSpeedWidgetAnchor(R.id.summaryBottomSheet);
                        }
                        break;
                    default:
                        return;
                }
            }

            @Override
            public void onSlide(@NonNull View bottomSheet, float slideOffset) {
            }
        });
    }

    private void setupNightModeFab() {
        //fabNightModeToggle.setOnClickListener(view -> toggleNightMode());
    }

    private void toggleNightMode() {
        int currentNightMode = getCurrentNightMode();
        alternateNightMode(currentNightMode);
    }

    private void initNightMode() {
       // int nightMode = retrieveNightModeFromPreferences();
        //AppCompatDelegate.setDefaultNightMode(nightMode);
    }

    private int getCurrentNightMode() {
        return getResources().getConfiguration().uiMode
                & Configuration.UI_MODE_NIGHT_MASK;
    }

    private void alternateNightMode(int currentNightMode) {
        int newNightMode;
        if (currentNightMode == Configuration.UI_MODE_NIGHT_YES) {
            newNightMode = AppCompatDelegate.MODE_NIGHT_NO;
        } else {
            newNightMode = AppCompatDelegate.MODE_NIGHT_YES;
        }
        saveNightModeToPreferences(newNightMode);
        recreate();
    }


    private void saveNightModeToPreferences(int nightMode) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        SharedPreferences.Editor editor = preferences.edit();
        //editor.putInt(getString(R.string.current_night_mode), nightMode);
        editor.apply();
    }

    private void setSpeed(Location location) {
        String string = String.format("%d\nMPH", (int) (location.getSpeed() * 2.2369));
        //int mphTextSize = getResources().getDimensionPixelSize(R.dimen.mph_text_size);
        //int speedTextSize = getResources().getDimensionPixelSize(R.dimen.speed_text_size);

        SpannableString spannableString = new SpannableString(string);
       // spannableString.setSpan(new AbsoluteSizeSpan(mphTextSize),
        //        string.length() - 4, string.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);

       // spannableString.setSpan(new AbsoluteSizeSpan(speedTextSize),
         //       0, string.length() - 3, Spanned.SPAN_INCLUSIVE_INCLUSIVE);


    }
}

Я использовал эту статью в качестве справочного материала, чтобы попытаться воспроизвести это, но я ударил многих ударов скорости, пытаясь заставить это работать должным образом: https://medium.com/flutter-community/flutter-platformview-how-to-create-flutter-widgets-from-native-views-366e378115b6

Это вывод моего доктора о трепетании:

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.12.13+hotfix.9, on Linux, locale en_US.UTF-8)

[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[✓] Android Studio (version 3.6)
[✓] Connected device (1 available)

• No issues found!

Как я уже говорил, я пытался найти нулевое значение и искал высоко и низко вопросы, похожие на этот, но У меня не было такой удачи, потому что это не то, что я видел, сделал. Я также проверил, есть ли какие-либо плагины для создания и встроенной карты, и, к сожалению, на данный момент их нет.

...