How to create standard design of ios switch on android? - c#

I want to create a custom switch on android which looks like standard ios switch.
Please help me do it

We could implement it by using Custom Renderer
in Forms
Create a Custom Button
public class CustomSwitch : Button
{
public bool IsToggle { get; set; }
public event EventHandler Toggled;
public void OnToggled() =>
Toggled?.Invoke(this, null);
}
in Android Project
Firstly, we need install the package Xamarin.Android.SwitchButton from Nuget .
And in the ButtonRenderer
using Android.Content;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using App14.Droid;
using Com.Kyleduo.Switchbutton;
using App14;
[assembly:ExportRenderer(typeof(CustomSwitch),typeof(MySwitchRenderer))]
namespace App14.Droid
{
public class MySwitchRenderer : ButtonRenderer
{
Context context { get;}
public MySwitchRenderer(Context context) : base(context)
{
this.context = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
SwitchButton switchButton = new SwitchButton(context);
// switchButton.SetHighlightColor(Android.Graphics.Color.Green);
switchButton.CheckedChange += SwitchButton_CheckedChange;
SetNativeControl(switchButton);
}
}
private void SwitchButton_CheckedChange(object sender, CompoundButton.CheckedChangeEventArgs e)
{
var customSwitch = Element as CustomSwitch;
customSwitch.IsToggle = e.IsChecked;
customSwitch.OnToggled();
}
}
}
Now in Forms we need to use Device class to add different Element on iOS and Android .
<StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<OnPlatform x:TypeArguments="View">
<On Platform="Android">
<local:CustomSwitch Toggled="CustomSwitch_Toggled" />
</On>
<On Platform="iOS">
<Switch Toggled="Switch_Toggled" />
</On>
</OnPlatform>
</StackLayout>
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
private void Switch_Toggled(object sender, ToggledEventArgs e)
{
Switch _switch = sender as Switch;
ToggledChanged(_switch.IsToggled);
}
private void CustomSwitch_Toggled(object sender, EventArgs e)
{
CustomSwitch customSwitch = sender as CustomSwitch;
ToggledChanged(customSwitch.IsToggle);
}
void ToggledChanged(bool isToggle)
{
DisplayAlert("Title", $"IsToggled{isToggle}", "OK");
}
}

You need to create custom renderer for switch;
public class CustomSwitchRenderer : SwitchRenderer
{
public CustomSwitchRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Switch> e)
{
base.OnElementChanged(e);
if (e.OldElement != null || e.NewElement == null)
return;
/*
Control.TrackDrawable.MinimumWidth holds the value of the tracker size.
to change it, you need a new shape for tracker.
*/
Control.SetTrackResource(Resource.Drawable.tracker);
}
}
So you need to create a drawable for tracker under your android project.

Related

Xamarin.Forms: change text size on DatePicker

I created the following custom renderer, but it only changes the selected value size
[assembly: ExportRenderer(typeof(DatePickerCustom), typeof(CustomDatePickerRenderer))]
namespace Vendo.Android.Renderers
{
public class CustomDatePickerRenderer : DatePickerRenderer
{
public CustomDatePickerRenderer(Context context) : base(context)
{ }
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
{
base.OnElementChanged(e);
if (this.Control == null)
return;
Control.TextSize = 16;
}
}
}
I need to change the text size this way:

Xamarin Forms get cursor position in editor control

