簡體   English   中英

如何在 flutter 中截取 Google Map 的屏幕截圖

[英]How to take screenshot of Google Map in flutter

我正在使用截圖插件在 flutter 中截圖,但問題是當我截圖時,顯示空白屏幕,之后我什么都沒有。每次都會發生這種情況。我正在使用下面的偽執行此任務。

void main() async {
runApp(MyApp());
}

class MyApp extends StatefulWidget {

@override
_MyAppState createState() => _MyAppState();

 }

 class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
    Completer<GoogleMapController> _controller = Completer();
    LocationData locationdata;
    ScreenshotController screenshotController = ScreenshotController();
    var location;
    var lat = 0.0;
    var lng = 0.0;
    CameraController controller;
    final Set<Marker> _markers = {};
    StreamSubscription<LocationData> locationSubcription;
    LatLng _center;
    File _imageFile;
    static GlobalKey screen = new GlobalKey();
    String imagePath;


      @override
   void initState() {
// TODO: implement initState
super.initState();
// Fetch the available cameras before initializing the app.
WidgetsBinding.instance.addObserver(this);

//  _cameraTogglesRowWidget();

onNewCameraSelected(null);

location = new Location();

_getLocation();

locationSubcription = location.onLocationChanged().listen((location) {
  setState(() {
    locationdata = location;
  });
});
}


 @override
 void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

 @override
 Widget build(BuildContext context) {
  return MaterialApp(
    home: Scaffold(
  appBar: AppBar(
    title: Text('Maps Sample App'),
    backgroundColor: Colors.green[700],
  ),
  body: Container(
    margin: EdgeInsets.all(5),
    child: Column(children: <Widget>[
        Screenshot(
        controller: screenshotController,
      //          RepaintBoundary(
   //            key: screen,
        child:
        Row(
          children: <Widget>[
            Expanded(
                child: Container(
              width: 200,
              height: 200,
              child: GoogleMap(
                  onMapCreated: _onMapCreated,
                  initialCameraPosition: CameraPosition(
                    target: _center,
                    zoom: 15.0,
                  ),
                  markers: _markers),decoration: BoxDecoration(
                  color: Colors.black,
                  border: Border.all(
                    color: controller != null &&
                        controller.value.isRecordingVideo
                        ? Colors.redAccent
                        : Colors.grey,
                    width: 3.0,
                  ),
                )
            ),),
            Expanded(
              child: Container(
                width: 200,
                height: 200,
                child: Padding(
                  padding: const EdgeInsets.all(1.0),
                  child: Center(
                    child: _cameraPreviewWidget(),
                  ),
                ),
                decoration: BoxDecoration(
                  color: Colors.black,
                  border: Border.all(
                    color: controller != null &&
                            controller.value.isRecordingVideo
                        ? Colors.redAccent
                        : Colors.grey,
                    width: 3.0,
                  ),
                ),
              ),
            )
          ],
        )),
     // ),
      _imageFile != null ? Image.file(_imageFile,height: 200,width: 200,) 
   : Container(),
  //          Screenshot(
   //            controller: screenshotController,
  //            child:
 //            imagePath != null ? Image.asset(imagePath,height: 
             100,width: 100,) : Container(),
    //        ),
      RaisedButton(
        onPressed: () {
          screenshotController.capture().then((File image) {
            //Capture Done
            setState(() {
              _imageFile = image;
            });
          }).catchError((onError) {
            print(onError);
          });

        //  onTakePictureButtonPressed();
      //   ScreenShot();
        },
        child: Text('Capture'),
        )
      ]),
      ),
        ));
        }

   ScreenShot() async{
  RenderRepaintBoundary boundary = 
  screen.currentContext.findRenderObject();
  ui.Image image = await boundary.toImage();
   ByteData byteData = await image.toByteData(format: 
  ui.ImageByteFormat.png);

  var filePath = await ImagePickerSaver.saveFile(
    fileData:byteData.buffer.asUint8List() );
  print(filePath);

  }

  void _onMapCreated(GoogleMapController controller) {
   _controller.complete(controller);
 }

      void _getLocation() async {
  var currentLocation;
   try {
    currentLocation = await location.getLocation();
   } catch (e) {
    currentLocation = null;
  }
  setState(() {
  locationdata = currentLocation;
  lat = locationdata.latitude;
  lng = locationdata.longitude;

  _center = LatLng(lat, lng);
  _markers.add(Marker(
    // This marker id can be anything that uniquely identifies each 
   marker.
    markerId: MarkerId(_center.toString()),
    position: _center,
    infoWindow: InfoWindow(
      title: 'Really cool place',
      snippet: '5 Star Rating',
    ),
      icon: BitmapDescriptor.defaultMarker,
  ));
   });
   }

   @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
  if (state == AppLifecycleState.inactive) {
  controller?.dispose();
  } else if (state == AppLifecycleState.resumed) {
  if (controller != null) {
    onNewCameraSelected(controller.description);
    }
  }
 }

   Widget _captureControlRowWidget() {
   return Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  mainAxisSize: MainAxisSize.max,
  children: <Widget>[
    IconButton(
      icon: const Icon(Icons.camera_alt),
      color: Colors.blue,
      onPressed: controller != null &&
          controller.value.isInitialized
          ? onTakePictureButtonPressed
          : null,

     ),
    ],
   );
  }

 String timestamp() => DateTime.now().millisecondsSinceEpoch.toString();

Future<String> takePicture() async {
if (!controller.value.isInitialized) {
 // showInSnackBar('Error: select a camera first.');
  return null;
}
final Directory extDir = await getApplicationDocumentsDirectory();
final String dirPath = '${extDir.path}/Pictures/flutter_test';
await Directory(dirPath).create(recursive: true);
final String filePath = '$dirPath/${timestamp()}.jpg';

if (controller.value.isTakingPicture) {
  // A capture is already pending, do nothing.
  return null;
}

try {
  await controller.takePicture(filePath);
} on CameraException catch (e) {
//  _showCameraException(e);
  return null;
}
return filePath;
 }

