flutter 长按图片保存到手机
阅读原文时间:2023年07月09日阅读:3
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;
import 'package:file_picker/file_picker.dart';
import 'package:permission_handler/permission_handler.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  String url = "https://i.loli.net/2020/01/14/w1dcNtf4SECG6yX.jpg";

  Offset _tapPosition;

  void _showCustomMenu() {
    final RenderBox overlay = Overlay.of(context).context.findRenderObject();

    showMenu(
      context: context,
      items: <PopupMenuEntry<int>>[
        const PopupMenuItem<int>(
          value: 1,
          child: Text('Download'),
        ),
      ],
      position: RelativeRect.fromRect(
          _tapPosition & Size.zero, // smaller rect, the touch area
          Offset.zero & overlay.size // Bigger rect, the entire screen
          ),
    ).then<void>((int r) {
      if (r == null) {
        print('cancel');
        return;
      }

      if (r == 1) _download();
    });
  }

  void _storePosition(TapDownDetails details) {
    _tapPosition = details.globalPosition;
  }

  void _download() async {
    /// 自动选择文件夹
    /// /Android/data/com.<appname>/files
    // final directory = await getExternalStorageDirectory();
    // if (directory != null) {
    //   var dirPath = path.join(directory.path, "images");
    //   var dir = Directory(dirPath);

    //   await dir.create(recursive: true);

    //   var name = path.basename(url);
    //   var p = path.join(dirPath, name);

    //   print(p);
    //   await File(p).writeAsBytes(r.bodyBytes);
    //   print("save ok");
    // }

    // 1. 获取权限
    var storageStatus = await Permission.storage.status;

    // 没有权限则申请
    if(storageStatus != PermissionStatus.granted) {
      storageStatus = await Permission.storage.request();
      if(storageStatus != PermissionStatus.granted) {
        return;
      }
    }

    // 2. 获取保存目录
    String dpath = await FilePicker.getDirectoryPath();
    print(dpath);

    if (dpath != null) {
      var name = path.basename(url);
      var p = path.join(dpath, name);

      print(p);

      // 3. 从网络获取图片保存到用户手机
      var r = await http.get(url);
      await File(p).writeAsBytes(r.bodyBytes);
      print("save ok");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home Page'),
      ),
      body: Center(
        child: GestureDetector(
          onLongPress: _showCustomMenu, // 长按打开Menu菜单
          onTapDown: _storePosition, // 按下去的时候记住位置
          child: Image.network(url),
        ),
      ),
    );
  }
}

配置权限:

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

可能需要安装的包:

dependencies:
  http:
  path_provider:
  path:
  file_picker:
  permission_handler: