How to set dynamic height of webview in Xamarin.Forms uwp? - xamarin.forms

I am working on a Xamarin.Forms application, and I want to set the height of a webview dynamically as pet text in uwp platform.

Define a Custom Renderer for your webview and then inject a javascript to calculate the content's size:
[assembly: ExportRenderer(typeof(CustomWebView), typeof(MyWebViewRenderer))]
namespace Demo.UWP
{
public class MyWebViewRenderer : WebViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.NavigationCompleted += Control_NavigationCompleted;
}
}
private async void Control_NavigationCompleted(Windows.UI.Xaml.Controls.WebView sender, Windows.UI.Xaml.Controls.WebViewNavigationCompletedEventArgs args)
{
var heightString = await Control.InvokeScriptAsync("eval", new[] { "document.body.scrollHeight.toString()" });
int height;
if (int.TryParse(heightString, out height))
{
Element.HeightRequest = height;
}
}
}
}
Your Forms page's Xaml could be like:
<ScrollView>
<StackLayout>
<local:CustomWebView Source="https://www.microsoft.com"/>
<!--Other controls-->
</StackLayout>
</ScrollView>

Related

Automatic height of the webview

I have a xamarin forms application and I have inserted a webview inside the layout stack, the problem is that I have multiple pages and in each page the length of the content is different from the others.
I wanted to ask if there was a way to have the webview automatically adjust the height.
I have read other similar questions on the site, but I admit they seemed confusing to me.
This is my code xaml
<ContentPage.Content>
<StackLayout Padding="0" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" Spacing="0" BackgroundColor="White">
<WebView
x:Name="wvSite"
VerticalOptions="FillAndExpand"
HeightRequest="2300" />
</StackLayout>
</ContentPage.Content>
You could reset the webview height according to the content height when loading page finished via custom renderer.
Android:
[assembly: ExportRenderer(typeof(WebView), typeof(CustomWebViewRenderer))]
namespace App1.Droid
{
public class CustomWebViewRenderer : WebViewRenderer
{
public CustomWebViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
Control.SetWebViewClient(new CustomWebViewClient(e.NewElement));
}
}
internal class CustomWebViewClient : Android.Webkit.WebViewClient
{
private WebView webView;
public CustomWebViewClient(WebView webView)
{
this.webView = webView;
}
public async override void OnPageFinished(Android.Webkit.WebView view, string url)
{
if (webView != null)
{
int i = 10;
while (view.ContentHeight == 0 && i-- > 0)
await System.Threading.Tasks.Task.Delay(100);
webView.HeightRequest = view.ContentHeight;
}
base.OnPageFinished(view, url);
}
}
}
iOS:
[assembly: ExportRenderer(typeof(WebView),
typeof(CustomWebviewRenderer))]
namespace App1.iOS
{
public class CustomWebviewRenderer : WkWebViewRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
NavigationDelegate = new CustomWebviewNavigationDelegate();
}
}
internal class CustomWebviewNavigationDelegate : WKNavigationDelegate
{
[Export("webview:didFinishNavigation:")]
public override void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
{
//base.DidFinishNavigation(webView, navigation);
webView.Frame = new CoreGraphics.CGRect(0, 0, webView.ScrollView.ContentSize.Width, webView.ScrollView.ContentSize.Height);
}
}
}

Xamarin.Forms Change the Orange ListView Backgroud-Color on tappping cell to white or transparent

I cant find solution about this orange color? Do i need to write a renderer or can change from resources in Android and IOS?
Yes,if you want to change ListView selecteditem background color, need to use custom render to do this in Xamarin.Forms.
In the PCL, create a class name is ExtendedViewCell which should inherit any ViewCell.
public class ExtendedViewCell : ViewCell
{
public static readonly BindableProperty SelectedBackgroundColorProperty =
BindableProperty.Create("SelectedBackgroundColor",
typeof(Color),
typeof(ExtendedViewCell),
Color.Default);
public Color SelectedBackgroundColor
{
get { return (Color)GetValue(SelectedBackgroundColorProperty); }
set { SetValue(SelectedBackgroundColorProperty, value); }
}
}
In Android project, create a class name as ExtendedViewCellRenderer and make sure to add renderer registration for our ExtendedViewCell class above the namespace.
[assembly: ExportRenderer(typeof(ExtendedViewCell), typeof(ExtendedViewCellRenderer))]
namespace demo3.Droid
{
public class ExtendedViewCellRenderer : ViewCellRenderer
{
private Android.Views.View _cellCore;
private Drawable _unselectedBackground;
private bool _selected;
protected override Android.Views.View GetCellCore(Cell item,
Android.Views.View convertView,
ViewGroup parent,
Context context)
{
_cellCore = base.GetCellCore(item, convertView, parent, context);
_selected = false;
_unselectedBackground = _cellCore.Background;
return _cellCore;
}
protected override void OnCellPropertyChanged(object sender, PropertyChangedEventArgs args)
{
base.OnCellPropertyChanged(sender, args);
if (args.PropertyName == "IsSelected")
{
_selected = !_selected;
if (_selected)
{
var extendedViewCell = sender as ExtendedViewCell;
_cellCore.SetBackgroundColor(extendedViewCell.SelectedBackgroundColor.ToAndroid());
}
else
{
_cellCore.SetBackground(_unselectedBackground);
}
}
}
}
}
Then you can set color for listview SelectedBackgroundColor.
<ListView ItemsSource="{Binding students}">
<ListView.ItemTemplate>
<DataTemplate>
<local:ExtendedViewCell SelectedBackgroundColor="White">
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Username}" TextColor="Yellow" />
<Label Text="{Binding Age}" TextColor="Blue" />
</StackLayout>
</local:ExtendedViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
More detail info and steps in ios platform, you can take a look:
https://blog.wislon.io/posts/2017/04/11/xamforms-listview-selected-colour
Update:
In ios project, create a class name as ExtendedViewCellRenderer and make sure to add renderer registration for our ExtendedViewCell class above the namespace.
[assembly: ExportRenderer(typeof(ExtendedViewCell), typeof(ExtendedViewCellRenderer))]
namespace xamformsdemo.iOS
{
public class ExtendedViewCellRenderer : ViewCellRenderer
{
public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
{
var cell = base.GetCell(item, reusableCell, tv);
var view = item as ExtendedViewCell;
cell.SelectedBackgroundView = new UIView
{
BackgroundColor = view.SelectedBackgroundColor.ToUIColor(),
};
return cell;
}
}
}

