fluttercandies / extended_sliver

A powerful extension library of Sliver, which include SliverToNestedScrollBoxAdapter, SliverPinnedPersistentHeader, SliverPinnedToBoxAdapter and ExtendedSliverAppbar.
MIT License
165 stars 30 forks source link

SliverToNestedScrollBoxAdapter, webview disappear on keyboard input open #14

Open JeanChristophePal opened 2 years ago

JeanChristophePal commented 2 years ago

I'm using part of the code from the example https://github.com/fluttercandies/extended_sliver/blob/master/example/lib/pages/nested/webview.dart

When I click on an editable field of the Webview, the complet view disappear, do you know why ?

import 'dart:io';
import 'dart:ui';

import 'package:extended_sliver/extended_sliver.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

class NestedWebview extends StatelessWidget {
  NestedWebview({
    required this.url,
    Key? key,
  })  : nestedWebviewController = NestedWebviewController(url),
        super(key: key);

  final String url;
  final NestedWebviewController nestedWebviewController;

  final ScrollController scrollController = ScrollController();

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      primary: false,
      shrinkWrap: true,
      controller: scrollController,
      slivers: <Widget>[
        ValueListenableBuilder<double>(
          valueListenable: nestedWebviewController.scrollHeightNotifier,
          builder: (
            BuildContext context,
            double scrollHeight,
            Widget? child,
          ) {
            return SliverToNestedScrollBoxAdapter(
              childExtent: scrollHeight,
              onScrollOffsetChanged: (double scrollOffset) {
                double y = scrollOffset;
                if (Platform.isAndroid) {
                  // https://github.com/flutter/flutter/issues/75841
                  y *= window.devicePixelRatio;
                }
                nestedWebviewController.webviewController
                    ?.scrollTo(0, y.ceil());
              },
              child: child,
            );
          },
          child: WebView(
            initialUrl: nestedWebviewController.initialUrl,
            onPageStarted: nestedWebviewController.onPageStarted,
            onPageFinished: nestedWebviewController.onPageFinished,
            onWebResourceError: nestedWebviewController.onWebResourceError,
            onWebViewCreated: nestedWebviewController.onWebViewCreated,
            javascriptChannels: <JavascriptChannel>{
              nestedWebviewController.scrollHeightNotifierJavascriptChannel
            },
            javascriptMode: JavascriptMode.unrestricted,
          ),
        ),
      ],
    );
  }
}

class NestedWebviewController {
  NestedWebviewController(this.initialUrl);

  final String initialUrl;

  WebViewController? _webviewController;

  WebViewController? get webviewController => _webviewController;

  ValueNotifier<double> scrollHeightNotifier = ValueNotifier<double>(1);
  ValueNotifier<WebViewStatus> webViewStatusNotifier =
      ValueNotifier<WebViewStatus>(WebViewStatus.loading);

  void onWebViewCreated(WebViewController controller) {
    _webviewController = controller;
  }

  void onPageStarted(String url) {
    if (url == initialUrl ||
        webViewStatusNotifier.value == WebViewStatus.failed) {
      webViewStatusNotifier.value = WebViewStatus.loading;
    }
  }

  void onPageFinished(String url) {
    if (webViewStatusNotifier.value != WebViewStatus.failed) {
      _webviewController?.runJavascript(scrollHeightJs);
    }
  }

  void onWebResourceError(WebResourceError error) {
    webViewStatusNotifier.value = WebViewStatus.failed;
  }

  JavascriptChannel get scrollHeightNotifierJavascriptChannel =>
      JavascriptChannel(
        name: 'ScrollHeightNotifier',
        onMessageReceived: (JavascriptMessage message) {
          final String msg = message.message;
          final double? height = double.tryParse(msg);
          if (height != null) {
            scrollHeightNotifier.value = height;
            webViewStatusNotifier.value = WebViewStatus.completed;
          }
        },
      );
}

enum WebViewStatus {
  loading,
  failed,
  completed,
}

const String scrollHeightJs = '''(function() {
  var height = 0;
  var notifier = window.ScrollHeightNotifier || window.webkit.messageHandlers.ScrollHeightNotifier;
  if (!notifier) return;

  function checkAndNotify() {
    var curr = document.body.scrollHeight;
    if (curr !== height) {
      height = curr;
      notifier.postMessage(height.toString());
    }
  }

  var timer;
  var ob;
  if (window.ResizeObserver) {
    ob = new ResizeObserver(checkAndNotify);
    ob.observe(document.body);
  } else {
    timer = setTimeout(checkAndNotify, 200);
  }
  window.onbeforeunload = function() {
    ob && ob.disconnect();
    timer && clearTimeout(timer);
  };
})();''';
zmtzawqlp commented 2 years ago

shrinkWrap: true, why need this

JeanChristophePal commented 2 years ago

shrinkWrap: true, why need this

You are right this is not useful, I removed it.

I added resizeToAvoidBottomInset: false, to the parent Scaffold() is not totally working but it better. There is still some weird views:

Scaffold(
          resizeToAvoidBottomInset: false,
          body: NestedScrollView (
          ....
                body: NestedWebview(
                     url: 'https://www.qwant.com',
                );
          )

Simulator Screen Shot - iPhone SE (3rd generation) - 2022-08-17 at 13 56 15

zmtzawqlp commented 2 years ago

runnable,simple demo,plz