Datepicker localization for Xamarin Forms Android - xamarin

Anyone can share them a workaround for this bug, I also need to implement the Localization for Datepicker,
I implementing the Localization in this link https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/localization/text?tabs=windows
Then Translate and Change the Culture using this
public void SetLocale(CultureInfo ci)
{
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
Console.WriteLine("CurrentCulture set: " + ci.Name);
}
But the app still using the Device OS culture setting.
I also try Custom Renderer.
public class CustomDatePickerRenderer : DatePickerRenderer
{
public CustomDatePickerRenderer(Context context) :base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.DatePicker> e)
{
base.OnElementChanged(e);
Locale locale = new Locale("ARA");
Control.TextLocale = locale;
Resources.Configuration.SetLocale(locale);
Resources.Configuration.Locale = locale;
Resources.Configuration.SetLayoutDirection(locale);
}
}

Related

Application get stuck at SplashScreen after MvvmCross upgrade to 8.x

I upgraded all MvvmCross libraries from 7.1.2 to 8.0.0. According to "Upgrade from 7 to 8" tutorial from mvvmcross documentation, I have implemented necessary changes (override CreateLogProvider and CreateLogFactory methods and added iocProvider as parameter to InitializeFirstChance, InitializeLastChance, InitializeNavigationService and CreateApp):
public class Setup : MvxAndroidSetup
{
protected override IMvxAndroidViewPresenter CreateViewPresenter() => new HistoryViewPresenter(ViewAssemblies);
protected override void InitializeFirstChance(IMvxIoCProvider iocProvider)
{
base.InitializeFirstChance(iocProvider);
//Things are done here
}
protected override void InitializeLastChance(IMvxIoCProvider iocProvider)
{
base.InitializeLastChance(iocProvider);
//Things are done here
}
protected override IMvxNavigationService InitializeNavigationService(IMvxIoCProvider iocProvider)
{
var loader = CreateViewModelLoader(iocProvider);
Mvx.IoCProvider.RegisterSingleton<IMvxViewModelLoader>(loader);
InitializeViewDispatcher(iocProvider);
var dispatcher = CreateViewDispatcher();
Mvx.IoCProvider.RegisterSingleton(dispatcher);
var navigationService = new DeepNavigationService(null, loader, dispatcher, iocProvider);
Mvx.IoCProvider.RegisterSingleton<IMvxNavigationService>(navigationService);
return navigationService;
}
//Another things are done here
protected override IMvxApplication CreateApp(IMvxIoCProvider iocProvider)
{
return new App();
}
protected override ILoggerProvider CreateLogProvider()
{
return new SerilogLoggerProvider();
}
protected override ILoggerFactory CreateLogFactory()
{
Serilog.Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.CreateLogger();
return new SerilogLoggerFactory();
}
}
I have also created custom app start in Core project and set this class RegisterCustomAppStart:
public class AppStart : MvxAppStart
{
public AppStart(IMvxApplication application, IMvxNavigationService navigationService) : base(application, navigationService) { }
protected override Task NavigateToFirstViewModel(object hint = null)
{
return NavigationService.Navigate<StartupViewModel>();
}
}
public class App : MvxApplication
{
public override void Initialize()
{
//Services and Singletons are registered here.
RegisterCustomAppStart<AppStart>();
}
}
And here is the issue- when I run app, my app get stuck in SplashScreen. Did anyone face similar issue? On the previous version, everything was fine. I would be grateful for some advice how to fix that
I resolved this issue - I changed line:
var dispatcher = CreateViewDispatcher();
For:
var dispatcher = Mvx.IoCProvider.Resolve<IMvxViewDispatcher>();
And it works.

How to disable Carousel Page scrolling in Android

