Windows Phone 8.1 - 外部ScrollViewer元素处理WebView的垂直滚动

19

问题

我需要在 Windows Phone 8.1 应用程序中的 ScrollViewer 中显示一个 WebView,具备以下要求:

  1. WebView 的高度应根据其内容调整。
  2. 外部 ScrollViewer 应处理 WebView 的垂直滚动。
  3. WebView 应处理水平滚动、缩放(捏合缩放)、文本选择(使用默认复制按钮)和链接导航。

下面的图片展示了我的模拟布局(左侧)和类似功能的最佳示例 - 内置邮件应用程序(右侧)

我的页面布局(左侧)和类似功能的最佳示例(右侧)

XAML 布局示例:

<ScrollViewer>
    <Grid Margin="12">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0">
            <TextBlock Text="My content" />
        </Grid>
        <WebView Grid.Row="1" x:Name="WebViewComponent"></WebView>
    </Grid>
</ScrollViewer>

我尝试了什么

测量 HTML 内容并调整 WebView 高度 - 这部分成功了,通过多次调整,我成功设置了 WebView 元素的正确高度。

订阅 WebView 中的边框元素 - 没有成功。这里的问题是,在 Windows Phone 8.1 中,WebView 组件似乎没有视觉子元素(至少不是DependencyObject)。

此外,我还尝试过使用 ManupulationModeIsHitTestVisible 属性进行操作,但均未成功

更新:添加了所需的文本选择和复制按钮到 WebView 功能中。在原始问题内容中不小心遗漏了这一点。


只是出于好奇,您是否尝试过注入一些CSS来禁用overflow:scroll,以便您的滚动查看器实际上可以执行其工作。类似于这样的链接?我希望我现在有更多的空闲时间去玩它,似乎这将是一个常见的问题。 - Chris W.
@Chris 我试过了。WebView 完全捕获指针交互,并以类似“压缩”滚动的方式做出反应(不确定这是否是一个合适的术语 - 滚动非常缓慢,一旦手指松开就会恢复)。 - danyloid
2
排序问题:有没有一种方法可以一次滚动来滚动它们全部? - danyloid
3个回答

5

我一直在面对这个问题,而且我已经部分地找到了一些解决方法(不包括文本选择)。

基本上,为了能够使用包含Webview的滚动查看器,需要有一些东西被拖动,所以我使用一个高度和宽度与Webview相同的矩形。

<ScrollViewer Name="ScrollViewer">
    <Grid x:Name="LayoutRoot" Height="Auto">
        <Grid.RowDefinitions>
            <RowDefinition Height="200"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid Name="GridHeader">
            <Image Stretch="UniformToFill" Source="ms-appx:///Assets/img_default_header.jpg" />
         </Grid>                
        <Grid Grid.Row="1" x:Name="GridNews" Margin="12,0">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <WebView Margin="-6,12,0,-6" Grid.Row="0" x:Name="WebviewContent" VerticalAlignment="Top" DefaultBackgroundColor="Transparent" /> 
            <Rectangle Margin="0,12,0,0" Height="{Binding Height, ElementName=WebviewContent}" Name="RecWeb" VerticalAlignment="Top" Fill ="#00000000" Tapped="RecWeb_Tapped" />
        </Grid>
        <Grid Name="GridRelatedNews" Grid.Row="2" Margin="12,0">
            <ListView ItemsSource="{Binding NewsDetail.RelatedStory}" ScrollViewer.VerticalScrollBarVisibility="Hidden">  
            </ListView>
        </Grid>
 </ScrollViewer>

现在我们需要注入一些 CSS 和 JavaScript,使 Webview 的高度适应内容(我在另一个 StackOverflow 帖子上找到了一些代码示例,但忘记了它来自哪里)。
string htmlFragment = @"
                                    <html>
                                        <head>
                                        <meta name=""viewport"" content=""width="+width+@", initial-scale=1, user-scalable=no"" />
                                            <script type=""text/javascript"">
                                                function loadLink(x,y){
                                                window.external.notify('x='+x+'y='+y);
                                                var el = document.elementFromPoint(x, y);
                                                el.click();};                                                   
                                            </script>
                                        <style>
                                        " + CSS + @"
                                        </style>
                                        </head>
                                        <body onLoad=""window.external.notify('rendered_height='+document.getElementById('content').offsetHeight);"">
                                            <div id='content' style=""font-size:16px; color:#222222;"">" + original +
                                          @"</div>
                                        </body>
                                    </html>";

