Flutter跨视图展示插件crossview的使用

Flutter跨视图展示插件crossview的使用

crossview 是一个用于在 Flutter 应用中展示网页内容的插件。它支持加载本地 HTML、URL 和从资产文件加载 HTML,并提供了对 JavaScript 的调用功能。

获取开始

首先,确保你已经在 pubspec.yaml 文件中添加了 crossview 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  crossview: ^x.x.x  # 请替换为最新版本号

然后运行 flutter pub get 来获取新的依赖。

示例代码

以下是一个完整的示例代码,展示了如何使用 crossview 插件来加载网页内容并进行一些基本操作,如前进、后退、刷新等。

import 'package:flutter/material.dart';
import 'package:crossview/crossview.dart';
import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'CrossView Example App',
      debugShowCheckedModeBanner: false,
      theme: ThemeData.dark(useMaterial3: true),
      home: const CrossViewExample()
    );
  }
}

class CrossViewExample extends StatefulWidget {
  const CrossViewExample({Key? key}) : super(key: key);

  [@override](/user/override)
  State<CrossViewExample> createState() => _CrossViewExampleState();
}

class _CrossViewExampleState extends State<CrossViewExample> {

  late CrossViewController webviewController;

  final initialContent = '<h4> This is some hardcoded HTML code embedded inside the webview <h4> <h2> Hello world! <h2>';

  final executeJsErrorMessage =
      'Failed to execute this task because the current content is (probably) URL that allows iframe embedding, on Web.\n\n'
      'A short reason for this is that, when a normal URL is embedded in the iframe, you do not actually own that content so you cant call your custom functions\n'
      '(read the documentation to find out why).';

