123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606 |
- import 'dart:io';
- import 'dart:math';
- import 'package:camera/camera.dart';
- import 'package:douyin_demo/providers/CameraProvider.dart';
- import 'package:firebase_ml_vision/firebase_ml_vision.dart';
- import 'package:flutter/material.dart';
- // import 'package:image_gallery_saver/image_gallery_saver.dart';
- import 'package:provider/provider.dart';
- class CameraPage extends StatelessWidget {
- const CameraPage({Key? key}) : super(key: key);
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- backgroundColor: Theme.of(context).primaryColor,
- body: CameraMain(
- rpx: MediaQuery.of(context).size.width / 750,
- ),
- bottomNavigationBar: BottomAppBar(),
- );
- }
- }
- class CameraMain extends StatefulWidget {
- CameraMain({Key? key, required this.rpx}) : super(key: key);
- final double rpx;
- @override
- _CameraMainState createState() => _CameraMainState();
- }
- class _CameraMainState extends State<CameraMain> {
- late CameraProvider provider;
- double rpx = 0;
- double toTop = 0;
- double outBox = 0;
- double innerBox = 0;
- late CameraController _controller;
- bool findFace = false;
- var cameras;
- @override
- void initState() {
- super.initState();
- // provider = Provider.of<CameraProvider>(context);
- // getCameras();
- rpx = widget.rpx;
- toTop = 100 * rpx;
- outBox = 170 * rpx;
- innerBox = 130 * rpx;
- }
- getCameras() async {
- cameras = await availableCameras();
- _controller = CameraController(cameras[1], ResolutionPreset.medium);
- _controller.initialize().then((_) {
- if (!mounted) {
- return;
- }
- _controller.startImageStream((CameraImage availableImage) {
- _controller.stopImageStream();
- _scanFrame(availableImage);
- });
- setState(() {});
- });
- }
- void _scanFrame(CameraImage availableImage) async {
- final FirebaseVisionImageMetadata metadata = FirebaseVisionImageMetadata(
- rawFormat: availableImage.format.raw,
- size: Size(
- availableImage.width.toDouble(), availableImage.height.toDouble()),
- planeData: availableImage.planes
- .map((currentPlane) => FirebaseVisionImagePlaneMetadata(
- bytesPerRow: currentPlane.bytesPerRow,
- height: currentPlane.height,
- width: currentPlane.width))
- .toList(),
- rotation: ImageRotation.rotation90);
- final FirebaseVisionImage visionImage =
- FirebaseVisionImage.fromBytes(availableImage.planes[0].bytes, metadata);
- final FaceDetector detector = FirebaseVision.instance.faceDetector();
- final List<Face> faces = await detector.processImage(visionImage);
- if (faces.length > 0) {
- setState(() {
- findFace = true;
- _controller.startImageStream((CameraImage availableImage) {
- _controller.stopImageStream();
- _scanFrame(availableImage);
- });
- });
- } else {
- setState(() {
- findFace = false;
- _controller.startImageStream((CameraImage availableImage) {
- _controller.stopImageStream();
- _scanFrame(availableImage);
- });
- });
- }
- // for (TextBlock block in visionText.blocks) {
- // // final Rectangle<int> boundingBox = block.boundingBox;
- // // final List<Point<int>> cornerPoints = block.cornerPoints;
- // print(block.text);
- // final List<RecognizedLanguage> languages = block.recognizedLanguages;
- // for (TextLine line in block.lines) {
- // // Same getters as TextBlock
- // print(line.text);
- // for (TextElement element in line.elements) {
- // // Same getters as TextBlock
- // print(element.text);
- // }
- // }
- // }
- }
- @override
- void dispose() {
- _controller.dispose();
- super.dispose();
- }
- @override
- Widget build(BuildContext context) {
- provider = Provider.of<CameraProvider>(context);
- _controller = provider.cameraController;
- if (_controller == null) {
- return Container(
- child: Center(child: CircularProgressIndicator()),
- );
- }
- bool ifMakeVideo = provider.ifMakeVideo;
- if (_controller.value == null) {
- return Container(
- child: Center(child: CircularProgressIndicator()),
- );
- }
- final size = MediaQuery.of(context).size;
- return _controller.value.isInitialized
- ? Stack(children: [
- // Camera.open(cameraId),
- findFace
- ? Positioned(
- top: 0,
- left: 0,
- child: Container(
- width: 100,
- height: 100,
- color: Colors.red,
- ))
- : Container(),
- ClipRect(
- child: Transform.scale(
- scale: _controller.value.aspectRatio / size.aspectRatio,
- child: Center(
- child: AspectRatio(
- aspectRatio: _controller.value.aspectRatio,
- child: CameraPreview(_controller),
- ),
- ),
- )),
- Positioned(
- //顶部关闭按钮
- top: toTop,
- left: 30 * rpx,
- child: IconButton(
- icon: Icon(
- Icons.close,
- color: Colors.white,
- size: 60 * rpx,
- ),
- onPressed: () {
- Navigator.pop(context);
- },
- ),
- ),
- Positioned(
- //选择音乐
- top: toTop,
- left: 250 * rpx,
- child: Container(
- width: 250 * rpx,
- child: TextButton(
- onPressed: () {},
- child: Row(
- children: [
- Icon(
- Icons.music_note,
- color: Colors.white,
- ),
- SizedBox(
- width: 10 * rpx,
- ),
- Text(
- "选择音乐",
- style: TextStyle(color: Colors.white),
- ),
- ],
- ),
- ),
- ),
- ),
- Positioned(
- //拍照按钮
- bottom: 140 * rpx,
- // left: (750*rpx-outBox)/2,
- child: Container(
- width: 750 * rpx,
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- children: [
- ifMakeVideo
- ? Container(
- width: 80 * rpx,
- )
- : IconWithText(
- icon: Icon(
- Icons.search,
- color: Colors.white,
- ),
- text: "道具"),
- ifMakeVideo
- ? AnimVideoButton(
- rpx: rpx,
- outWidth: outBox,
- innerWidth: innerBox - 30 * rpx,
- provider: provider,
- )
- : CircleTakePhoto(
- outBox: outBox,
- innerBox: innerBox,
- ),
- ifMakeVideo
- ? IconButton(
- padding: EdgeInsets.all(0),
- icon: Icon(
- Icons.check_circle,
- color: Color.fromARGB(255, 219, 48, 85),
- size: 80 * rpx,
- ),
- onPressed: () async {
- provider.cameraController
- .stopVideoRecording();
- // await ImageGallerySaver.saveFile(
- // provider.fileName);
- File(provider.fileName).delete();
- },
- )
- : IconWithText(
- icon: Icon(
- Icons.search,
- color: Colors.white,
- ),
- text: "道具"),
- ])),
- ),
- Positioned(
- bottom: 40 * rpx,
- child: ScrollBottomBar(
- rpx: rpx,
- ),
- ),
- Positioned(
- right: 30 * rpx,
- top: 80 * rpx,
- child: IconButton(
- icon: Icon(Icons.camera_front),
- onPressed: () {
- provider.changeCamera();
- }),
- )
- ])
- : Container();
- }
- }
- class AnimVideoButton extends StatefulWidget {
- AnimVideoButton(
- {Key? key,
- required this.outWidth,
- required this.innerWidth,
- required this.rpx,
- required this.provider})
- : super(key: key);
- final double outWidth;
- final double innerWidth;
- final double rpx;
- final CameraProvider provider;
- _AnimVideoButtonState createState() => _AnimVideoButtonState();
- }
- class _AnimVideoButtonState extends State<AnimVideoButton>
- with TickerProviderStateMixin {
- late Animation<double> animation;
- late AnimationController controller;
- double outWidth = 0;
- double innerWidth = 0;
- double outBorder = 0;
- double rpx = 0;
- double maxBorder = 0;
- bool ifRecording = false;
- late CameraProvider provider;
- double curBorder = 0;
- @override
- void dispose() {
- controller.dispose();
- super.dispose();
- }
- @override
- void initState() {
- super.initState();
- ifRecording = true;
- provider = widget.provider;
- outWidth = widget.outWidth;
- innerWidth = widget.innerWidth;
- rpx = widget.rpx;
- outBorder = 5 * rpx;
- maxBorder = (outWidth - innerWidth) / 2 - 10 * rpx;
- curBorder = outBorder;
- controller =
- AnimationController(duration: Duration(milliseconds: 500), vsync: this);
- animation =
- Tween<double>(begin: outBorder, end: maxBorder).animate(controller)
- ..addListener(() {
- setState(() {
- curBorder = animation.value;
- });
- });
- controller.repeat(reverse: true);
- }
- pauseRecording() {
- // provider.cameraController.pauseVideoRecording();
- controller.stop();
- provider.cameraController.pauseVideoRecording();
- setState(() {
- ifRecording = false;
- });
- }
- resumeRecording() {
- // provider.cameraController.resumeVideoRecording();
- controller.repeat(reverse: true);
- provider.cameraController.resumeVideoRecording();
- setState(() {
- ifRecording = true;
- });
- }
- @override
- Widget build(BuildContext context) {
- return Container(
- width: outWidth,
- height: outWidth,
- decoration: BoxDecoration(
- shape: BoxShape.circle,
- color: Colors.transparent,
- border: Border.all(
- width: curBorder, color: Color.fromARGB(128, 219, 48, 85))),
- child: Container(
- child: !ifRecording
- ? IconButton(
- padding: EdgeInsets.all(0),
- icon: Icon(
- Icons.play_arrow,
- size: innerWidth,
- color: Color.fromARGB(255, 219, 48, 85),
- ),
- onPressed: () {
- resumeRecording();
- },
- )
- : IconButton(
- padding: EdgeInsets.all(0),
- icon: Icon(
- Icons.pause,
- size: innerWidth,
- color: Color.fromARGB(255, 219, 48, 85),
- ),
- onPressed: () {
- pauseRecording();
- },
- ),
- ),
- );
- }
- }
- class ScrollBottomBar extends StatefulWidget {
- ScrollBottomBar({Key? key, required this.rpx}) : super(key: key);
- final double rpx;
- _ScrollBottomBarState createState() => _ScrollBottomBarState();
- }
- class _ScrollBottomBarState extends State<ScrollBottomBar> {
- double rpx=0;
- double eachWidth = 0;
- double eachSide = 0;
- List<String> items=[];
- late ScrollController controller;
- double startX = 0;
- double finalX = 0;
- double minValue = 0;
- double maxValue = 0;
- double curX = 0;
- int curIndex = 0;
- @override
- void initState() {
- super.initState();
- rpx = widget.rpx;
- eachWidth = 130 * rpx;
- eachSide = (750 - eachWidth / rpx) / 2 * rpx;
- curIndex = 2;
- minValue = 0;
- items = [
- '拍照',
- '拍15秒',
- '拍60秒',
- '影集',
- '开直播',
- ];
- maxValue = (items.length - 1) * eachWidth;
- curX = curIndex * eachWidth;
- controller = ScrollController(initialScrollOffset: curX);
- }
- moveToItem(index) {
- curX = index * eachWidth;
- controller.animateTo(curX,
- duration: Duration(milliseconds: 200), curve: Curves.linear);
- setState(() {
- curX = curX;
- curIndex = index;
- });
- }
- @override
- Widget build(BuildContext context) {
- return Column(children: [
- Listener(
- onPointerDown: (result) {
- setState(() {
- startX = result.position.dx;
- });
- },
- onPointerMove: (result) {
- double moveValue = result.position.dx;
- double moved = startX - moveValue;
- // curX+moved
- double afterMoved = min(max(curX + moved, minValue), maxValue);
- setState(() {
- curX = afterMoved;
- startX = result.position.dx;
- });
- },
- onPointerUp: (result) {
- int index = 0;
- double finalPosition = curX - eachWidth / 2;
- index = (finalPosition / eachWidth).ceil();
- moveToItem(index);
- },
- child: Container(
- width: 750 * rpx,
- height: 100 * rpx,
- child: SingleChildScrollView(
- scrollDirection: Axis.horizontal,
- controller: controller,
- child: Container(
- child: Row(
- mainAxisSize: MainAxisSize.min,
- children: [
- SizedBox(
- width: eachSide,
- ),
- Row(
- children: List.generate(items.length, (index) {
- return Container(
- width: eachWidth,
- child: TextButton(
- child: Text(
- items[index],
- style: TextStyle(
- color: curIndex == index
- ? Colors.white
- : Colors.white.withOpacity(0.5)),
- ),
- style: ButtonStyle(
- padding:
- MaterialStateProperty.all(EdgeInsets.zero)),
- onPressed: () {
- moveToItem(index);
- },
- ),
- );
- })),
- SizedBox(
- width: eachSide,
- ),
- ],
- ),
- ),
- )),
- ),
- Center(
- child: Container(
- decoration:
- BoxDecoration(shape: BoxShape.circle, color: Colors.white),
- width: 8 * rpx,
- height: 8 * rpx,
- ),
- )
- ]);
- }
- }
- class CircleTakePhoto extends StatelessWidget {
- const CircleTakePhoto(
- {Key? key, required this.outBox, required this.innerBox})
- : super(key: key);
- final double outBox;
- final double innerBox;
- @override
- Widget build(BuildContext context) {
- double rpx = MediaQuery.of(context).size.width / 750;
- CameraProvider provider = Provider.of<CameraProvider>(context);
- // double outBox=160*rpx;
- // double innerBox=130*rpx;
- return Container(
- width: outBox,
- height: outBox,
- padding: EdgeInsets.all(10 * rpx),
- decoration: BoxDecoration(
- color: Colors.transparent,
- borderRadius: BorderRadius.circular(90 * rpx),
- border: Border.all(
- width: 10 * rpx, color: Color.fromARGB(128, 219, 48, 85)),
- ),
- child: TextButton(
- style:
- ButtonStyle(padding: MaterialStateProperty.all(EdgeInsets.zero)),
- onPressed: () async {
- // provider.changeFileName('png');
- // print(provider.fileName);
- // await provider.cameraController
- // .takePicture(provider.fileName)
- // .then((_) {
- // // Navigator.push(context, MaterialPageRoute(fullscreenDialog: true,builder: (_){
- // // return Image.file(File(provider.fileName) );
- // // }));
- // ImagePickerSaver.saveFile(
- // fileData: File(provider.fileName).readAsBytesSync());
- // });
- provider.changeFileName('mp4');
- provider.cameraController.startVideoRecording(provider.fileName);
- // provider.cameraController.startVideoRecording();
- provider.changePhotoWidget();
- },
- child: Container(
- width: innerBox,
- height: innerBox,
- alignment: Alignment.center,
- decoration: BoxDecoration(
- color: Color.fromARGB(255, 219, 48, 85),
- borderRadius: BorderRadius.circular(75 * rpx)),
- )),
- );
- }
- }
- class IconWithText extends StatelessWidget {
- const IconWithText({Key? key, required this.icon, required this.text})
- : super(key: key);
- final Icon icon;
- final String text;
- @override
- Widget build(BuildContext context) {
- return Column(
- children: [
- icon,
- Text(
- text,
- style: TextStyle(color: Colors.white),
- )
- ],
- );
- }
- }
|