Flutter中为InAppWebView Epub阅读器添加翻页卷曲效果问题
解决InAppWebView中EPUB翻页卷曲动画后页面切换失败问题
问题描述
我在应用中使用InAppWebView展示EPUB文件,已通过JavaScript实现字体样式及设置修改。添加JavaScript翻页卷曲效果实现前后翻页时,动画可正常播放,但动画结束后无法切换页面,且下方显示空白背景而非目标页面,求解决办法。
关联Dart代码
InAppWebView( onProgressChanged: (s, p) { progress = p / 100; setState(() {}); }, onWebViewCreated: (s) { webViewController = s; setState(() {}); webViewController?.platform.clearAllCache(); if (Platform.isAndroid) { webViewController?.platform .clearClientCertPreferences(); } styleWebView = StyleWebView(controller: webViewController!); webViewController?.addJavaScriptHandler( handlerName: "share", callback: (args) async { final text = (args[0])['text']; if (Utils.token.isEmpty) { Alerts.dialog(context, child: const LoginDialog()); return; } Alerts.bottomSheet(context, child: ShareBottomSheet( cubit: cubit, text: text, id: widget.id, )); }); webViewController?.addJavaScriptHandler( handlerName: "translate", callback: (args) async { log(args[0].runtimeType.toString()); final text = (args[0])['text']; Alerts.dialog( context, child: TranslationDialog( text: text, ), ); }); webViewController?.addJavaScriptHandler( handlerName: "current_chapter", callback: (args) async { final text = (args[0][0]); isCurrentBookMark = false; currentChapter = ChapterWebview.fromJson(text); setState(() {}); }); webViewController?.addJavaScriptHandler( handlerName: "reader_customization", callback: (args) async { final data = (args[0]); textStyle = textStyle.copyWith( fontFamily: data['font_family'], fontSize: double.tryParse(data['font_size']), height: double.tryParse(data['line_height'])); textAlign = styleWebView.textAlignFromName( data['text_alignment'] ?? "center"); backgroundColor = Color(int.parse( data['background'].substring(1, null), radix: 16) + 0xFF000000); if (data['background'] == "#333333") { brightness = Brightness.dark; } setState(() {}); }); webViewController?.addJavaScriptHandler( handlerName: "add_note", callback: (args) async { final data = args[0]; Alerts.dialog(context, child: AddNoteDialog( bookId: widget.id, chapterName: data["chapter_name"] ?? "", content: data['text'] ?? "", path: data['path'] ?? "", )); }); webViewController?.addJavaScriptHandler( handlerName: "current_bookmark", callback: (args) async { isCurrentBookMark = true; setState(() {}); }); webViewController?.addJavaScriptHandler( handlerName: "chapters", callback: (args) async { log("here chapters $args"); final chapters = (args[0]); chaptersWebView = []; for (var element in chapters) { chaptersWebView ?.add(ChapterWebview.fromJson(element)); } setState(() {}); print(chaptersWebView?.length); }); }, contextMenu: ContextMenu( onCreateContextMenu: (s) { webViewController?.evaluateJavascript( source: openMenu); }, settings: ContextMenuSettings( hideDefaultSystemContextMenuItems: true)), initialUrlRequest: URLRequest(url: webUri), gestureRecognizers: <Factory< OneSequenceGestureRecognizer>>{ Factory<OneSequenceGestureRecognizer>( () => EagerGestureRecognizer(), ), Factory<LongPressGestureRecognizer>( () => LongPressGestureRecognizer(), ), Factory<TapGestureRecognizer>( () => TapGestureRecognizer() ..onTap = () { print("tapped"); }, ), Factory<TapAndHorizontalDragGestureRecognizer>( () => TapAndHorizontalDragGestureRecognizer() ..onDragStart = (details) { print(details); }, ), Factory<HorizontalDragGestureRecognizer>( () => HorizontalDragGestureRecognizer() ..onUpdate = (details) { log(details.delta.toString()); }, ), Factory<PanGestureRecognizer>( () => PanGestureRecognizer() ..onUpdate = (details) { log(details.delta.toString()); }, ) }, ),
解决方案
修复动画回调中的页面切换逻辑
动画结束后无页面切换,通常是animationend事件的回调逻辑缺失或错误。确保动画完成后正确替换页面内容:// 示例:绑定动画结束事件 const flipContainer = document.getElementById('flip-container'); flipContainer.addEventListener('animationend', () => { // 确认目标页面DOM已加载 const targetPage = document.getElementById('target-page'); const currentPage = document.getElementById('current-page'); if (targetPage?.innerHTML.trim()) { // 切换页面显示状态 currentPage.style.display = 'none'; targetPage.style.display = 'block'; // 通知Flutter更新当前章节信息 window.flutter_inappwebview.callHandler('current_chapter', [newChapterData]); } });提前预加载目标页面内容
空白背景说明目标页面未加载完成。在翻页动画启动前,提前加载下/上一章内容到隐藏容器:// 预加载下一章 async function preloadNextChapter(nextChapterHref) { const response = await fetch(nextChapterHref); const html = await response.text(); document.getElementById('target-page').innerHTML = html; }简化手势识别器避免冲突
代码中过多手势识别器可能拦截JS侧的翻页事件,保留核心手势并传递事件给JS:gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{ Factory<HorizontalDragGestureRecognizer>( () => HorizontalDragGestureRecognizer() ..onUpdate = (details) { // 将手势事件传递给JS处理 webViewController?.evaluateJavascript( source: `handleDragUpdate(${details.delta.dx})` ); }, ), },验证Flutter-JS通信逻辑
检查JS侧是否在页面切换后正确调用window.flutter_inappwebview.callHandler('current_chapter', ...),同时确保Flutter侧current_chapter回调能正确解析数据,避免因数据格式错误导致状态更新失败。重置EPUB页面样式
部分EPUB章节的固定定位、溢出隐藏样式会导致页面无法正常显示,添加样式重置:document.querySelectorAll('.epub-chapter').forEach(chapter => { chapter.style.position = 'relative'; chapter.style.overflow = 'visible'; chapter.style.display = 'none'; }); // 默认显示当前章节 document.querySelector('.current-chapter').style.display = 'block';
内容的提问来源于stack exchange,提问作者Hamza Kaleem
相关产品推荐
相关产品推荐