void onTakePictureButtonPressed() {
  takePicture().then((String filePath) {
  if (mounted) {
    setState(() {
      imagePath = filePath;

    });
   // if (filePath != null)
      //showInSnackBar('Picture saved to $filePath');
  }
  });
}

 void onNewCameraSelected(CameraDescription cameraDescription) async {
  if (controller != null) {
  await controller.dispose();
   }
  controller = CameraController(
  CameraDescription(
      name: "1",
      lensDirection: CameraLensDirection.front,
      sensorOrientation: 270),
  ResolutionPreset.high,
  enableAudio: true,
   );

  // If the controller is updated then update the UI.
  controller.addListener(() {
  if (mounted) setState(() {});
  if (controller.value.hasError) {
    //  showInSnackBar('Camera error 
  ${controller.value.errorDescription}');
    print(controller.value.errorDescription);
   }
   });

   try {
   await controller.initialize();
  } on CameraException catch (e) {
  print(e);
  //  _showCameraException(e);
  }

  if (mounted) {
  setState(() {});
  }
  }

  Widget _cameraTogglesRowWidget() {
   final List<Widget> toggles = <Widget>[];

  if (cameras.isEmpty) {
    return const Text('No camera found');
  } else {
    for (CameraDescription cameraDescription in cameras) {
     toggles.add(
      SizedBox(
        width: 90.0,
        child: RadioListTile<CameraDescription>(
          title: Icon(getCameraLensIcon(cameraDescription.lensDirection)),
          groupValue: controller?.description,
          value: cameraDescription,
          onChanged: controller != null ? null : onNewCameraSelected,
        ),
      ),
       );
        }
      }

          return Row(children: toggles);
        }

       IconData getCameraLensIcon(CameraLensDirection direction) {
     switch (direction) {
      case CameraLensDirection.back:
       return Icons.camera_rear;
         case CameraLensDirection.front:
     return Icons.camera_front;
        case CameraLensDirection.external:
          return Icons.camera;
         }
        throw ArgumentError('Unknown lens direction');
          }

             Widget _cameraPreviewWidget() {
       if (controller == null || !controller.value.isInitialized) {
       return const Text(
      'Tap a camera',
      style: TextStyle(
        color: Colors.white,
      fontSize: 24.0,
      fontWeight: FontWeight.w900,
      ),
      );
      } else {
   return AspectRatio(
    aspectRatio: controller.value.aspectRatio,
     child: CameraPreview(controller),
    );
    }
   }
        }

''''''

那是代碼 Output: https://i.stack.imgur.com/PMLKu.jpg

但我需要那個 Output: https://i.stack.imgur.com/rAAs8.jpg

我向實現這一點的 Flutter 發送了一個拉取請求。 在他們合並之前,您可以使用我的插件分支: https ://github.com/duzenko/plugins/tree/maps-snapshot

檢查包:google_maps_flutter 2.0.6

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GoogleMap(
        initialCameraPosition: CameraPosition(
          target: LatLng(52.45594441365693, 30.96944870261119),
          zoom: 14,
        ),
        onMapCreated: (controller) async {
          final uin8list = await controller.takeSnapshot(); // its our screenshot

          // For examle, we can convert this uin8list to base64 and send 
          // to photohosting imgbb.com and get url on this image
          final base64image = base64Encode(uin8list);

          //...api post request
        },
      ),

這里的問題是快照方法和截圖插件都在地圖渲染之前拍攝圖像。 flutter_maps 插件中有兩個可用的回調:

  1. onMapCreated觸發太快,而不是在每次重繪時觸發。
  2. onCameraIdle在 Android 上很好,但在 iOS 上第一次渲染時不會觸發。

如果您在onMapCreated回調中放置animateCamera並在onCameraIdle 中捕獲圖像,則可以使用 onCameraIdle 我發現您每次都需要通過添加一個小的隨機縮放偏移來移動相機。

class GoogleMapWidget extends StatefulWidget {
  const GoogleMapWidget(
      {Key? key, required this.latLng, required this.markers})
      : super(key: key);

  final LatLng latLng;

  final Set<Marker> markers;

  @override
  State<GoogleMapWidget> createState() => GoogleMapWidgetState();
}

class GoogleMapWidgetState extends State<GoogleMapWidget> {
  final Completer<GoogleMapController> _mapController =
      Completer<GoogleMapController>();

  Uint8List? imageBytes;

  @override
  Widget build(BuildContext context) {
    return imageBytes != null
        ? Image.memory(imageBytes!, fit: BoxFit.cover)
        : GoogleMap(
            onMapCreated: (GoogleMapController controller) {
              _mapController.complete(controller);
              takeSnapShot();
            },
            initialCameraPosition: CameraPosition(
              target: widget.latLng,
              zoom: 13.0,
            ),
            markers: widget.markers,
            compassEnabled: false,
            indoorViewEnabled: false,
            myLocationEnabled: false,
            myLocationButtonEnabled: false,
            zoomControlsEnabled: false,
            zoomGesturesEnabled: false,
            tiltGesturesEnabled: false,
            scrollGesturesEnabled: false,
            rotateGesturesEnabled: false,
          );
  }

  void takeSnapShot() async {
    GoogleMapController controller = await _mapController.future;
    Future<void>.delayed(const Duration(milliseconds: 1000), () async {
      imageBytes = await controller.takeSnapshot();
      setState(() {});
    });
  }

要獲取唯一 map 內容的屏幕截圖,您可以使用GoogleMapController.takeSnapshot() function。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM