import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:loading_animation_widget/loading_animation_widget.dart'; import 'package:skywood/global/const/common_color.dart'; import 'package:skywood/utils/tools/widgets/sky_app_bar.dart'; import 'package:webview_flutter/webview_flutter.dart'; import '../../../utils/tools/help_img.dart'; /// WebView 页面参数 class WebLinkParams { final String title; final String urlString; final bool showAppbar; const WebLinkParams({ this.title = 'Web View', required this.urlString, this.showAppbar = true, }); } /// WebView 页面 class SkyWebPage extends StatefulWidget { final WebLinkParams params; const SkyWebPage({ super.key, required this.params, }); @override State createState() => _WebLinkViewState(); } class _WebLinkViewState extends State { late WebViewController _webViewController; int _loadingProgress = 0; bool _isLoading = true; bool _hasError = false; String _errorMessage = ''; String _urlString = ''; @override void initState() { super.initState(); _initializeParameters(); _initializeWebView(); _loadUrl(); } void _initializeParameters() { _urlString = _validateAndFixUrl(widget.params.urlString); } void _initializeWebView() { _webViewController = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) ..setBackgroundColor(const Color(0x00FF0000)) ..setNavigationDelegate( NavigationDelegate( onProgress: (int progress) { setState(() { _loadingProgress = progress; }); }, onPageStarted: (String url) { setState(() { _isLoading = true; _hasError = false; _loadingProgress = 0; }); }, onPageFinished: (String url) async { setState(() { _isLoading = false; _loadingProgress = 100; }); // 修改网页背景为透明,文字为白色 await _webViewController.runJavaScript(''' document.body.style.background = 'none'; document.body.style.color = '#fff'; // 修改标题样式 var titleElements = document.getElementsByClassName('title'); for (var i = 0; i < titleElements.length; i++) { titleElements[i].style.display = 'none'; } // 修改文本背景为白色 var bgElements = document.getElementsByClassName('bg-fff'); for (var i = 0; i < bgElements.length; i++) { bgElements[i].style.background = 'none'; bgElements[i].style.paddingTop = '0px'; } // 修改所有文本元素为白色 var allElements = document.getElementsByTagName('*'); for (var i = 0; i < allElements.length; i++) { allElements[i].style.color = '#fff'; } // 修改链接颜色 var links = document.getElementsByTagName('a'); for (var i = 0; i < links.length; i++) { links[i].style.color = '#87CEEB'; } '''); }, onHttpError: (HttpResponseError error) { setState(() { _hasError = true; _errorMessage = 'HTTP Error: ${error.response?.statusCode ?? "Unknown"}'; _isLoading = false; }); }, onWebResourceError: (WebResourceError error) { setState(() { _hasError = true; _errorMessage = error.description; _isLoading = false; }); }, onNavigationRequest: (NavigationRequest request) { return NavigationDecision.navigate; }, ), ); } void _loadUrl() { if (_urlString.isEmpty) { setState(() { _hasError = true; _errorMessage = 'Invalid URL'; _isLoading = false; }); return; } try { final uri = Uri.parse(_urlString); _webViewController.loadRequest(uri); } catch (e) { setState(() { _hasError = true; _errorMessage = 'Failed to load URL: $e'; _isLoading = false; }); } } String _validateAndFixUrl(String url) { if (url.isEmpty) { return ''; } url = url.trim(); // Already has a valid scheme if (url.startsWith('http://') || url.startsWith('https://')) { return url; } // Looks like a domain (has a dot and no spaces) if (url.contains('.') && !url.contains(' ')) { return 'https://$url'; } // Treat as search query return 'https://www.google.com/search?q=${Uri.encodeComponent(url)}'; } void _reload() { setState(() { _hasError = false; _isLoading = true; _loadingProgress = 0; _errorMessage = ''; }); _initializeWebView(); _loadUrl(); } void _goBack() { _webViewController.goBack(); } void _goForward() { _webViewController.goForward(); } @override void dispose() { _webViewController.clearCache(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( extendBodyBehindAppBar: true, appBar: widget.params.showAppbar ? _buildAppBar() : null, body: _buildBody(), ); } PreferredSizeWidget _buildAppBar() { return SkyAppBar( backgroundColor: Colors.transparent, title: widget.params.title, titleColor: Colors.white, actions: [ IconButton( icon: const Icon(Icons.refresh, color: Colors.white,), onPressed: _reload, ), ], ); } Widget _buildBody() { return Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ CommonColor.primacyColor, Color(0xFF2D1B4E), ], ), ), child: SafeArea( child: Column( children: [ // 加载进度条(可选) if (_isLoading) LinearProgressIndicator( value: _loadingProgress / 100, backgroundColor: Colors.white.withOpacity(0.2), valueColor: const AlwaysStoppedAnimation( Color(0xFFFB98E0), ), ), Expanded( child: _buildContent(), ), ], ), ), ); } Widget _buildContent() { if (_isLoading) { return Center( child: SizedBox( width: 120, height: 120, child: Image.asset(ConstImg.loading, fit: BoxFit.fill), ), ); } if (_hasError) { return _buildErrorWidget(); } return WebViewWidget( controller: _webViewController, ); } Widget _buildErrorWidget() { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.error_outline, size: 64.w, color: Colors.white.withOpacity(0.6), ), SizedBox(height: 16.h), Text( _errorMessage, style: TextStyle( color: Colors.white.withOpacity(0.8), fontSize: 16.sp, ), textAlign: TextAlign.center, ), SizedBox(height: 24.h), ElevatedButton( onPressed: _reload, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFFB98E0), foregroundColor: Colors.white, ), child: const Text('重试'), ), ], ), ); } }