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. Web渗透-SQLmap

    Web渗透-SQLmap 一.sqlmap简介 1.1 sqlmap 参数解析 二.sqlmap自动化注入 2.4 提权操作 示例步骤: 1.获得当前数据库 2.获得数据库表 3.获得表的字段 4.获 ...

  2. Spark JDBC系列--取数的四种方式

    Spark JDBC系列--取数的四种方式 一.单分区模式 二.指定Long型column字段的分区模式 三.高自由度的分区模式 四.自定义option参数模式 五.JDBC To Other Dat ...

  3. UML实战总结——机房收费系统UML第一版部分图展

    距离机房收费系统已经过去了近2个月之久,如今的UML图才出来,从软件开发设计的逻辑上来讲这是顺序有问题的,不过,对于我们而言,而且是初次用面向对象的思想去设计和建模,就当是UML的一个实战练手的项目吧 ...

  4. git回退版本,再返回最新分支git pull失败的解决经验

    ​ 点击"蓝字"关注我吧 作者:良知犹存 转载授权以及围观:欢迎添加微信公众号:Conscience_Remains 总述     一篇解决gti分支切换问题的文章,大家应该都有过 ...

  5. HDU - 2328 Corporate Identity(kmp+暴力)

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2328 题意:多组输入,n==0结束.给出n个字符串,求最长公共子串,长度相等则求字典序最小. 题解:(居 ...

  6. Codeforces Round #645 (Div. 2) C. Celex Update

    题目链接:C.Celex Update 题意: 给你如图所示的图形,问从(x1,y1)−>(x2,y2)路径上的不同的元素和的数量是多少. 题解: 从(1,1)到(3,3) 元素和的1−2−4− ...

  7. UESTC 1218 Pick The Sticks

    Time Limit: 15000/10000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit  Status ...

  8. Codeforces Round #653 (Div. 3) B. Multiply by 2, divide by 6 (数学)

    题意:有一个数\(n\),每次操作可以使\(n*=2\)或\(n/=6\)(如果能被整除),求最少操作次数使得\(n=1\),如果不满足,输出\(-1\). 题解:我们只要看\(n\)的质因子即可,如 ...

  9. 2020牛客暑期多校训练营(第二场) F.Fake Maxpooling (单调队列)

    题意:有一个\(n\)x\(m\)的矩阵,\(A_{i,j}=lcm(i,j)\),对于每个\(k\)x\(k\)的子矩阵,其最大元素贡献给答案,求答案的最大值. 题解:矩阵构成我们直接\(i*j/g ...

  10. 【.NET 与树莓派】让喇叭播放音乐

    如果你和老周一样,小时候特别喜欢搞破坏(什么电器都敢拆),那下面这样小喇叭你一定见过. 这种喇叭其实以前很多录音机都用,包括上小学时买来做英语听力的便携录音机.嗯,就是放录音带的那种,录音带也叫磁带或 ...