main.dart

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:

flutter 长按图片保存到手机的更多相关文章

  1. 微信小程序base64图片保存到手机相册

    问题:base64图片不能直接用wx.saveImageToPhotosAlbum保存到手机相册 解决: 先用fs.writeFile写入本地文件,再wx.saveImageToPhotosAlbum ...

  2. 微信小程序点击按钮将图片保存到手机

    SaveCard: function(e) { let that = this; console.log('保存'); var imgSrc = e.currentTarget.dataset.img ...

  3. iOS,长按图片保存实现方法,轻松搞定!

    1.添加手势识别: UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@s ...

  4. ios 点击放大图片,保存至手机相册

    直接贴.m文件代码 #import "UIImageView+Scale.h" static CGRect oldframe; @implementation UIImageVie ...

  5. 微信APP长按图片禁止保存到本地

    项目遇到一个问题,在web页面中,禁止长按图片保存, 使用css属性:  img { pointer-events: none; } 或者  img { -webkit-user-select: no ...

  6. iOS UIWebview 长按图片,保存到本地相册

    我们所要解决的问题如题目所示:ios中,长按Webview中的图片,将图片保存到本地相册.解决方案:对load的html网页,执行js注入,通过在webview中执行js代码,来响应点击事件,通过js ...

  7. 小程序base64图片格式保存至手机相册

    // 保存图片至相册 saveImg() { //获取文件管理器对象 const fs = wx.getFileSystemManager() //文件保存路径 const Imgpath = wx. ...

  8. [Egret]长按图片分享、分享图片、本地存储

    egret 分享有API可以把一个显示对象树渲染成一个位图纹理,我把它赋值给 HTML 的 Image 元素,就实现了图片的显示,在微信中,通过长按图片可以分享出去.当然在其他浏览器可以保存在本地. ...

  9. js截图及绕过服务器图片保存至本地(html2canvas)

    今天要分享的是用html2canvas根据自己的需求生成截图,并且修复html2canvas截图模糊,以及绕过服务器图片保存至本地. 只需要短短的几行代码,就能根据所需的dom截图,是不是很方便,但是 ...

随机推荐

  1. 像羽毛一样轻的MVVMLight(一)(MVVM 和 MVVMLight简介)

    致敬 在此致敬翁智华大佬,感谢大佬为后辈们写下如此详细的文档,本文将在原文基础上添加些自己的理解,希望这样优秀的文档广为流传. 原文请参考 https://www.cnblogs.com/wzh201 ...

  2. BIO,NIO,AIO 总结

    BIO,NIO,AIO 总结 Java 中的 BIO.NIO和 AIO 理解为是 Java 语言对操作系统的各种 IO 模型的封装.程序员在使用这些 API 的时候,不需要关心操作系统层面的知识,也不 ...

  3. IntelliJ Idea 解决 Could not autowire. No beans of 'xxxx' type found 的错误提示

    IntelliJ Idea 解决 Could not autowire. No beans of 'xxxx' type found 的错误提示哈,在使用 @Autowired 时,今天又遇一坑,这俩 ...

  4. Language Guide (proto3) | proto3 语言指南(十)映射

    Maps - 映射 如果要创建关联映射作为数据定义的一部分,协议缓冲区提供了一种方便的快捷语法: map<key_type, value_type> map_field = N; -其中k ...

  5. 静默安装Oracle也没那么恐怖

    几种必须静默安装的情况 服务器为了减少资源占用,没安装图形组件 不能进入机房,只能远程SSH 想炫(Z)耀(B),静默安装显得有技术含量 磁盘分区要求 如没有特别要求,装机时可按如下分区比较好管理 / ...

  6. Java中把对象、对象bean、list集合、对象数组、Map和Set以及字符串转换成Json

    对象转换为Json 对象bean转换为Json List集合转换为Json 对象数组转换为Json Map集合转换为Json Set集合转为Json 字符串转换为Json 把Java对常用的一些数据转 ...

  7. Spring boot 异步线程池

    package com.loan.msg.config; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandle ...

  8. Dubbo官网实战使用技巧

    原文链接:Dubbo官网实战使用技巧 1.启动时检查: 我们检查依赖的服务是否启动,可利用下面三个属性,优先级从左到右逐渐降低. 如果服务不是强依赖,或者说服务之间可能存在死循环依赖,我们应该将 ch ...

  9. jackson学习之七:常用Field注解

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  10. P1091 合唱队形(LIS)

    题目描述 NNN位同学站成一排,音乐老师要请其中的(N−KN-KN−K)位同学出列,使得剩下的KKK位同学排成合唱队形. 合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2,-,K1,2, ...