Using a custom renderer one can disable the swiping gesture of an CarouselPage on iOS like so:
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(CarouselPage), typeof(CustomCarouselPageRenderer))]
namespace App.iOS
{
public class CustomCarouselPageRenderer : CarouselPageRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
UIView view = this.NativeView;
UIScrollView scrollView = (UIKit.UIScrollView)view.Subviews[0];
scrollView.ScrollEnabled = false;
}
}
}
How to accomplish the same on Android?
using Android.Content;
using XamFormsApp.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(CarouselPage), typeof(CustomCarouselPageRenderer))]
namespace StixApp.Droid.Renderers
{
public class CustomCarouselPageRenderer : VisualElementRenderer<CarouselPage>
{
public CustomCarouselPageRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<CarouselPage> e)
{
base.OnElementChanged(e);
var view = this.RootView;
X
X
}
}
}
There appears to be no way to access Subviews in the same way. One can access Children like so
Android.Views.View view = (Android.Views.View)GetChildAt(i);
How to know which Child is ScrollView if any?
Using a loop to check for this, like so,
for (int i = 0; i < ChildCount; ++i)
{
Android.Views.View view = (Android.Views.View)GetChildAt(i);
if (view is ScrollView)
{
}
}
Yields the following: "The given expression is never of the provided (ScrollView) type"
So! How to disable CarouselPage swipe/scrolling as is done in iOS quite elegantly?
UPDATE: Please see sample solution.
A couple of things.
For Android the view you are looking for is not a ScrollView but a ViewPager.
This can be found under the index 0 with the GetChildAt method.
Also, why are you using VisualElementRenderer<CarouselPage> as the parent class of your CustomCarouselPageRenderer. Instead use the CarouselPageRenderer as you did with iOS.
One last thing is that on Android the Scroll of a ViewPager cannot be disabled. To get this behavior you can listen to the Touch event. Setting the Handled property of TouchEventArgs to true will prevent the scrolling from happening.
Your whole class would look something like:
[assembly: ExportRenderer(typeof(CarouselPage), typeof(CustomCarouselPageRenderer))]
namespace StixApp.Droid.Renderers
{
public class CustomCarouselPageRenderer : CarouselPageRenderer
{
private bool _canScroll = false;
public CustomCarouselPageRenderer(Context context) : base(context)
{
}
public CustomCarouselPageRenderer()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<CarouselPage> e)
{
base.OnElementChanged(e);
if (this.ChildCount > 0 && this.GetChildAt(0) is ViewPager viewPager)
{
viewPager.Touch -= ViewPagerTouched;
viewPager.Touch += ViewPagerTouched;
}
}
private void ViewPagerTouched(object sender, TouchEventArgs e)
{
e.Handled = !_canScroll;
}
}
}
Just change the value of _canScroll to true to allow the scrolling.
Hope this helps.-
Overridden Methods in ViewPager class:
public class NonSwipeableViewPager : ViewPager
{
public override bool OnTouchEvent(MotionEvent e)
{
return false;
}
public override bool OnInterceptTouchEvent(MotionEvent ev)
{
return false;
}
public override bool ExecuteKeyEvent(KeyEvent ev)
{
return false;
}
}
Changes to CarouselPageRenderer:
In class declaration:
public class MyCarouselPageRenderer : VisualElementRenderer<CarouselPage>
{
NonSwipeableViewPager _viewPager;
}
In OnElementChanged:
protected override void OnElementChanged(ElementChangedEventArgs<CarouselPage> e)
{
_viewPager = new NonSwipeableViewPager(Context);
}
Note: CarouselPageAdapter, CarouselPageRenderer, MeasureSpecFactory, ObjectJavaBox, and PageContainer all had to be copied from the Xamarin.Forms github to enable a custom CarouselPageRenderer implementation. All of this is in the github sample but hopefully this spells it out more clearly for future visitors.
Note2: I would like to stress that the true behavior we were trying to achieve is probably best done with a NavigationPage as this allows us to easily pop and push any and all pages at any time without having to address the swipe issue. That being said, hopefully this solution serves to aid anyone who need this behavior on a CarouselPage.

Xamarin Android Share Link/Text via social media from custom renderer

I wan't to share a link via social media from custom renderer
public class CustomActions : ICustomActions
{
Context context = Android.App.Application.Context;
public void ShareThisLink()
{
Intent sharingInt = new Intent(Android.Content.Intent.ActionSend);
sharingInt.SetType("text/plain");
string shareBody = "https://www.google.com";
sharingInt.PutExtra(Android.Content.Intent.ExtraSubject, "Subject");
sharingInt.PutExtra(Android.Content.Intent.ExtraText, shareBody);
context.StartActivity(Intent.CreateChooser(sharingInt, "Share via"));
}
}
This error occur
Android.Util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
even when I added the below code I still get same error
sharingInt.AddFlags(ActivityFlags.NewTask);
The problem is that Intent.CreateChooser creates yet another Intent. What you want to do is to set the flag on this new intent:
public void ShareThisLink()
{
Intent sharingInt = new Intent(Android.Content.Intent.ActionSend);
sharingInt.SetType("text/plain");
string shareBody = "https://www.google.com";
sharingInt.PutExtra(Android.Content.Intent.ExtraSubject, "Subject");
sharingInt.PutExtra(Android.Content.Intent.ExtraText, shareBody);
var intent = Intent.CreateChooser(sharingInt, "Share via");
intent.AddFlags(ActivityFlags.NewTask);
context.StartActivity(intent);
}
Alternatively to avoid the need to do this, you could cache the MainActivity instance Xamarin.Forms uses:
public MainActivity
{
public static MainActivity Instance {get;private set;}
protected override void OnCreate(Bundle bundle)
{
Instance = this;
...
}
}
And then use the Instance as the Context in your code instead of the Application.Context

MVVMCross 5.3.2 UWP: Where to Get IMvxWindowsFrame for MvxFormsUwpViewPresenter