How can I get the cursor position inside Editor control?
Ive been looking for an answer but the best I could find was the Cursor class, but that doesnt seem to exist in xamarin.
You could custom a Editor,and use custom renderer to get the SelectionPosition of the EditText.
custom a FormEditor in your fomrs project:
public class FormEditor:Editor
{
public int SelectionPosition;
public EventHandler SelectChanageEvent { get; set; }
}
create AndroidEditor in your Android project:
class AndroidEditor : EditorRenderer, EditTextSelectChange
{
private Context mContext;
public AndroidEditor(Context context) : base(context)
{
mContext = context;
}
public void Change(int lastPos, int curPos)
{
((FormEditor)Element).SelectionPosition = curPos;
((FormEditor)Element).SelectChanageEvent.Invoke(this, null);
}
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
MyEditText myEditText = new MyEditText(mContext);
myEditText.SetEditTextSelectChange(this);
SetNativeControl(myEditText);
}
}
custom MyEditText in your Android project:
public class MyEditText : FormsEditText
{
private int mLastPos = 0;
private int mCurPos = 0;
private EditTextSelectChange editTextSelectChange;
public void SetEditTextSelectChange(EditTextSelectChange editTextSelectChange)
{
this.editTextSelectChange = editTextSelectChange;
}
public MyEditText(Context context) : base(context)
{
}
protected override void OnSelectionChanged(int selStart, int selEnd)
{
base.OnSelectionChanged(selStart, selEnd);
if (editTextSelectChange != null)
{
mCurPos = selEnd;
editTextSelectChange.Change(mLastPos, mCurPos);
mLastPos = mCurPos;
}
}
public interface EditTextSelectChange
{
void Change(int lastPos, int curPos);
}
}
then use in your page.xaml:
<local:FormEditor x:Name="editor" Placeholder="Hello"></local:FormEditor>
in your page.xaml.cs:
public YourPage()
{
InitializeComponent();
editor.SelectChanageEvent += SelectEvent;
}
private void SelectEvent(object sender, EventArgs e)
{
// you could get the Curson Position by editor.SelectionPosition
Console.WriteLine("curPos = {0}", editor.SelectionPosition);
}

How to remove visual material entry underline

We are using the visual material entry for our project.
using Xamarin.Forms.Material.Android;
[assembly: ExportRenderer(typeof(ProgressBar), typeof(CustomMaterialProgressBarRenderer), new[] { typeof(VisualMarker.MaterialVisual) })]
namespace MyApp.Android
{
public class CustomMaterialProgressBarRenderer : MaterialProgressBarRenderer
{
//...
}
}
How to remove material entry underline?
Create a dimension resource (Add a new .xml file and save it under your Android project in Resources\values)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="box_stroke_dim">0dp</dimen>
</resources>
Custom renderer implementation for every Entry with Visual="Material"
[assembly: ExportRenderer(typeof(Entry), typeof(App.Droid.MyMaterialEntryRenderer),
new[] { typeof(VisualMarker.MaterialVisual) })]
namespace App.Droid
{
public class MyMaterialEntryRenderer : MaterialEntryRenderer
{
public MyMaterialEntryRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
Control?.SetBoxStrokeWidthResource(Resource.Dimension.box_stroke_dim);
Control?.SetBoxStrokeWidthFocusedResource(Resource.Dimension.box_stroke_dim);
}
}
}
You can use custom renderers with material visual to achieve entry underline removal.
I am using the below code to apply it for all entries in the project and it is working with Xamarin Forms 4.8+
Xamarin Android
Entry
[assembly: ExportRenderer(typeof(Entry), typeof(EntryMaterialRendererAndroid), new[] { typeof(VisualMarker.MaterialVisual) })]
namespace XFTest.Droid.Renderers
{
public class EntryMaterialRendererAndroid : MaterialEntryRenderer
{
public EntryMaterialRendererAndroid(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.BoxStrokeWidth = 0;
Control.BoxStrokeWidthFocused = 0;
}
}
}
}
Xamarin iOS
Entry
[assembly: ExportRenderer(typeof(Entry), typeof(EntryMaterialRendereriOS), new[] { typeof(VisualMarker.MaterialVisual) })]
namespace XFTest.iOS.Renderers
{
public class EntryMaterialRendereriOS : MaterialEntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
EntryRemoveUnderLine();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
EntryRemoveUnderLine();
}
protected void EntryRemoveUnderLine()
{
if (Control != null)
{
Control.BorderStyle = UITextBorderStyle.None;
Control.Underline.Enabled = false;
Control.Underline.DisabledColor = UIColor.Clear;
Control.Underline.Color = UIColor.Clear;
Control.Underline.BackgroundColor = UIColor.Clear;
Control.ActiveTextInputController.UnderlineHeightActive = 0f;
Control.PlaceholderLabel.BackgroundColor = UIColor.Clear;
}
}
}
}

Webview display problem on Android when changing page and display mode (Portrait -> Landscape)

