How to change TimeFormat depending on system setting in Xamarin - xamarin

I updated Xamarin.Forms to the latest version 4.8.0.1560. I managed to bind the timepicker on both Android and iOS. The only discrepancy with my application is when the user use 24 time setting in their phone the time picker "stuck" in 12 hour format.
In order to do that I created a custom renderer in iOS
[assembly: ExportRenderer(typeof(TimePicker), typeof(TimeRenderer))]
namespace TabsApp.iOS.custom.renderers
{
public class TimeRenderer : TimePickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
{
base.OnElementChanged(e);
int hours = Element.Time.Hours;
int minutes = Element.Time.Minutes;
if (!Is12Hours())
{
var timePicker = (UIDatePicker)Control.InputView;
timePicker.Locale = new NSLocale("no_nb");
}
string format = Is12Hours()?"hh:mm tt":"HH:mm";
DateTime currTime = DateTime.Now;
currTime = new DateTime(currTime.Year,currTime.Month,currTime.Day,hours,minutes,0);
Control.Text = currTime.ToString(format);
}
private bool Is12Hours()
{
var dateFormatter = new NSDateFormatter();
dateFormatter.DateStyle = NSDateFormatterStyle.None;
dateFormatter.TimeStyle = NSDateFormatterStyle.Short;
var dateString = dateFormatter.ToString(NSDate.Now);
var isTwelveHourFormat =
dateString.Contains(dateFormatter.AMSymbol) ||
dateString.Contains(dateFormatter.PMSymbol);
return isTwelveHourFormat;
}
}
}
OnElementChanged is being called once the application is loaded, and it will show the correct time format. When you change the time, this callback is not being called. Do I need to override other functions?

At the end I found the answer from xamarin forms. You will need to change/add custom timepicker renderer.
This is the code
[assembly: ExportRenderer(typeof(TimePicker), typeof(TimeRenderer))]
namespace TabsApp.iOS.custom.renderers
{
public class TimeRenderer : TimePickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
{
base.OnElementChanged(e);
if (Is12Hours())
{
Element.Format = "hh:mm tt";
}
else
{
var timePicker = (UIDatePicker)Control.InputView;
timePicker.Locale = new NSLocale("no_nb");
Element.Format = "HH:mm";
}
}
private bool Is12Hours()
{
var dateFormatter = new NSDateFormatter();
dateFormatter.DateStyle = NSDateFormatterStyle.None;
dateFormatter.TimeStyle = NSDateFormatterStyle.Short;
var dateString = dateFormatter.ToString(NSDate.Now);
var isTwelveHourFormat =
dateString.Contains(dateFormatter.AMSymbol) ||
dateString.Contains(dateFormatter.PMSymbol);
return isTwelveHourFormat;
}
}
}

Related

How can I enable video autoplay in WKWebView on iOS