I'm working out of the Xamarin Forms for MVVMCross 5 Solution Template and updated the packages to the latest version (5.3.2 for MVVMCross). Doing that changes some namespaces around particularly in the UWP project.
It seems that I need to resolve IMvxViewPresenter as MvxFormsUwpViewPresenter which takes a IMvxWindowsFrame as an argument. In the setup file method of Setup.cs there's a XamlControls.Frame rootFrame passed as an argument but I'm not sure if that's suppose to be cast somehow as IMvxWindowsFrame.
Where can you pull the object that implements IMvxWindowsFrame from or is there another way to turn the rootFrame into an IMvxWindowsFrame legitimately.
public class Setup : MvxFormsWindowsSetup
{
private readonly LaunchActivatedEventArgs _launchActivatedEventArgs;
public Setup(XamlControls.Frame rootFrame, LaunchActivatedEventArgs e) : base(rootFrame, e)
{
_launchActivatedEventArgs = e;
// Mvx.RegisterSingleton<IMvxWindowsFrame>(rootFrame);
}
protected override void InitializeFirstChance()
{
base.InitializeFirstChance();
Mvx.RegisterSingleton<Core.Services.ILocalizeService>(new Services.LocalizeService());
Mvx.RegisterSingleton<ISettings>(CrossSettings.Current);
Mvx.RegisterType<IMvxViewPresenter, MvxFormsUwpViewPresenter>();
}
protected override MvxFormsApplication CreateFormsApplication()
{
return new Core.FormsApp();
}
protected override IMvxApplication CreateApp()
{
return new Core.MvxApp();
}
protected override IMvxTrace CreateDebugTrace()
{
return new Core.DebugTrace();
}
}
public sealed partial class MainPage : WindowsPage
{
public MainPage()
{
this.InitializeComponent();
var start = Mvx.Resolve<IMvxAppStart>();
start.Start();
var presenter = Mvx.Resolve<IMvxViewPresenter>() as MvxFormsUwpViewPresenter;
LoadApplication(presenter.FormsApplication);
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
}
}
EDIT: I've been looking more into the class MvxFormsWindowsSetup in the source code at https://github.com/MvvmCross/MvvmCross/blob/develop/MvvmCross-Forms/MvvmCross.Forms.Uwp/Platform/MvxFormsWindowsSetup.cs. It appears that in the method CreateViewPresenter that the IMvxViewPresenter is registered as a singleton with the MvxWrappedFrame already inside but by default the code does not resolve when calling var presenter = Mvx.Resolve() as MvxFormsUwpViewPresenter; in the windows page. Possible bug? Trying to see if I can resolve it myself.
Looks like it fails to resolve even if I put the code right after when Mvx is suppose to register the type / singleton
protected override IMvxWindowsViewPresenter CreateViewPresenter(IMvxWindowsFrame rootFrame)
{
var presenter = new MvxFormsUwpViewPresenter(rootFrame, FormsApplication);
Mvx.RegisterSingleton<IMvxFormsViewPresenter>(presenter);
var presenter2 = Mvx.GetSingleton<IMvxViewPresenter>() as MvxFormsUwpViewPresenter;
return presenter;
}
When updating to MvvmCross 5.3.2 for UWP, the presenter needs to resolve as IMvxFormsViewPresenter rather than IMvxViewPresenter. Change the interface type and it should load properly.
public MainPage()
{
this.InitializeComponent();
var start = Mvx.Resolve<IMvxAppStart>();
start.Start();
var presenter = Mvx.Resolve<IMvxFormsViewPresenter>() as MvxFormsUwpViewPresenter;
LoadApplication(presenter.FormsApplication);
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
}

Xamarin Forms WebView.CanGoBack always returns false on UWP

Using the Xamarin Forms WebView control, I'm overriding the OnBackButtonPressed() and finding that the CanGoBack always returns false in UWP.
I don't see this problem in Android.
Is this a XF bug or am I doing something wrong?
Note: I'm running XF v2.3.3.193
EDIT: I upgraded to XF 2.3.4.247 and the problem persists.
I have created a code sample and reproduce your issue when the WebView browse several website. And I have found reason in the Xamarin.Forms source code.
void UpdateCanGoBackForward()
{
((IWebViewController)Element).CanGoBack = Control.CanGoBack;
((IWebViewController)Element).CanGoForward = Control.CanGoForward;
}
The CanGoBack property will be changed when UpdateCanGoBackForward method invoked. And UpdateCanGoBackForward method was called only when the native NavigationCompleted event was invoked. So if some website could not be loaded quickly, the CanGoBack property would not be changed.
You can improve this design by custom WebView. And you could follow the code below.
CustomWebView.cs
Add the new property for CustomWebView.
public class CustomWebView : WebView
{
public bool CCanGoBack { get; set; }
public CustomWebView()
{
}
}
CustomWebViewRenderer.cs
And change the property when the ContentLoading event invoked.
[assembly: ExportRenderer(typeof(CustomWebView), typeof(CustomWebViewRenderer))]
namespace CustomWebViewTest.UWP
{
public class CustomWebViewRenderer : WebViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.ContentLoading += Control_ContentLoading;
}
}
private void Control_ContentLoading(Windows.UI.Xaml.Controls.WebView sender, Windows.UI.Xaml.Controls.WebViewContentLoadingEventArgs args)
{
(Element as CustomWebView).CCanGoBack = Control.CanGoBack;
}
}
}
MainPage.cs
private void backClicked(object sender, EventArgs e)
{
if (Browser.CCanGoBack)
{
Browser.GoBack();
}
}

Resources