when I try to display in a webView one of my web page in Landscape mode ( https://web-labosims.org/animations/App_refraction_reflexion/App_refraction&reflexion.html ) it works correctly on Android.
Screenshots
But when it's not the first page and I change orientation between pages it doesn't work properly anymore on Android (display problem) ...
MainPage.xaml.cs
public partial class MainPage : ContentPage
{
private List<Anim> lesAnimations;
public MainPage()
{
InitializeComponent();
String animsJson = "[{\"Nom\":\"Réfraction et réfexion\",\"url\":\"https://web-labosims.org/animations/App_refraction_reflexion/App_refraction&reflexion.html\",\"imageUrl\":\"App_refraction.png\"},{\"Nom\":\"Synthèse soustractive\",\"url\":\"https://web-labosims.org/animations/App_lumiere3/App_lumiere3.html\",\"imageUrl\":\"App_soustractive.png\"}]";
lesAnimations = JsonConvert.DeserializeObject<List<Anim>>(animsJson);
maListView.ItemsSource = lesAnimations;
maListView.ItemSelected += (sender, e) =>
{
if (maListView.SelectedItem != null)
{
Anim item = maListView.SelectedItem as Anim;
GoAnimation(item.url);
}
maListView.SelectedItem = null;
};
}
private async Task GoAnimation(String url)
{
await this.Navigation.PushAsync(new Animation(url));
}
protected override void OnAppearing()
{
base.OnAppearing();
DependencyService.Get<IOrientationHandler>().ForcePortrait();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
DependencyService.Get<IOrientationHandler>().ForceLandscape();
}
}
Animation.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:LaboSims;assembly=LaboSims"
x:Class="LaboSims.Animation">
<ContentPage.Content>
<WebView x:Name="maWebView"
WidthRequest="1000"
HeightRequest="1000"
/>
</ContentPage.Content>
</ContentPage>
Animation.xaml.cs
public partial class Animation : ContentPage
{
public Animation(String url)
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, false);
maWebView.Source = url;
}
}
IOrientationHandler.cs
namespace LaboSims
{
public interface IOrientationHandler
{
void ForceLandscape();
void ForcePortrait();
}
}
And on Android
using Android.Content.PM;
using LaboSims.Droid;
using Plugin.CurrentActivity;
[assembly: Xamarin.Forms.Dependency(typeof(OrientationHandler))]
namespace LaboSims.Droid
{
public class OrientationHandler : IOrientationHandler
{
public void ForceLandscape()
{
CrossCurrentActivity.Current.Activity.RequestedOrientation = ScreenOrientation.Landscape;
}
public void ForcePortrait()
{
CrossCurrentActivity.Current.Activity.RequestedOrientation = ScreenOrientation.Portrait;
}
}
}
Screenshots
I don't understand where I make an error...
I was sure that the problem should be simple and indeed it is a simple mistake ... I had made a small mistake in my meta tag on my web page.
I changed it to :
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
And everything is working properly

Opening a pdf in webview needs more than 5 clicks or no load