I have a WebView that contains an iframe (an HTML element). this iframe has a Peertube video plyaer, I pass &autoplay=1 to that iframe and it works good on android, iPad and browser, but on iPhone the video can not be autoplayed.
I tried custom render with WKWebView with this code:
class FullScreenEnabledWebViewRenderer : WkWebViewRenderer
{
WKUserContentController userController;
public FullScreenEnabledWebViewRenderer() : this(new WKWebViewConfiguration() { MediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypes.None, AllowsInlineMediaPlayback = true, MediaPlaybackRequiresUserAction = false, RequiresUserActionForMediaPlayback = false })
{
}
public FullScreenEnabledWebViewRenderer(WKWebViewConfiguration config) : base(config)
{
config.AllowsInlineMediaPlayback = true;
config.AllowsAirPlayForMediaPlayback = true;
config.AllowsPictureInPictureMediaPlayback = true;
config.MediaPlaybackAllowsAirPlay = true;
config.MediaPlaybackRequiresUserAction = false;
config.RequiresUserActionForMediaPlayback = false;
config.MediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypes.None;
}
}
and still does not work.
Can you help me with that please.
Webview in iOS couldn't support iframe very well . So it could better to use <video> like
var htmlSource = new HtmlWebViewSource();
htmlSource.Html = #"<html><body><video width='300' height='500' muted='muted' controls autoplay='autoplay'><source src='https://ia800201.us.archive.org/12/items/BigBuckBunny_328/BigBuckBunny_512kb.mp4' type='video/mp4'></video></body></html>";
webview.Source = htmlSource;
If it still could not auto play in iOS , we could invoked JS to play it .
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using App4;
using App4.iOS;
using WebKit;
using ObjCRuntime;
[assembly: ExportRenderer(typeof(WebView), typeof(FullScreenEnabledWebViewRenderer))]
namespace App4.iOS
{
public class FullScreenEnabledWebViewRenderer: ViewRenderer<WebView, WKWebView>
{
WKWebView wkWebView;
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
var config = new WKWebViewConfiguration();
config.AllowsInlineMediaPlayback = true;
config.AllowsAirPlayForMediaPlayback = true;
config.AllowsPictureInPictureMediaPlayback = true;
config.MediaPlaybackAllowsAirPlay = true;
config.MediaPlaybackRequiresUserAction = false;
config.RequiresUserActionForMediaPlayback = false;
config.MediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypes.None;
wkWebView = new WKWebView(Frame, config);
wkWebView.NavigationDelegate = new WkWebviewPolicy();
SetNativeControl(wkWebView);
}
}
}
public class WkWebviewPolicy : WKNavigationDelegate
{
public override void DecidePolicy(WKWebView webView, WKNavigationAction navigationAction, WKWebpagePreferences preferences, [BlockProxy(typeof(NIDActionArity2V120))] Action<WKNavigationActionPolicy, WKWebpagePreferences> decisionHandler)
{
decisionHandler.Invoke(WKNavigationActionPolicy.Allow, preferences);
//base.DecidePolicy(webView, navigationAction, preferences, decisionHandler);
}
public override void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
{
base.DidFinishNavigation(webView, navigation);
var JSstr = #"var videos = document.querySelectorAll('video'); for (var i = videos.length - 1; i >= 0; i--) { var ivideo = videos[i]; ivideo.setAttribute('webkit-playsinline','\'); ivideo.play(); };";
webView.EvaluateJavaScript(JSstr,null);
}
}
}

xamarin binding variable to label using timer event