然后将 webview webscript 通知事件添加到确定 webview 的渲染高度(和矩形)中:
void WebviewContent_ScriptNotify(object sender, NotifyEventArgs e)
{
    if (e.Value.Contains("rendered_height"))
    {
        if (valuePair != null && valuePair[0] == "rendered_height")
        {
            double renderedHeight = double.Parse(valuePair[1]);                 
            WebviewContent.Height = renderedHeight;

        }
    }
 }

我使用这种方法(loadLink JavaScript 方法)使得这个解决方案可以在内容中点击某些链接:
private async void RecWeb_Tapped(object sender, TappedRoutedEventArgs e)
    {
        Point p = e.GetPosition(WebviewContent);
        int x = Convert.ToInt32(p.X);
        int y = Convert.ToInt32(p.Y);
        string[] size = { x.ToString(), y.ToString() };
        await WebviewContent.InvokeScriptAsync("loadLink",size);
    }

也许你可以从中获得启示,为你的文本选择问题添加事件处理程序。使用这个解决方案的重点也是在于找到javascript中的等效事件处理程序。

谢谢。我猜这是最接近的一个。 - danyloid
这里是@tdmanutd解决方案的完整实现 https://gist.github.com/Ouadie/78fc85965ebaf49e06d4 - Ouadie
我也遇到了同样的问题。我会尝试这个解决方案。谢谢你的发布。 - Archana
@Ouadie,我的LoadLink函数无法正常工作,链接没有被点击。你有什么想法吗? - Archana
@LovetoCode 首先你需要检查是否正确调用了 await this.WebviewContent.InvokeScriptAsync("loadLink", size); 然后在 JavaScript 中使用 alertconsole.log 检查是否正确接收到了 loadLink 调用。 - Ouadie
显示剩余3条评论

1
我已经查看并尝试了一些方法,但无法使其按照你想要的方式工作。也许想出一个不包含外部ScrollViewer的不同设计可能更容易。基本上,需要一个东西,它不包括外部ScrollViewer
  • 其中一种选项(可能有点巧妙,没有测试过)是通过某些 JS 将您的内容注入页面,并仅使用WebView

  • 如果您的内容很小,可以将其留在页面顶部,删除ScrollViewer,并让WebView处理所有内容。 WebView会更小,但它将完美地工作。

这些只是不同设计的一些例子。如果您告诉我为什么它们行不通,或者如果您提供有关您的实际问题的更多信息,我可能能够想出更合适的东西。

问题在于屏幕顶部显示的内容可能是复杂的,包含图像、按钮等等。很抱歉,在原始问题帖子中我不知何故错过了那一部分。我意识到可以将所有内容包含在“WebView”中,但这需要很大的努力。无论如何,感谢您的建议。 - danyloid
1
@danyloid 是的,复杂的内容会让它变得更加复杂:) 还有两个想法:1)使用Pivot,在一页上显示内容,在另一页上显示Web视图;2)类似于垂直Pivot-在底部看到Web视图,一旦点击后几乎全屏,只有顶部的小东西可以返回到其他内容。 - yasen
谢谢,我还没有考虑过第二种方法。虽然它可能不是最佳解决方案,但是考虑它是一个不错的选择。 - danyloid

-1
你尝试过将 WebView 的 Height 属性设置为 Auto 吗?
<ScrollViewer x:Name="scrollViewer" >
    <Grid Margin="12">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <TextBlock Text="My content" />
        <Grid Background="Transparent"
              Margin="0"
              Grid.Row="1">
            <WebView ScrollViewer.ZoomMode="Enabled"
                     x:Name="WebViewComponent"  
                     Margin="0" 
                     Height="Auto" />
        </Grid>
    </Grid>
</ScrollViewer>

我相信 WebView.Height 属性的默认值是 Auto,但实际上并不是。没有任何效果。同样, ScrollViewer.ZoomMode="Enabled" 对内部浏览器滚动没有影响。 - danyloid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接