I'm trying to open pdf with a webview but some pdf says "No Preview Avaliable", or you have to give it many clicks to open it or directly some crash the app.
Im using the web https://www.pdfpdf.com/samples.html and the first 5 pdfs work fine although sometimes I have to click them 5 times to open them. With those of the last sections, the app crashes when I click on one of them.
The following code can work if I open the pdf in WebView directly .
This is my code:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="webviewproblema.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<StackLayout>
<WebView
x:Name="Browser"
HeightRequest="1000"
Navigating="Browser_Navigating"
Source="{Binding HTMLContent}"
WidthRequest="1000" />
</StackLayout>
</ContentPage>
public partial class MainPage : ContentPage
{
public string HTMLContent { get; set; }
public MainPage()
{
InitializeComponent();
Browser.Source = "https://www.pdfpdf.com/samples.html";
}
private void Browser_Navigating(object sender, WebNavigatingEventArgs e)
{
// With this,the app crash
//string url = "https://docs.google.com/gview?embedded=true&url=" + System.Net.WebUtility.UrlEncode(e.Url);
Browser.IsVisible = true;
string url = e.Url;
if ( e.Url.EndsWith(".pdf") || e.Url.EndsWith(".PDF") && !e.Url.Contains("drive.google.com"))
{
Browser.Source = "https://drive.google.com/viewerng/viewer?embedded=true&url=" + url;
}
}
}
You could use custom renderer to open external link in a website .
In forms
Create a custom webview
public class MyWebView : WebView
{
public static readonly BindableProperty UriProperty = BindableProperty.Create(propertyName: "Uri",
returnType: typeof(string),
declaringType: typeof(MyWebView),
defaultValue: default(string));
public string Uri
{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
}
in Android project
using Android.Content;
using Android.Net.Http;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Webkit;
using Android.Widget;
using App32;
using App32.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(MyWebView), typeof(CustomWebViewRenderer))]
namespace App32.Droid
{
public class CustomWebViewRenderer : WebViewRenderer
{
Context _context;
public CustomWebViewRenderer(Context context) : base(context)
{
_context = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
Android.Webkit.WebView web_view = new Android.Webkit.WebView(_context);
web_view.LoadUrl(((MyWebView)Element).Uri);
web_view.SetWebViewClient(new MyWebViewClient());
SetNativeControl(web_view);
Control.Settings.JavaScriptEnabled = true;
}
}
}
public class MyWebViewClient : WebViewClient
{
public override void OnReceivedSslError(Android.Webkit.WebView view, SslErrorHandler handler, SslError error)
{
handler.Proceed();
}
public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, IWebResourceRequest request)
{
var url = request.Url.ToString();
if (request.Url.ToString().EndsWith(".pdf") || request.Url.ToString().EndsWith(".PDF") && !request.Url.ToString().Contains("drive.google.com"))
{
view.LoadUrl("https://drive.google.com/viewerng/viewer?embedded=true&url=" + request.Url.ToString());
view.SetWebViewClient(new MyWebViewClient());
}
return true;
}
}
}
in iOS project
using System;
using App32;
using App32.iOS;
using Foundation;
using ObjCRuntime;
using UIKit;
using WebKit;
using Xamarin.Forms.Platform.iOS;
[assembly: Xamarin.Forms.ExportRenderer(typeof(MyWebView), typeof(MyWebViewRenderer))]
namespace App32.iOS
{
public class MyWebViewRenderer : ViewRenderer<MyWebView, WKWebView>
{
WKWebView _wkWebView;
protected override void OnElementChanged(ElementChangedEventArgs<MyWebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
var config = new WKWebViewConfiguration();
_wkWebView = new WKWebView(Frame, config);
_wkWebView.NavigationDelegate = new MyDelegete();
SetNativeControl(_wkWebView);
}
if(e.NewElement!=null)
{
var webview = Element as MyWebView;
var url = webview.Uri;
if (url.EndsWith(".pdf") || url.EndsWith(".PDF") && !url.Contains("drive.google.com"))
{
Control.LoadRequest(new NSUrlRequest(new NSUrl("https://drive.google.com/viewerng/viewer?embedded=true&url=" + webview.Uri)));
}
else
{
Control.LoadRequest(new NSUrlRequest(new NSUrl(webview.Uri)));
}
}
}
}
public class MyDelegete :WKNavigationDelegate
{
public override void DecidePolicy(WKWebView webView, WKNavigationAction navigationAction, WKWebpagePreferences preferences, Action<WKNavigationActionPolicy, WKWebpagePreferences> decisionHandler)
{
// base.DecidePolicy(webView, navigationAction, preferences, decisionHandler);
var url = navigationAction.Request.Url.ToString();
if (url.EndsWith(".pdf") || url.EndsWith(".PDF") && !url.Contains("drive.google.com"))
{
webView.LoadRequest(new NSUrlRequest(new NSUrl("https://drive.google.com/viewerng/viewer?embedded=true&url=" + url)));
}
decisionHandler.Invoke(WKNavigationActionPolicy.Allow, preferences);
}
}
}
in xaml
Now you can use it in xaml like
<StackLayout>
<local:MyWebView x:Name="Browser" Uri="https://xxx" HeightRequest="1000" WidthRequest="1000" />
</StackLayout>

Categories