I want to binding a variable to a label which as a children in a grid.
the variable changed with a timer event.pls check my code help me found out where i am wrong.I can see the label init value is 0,but it won't update when the variable do.
public class DevicePage : ContentPage
{
IDevice device;
Label testLb = new Label();
System.Timers.Timer testtimer;
Grid gridView;
byte testt { get; set; } = 0;
GetSendData communicate;
private byte _maintext;
public byte MainText
{
get
{
return _maintext;
}
set
{
_maintext = value;
OnPropertyChanged();
}
}
public DevicePage(IDevice currDevice)
{
device = currDevice;
this.Title = "Status";
testtimer = new System.Timers.Timer();
testtimer.Interval = 1000;
testtimer.Elapsed += OnTimedEvent;
testtimer.Enabled = true;
gridView = new Grid();
testLb.Text = testt.ToString();
testLb.SetBinding(Label.TextProperty, ".");
testLb.BindingContext = MainText;
gridView.Children.Add(testLb, 0, 0);
this.Content = gridView;
}
private void OnTimedEvent(object sender, System.Timers.ElapsedEventArgs e)
{
MainText += 1;
}
after I implement INotifyPropertyChanged,testLb won't update either.But I change testLb.SetBinding(Label.TextProperty, "."); testLb.BindingContext = MainText; to testLb.SetBinding(Label.TextProperty, "MainText"); testLb.BindingContext = this; It works!

How can I change the font for the header of a Navigation page with Xamarin Forms?

I can change the font color like this:
var homePage = new NavigationPage(new HomePage())
{
Title = "Home",
Icon = "ionicons_2_0_1_home_outline_25.png",
BarTextColor = Color.Gray,
};
But is there a way to change the font for the Title. I would like to change it for the iOS and Android platforms only. Hoping that someone knows of custom renderer code that can help me to do this.
You need Custom Renderer , refer to this sample
iOS
[assembly: ExportRenderer(typeof(CustomNavigationPage), typeof(CustomNavigationPageRenderer))]
namespace CustomFontsNavigationPage.iOS.Renderers
{
public class CustomNavigationPageRenderer : NavigationRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
var att = new UITextAttributes();
UIFont customFont = UIFont.FromName("Trashtalk", 20);
UIFont systemFont = UIFont.SystemFontOfSize(20.0);
UIFont systemBoldFont = UIFont.SystemFontOfSize(20.0 , FontAttributes.Bold);
att.Font = font;
UINavigationBar.Appearance.SetTitleTextAttributes(att);
}
}
}
}
Android
[assembly: ExportRenderer(typeof(CustomNavigationPage), typeof(CustomNavigationPageRenderer))]
namespace CustomFontsNavigationPage.Droid.Renderers
{
public class CustomNavigationPageRenderer : NavigationPageRenderer
{
private Android.Support.V7.Widget.Toolbar _toolbar;
public override void OnViewAdded(Android.Views.View child)
{
base.OnViewAdded(child);
if (child.GetType() == typeof(Android.Support.V7.Widget.Toolbar))
{
_toolbar = (Android.Support.V7.Widget.Toolbar)child;
_toolbar.ChildViewAdded += Toolbar_ChildViewAdded;
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if(disposing)
{
_toolbar.ChildViewAdded -= Toolbar_ChildViewAdded;
}
}
private void Toolbar_ChildViewAdded(object sender, ChildViewAddedEventArgs e)
{
var view = e.Child.GetType();
if (e.Child.GetType() == typeof(Android.Widget.TextView))
{
var textView = (Android.Widget.TextView)e.Child;
var spaceFont = Typeface.CreateFromAsset(Forms.Context.ApplicationContext.Assets, "Trashtalk.ttf");
var systemFont = Typeface.DEFAULT;
var systemBoldFont = Typeface.DEFAULT_BOLD;
textView.Typeface = spaceFont;
_toolbar.ChildViewAdded -= Toolbar_ChildViewAdded;
}
}
}
}
There is no need in a custom renderer on iOS, you can just use the Appearance API:
UINavigationBar.Appearance.SetTitleTextAttributes(new UITextAttributes
{
Font = UIFont.FromName("MyCoolFont", 20)
});
In Android you do need a renderer, however you should check against Android.Support.V7.Widget.AppCompatTextView and not Android.Widget.TextView.
Tested on Xamarin.Forms 3.4.0

Xamarin Forms timepicker 24hour

I'm new to Xamarin.Forms and i can't seems to find how to show the dialog in a 24hour format instead of a AM/PM
can someone help me ?
Thank you
This page is really usefull to learn how to format dates in C#:
https://msdn.microsoft.com/en-us/library/8kb3ddd4%28v=vs.110%29.aspx
And with this code I was able to show a 24 hour format:
TimePicker timePicker = new TimePicker
{
Format = "HH:mm"
};
The only solution i found is here:
24h timepicker
Basically a custom renderer within each platform project will be needed.
Xamarin.iOS:
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using PersonalTrainer.iOS.View.Controls;
[assembly: ExportRenderer (typeof (TimePicker), typeof (TimePicker24HRenderer))]
namespace YourNamespace.iOS.View.Controls {
public class TimePicker24HRenderer : TimePickerRenderer {
protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e) {
base.OnElementChanged(e);
var timePicker = (UIDatePicker)Control.InputView;
timePicker.Locale = new NSLocale("no_nb");
}
}
}
For Android:
[assembly: ExportRenderer(typeof(TimePicker), typeof(TimePicker24HRenderer))]
namespace YourNamespace.Droid.View.Controls {
public class TimePicker24HRenderer : ViewRenderer<Xamarin.Forms.TimePicker, Android.Widget.EditText>, TimePickerDialog.IOnTimeSetListener, IJavaObject, IDisposable {
private TimePickerDialog dialog = null;
protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e) {
base.OnElementChanged(e);
this.SetNativeControl(new Android.Widget.EditText(Forms.Context));
this.Control.Click += Control_Click;
this.Control.Text = DateTime.Now.ToString("HH:mm");
this.Control.KeyListener = null;
this.Control.FocusChange += Control_FocusChange;
}
void Control_FocusChange(object sender, Android.Views.View.FocusChangeEventArgs e) {
if (e.HasFocus) { ShowTimePicker(); }
}
void Control_Click(object sender, EventArgs e) {
ShowTimePicker();
}
private void ShowTimePicker() {
if (dialog == null) {
dialog = new TimePickerDialog(Forms.Context, this, DateTime.Now.Hour, DateTime.Now.Minute, true);
}
dialog.Show();
}
public void OnTimeSet(Android.Widget.TimePicker view, int hourOfDay, int minute) {
var time = new TimeSpan(hourOfDay, minute, 0);
this.Element.SetValue(TimePicker.TimeProperty, time);
this.Control.Text = time.ToString(#"hh\:mm");
}
}
}
For Windows Phone:
[assembly: ExportRenderer (typeof (MyTimePicker), typeof (TimePicker24HRenderer))]
namespace YourNamespace.WindowsPhone.View.Controls {
public class TimePicker24HRenderer : TimePickerRenderer {
// Override the OnElementChanged method so we can tweak this renderer post-initial setup
protected override void OnElementChanged (ElementChangedEventArgs<Xamarin.Forms.TimePicker> e) {
base.OnElementChanged (e);
if (Control != null) {
var nativeControl = (Windows.UI.Xaml.Controls.TimePicker)Control;
nativeControl.Foreground = new SolidColorBrush(Colors.Gray);
Control.ClockIdentifier = "24HourClock";
}
}
}
}
In XAML you can set the the 24 hours format string to TimePicker by using the Format property:
<TimePicker Format="HH:mm"/>
Ok. You have to do it plateform specific.. I did something like that.
So create an interface
public interface TimePickerInterface
{
void showTimePicker (ButtonOrLabel lbl);
}
In Android you create your timepicker class
[assembly:Dependency(typeof(yournamespace.MyTimePicker))]
namespace yournamespace
{
public class MyTimePicker:Java.Lang.Object,TimePickerInterface,Android.App.TimePickerDialog.IOnTimeSetListener
{
String originalText="";
LabelOrButton lbl=new LabelOrButton();
public void showTimePicker(LabelOrButton lbl)
{
var c = Forms.Context;
originalText = lbl.Text;
this.lbl = lbl;
var time = DateTime.Now.TimeOfDay;
TimePickerDialog dialog = new TimePickerDialog(c,this,time.Hours,time.Minutes,true);
dialog.SetCanceledOnTouchOutside (true);
dialog.Show ();
}
public void OnTimeSet (Android.Widget.TimePicker view, int hourOfDay, int minute)
{
if(view.IsShown)
lbl.Text = (hourOfDay<=9 ? ("0"+hourOfDay+""):hourOfDay+"")+":"+(minute<=9 ? ("0"+minute+""):minute+"");
}
}
}
And in your xamarin forms you call it in actionlistener of your button or gesturerecognizer of your label:
DependencyService.Get<TimePickerInterface> ().showTimePicker(myButtonOrLabel);
You can do the same thing for DatePicker..
Hope it helps..