  Size get screenSize => MediaQuery.of(context).size;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
          title: const Text('CrossView Page'),
          actions: [
            IconButton(
              onPressed: () => _showMenu(),
              icon: const Icon(Icons.info_outline),
            ),
          ],
        ),
        body: Center(
          child: Column(
            children: <Widget>[
              TextField(
                onSubmitted: (value) {
                  if (Uri.parse(value).isAbsolute) {
                    webviewController.loadContent(
                      value,
                      SourceType.urlBypass,
                    );
                  } else {
                    webviewController.loadContent(
                      'https://www.google.com/search?q=$value',
                      SourceType.urlBypass,
                    );
                  }
                },
                style: const TextStyle(color: Colors.white),
                decoration: const InputDecoration(
                  hintText: 'Enter a URL',
                  hintStyle: TextStyle(color: Colors.white),
                  contentPadding: EdgeInsets.all(10),
                  prefixIcon: Icon(Icons.search),
                ),
              ),
              Expanded(child: _buildCrossView()),
              Container(
                width: screenSize.width,
                height: 50,
                color: Colors.white.withOpacity(0.5),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: [
                    IconButton(
                      onPressed: _goBack,
                      icon: const Icon(Icons.arrow_back_ios),
                    ),
                    IconButton(
                      onPressed: _goForward,
                      icon: const Icon(Icons.arrow_forward_ios),
                    ),
                    IconButton(
                      onPressed: _reload,
                      icon: const Icon(Icons.refresh),
                    ),
                    IconButton(
                      onPressed: _toggleIgnore,
                      icon: const Icon(Icons.touch_app),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Future<void> _showMenu() async {
    showCupertinoModalPopup(
        context: context,
        builder: (context) {
          return SizedBox(
              height: MediaQuery.of(context).size.height * 0.8,
              child: CupertinoActionSheet(
                title: const Text("Select Action"),
                actions: [
                  _buildAction(
                      "Change content to URL that allows iframes embedding\n(https://flutter.dev)",
                      _setUrl,
                      context
                  ),
                  _buildAction(
                      "Change content to URL that doesn't allow iframes embedding\n(https://google.com/)",
                      _setUrlBypass,
                      context
                  ),
                  _buildAction(
                      "Change content to HTML (hardcoded)",
                      _setHtml,
                      context
                  ),
                  _buildAction(
                      "Change content to HTML (from assets)",
                      _setHtmlFromAssets,
                      context
                  ),
                  _buildAction(
                      "Evaluate 2+2 in the global \"window\" (javascript side)",
                      _evalRawJsInGlobalContext,
                      context
                  ),
                  _buildAction(
                      "Call platform independent Js method (console.log)",
                      _callPlatformIndependentJsMethod,
                      context
                  ),
                  _buildAction(
                      "Call platform specific Js method, that calls back a Dart function",
                      _callPlatformSpecificJsMethod,
                      context
                  ),
                  _buildAction(
                      "Show current webview content",
                      _getWebviewContent,
                      context
                  ),
                ],
                cancelButton: CupertinoActionSheetAction(
                  onPressed: () {
                    Navigator.maybePop(context);
                  },
                  child: Text(
                    "Cancel",
                    textAlign: TextAlign.left,
                    maxLines: 2,
                    style: Theme.of(context).textTheme.titleMedium,
                  ),
                ),
              )
          );
        }
    );
  }

  Widget _buildAction(String text, VoidCallback onTap, context) {
    return CrossViewAware(
      child: CupertinoActionSheetAction(
        onPressed: () {
          onTap();
          Navigator.of(context).pop();
        },
        child: Text(text),
      ),
    );
  }

  Widget _buildCrossView() {
    return CrossView(
      key: const ValueKey('CrossView'),
      initialContent: initialContent,
      initialSourceType: SourceType.html,
      onViewCreated: (controller) => webviewController = controller,
      webSpecificParams: const WebSpecificParams(printDebugInfo: true),
      mobileSpecificParams: const MobileSpecificParams(androidEnableHybridComposition: true),
    );
  }

  void _setUrl() {
    webviewController.loadContent(
      'https://flutter.dev',
      SourceType.url,
    );
  }

  void _setUrlBypass() {
    webviewController.loadContent(
      'https://google.com/',
      SourceType.urlBypass,
    );
  }

  void _setHtml() {
    webviewController.loadContent(
      initialContent,
      SourceType.html,
    );
  }

  void _setHtmlFromAssets() {
    webviewController.loadContent(
      'assets/test.html',
      SourceType.html,
      fromAssets: true,
    );
  }

  Future<void> _goForward() async {
    if (await webviewController.canGoForward()) {
      await webviewController.goForward();
      showSnackBar('Did go forward', context);
    } else {
      showSnackBar('Cannot go forward', context);
    }
  }

  Future<void> _goBack() async {
    if (await webviewController.canGoBack()) {
      await webviewController.goBack();
      showSnackBar('Did go back', context);
    } else {
      showSnackBar('Cannot go back', context);
    }
  }

  void _reload() {
    webviewController.reload();
  }

  void _toggleIgnore() {
    final ignoring = webviewController.ignoresAllGestures;
    webviewController.setIgnoreAllGestures(!ignoring);
    showSnackBar('Ignore events = ${!ignoring}', context);
  }

  Future<void> _evalRawJsInGlobalContext() async {
    try {
      final result = await webviewController.runJavaScript(
        '2+2',
        inGlobalContext: true,
      );
      showSnackBar('The result is $result', context);
    } catch (e) {
      showAlertDialog(executeJsErrorMessage, context);
    }
  }

  Future<void> _callPlatformIndependentJsMethod() async {
    try {
      await webviewController.callJsMethod('testPlatformIndependentMethod', []);
    } catch (e) {
      showAlertDialog(executeJsErrorMessage, context);
    }
  }

  Future<void> _callPlatformSpecificJsMethod() async {
    try {
      await webviewController.callJsMethod('testPlatformSpecificMethod', ['Hi']);
    } catch (e) {
      showAlertDialog(executeJsErrorMessage, context);
    }
  }

  Future<void> _getWebviewContent() async {
    try {
      final content = await webviewController.getContent();
      showAlertDialog(content.source, context);
    } catch (e) {
      showAlertDialog('Failed to execute this task.', context);
    }
  }

  Widget buildSpace({ Axis direction = Axis.horizontal, double amount = 0.2,  bool flex = true }) {
    return flex
        ? Flexible(
      child: FractionallySizedBox(
        widthFactor: direction == Axis.horizontal ? amount : null,
        heightFactor: direction == Axis.vertical ? amount : null,
      ),
    )
        : SizedBox(
      width: direction == Axis.horizontal ? amount : null,
      height: direction == Axis.vertical ? amount : null,
    );
  }

  Widget createButton({ VoidCallback? onTap, required String text }) {
    return ElevatedButton(
      onPressed: onTap,
      style: ElevatedButton.styleFrom(
        padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0),
      ),
      child: Text(text),
    );
  }

  void showAlertDialog(String content, BuildContext context) {
    showDialog(
      context: context,
      builder: (_) => CrossViewAware(
        child: AlertDialog(
          content: Text(content),
          actions: [
            TextButton(
              onPressed: Navigator.of(context).pop,
              child: const Text('Close'),
            ),
          ],
        ),
      ),
    );
  }

  void showSnackBar(String content, BuildContext context) {
    ScaffoldMessenger.of(context)
      ..hideCurrentSnackBar()
      ..showSnackBar(
        SnackBar(
          behavior: SnackBarBehavior.floating,
          margin: const EdgeInsets.only(bottom: 60.0, left: 10.0, right: 10.0),
          backgroundColor: Colors.black,
          content: Text(
            content,
            style: const TextStyle(
              color: Colors.white,
            ),
          ),
          duration: const Duration(seconds: 1),
        ),
      );
  }

  [@override](/user/override)
  void dispose() {
    webviewController.dispose();
    super.dispose();
  }
}

更多关于Flutter跨视图展示插件crossview的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter跨视图展示插件crossview的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter中使用crossview插件来实现跨视图展示的示例代码。crossview插件允许你在Flutter应用中创建和管理跨多个视图的复杂布局。虽然crossview并不是Flutter官方生态系统中的一个非常知名的插件,但假设它是一个第三方插件,我们可以模拟一个类似的实现逻辑。

首先,你需要确保在pubspec.yaml文件中添加了crossview(或类似的插件)依赖:

dependencies:
  flutter:
    sdk: flutter
  crossview: ^x.y.z  # 假设版本号为x.y.z,请替换为实际版本号

然后运行flutter pub get来获取依赖。

以下是一个示例代码,展示如何使用crossview(假设它提供类似功能)在Flutter中实现跨视图展示:

import 'package:flutter/material.dart';
import 'package:crossview/crossview.dart';  // 假设crossview插件提供这个导入路径

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter CrossView Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: CrossViewDemo(),
    );
  }
}

class CrossViewDemo extends StatefulWidget {
  @override
  _CrossViewDemoState createState() => _CrossViewDemoState();
}

class _CrossViewDemoState extends State<CrossViewDemo> {
  CrossViewController? _controller;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('CrossView Demo'),
      ),
      body: Column(
        children: <Widget>[
          Expanded(
            child: CrossView(
              controller: _controller,
              child: Container(
                color: Colors.lightBlue,
                alignment: Alignment.center,
                child: Text('This is CrossView Content'),
              ),
            ),
          ),
          ElevatedButton(
            onPressed: () {
              // 假设 CrossViewController 提供了 showView 方法来展示另一个视图
              _controller?.showView(
                context,
                builder: (context) => Center(
                  child: Text('This is another CrossView Content'),
                ),
              );
            },
            child: Text('Show Another View'),
          ),
        ],
      ),
    );
  }

  @override
  void initState() {
    super.initState();
    _controller = CrossViewController();  // 初始化控制器
  }

  @override
  void dispose() {
    _controller?.dispose();  // 释放控制器资源
    super.dispose();
  }
}

// 假设 CrossViewController 是插件提供的控制器类
class CrossViewController {
  // 假设的方法,用于管理跨视图展示
  void showView(BuildContext context, WidgetBuilder builder) {
    // 这里应该是插件内部实现跨视图展示的逻辑
    // 例如,使用 Navigator 或 Overlay 来展示新的视图
    // 这里只是一个模拟示例,实际实现取决于插件的API
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        content: builder(context),
      ),
    );
  }

  void dispose() {
    // 清理资源,如果有的话
  }
}

注意:上述代码是一个模拟示例,CrossViewCrossViewController并不是实际存在的Flutter组件或控制器。实际使用时,你需要根据crossview插件的文档和API来实现跨视图展示。如果crossview插件提供特定的方法或组件来实现跨视图功能,你应该参考其文档来进行实现。

由于crossview可能不是一个实际存在的Flutter插件,如果它是一个假想的或特定项目中的自定义插件,你需要根据该插件的实际API来调整上述代码。如果你正在寻找一个实际的跨视图展示解决方案,你可能需要考虑使用Flutter的NavigatorOverlay或其他布局技术来实现。

回到顶部