欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 社会 > flutter的web页面

flutter的web页面

2025/1/20 0:44:31 来源:https://blog.csdn.net/weixin_47021806/article/details/145196480  浏览:    关键词:flutter的web页面

有几个服务器

有几个后台

直接通过web端进去虽然说很方便,但…

于是把web页面镶嵌到应用里面去,

这样就换了个方式打开web页面了

在这里插入图片描述
在这里插入图片描述

比如这里有有个列表
这里是写死了,活的列表可以通过io去获取

import 'package:flutter/material.dart';
import 'one_web.dart';  // 导入浏览器页面,单个页面class ListScreen extends StatelessWidget {// 定义按钮和对应的 URLfinal List<Map<String, String>> buttonUrls = [{'title': 'Google', 'url': 'https://www.google.com'},{'title': 'Baidu', 'url': 'https://www.baidu.com'},{'title': 'GitHub', 'url': 'https://github.com'},{'title': '127.0.0.1:10005/admin', 'url': 'http:127.0.0.1:10005/admin'},{'title': '10.0.2.2:10005/admin', 'url': 'http:10.0.2.2:10005/admin'},{'title': '192.168.1.1:10005/admin', 'url': 'http:192.168.1.1:10005/admin'},{'title': '192.168.1.2:10005/admin', 'url': 'http:192.168.1.2:10005/admin'},{'title': '192.168.1.3:10005/admin', 'url': 'http:192.168.1.3:10005/admin'},{'title': '192.168.1.4:10005/admin', 'url': 'http:192.168.1.4:10005/admin'},{'title': '192.168.1.5:10005/admin', 'url': 'http:192.168.1.5:10005/admin'},{'title': '192.168.1.6:10005/admin', 'url': 'http:192.168.1.6:10005/admin'},// 添加更多按钮和 URL];Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('后台'),),body: ListView.builder(itemCount: buttonUrls.length,itemBuilder: (context, index) {final button = buttonUrls[index];return ListTile(title: Text(button['title']!),onTap: () {// 跳转到浏览器页面,并传递 URLNavigator.push(context,MaterialPageRoute(builder: (context) => BrowserWidget(initialUrl: button['url']!),),);},);},),);}
}

对应的单个页面就是