how translate getApplication from java to monodroid?

i got a java project about floating view from web. i try to translate it to monodroid, but i fail, because on function ,i don't know how to write in monodroid .
java code is in http://www.xsmile.net/file/FloatViewDemo.rar
namespace MonoFloatView
{
[Activity(Label = "MonoFloatView", MainLauncher = true, Icon = "#drawable/icon")]
public class MyFloatViewActivity : Activity
{
private IWindowManager wm = null;
private WindowManagerLayoutParams wmParams = null;
private MyFloatView myFV = null;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
createView();
// Create your application here
}
private void createView()
{
//myFV = new MyFloatView(getApplicationContext()); //java
myFV = new MyFloatView(ApplicationContext);
myFV.SetImageResource(Resource.Drawable.Icon);
//wm = (WindowManager)getApplicationContext().getSystemService("window");
//http://stackoverflow.com/questions/13634835/monodroid-screen-dimensions
//i get some tip from url above.
wm = GetSystemService(Activity.WindowService).JavaCast<IWindowManager>();
//i don't know the getApplication, how to write in monodroid?
wmParams = ((MyApplication)getApplication()).getMywmParams();
wmParams.Type = LayoutParams.TYPE_PHONE;
wmParams.Format = PixelFormat.RGBA_8888;
wmParams.Flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
| LayoutParams.FLAG_NOT_FOCUSABLE;
wmParams.Gravity = Gravity.LEFT | Gravity.TOP;
wmParams.X = 0;
wmParams.Y = 0;
wmParams.Width = 40;
wmParams.Height = 40;
wm.AddView(myFV, wmParams);
}
public override void onDestroy()
{
base.OnDestroy();
wm.RemoveView(myFV);
}
}
}
If you're in an Activity, you should be able to use:
this.Application

Resources