Подтвердить что ты не робот

Windows Phone 8.1 - Управление вертикальной прокруткой WebView внешним элементом ScrollViewer

Проблема

Мне нужно показать WebView внутри ScrollViewer в приложении Windows Phone 8.1 со следующими требованиями:

  • Высота
  • WebView должна быть скорректирована на основе ее содержимого.
  • WebView вертикальная прокрутка должна обрабатываться внешним ScrollViewer.
  • WebView должен обрабатывать горизонтальную прокрутку, масштаб (масштабирование), выбор текста (с кнопкой копирования по умолчанию) и ссылки на навигацию.

На приведенном ниже рисунке представлен мой макет (слева) и лучший пример аналогичной функциональности - это будет встроенное почтовое приложение (справа)

My page layout (to the left) and example of similar functionality (to the right)

Пример компоновки 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.

Подписывание элемента Border внутри WebView - Не работает. Проблема в том, что в Windows Phone 8.1 кажется, что компонент WebView не имеет визуальных дочерних элементов (по крайней мере, не DependencyObject)

Также я пробовал играть со свойствами ManupulationMode и IsHitTestVisible с без успеха.

UPDATE Добавлена ​​кнопка выбора текста и копирования для требуемой функциональности WebView. Как-то пропустил его в исходном вопросе.

4b9b3361

Ответ 1

Я столкнулся с этой проблемой, и у меня есть некоторое обходное решение (исключая выбор текста).

В принципе, чтобы использовать scrollviewer, содержащий веб-просмотр, вам нужно что-то перетаскивать, поэтому я использую прямоугольник с высотой и шириной, такой же, как и для веб-просмотра.

<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, чтобы настроить высоту веб-просмотра на контент (я нашел пример кода в другом потоке stackoverflow, забыл отслеживать, откуда он)

string htmlFragment = @"
                                    <html>
                                        <head>
                                        <meta name=""viewport"" content=""width="[email protected]", 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, чтобы определить отображаемую высоту веб-представления (и прямоугольника):

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;

        }
    }
 }

Мне удается разрешить этому решению иметь возможность щелкнуть какую-либо ссылку в контенте с помощью этого метода (метод javascript loadLink):

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.

Ответ 2

Я проверил это и пробовал несколько вещей, но не мог заставить его работать так, как вы этого хотите. Возможно, было бы проще придумать другой дизайн. В принципе, что-то, что не включает внешний ScrollViewer.

  • Один из вариантов (который может быть немного взломан, не проверял его) заключается в том, чтобы вводить ваш контент на страницу через некоторые JS и использовать только WebView.

  • Если ваш контент мал, вы можете просто оставить его в верхней части страницы, удалить ScrollViewer и позволить WebView обрабатывать все. WebView будет меньше, но он будет работать нормально.

Это лишь некоторые примеры различных конструкций. Если вы скажете мне, почему они не сработают, или если вы дадите мне больше информации о вашей реальной проблеме, я, возможно, смогу придумать что-то более подходящее.

Ответ 3

Попробуйте настроить свойство Height для WebView на 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>