I can`t find how to save map (Xamarin.Forms.Maps.Map) as image? There is common approach for iOS and Android? There is possible create implementation in common project?
Thanks for answer.
I have resolved problem, that is working code
public class ScreenshotManager : IScreenshotManager
{
private readonly Activity _activity;
public ScreenshotManager(Activity activity)
{
_activity = activity;
}
public async Task<byte[]> CaptureMapAsync(Map map)
{
if (_activity == null)
{
throw new Exception("You have to set ScreenshotManager.Activity in your Android project");
}
var renderer = Platform.GetRenderer(map);
Platform.SetRenderer(map, renderer);
var viewRenderer = renderer.View;
var mapRenderer = (MapRenderer)viewRenderer;
var mapView = mapRenderer.Control;
var mapDownloaderTask = new TaskCompletionSource<byte[]>();
mapView.GetMapAsync(new OnMapReadyCallback(m =>
{
mapDownloaderTask.SetResult(m);
}));
return await mapDownloaderTask.Task;
}
}
internal class OnMapReadyCallback : Java.Lang.Object, IOnMapReadyCallback
{
readonly Action<byte[]> handler;
public OnMapReadyCallback(Action<byte[]> handler)
{
this.handler = handler;
}
void IOnMapReadyCallback.OnMapReady(GoogleMap googleMap)
{
googleMap.Snapshot(new SnapshotMapCallBack(handler));
}
}
internal class SnapshotMapCallBack : Java.Lang.Object, GoogleMap.ISnapshotReadyCallback
{
readonly Action<byte[]> handler;
public SnapshotMapCallBack(Action<byte[]> handler)
{
this.handler = handler;
}
public void OnSnapshotReady(Bitmap snapshot)
{
using (var stream = new MemoryStream())
{
snapshot.Compress(Bitmap.CompressFormat.Png, 0, stream);
byte[] bitmapData = stream.ToArray();
handler?.Invoke(bitmapData);
}
}
}
Related
I've been working with the "Getting started with CameraX" port to c# https://github.com/venetasoft/Xamarin.CameraX.
The example uses the ImageSaveCallback, but I'd like to use ImageCapturedCallback instead, since I'd like to access the image in memory.
My code is generating the error "cannot convert from 'CameraX.ImageCapturedCallback' to 'AndroidX.Camera.Core.ImageCapture.OnImageCapturedCallback'", so clearly I'm missing something obvious here.
In the ImageSaveCallback example, the code is:
imageCapture.TakePicture(outputOptions, ContextCompat.GetMainExecutor(this), new ImageSaveCallback(
onErrorCallback: (exc) =>
{
var msg = $"Photo capture failed: {exc.Message}";
Log.Error(TAG, msg, exc);
Toast.MakeText(this.BaseContext, msg, ToastLength.Short).Show();
},
onImageSaveCallback: (output) =>
{
var savedUri = output.SavedUri;
var msg = $"Photo capture succeeded: {savedUri}";
Log.Debug(TAG, msg);
Toast.MakeText(this.BaseContext, msg, ToastLength.Short).Show();
}
));
and the callback is:
class ImageSaveCallback : Java.Lang.Object, IOnImageSavedCallback
{
private const string TAG = "CameraXBasic";
private readonly Action<ImageCaptureException> onErrorCallback;
private readonly Action<OutputFileResults> onImageSaveCallback;
public ImageSaveCallback(Action<OutputFileResults> onImageSaveCallback, Action<ImageCaptureException> onErrorCallback)
{
this.onImageSaveCallback = onImageSaveCallback;
this.onErrorCallback = onErrorCallback;
}
public void OnError(ImageCaptureException exc)
{
this.onErrorCallback.Invoke(exc);
}
public void OnImageSaved(OutputFileResults photoFile)
{
this.onImageSaveCallback.Invoke(photoFile);
}
}
My attempt, based on the above:
imageCapture.TakePicture(ContextCompat.GetMainExecutor(this), new ImageCapturedCallback(
onErrorCallback: (exc) =>
{
// handle error
},
onImageCapturedCallback: (output) =>
{
// handle image
}
));
And the callback class:
class ImageCapturedCallback : Java.Lang.Object {
private readonly Action<ImageCaptureException> onErrorCallback;
private readonly Action<IImageProxy> onImageCapturedCallback;
public ImageCapturedCallback(Action<ImageCaptureException> onErrorCallback, Action<IImageProxy> onImageCapturedCallback)
{
onErrorCallback = onErrorCallback;
onImageCapturedCallback = onImageCapturedCallback;
}
public void OnError(ImageCaptureException exc)
{
this.onErrorCallback.Invoke(exc);
}
public void OnCaptureSuccess(IImageProxy proxyImage)
{
this.onImageCapturedCallback.Invoke(proxyImage);
}
}
I found the answer - there's a branch of the example code https://github.com/venetasoft/Xamarin.CameraX/tree/CameraX_Updated.
Based on that code, the ImageCapturedCallback class looks like this:
class ImageCapturedCallback : OnImageCapturedCallback
{
private readonly Action<ImageCaptureException> onErrorCallback;
private readonly Action<Bitmap> onCapturedSuccessCallback;
public ImageCapturedCallback(Action<Bitmap> onCapturedSuccessCallback, Action<ImageCaptureException> onErrorCallback)
{
this.onCapturedSuccessCallback = onCapturedSuccessCallback;
this.onErrorCallback = onErrorCallback;
}
public override void OnError(ImageCaptureException exc)
{
this.onErrorCallback?.Invoke(exc);
}
public override void OnCaptureSuccess(IImageProxy image)
{
var data = ImageUtil.ImageToJpegByteArray(image);
var imageBitmap = BitmapFactory.DecodeByteArray(data, 0, data.Length);
this.onCapturedSuccessCallback?.Invoke(imageBitmap);
base.OnCaptureSuccess(image);
image.Close();
}
}
I'm new with Xamarin.Forms and I have implemented a custom web view renderer in Droid project.
The issue is when implementing the renderer in iOS project, it's like the Webview is initialized without loading the CSS and Javascript. Because it only display HTML page without any functionality.
After some research, I know we have to implement WKWebviewRenderer and we have to load the LoadFileUrl method in iOS but I still can't catch the url in the renderer.
Anyone have an idea please about how to implement the following Android Renderer code into iOS Renderer??
Custom renderer in Droid project:
[assembly: ExportRenderer(typeof(Xamarin.Forms.WebView), typeof(MyProject.Droid.WebViewRenderer))]
namespace MyProject.Droid
{
public class WebViewRenderer : Xamarin.Forms.Platform.Android.WebViewRenderer
{
private bool isMyCustomWebview = false;
public IWebViewController ElementController => Element;
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement.GetType() == typeof(MyCustomWebview))
{
Control.SetWebViewClient(new Callback(this));
isMyCustomWebview = true;
}
else
{
Control.SetWebViewClient(new Callback(Plugin.CurrentActivity.CrossCurrentActivity.Current.Activity));
isMyCustomWebview = false;
}
}
public class Callback : WebViewClient
{
Activity _context;
public Callback(Activity _context)
{
this._context = _context;
}
WebViewRenderer _renderer;
public Callback(WebViewRenderer renderer)
{
_renderer = renderer ?? throw new ArgumentNullException("Renderer");
}
public override void OnPageStarted(Android.Webkit.WebView view, string url, Android.Graphics.Bitmap favicon)
{
base.OnPageStarted(view, url, favicon);
if (_renderer != null && _renderer.isMyCustomWebview)
{
DependencyService.Get<ILoadingIndicator>().Show();
var args = new WebNavigatingEventArgs(WebNavigationEvent.NewPage, new UrlWebViewSource { Url = url }, url);
_renderer.ElementController.SendNavigating(args);
}
}
public override void OnPageFinished(Android.Webkit.WebView view, string url)
{
base.OnPageFinished(view, url);
if (_renderer != null && _renderer.isMyCustomWebview)
{
DependencyService.Get<ILoadingIndicator>().Dismiss();
var source = new UrlWebViewSource { Url = url };
var args = new WebNavigatedEventArgs(WebNavigationEvent.NewPage, source, url, WebNavigationResult.Success);
_renderer.ElementController.SendNavigated(args);
}
}
}
}
}
UPDATE: Custom renderer in iOS project:
[assembly: ExportRenderer(typeof(Xamarin.Forms.WebView), typeof(MyProject.iOS.WebViewRenderer))]
namespace MyProject.iOS
{
// Xamarin.Forms.Platform.iOS.WebViewRenderer
public class WebViewRenderer : ViewRenderer<WebView, WKWebView>
{
WKWebView wkWebView;
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control != null) return;
var config = new WKWebViewConfiguration();
wkWebView = new WKWebView(Frame, config) { NavigationDelegate = new MyNavigationDelegate() };
SetNativeControl(wkWebView);
}
}
public class MyNavigationDelegate : WKNavigationDelegate
{
public override void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
{
//get url here
var url = webView.Url;
// webView.LoadFileUrl(url, url);
}
}
}
UPDATE:
Here's how I'm setting the source and base url for the webview in the portable project:
var result = await client.PostAsync("/embedded/pay", content);
if (result.IsSuccessStatusCode)
{
var resp = await result.Content.ReadAsStringAsync();
var html = new HtmlWebViewSource
{
Html = resp,
BaseUrl = paymentGatewayUrl
};
//Adding Cookie
CookieContainer cookies = new CookieContainer();
var domain = new Uri(html.BaseUrl).Host;
var cookie = new Cookie
{
Secure = true,
Expired = false,
HttpOnly = false,
Name = "cookie",
Expires = DateTime.Now.AddDays(10),
Domain = domain,
Path = "/"
};
cookies.Add(new Uri(html.BaseUrl), cookie);
webView.Source = html;
}
You could modify the code of Custom Renderer like following .
[assembly: ExportRenderer(typeof(WebView), typeof(MyWebViewRenderer))]
namespace xxx.iOS
{
public class MyWebViewRenderer : ViewRenderer<WebView, WKWebView>
{
WKWebView wkWebView;
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control != null) return;
var config = new WKWebViewConfiguration();
wkWebView = new WKWebView(Frame, config) { NavigationDelegate = new MyNavigationDelegate() };
SetNativeControl(wkWebView);
}
}
public class MyNavigationDelegate : WKNavigationDelegate
{
public override void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
{
//get url here
var url = webView.Url;
//webView.LoadFileUrl();
}
}
}
I am using xamarin forms webview and want to pass username and password json body with url like below.
I Implement Hybrid webview in xamarin forms
My PCL Code:
public class HybridWebView : WebView
{
Action<string> action;
public EventHandler<bool> WebNavigating;
public void RegisterAction (Action<string> callback)
{
action = callback;
}
public void Cleanup ()
{
action = null;
}
public void InvokeAction (string data)
{
if (action == null || string.IsNullOrEmpty(data)) {
return;
}
action.Invoke (data);
}
}
My Android HybridWebViewRenderer Code :
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, Android.Webkit.WebView>
{
Context _context;
public HybridWebViewRenderer(Context context) : base(context)
{
_context = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
var webView = new Android.Webkit.WebView(_context);
webView.Settings.JavaScriptEnabled = true;
webView.SetWebViewClient(new MyWebViewClient(webView,e,this));
SetNativeControl(webView);
}
}
}
public class MyWebViewClient : WebViewClient
{
const string JavaScriptFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}";
public Android.Webkit.WebView _webView;
public Android.Webkit.WebView WebView
{
get
{
return _webView;
}
}
public ElementChangedEventArgs<HybridWebView> _element;
public MyWebViewClient(Android.Webkit.WebView view, ElementChangedEventArgs<HybridWebView> element, HybridWebViewRenderer x)
{
_webView = view;
_element = element;
if (_element.OldElement != null)
{
_webView.RemoveJavascriptInterface("jsBridge");
var hybridWebView = _element.OldElement as HybridWebView;
hybridWebView.Cleanup();
}
if (_element.NewElement != null)
{
_webView.AddJavascriptInterface(new JSBridge(x), "jsBridge");
string url = "https://Myspecific.com/Account/MobileLogin";
string postData = "{\"UserName\":\"User1\",\"Password\":\"pass123\",\"RememberMe\":false}";
_webView.PostUrl(url, Encoding.UTF8.GetBytes(postData));
}
}
output:
It shows wrong username and password
Please help...
Thanks in advance...
I am working to achieve a recycler view interface that looks like this:
Presently, am only using a recyclerview with LinearLayoutManager using an adapter with two viewholders, i tried gridLayout manager too but i did not achieve the target interface: I need help achieving this, Do i have to create a custom Layout Manager? or What exactly do i have to do? Please, I am really stuck on this.
This is my adapter code
public class SimpleStringRecyclerViewAdapter : RecyclerView.Adapter
{
private List<Data> mValues;
private Context context;
private const int TYPE_FULL = 0;
private const int TYPE_HALF = 1;
private const int TYPE_QUARTER = 2;
public SimpleStringRecyclerViewAdapter(Context context, List<Data> items)
{
this.context = context;
mValues = items;
}
public override int ItemCount
{
get
{
return mValues.Count();
}
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
if (holder is SimpleViewHolder)
try
{
Data item = mValues.ElementAt(position);
var simpleHolder = holder as SimpleViewHolder;
simpleHolder.mTxtView.Text = Android.Text.Html.FromHtml(item.article.Title).ToString();
simpleHolder.mTxtView2.Text = item.article.Description;
using (var imageView = simpleHolder.mImageView)
{
string url = Android.Text.Html.FromHtml(item.article.UrlToImage).ToString();
//Download and display image
UrlImageViewHelper.SetUrlDrawable(imageView,
url, Resource.Drawable.cheese_1
);
}
// simpleHolder.mprogressbar.Visibility = ViewStates.Gone;
}
catch (Exception e)
{
//Toast.MakeText(this.context, e.ToString(), ToastLength.Long).Show();
}
else
{
try
{
Data item = mValues.ElementAt(position);
var simpleHolder = holder as SimpleViewHolder2;
simpleHolder.mTxtView.Text = Android.Text.Html.FromHtml(item.youTubeItem.Title).ToString();
// simpleHolder.mTxtView2.Text = item.DescriptionShort;
using (var imageView = simpleHolder.mImageView)
{
string url = Android.Text.Html.FromHtml(item.youTubeItem.MaxResThumbnailUrl).ToString();
//Download and display image
UrlImageViewHelper.SetUrlDrawable(imageView,
url, Resource.Drawable.cheese_1
);
}
}
catch (Exception e)
{
//Toast.MakeText(this.context, e.ToString(), ToastLength.Long).Show();
}
}
}
public override int GetItemViewType(int position)
{
if (mValues.ElementAt(position).type == 1)
{
return Resource.Layout.ItemsList;
}
else
{
return Resource.Layout.VideoList;
}
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
if (viewType == Resource.Layout.ItemsList)
{
View view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.ItemsList, parent, false);
view.SetBackgroundColor(Color.White);
SimpleViewHolder holder = new SimpleViewHolder(view);
// holder.mprogressbar = view.FindViewById<ProgressBar>(Resource.Id.progressBar);
// holder.mprogressbar.Visibility = ViewStates.Visible;
//Showing loading progressbar
return holder;
}
else
{
View view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.VideoList, parent, false);
view.SetBackgroundColor(Color.White);
SimpleViewHolder2 holder = new SimpleViewHolder2(view);
return holder;
}
}
}
public class SimpleViewHolder : RecyclerView.ViewHolder
{
public string mBoundString;
public readonly View mView;
public readonly ImageView mImageView;
public readonly TextView mTxtView;
public readonly TextView mTxtView2;
// public ProgressBar mprogressbar;
public SimpleViewHolder(View view) : base(view)
{
mView = view;
mImageView = view.FindViewById<ImageView>(Resource.Id.avatar2);
mTxtView = view.FindViewById<TextView>(Resource.Id.Text11);
mTxtView2 = view.FindViewById<TextView>(Resource.Id.Text12);
// mprogressbar = view.FindViewById<ProgressBar>(Resource.Id.progressBar);
}
public override string ToString()
{
return base.ToString() + " '" + mTxtView.Text;
}
}
public class SimpleViewHolder2 : RecyclerView.ViewHolder
{
public string mBoundString;
public readonly View mView;
public readonly ImageView mImageView;
public readonly TextView mTxtView;
public readonly TextView mTxtView2;
public SimpleViewHolder2(View view) : base(view)
{
mView = view;
mImageView = view.FindViewById<ImageView>(Resource.Id.videoavatar);
mTxtView = view.FindViewById<TextView>(Resource.Id.videoText1);
// mprogressbar = view.FindViewById<ProgressBar>(Resource.Id.progressBar);
}
}
SetUpRecyclerView Method:
dataUse = OfflineDeserializer.OfflineData(content, json2);
recyclerView.SetLayoutManager(new LinearLayoutManager(recyclerView.Context));
recyclerView.SetAdapter(new SimpleStringRecyclerViewAdapter(recyclerView.Context, dataUse));
if (vp.IsShown)
{
vp.Visibility = ViewStates.Invisible;
}
This is what I have presently:
you can use recycler view with multiple view type
here is the link you can refer
Recyclerview with multiple view types
Here is a sample code you can modify it according to your need
public class MyFeedsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
final int
VIDEO = 1,
IMAGE = 2,
AUDIO = 3;
public MyFeedsAdapter(HomeActivity homeActivity, ArrayList<MyFeedsModel> list, MyFeedsFragment myFeedsFragment) {
this.activity = homeActivity;
this.list = list;
this.myFeedsFragment = myFeedsFragment;
metrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
switch (viewType) {
case VIDEO:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_myfeeds, parent, false);
return new ViewForVideo(view);
case IMAGE:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_myfeeds, parent, false);
return new ViewForImage(view);
case AUDIO:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_myfeeds, parent, false);
return new ViewForAudio(view);
default:
return null;
}
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
if (list.get(position).getFile_type().equals(IntentString.VIDEO)) {
setViewForVideo((ViewForVideo) holder, position);
} else if (list.get(position).getFile_type().equals(IntentString.IMAGE)) {
setViewForImage((ViewForImage) holder, position);
} else if (list.get(position).getFile_type().equals(IntentString.AUDIO)) {
setViewForAudio((ViewForAudio) holder, position);
}
}
#Override
public int getItemCount() {
return list.size();
}
#Override
public int getItemViewType(int position) {
if (list.get(position).getFile_type().equals(IntentString.VIDEO)) {
return VIDEO;
} else if (list.get(position).getFile_type().equals(IntentString.IMAGE)) {
return IMAGE;
} else if (list.get(position).getFile_type().equals(IntentString.AUDIO)) {
return AUDIO;
} else {
return 0;
}
}
public void setViewForVideo(final ViewForVideo holder, final int position) {
}
public void setViewForImage(final ViewForImage holder, final int position) {
}
public void setViewForAudio(final ViewForAudio holder, int position) {
}
public class ViewForVideo extends RecyclerView.ViewHolder {
public ViewForVideo(View itemView) {
super(itemView);
}
}
public class ViewForImage extends RecyclerView.ViewHolder {
public ViewForImage(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
public class ViewForAudio extends RecyclerView.ViewHolder {
public ViewForAudio(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
When open renderer page many times, when back to last page, it crashed and log this exception:
System.NotSupportedException: Unable to activate instance of type
AppZPMC.Droid.Renderers.CustomVideoWebViewRenderer from native handle
0xff9919cc (key_handle 0xf2ff0de).
Here is my code:
public class CustomVideoWebViewRenderer : WebViewRenderer
{
string url;
Activity activity;
WebView webView;
View customView;
CustomVideoWebView element;
FrameLayout.LayoutParams COVER_SCREEN_PARAMS = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent);
FrameLayout fullscreenContainer;
WebChromeClient.ICustomViewCallback customViewCallback;
public CustomVideoWebViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
webView = this.Control;
activity = CrossCurrentActivity.Current.Activity;
if (e.NewElement != null)
{
element = e.NewElement as CustomVideoWebView;
url = element.VideoUrl;
}
if (webView != null)
{
InitWebView();
}
}
protected override void OnDetachedFromWindow()
{
if (Element == null)
{
return;
}
base.OnDetachedFromWindow();
if (Control != null)
{
Control.StopLoading();
Control.LoadUrl("");
Control.Reload();
Control.Destroy();
}
}
public void FullScreen(Activity pActivity)
{
element.IsFullScreen = true;
WindowManagerLayoutParams attrs = pActivity.Window.Attributes;
attrs.Flags |= WindowManagerFlags.Fullscreen;
attrs.Flags |= WindowManagerFlags.KeepScreenOn;
pActivity.Window.Attributes = attrs;
pActivity.RequestedOrientation = Android.Content.PM.ScreenOrientation.Landscape;
}
public void SmallScreen(Activity pActivity)
{
element.IsFullScreen = false;
WindowManagerLayoutParams attrs = pActivity.Window.Attributes;
attrs.Flags &= ~WindowManagerFlags.Fullscreen;
attrs.Flags &= ~WindowManagerFlags.KeepScreenOn;
pActivity.Window.Attributes = attrs;
pActivity.RequestedOrientation = Android.Content.PM.ScreenOrientation.UserPortrait;
}
private void InitWebView()
{
WebChromeClient wvcc = new WebChromeClient();
WebSettings webSettings = webView.Settings;
webSettings.JavaScriptEnabled = true;
webSettings.SetSupportZoom(false);
webSettings.CacheMode = CacheModes.NoCache;
webView.SetWebViewClient(new VideoWebViewClient());
FrameLayout frameLayout = new FrameLayout(activity.ApplicationContext);
frameLayout.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent);
webView.SetWebChromeClient(new VideoWebChromeClient(frameLayout, ShowCustomView, HideCustomView));
webView.LoadUrl(url);
}
private class VideoWebViewClient : WebViewClient
{
public override bool ShouldOverrideUrlLoading(WebView view, IWebResourceRequest request)
{
view.LoadUrl(request.Url.ToString());
return base.ShouldOverrideUrlLoading(view, request);
}
}
private class VideoWebChromeClient : WebChromeClient
{
FrameLayout frameLayout;
Action HideCustomView;
Action<View, ICustomViewCallback> ShowCustomView;
public VideoWebChromeClient(FrameLayout frameLayout, Action<View, ICustomViewCallback> showCustomView, Action hideCustomView)
{
this.frameLayout = frameLayout;
ShowCustomView = showCustomView;
HideCustomView = hideCustomView;
}
public override View VideoLoadingProgressView => frameLayout;
public override void OnShowCustomView(View view, ICustomViewCallback callback)
{
ShowCustomView(view, callback);
base.OnShowCustomView(view, callback);
}
public override void OnHideCustomView()
{
HideCustomView();
base.OnHideCustomView();
}
}
private void ShowCustomView(View view, WebChromeClient.ICustomViewCallback callback)
{
if (customView != null)
{
callback.OnCustomViewHidden();
return;
}
FrameLayout decor = (FrameLayout)activity.Window.DecorView;
fullscreenContainer = new FullscreenHolder(activity.ApplicationContext);
fullscreenContainer.AddView(view, COVER_SCREEN_PARAMS);
decor.AddView(fullscreenContainer, COVER_SCREEN_PARAMS);
customView = view;
customViewCallback = callback;
FullScreen(activity);
}
private void HideCustomView()
{
if (customView == null)
{
return;
}
FrameLayout decor = (FrameLayout)activity.Window.DecorView;
decor.RemoveView(fullscreenContainer);
fullscreenContainer = null;
customView = null;
customViewCallback.OnCustomViewHidden();
webView.Visibility = ViewStates.Visible;
SmallScreen(activity);
}
private class FullscreenHolder : FrameLayout
{
public FullscreenHolder(Context ctx) : base(ctx)
{
SetBackgroundColor(Color.Black);
}
public override bool OnTouchEvent(MotionEvent e)
{
return true;
}
}
}
This is full crash log:
Java.Lang.Error: Exception of type 'Java.Lang.Error' was thrown.
java.lang.Error: Java callstack:
md5ff1c77b81adfd2c553f48967fc623ae5.CustomVideoWebViewRenderer.n_onDetachedFromWindow(Native Method)
md5ff1c77b81adfd2c553f48967fc623ae5.CustomVideoWebViewRenderer.onDetachedFromWindow(CustomVideoWebViewRenderer.java:45)
android.view.View.dispatchDetachedFromWindow(View.java:14595)
android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:3074)
android.view.ViewGroup.removeAllViewsInLayout(ViewGroup.java:4792)
android.view.ViewGroup.removeAllViews(ViewGroup.java:4738)
md5270abb39e60627f0f200893b490a1ade.FragmentContainer.n_onDestroyView(Native Method)
md5270abb39e60627f0f200893b490a1ade.FragmentContainer.onDestroyView(FragmentContainer.java:59)
android.support.v4.app.Fragment.performDestroyView(Fragment.java:2480)
android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1422)
android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1569)
android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:753)
android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2415)
android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2201)
android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.java:2155)
android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2064)
android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:718)
android.os.Handler.handleCallback(Handler.java:742)
android.os.Handler.dispatchMessage(Handler.java:95)
android.os.Looper.loop(Looper.java:157)
android.app.ActivityThread.main(ActivityThread.java:5551)
java.lang.reflect.Method.invoke(Native Method)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:742)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:632)
Its common problem (bug) in Xamarin.Forms, take a look at: https://github.com/xamarin/Xamarin.Forms/issues/1646, no fix yet :(