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;
}
}
}
}
Related
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:
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);
}
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.
I have a sample pdf URL "http://www.africau.edu/images/default/sample.pdf". I want to show this pdf file and display in my mobile app using Xamarin.Forms. I tried using webviews and some custom renderers but did not work.
public class PdfViewRenderer : WebViewRenderer
{
internal class PdfWebChromeClient : WebChromeClient
{
public override bool OnJsAlert(Android.Webkit.WebView view, string url, string message, JsResult result)
{
if (message != "PdfViewer_app_scheme:print")
{
return base.OnJsAlert(view, url, message, result);
}
using (var printManager = Forms.Context.GetSystemService(Android.Content.Context.PrintService) as PrintManager)
{
printManager?.Print(FileName, new FilePrintDocumentAdapter(FileName, Uri), null);
}
return true;
}
public string Uri { private get; set; }
public string FileName { private get; set; }
}
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement == null)
{
return;
}
var pdfView = Element as PdfView;
if (pdfView == null)
{
return;
}
if (string.IsNullOrWhiteSpace(pdfView.Uri) == false)
{
Control.SetWebChromeClient(new PdfWebChromeClient
{
Uri = pdfView.Uri,
//FileName = GetFileNameFromUri(pdfView.Uri)
});
}
Control.Settings.AllowFileAccess = true;
Control.Settings.AllowUniversalAccessFromFileURLs = true;
LoadFile(pdfView.Uri);
}
private static string GetFileNameFromUri(string uri)
{
var lastIndexOf = uri?.LastIndexOf("/", StringComparison.InvariantCultureIgnoreCase);
return lastIndexOf > 0 ? uri.Substring(lastIndexOf.Value, uri.Length - lastIndexOf.Value) : string.Empty;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName != PdfView.UriProperty.PropertyName)
{
return;
}
var pdfView = Element as PdfView;
if (pdfView == null)
{
return;
}
if (string.IsNullOrWhiteSpace(pdfView.Uri) == false)
{
Control.SetWebChromeClient(new PdfWebChromeClient
{
Uri = pdfView.Uri,
// FileName = GetFileNameFromUri(pdfView.Uri)
});
}
LoadFile(pdfView.Uri);
}
private void LoadFile(string uri)
{
if (string.IsNullOrWhiteSpace(uri))
{
return;
}
//Control.Resources = new Uri(string.Format("ms-appx-web:///Assets/pdfjs/web/viewer.html?file={0}", string.Format("ms-appx-web:///Assets/Content/{0}", WebUtility.UrlEncode(PdfView.Uri))));
Control.LoadUrl($"file:///android_asset/pdfjs/web/viewer.html?file=file://{uri}");
//Control.LoadUrl(uri);
Control.LoadUrl(string.Format("ms-appx-web:///Assets/pdfjs/web/viewer.html?file={0}", string.Format("ms-appx-web:///Assets/Content/{0}", WebUtility.UrlEncode(uri))));
}
}
Your XAML
<WebView x:Name="Webview"
HeightRequest="1000"
WidthRequest="1000"
VerticalOptions="FillAndExpand"/>
Put your Webview source like this
Webview.Source = "https://docs.google.com/gview?
embedded=true&url="+"http://www.africau.edu/images/default/sample.pdf";
In Android
[assembly: ExportRenderer(typeof(CustomWebView), typeof(CustomWebViewRenderer))]
namespace DipsDemoXaml.Droid.Renderer
public class CustomWebViewRenderer : WebViewRenderer
{
public CustomWebViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
Control.Settings.AllowUniversalAccessFromFileURLs = true;
Control.Settings.BuiltInZoomControls = true;
Control.Settings.DisplayZoomControls = true;
}
this.Control.SetBackgroundColor(Android.Graphics.Color.Transparent);
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName != "Uri") return;
var customWebView = Element as CustomWebView;
if (customWebView != null)
{
Control.LoadUrl(string.Format("file:///android_asset/pdfjs/web/viewer.html?file={0}", string.Format("file:///android_asset/Content/{0}", WebUtility.UrlEncode(customWebView.Uri))));
}
}
}
}
for iOS
[assembly: ExportRenderer(typeof(CustomWebView), typeof(CustomWebViewRenderer))]
namespace DipsDemoXaml.iOS.Renderes
{
public class CustomWebViewRenderer : ViewRenderer<CustomWebView, UIWebView>
{
protected override void OnElementChanged(ElementChangedEventArgs<CustomWebView>
e)
{
base.OnElementChanged(e);
if (Control == null)
{
SetNativeControl(new UIWebView());
}
if (e.OldElement != null)
{
// Cleanup
}
if (e.NewElement != null)
{
var customWebView = Element as CustomWebView;
string fileName = Path.Combine(NSBundle.MainBundle.BundlePath, string.Format("Content/{0}", WebUtility.UrlEncode(customWebView.Uri)));
Control.LoadRequest(new NSUrlRequest(new NSUrl(fileName, false)));
Control.ScalesPageToFit = true;
}
this.Opaque = false;
this.BackgroundColor = Color.Transparent.ToUIColor();
}
}
}
In shared
namespace DipsDemoXaml.Custom.Renderer
{
public class CustomWebView : WebView
{
public static readonly BindableProperty UriProperty =
BindableProperty.Create(nameof(Uri),typeof(string),
typeof(CustomWebView),default(string))
;
public string Uri
{
get => (string) GetValue(UriProperty);
set => SetValue(UriProperty, value);
}
}
}
In XAML You can Call Like this
<renderer:CustomWebView Uri="{Binding SelectedJournal.Uri}" />
I think Problem in your Custom Rendering You can Create a new property like URI in a string and You can Call the URI you need a way to access Android and iOS webview for that you can call android asset pdf viewer for android and for Ios you can pass a new NSUrl to load the pdf inside your app
I´m using a custom renderer to customize the height and color of my progress bar, but my progress bar gets blurred:
My CustomRenderer looks like this:
public class ColorProgressBarRenderer : ProgressBarRenderer
{
public ColorProgressBarRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.ProgressBar> e)
{
base.OnElementChanged(e);
if (e.NewElement == null)
{
return;
}
if (Control != null)
{
UpdateBarColor();
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == ColorProgressBar.BarColorProperty.PropertyName)
{
UpdateBarColor();
}
}
private void UpdateBarColor()
{
var element = Element as ColorProgressBar;
Control.ProgressTintList = Android.Content.Res.ColorStateList.ValueOf(element.BarColor.ToAndroid());
Control.ScaleY = 10f;
}
}
My CustomProgressBar looks like this:
public class ColorProgressBar : ProgressBar
{
//public static BindableProperty BarColorProperty = BindableProperty.Create<ColorProgressBar, Color>(p => p.BarColor, default(Color));
public static BindableProperty BarColorProperty = BindableProperty.Create(nameof(BarColor), typeof(Color), typeof(ColorProgressBar), default(Color));
public Color BarColor
{
get { return (Color)GetValue(BarColorProperty); }
set { SetValue(BarColorProperty, value); }
}
}
This only happens in Android, with my iOS Renderer all is working fine!
Why this is happen?
You can try this advanced progress bar.
https://www.nuget.org/packages/MultiColor.ProgressBar/
Documentation: https://github.com/udayaugustin/ProgressBar/blob/master/README.md
It supports multi color.
It has properties like
Height
Width
Corner Radius and etc