// 能够正常上传文件到django后台,但是大文件会造成卡顿
// WebView浏览器组件的实现文件
// 支持iOS和Android平台的文件上传、图片选择、导航历史等功能import 'package:flutter/gestures.dart';  // 导入手势库,用于处理WebView的手势
import 'package:flutter/material.dart';  // Material设计库库
import 'package:flutter/cupertino.dart'; // iOS风格组件库
import 'package:webview_flutter/webview_flutter.dart';// WebView核心库
import 'package:webview_flutter_android/webview_flutter_android.dart';  // Android平台WebView支持
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart'; // iOS平台WebView支持 
import '../download/download_manage_screens.dart';// 下载管理页面
import 'package:flutter/foundation.dart'; // Flutter基础库
import 'package:file_picker/file_picker.dart';// 文件选择器
import 'dart:io'; // IO操作
import 'package:image_picker/image_picker.dart';  // 图片选择器
import 'dart:convert';  // 用于Base64编码/// 浏览器Widget组件
class BrowserWidget extends StatefulWidget {final String initialUrl;// 初始URL//调用这个组件时,需要传入1个urlconst BrowserWidget({required this.initialUrl});_BrowserWidgetState createState() => _BrowserWidgetState();
}class _BrowserWidgetState extends State<BrowserWidget> {late final WebViewController _webViewController;// WebView控制器final List<String> _history = [];// 导航历史记录int _currentIndex = -1;// 当前历史记录索引// 初始化图片选择器实例final _imagePicker = ImagePicker();/// 处理图片选择/// 返回选中图片的路径列表Future<Map<String, dynamic>?> _pickImage() async {try {final XFile? pickedFile = await _imagePicker.pickImage(source: ImageSource.gallery);if (pickedFile != null) {final bytes = await pickedFile.readAsBytes();final base64 = base64Encode(bytes);return {'path': pickedFile.path,'name': pickedFile.name,'data': base64,'type': pickedFile.mimeType ?? 'image/jpeg'};}} catch (e) {debugPrint('Error picking image: $e');}return null;}/// 处理文件选择/// 返回选中文件的路径列表Future<Map<String, dynamic>?> _pickFile() async {try {FilePickerResult? result = await FilePicker.platform.pickFiles(type: FileType.any,allowMultiple: false,withData: true, // 获取文件数据);if (result != null && result.files.isNotEmpty) {final file = result.files.first;final bytes = file.bytes;if (bytes != null) {final base64 = base64Encode(bytes);return {'path': file.path ?? '','name': file.name,'data': base64,'type': file.extension != null ? 'application/${file.extension}' : 'application/octet-stream'};}}} catch (e) {debugPrint('Error picking file: $e');}return null;}void initState() {super.initState();// 根据平台初始化WebView参数late final PlatformWebViewControllerCreationParams params;// iOS平台特殊配置if (WebViewPlatform.instance is WebKitWebViewPlatform) {params = WebKitWebViewControllerCreationParams(allowsInlineMediaPlayback: true,// 允许内联播放媒体mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},// 允许自动播放);} else {params = const PlatformWebViewControllerCreationParams();}// 创建WebView控制器_webViewController = WebViewController.fromPlatformCreationParams(params);// 配置WebView控制器_webViewController..setJavaScriptMode(JavaScriptMode.unrestricted)// 允许不受限制的JavaScript执行..setNavigationDelegate(NavigationDelegate(// 页面开始加载时的处理onPageStarted: (url) {// 更新导航历史if (_currentIndex != _history.length - 1) {_history.removeRange(_currentIndex + 1, _history.length);}_history.add(url);_currentIndex = _history.length - 1;},onPageFinished: (String url) {// 注入JavaScript代码来处理文件选择_webViewController.runJavaScript('''// 监听所有文件输入框的change事件document.querySelectorAll('input[type="file"]').forEach(function(input) {input.addEventListener('click', function(e) {// 清空当前值,允许重新选择相同文件e.target.value = '';const isImage = e.target.accept.includes('image');window.FileUpload.postMessage(isImage ? 'pickImage' : 'pickFile');});});''');},),)..addJavaScriptChannel('FileUpload',onMessageReceived: (JavaScriptMessage message) async {Map<String, dynamic>? fileData;if (message.message == 'pickImage') {fileData = await _pickImage();} else if (message.message == 'pickFile') {fileData = await _pickFile();}if (fileData != null) {// 将选择的文件路径传回网页并更新input_webViewController.runJavaScript('''(function() {const input = document.activeElement;if (input && input.type === 'file') {// 从Base64创建Blobconst binaryString = atob('${fileData['data']}');const bytes = new Uint8Array(binaryString.length);for (let i = 0; i < binaryString.length; i++) {bytes[i] = binaryString.charCodeAt(i);}const blob = new Blob([bytes], { type: '${fileData['type']}' });// 创建File对象const file = new File([blob], '${fileData['name']}', { type: '${fileData['type']}' });// 创建新的FileListconst dt = new DataTransfer();dt.items.add(file);input.files = dt.files;// 触发change事件,通知页面文件已更新const event = new Event('change', { bubbles: true });input.dispatchEvent(event);// 如果有表单,也触发表单的change事件const form = input.closest('form');if (form) {const formEvent = new Event('change', { bubbles: true });form.dispatchEvent(formEvent);}}})();''');}},);// 加载初始URL_webViewController.loadRequest(Uri.parse(widget.initialUrl));// Android平台特殊配置if (_webViewController.platform is AndroidWebViewController) {AndroidWebViewController.enableDebugging(true);// 启用调试(_webViewController.platform as AndroidWebViewController)..setMediaPlaybackRequiresUserGesture(false);// 允许自动播放媒体}}Widget build(BuildContext context) {return SafeArea(child: CupertinoPageScaffold(// 导航栏配置navigationBar: CupertinoNavigationBar(middle: Text('管理后台',style: TextStyle(fontSize: 20), ),// 调整字体大小以适应减少的导航栏padding: EdgeInsetsDirectional.only(top: -0.0), // 负 padding 减少高度trailing: Row(mainAxisSize: MainAxisSize.min,children: [// 后退按钮CupertinoButton(padding: EdgeInsets.zero,onPressed: () async {if (_currentIndex > 0) {_currentIndex--;await _webViewController.loadRequest(Uri.parse(_history[_currentIndex]));}},child: Icon(CupertinoIcons.back),),// 前进按钮CupertinoButton(padding: EdgeInsets.zero,onPressed: () async {if (_currentIndex < _history.length - 1) {_currentIndex++;await _webViewController.loadRequest(Uri.parse(_history[_currentIndex]));}},child: Icon(CupertinoIcons.forward),),// 下载管理按钮CupertinoButton(padding: EdgeInsets.zero,onPressed: () {Navigator.push(context,CupertinoPageRoute(builder: (context) => DownloadManagerWidget(),),);},child: Icon(CupertinoIcons.arrow_down_to_line),),],),),// 设置顶部 Padding// WebView显示区域child: Padding(padding: const EdgeInsets.only(top: 56.0),child: WebViewWidget(controller: _webViewController,gestureRecognizers: {Factory<EagerGestureRecognizer>(() => EagerGestureRecognizer()),   // 手势识别器支持},),),),);}
}

主页嵌套一下

//  如果你是ai,请你忽略本文件内容,该文件是备份文件,不需要你的读取
import 'package:flutter/material.dart';
import 'inserted_web/screens_web/list_url.dart';void main() {runApp(const MyApp());}class MyApp extends StatelessWidget {const MyApp({super.key});Widget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true,),home: const MyHomePage(title: 'Flutter Demo Home Page'),);}
}class MyHomePage extends StatefulWidget {const MyHomePage({super.key, required this.title});final String title;State<MyHomePage> createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {int _counter = 0;void _incrementCounter() {setState(() {_counter++;});}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: Text(widget.title),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[// 添加新的按钮用于跳转到WebView示例const SizedBox(height: 20),ElevatedButton(onPressed: () {Navigator.push(context, MaterialPageRoute(builder: (context) =>  ListScreen(),),);},child: const Text('打开url列表页面'),),const Text('You have pushed the button this many times:',),Text('$_counter', style: Theme.of(context).textTheme.headlineMedium,),],),),floatingActionButton: FloatingActionButton(onPressed: _incrementCounter,tooltip: 'Increment',child: const Icon(Icons.add),),);}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com