how to scroll to top in editor when user stop writing in xamarin forms

i tried from scrolToAsync method but not working .on xaml when stop writing message or
keyboard keydown button is pressed control goes to start of message.when keyboard
keydown click,editor control goes to start of the message.
i use this method on editor propertyChanged.
double iScrollPosition = 0;
await editorScrollView.ScrollToAsync(0, iScrollPosition, true);
<Frame Margin="10">
<ScrollView x:Name="editorScrollView" >
<Editor x:Name="txtEditor"
HeightRequest="110"
Placeholder="Write message here"
PropertyChanged="OnStatusLabelPropertyChanged" />
</ScrollView>
</Frame>
can anyone please help me with this
You can use CustomRenderer and implement it in specific platforms.
in Android
using Android.Content;
using xxx.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using static Android.Widget.TextView;
[assembly: ExportRenderer(typeof(Editor), typeof(MyEditorRenderer))]
namespace xxx.Droid
{
public class MyEditorRenderer : EditorRenderer
{
public MyEditorRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
Control.FocusChange += Control_FocusChange;
}
}
private void Control_FocusChange(object sender, FocusChangeEventArgs e)
{
if(!e.HasFocus)
{
Control.SetSelection(0);
}
}
}
}
in iOS
using System;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using xxx.iOS;
[assembly:ExportRenderer(typeof(Editor),typeof(MyEditorRenderer))]
namespace xxx.iOS
{
public class MyEditorRenderer:EditorRenderer,IUITextViewDelegate
{
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
Control.Ended += Control_Ended;
}
}
private void Control_Ended(object sender, EventArgs e)
{
var editor = sender as UITextView;
editor.ScrollRangeToVisible(new NSRange(0,0));
}
}
}

My scroll view does not responding i can not scroll down

In my XAML file, I used scroll view for scroll down but it does not work I can not find any issue where I did a couple of extra things here one is I add pull to refresh nuget and use it and I create a theme content class and I inherited it with default content page. another command in content page is working but scroll view does not support
Here my Xaml file
<views:BaseContentPage.Content>
<ScrollView BackgroundColor="White">
<controls:PullToRefreshLayout x:Name="PullToRefreshLayout" IsPullToRefreshEnabled="True" RefreshCommand="RefreshPatientDetailsPage">
<StackLayout>
// some code
</StackLayout>
</controls:PullToRefreshLayout>
</ScrollView>
</views:BaseContentPage.Content>
this is the Base content page I create
public abstract class BaseContentPage : ContentPage
{
public readonly BaseViewModel BaseViewModel;
protected bool IsNavigated;
public BaseContentPage(BaseViewModel baseViewModel)
{
BaseViewModel = baseViewModel;
}
protected abstract override void OnAppearing();
protected override void OnDisappearing()
{
IsNavigated = true;
}
}
I think this scroll view does not work because of the NuGet I put or it's the base content page
for android, I used this customer render
public class SortPaneListViewRendererAndroid : ListViewRenderer
{
public SortPaneListViewRendererAndroid(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.VerticalScrollBarEnabled = false;
var listView = Control as Android.Widget.ListView;
listView.DividerHeight = 1;
}
}
}
The reason this was happening is because you are nesting scrollable controls, Removing one of them will solve the issue

Web page height correctly rendered with WebViewRenderer, but not with ViewRenderer<HybridWebView, Android.Webkit.WebView>

There is something different between the default WebViewRenderer and my custom ViewRenderer and I have to find out why. Basically, the web page isn't displayed if I use my custom ViewRenderer.
The ViewRenderer has some issues with height: 100%; and interprets this CSS wrong. As result the height is 0px, despite it should use the full height. On the other side it works with exact sizes (e.g. 400px).
Code for WebViewRenderer:
<local:CustomWebView x:Name="webView"
Source="http://somesite"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
HeightRequest="1000"
WidthRequest="1000"/>
public class CustomWebView : WebView
{
}
public class CustomWebViewRenderer : WebViewRenderer
{
public CustomWebViewRenderer(Context context) : base(context)
{
}
}
Code for ViewRenderer:
<local:HybridWebView x:Name="webView"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
HeightRequest="1000"
WidthRequest="1000"/>
public class HybridWebView : View
{
}
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, Android.Webkit.WebView>
{
private Context context;
public HybridWebViewRenderer(Context context) : base(context)
{
this.context = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
var webView = new Android.Webkit.WebView(this.context);
webView.Settings.JavaScriptEnabled = true;
webView.SetWebViewClient(new CustomWebViewClient());
SetNativeControl(webView);
}
if (e.OldElement != null)
{
}
if (e.NewElement != null)
{
Control.LoadUrl("http://somesite");
}
}
}
public class CustomWebViewClient : WebViewClient
{
}
One assumption is that the responsive website adapts to its WebView size, and since the rendering process takes place in background it somehow has a height of zero at this time.
I don't know why, but this solves the issue for me:
webView.LayoutParameters = new LinearLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent);
If anyone has a clue, please comment.

Resources