when focused remove underline from material entry control in xamarin forms for ios - xamarin

using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using Xamarin.Forms.Material.iOS;
using MyApp.iOS;
using MyApp;
using UIKit;
using System.ComponentModel;
[assembly: ExportRenderer(typeof(CustomMaterialEntry), typeof(CustomMaterialEntryRenderer), new[] { typeof(VisualMarker.MaterialVisual) })]
namespace MyApp.iOS
{
public class CustomMaterialEntryRenderer : MaterialEntryRenderer
{
/// <summary>
/// Element Changed Event
/// </summary>
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (this.Control != null)
{
UITextField UpdatedEntry = (UITextField)Control;
UpdatedEntry.Background = null;
UpdatedEntry.BackgroundColor = UIColor.Clear;
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (this.Control != null)
this.Control.Underline.Color = UIColor.Clear;
}
}
}
For android, it's working but when focused on the material entry in ios, it displays with the underline. please help me to remove the underline in ios for xamarin.forms

Try to set the active underline height to 0f :
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (this.Control != null)
{
Control.ActiveTextInputController.UnderlineHeightActive = 0f;
}
}

Related

PageRenderer does not work with camera2 API

I am trying to get Camera2 API to work from Xamarin Forms through Page Rendering.
[assembly: ExportRenderer(typeof(CameraPage), typeof(CameraActivity))]
namespace BlueDemo.Droid
{
[Activity(Label = "CameraActivity")]
public class CameraActivity : PageRenderer
{
Activity activity;
TextureView textureView;
global::Android.Views.View view;
public CameraActivity(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
if (e.OldElement != null || Element == null)
{
return;
}
try
{
SetupUserInterface();
AddView(view);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(#" ERROR: ", ex.Message);
}
}
void SetupUserInterface()
{
//activity = Context as Activity;
view = activity.LayoutInflater.Inflate(Resource.Layout.activity_camera, this, false);
activity.FragmentManager.BeginTransaction().Replace(Resource.Id.container, Camera2BasicFragment.NewInstance()).Commit();
}
The break point does hit the LayoutInflater but it does not open the view for the camera. The original Camera2 API: Camera2 API link for camera activity
This has SetContentView which does not work with Page Renderer.

Is there a better way to set TabbedPage bottom tab bar height than in ViewModel?

I want to change the height of the bottom TabBar in my Xamarin app. Now I am doing this via ViewModel properties:
public partial class MainPage : TabbedPage
{
public int TabBarHeight
{
get { return _tabBarHeight; }
set { _tabBarHeight = value; OnPropertyChanged(); }
}
int _tabBarHeight = 200;
And a custom renderer for iOS:
using System;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using System.Diagnostics;
using Ja.Enums;
using System.ComponentModel;
using CoreGraphics;
[assembly: ExportRenderer(typeof(TabbedPage), typeof(Ja.iOS.TabbedPageRenderer))]
namespace Ja.iOS
{
public class TabbedPageRenderer : TabbedRenderer
{
private MainPage _page;
public TabbedPageRenderer()
{
this.ViewControllerSelected += OnTabbarControllerItemSelected;
}
public override void ViewWillLayoutSubviews()
{
base.ViewWillLayoutSubviews();
TabBar.Frame = new CGRect(TabBar.Frame.X, TabBar.Frame.Y + (TabBar.Frame.Height - _page.TabBarHeight), TabBar.Frame.Width, _page.TabBarHeight);
}
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
e.OldElement.PropertyChanged -= Current_PropertyChanged;
return;
}
if (e.NewElement != null)
{
_page = (MainPage)e.NewElement;
e.NewElement.PropertyChanged += Current_PropertyChanged;
}
}
void Current_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "FrameHeight")
ViewWillLayoutSubviews();
}
}
}
Is this an optimal way to be doing this? I seem to remember having a shared class. That class would contain the code that's in the first few lines of my main as bound elements.
Could anyone comment on this and perhaps suggest a better way of doing this.
Looks like something I would use a Custom Control for (which is what I think you mean with 'shared class').
First you create the class below in your PCL. A CustomTabbedPage, which inherits from TabbedPage but has one extra property: 'TabBarHeight'
public class CustomTabbedPage : TabbedPage {
public static readonly BindableProperty TabBarHeightProperty = BindableProperty.Create("TabBarHeight", typeof(int), typeof(TabbedPage), 0);
public int TabBarHeight {
get { return (int)GetValue(TabBarHeightProperty); }
set { SetValue(TabBarHeightProperty, value); }
}
}
Now edit your renderer to a renderer of the CustomTabbedPage. Then you can easily access the TabBarHeight property by using this.Element.TabBarHeight.
using System;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using System.Diagnostics;
using Ja.Enums;
using System.ComponentModel;
using CoreGraphics;
[assembly: ExportRenderer(typeof(CustomTabbedPage), typeof(Ja.iOS.CustomTabbedPageRenderer))]
namespace Ja.iOS
{
public class CustomTabbedPageRenderer : TabbedRenderer
{
public TabbedPageRenderer()
{
this.ViewControllerSelected += OnTabbarControllerItemSelected;
}
public override void ViewWillLayoutSubviews()
{
base.ViewWillLayoutSubviews();
TabBar.Frame = new CGRect(TabBar.Frame.X, TabBar.Frame.Y + (TabBar.Frame.Height - this.Element.TabBarHeight), TabBar.Frame.Width, this.Element.TabBarHeight);
}
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.OldElement != null) {
e.OldElement.PropertyChanged -= Element_PropertyChanged;
}
if (e.NewElement != null) {
e.NewElement.PropertyChanged += Element_PropertyChanged;
}
}
void Current_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "FrameHeight")
ViewWillLayoutSubviews();
}
}
}
There might be some syntax errors in there but you get the point.
Shoot if you have any questions.

Is there a way to recognize a short or long press on a screen with Xamarin.Forms?

I have an application that responds to a short tap on the screen. I do this by adding a gesture recognizer.
Is there a way that I can make it respond to either a short or a long press and have these call different methods?
You will have implement renderers for that. In case of iOS you can use UILongPressGestureRecognizer to detect a long-press action, while in case of Android, you can use GestureDetector to do the same.
Forms control
public class CustomView : ContentView
{
public event EventHandler<EventArgs> LongPressEvent;
public void RaiseLongPressEvent()
{
if (IsEnabled)
LongPressEvent?.Invoke(this, EventArgs.Empty);
}
}
iOS renderer
[assembly: ExportRenderer(typeof(CustomView), typeof(CustomViewRenderer))]
namespace AppNamespace.iOS
{
public class CustomViewRenderer : ViewRenderer<CustomView, UIView>
{
UILongPressGestureRecognizer longPressGestureRecognizer;
protected override void OnElementChanged(ElementChangedEventArgs<CustomView> e)
{
longPressGestureRecognizer = longPressGestureRecognizer ??
new UILongPressGestureRecognizer(() =>
{
Element.RaiseLongPressEvent();
});
if (longPressGestureRecognizer != null)
{
if (e.NewElement == null)
{
this.RemoveGestureRecognizer(longPressGestureRecognizer);
}
else if (e.OldElement == null)
{
this.AddGestureRecognizer(longPressGestureRecognizer);
}
}
}
}
}
Android renderer
[assembly: ExportRenderer(typeof(CustomView), typeof(CustomViewRenderer))]
namespace AppNamespace.Droid
{
public class CustomViewRenderer : ViewRenderer<CustomView, Android.Views.View>
{
private CustomViewListener _listener;
private GestureDetector _detector;
public CustomViewListener Listener
{
get
{
return _listener;
}
}
public GestureDetector Detector
{
get
{
return _detector;
}
}
protected override void OnElementChanged(ElementChangedEventArgs<CustomView> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
GenericMotion += HandleGenericMotion;
Touch += HandleTouch;
_listener = new CustomViewListener(Element);
_detector = new GestureDetector(_listener);
}
}
protected override void Dispose(bool disposing)
{
GenericMotion -= HandleGenericMotion;
Touch -= HandleTouch;
_listener = null;
_detector?.Dispose();
_detector = null;
base.Dispose(disposing);
}
void HandleTouch(object sender, TouchEventArgs e)
{
_detector.OnTouchEvent(e.Event);
}
void HandleGenericMotion(object sender, GenericMotionEventArgs e)
{
_detector.OnTouchEvent(e.Event);
}
}
public class CustomViewListener : GestureDetector.SimpleOnGestureListener
{
readonly CustomView _target;
public CustomViewListener(CustomView s)
{
_target = s;
}
public override void OnLongPress(MotionEvent e)
{
_target.RaiseLongPressEvent();
base.OnLongPress(e);
}
}
}
Sample Usage
<local:CustomView LongPressEvent="Handle_LongPress" />
Code-behind
void Handle_LongPressEvent(object sender, System.EventArgs e)
{
//handle long press event here
}
You can also customize above to add a command to make it more MVVM friendly.
You can refer this link for more details regarding gesture recognizers.
http://arteksoftware.com/gesture-recognizers-with-xamarin-forms/
You will have implement renderers for that. In case ios and android
best way for do that!

Xamarin Forms Map Tap Gesture IOS

I implement a custom renderer for Xamarin Forms Map to implement a Tap Event.
I the PCL I have this code :
public class ExtMap : Map
{
/// <summary>
/// Event thrown when the user taps on the map
/// </summary>
public event EventHandler<MapTapEventArgs> Tapped;
#region Constructors
/// <summary>
/// Default constructor
/// </summary>
public ExtMap()
{
}
/// <summary>
/// Constructor that takes a region
/// </summary>
/// <param name="region"></param>
public ExtMap(MapSpan region)
: base(region)
{
}
#endregion
public void OnTap(Position coordinate)
{
OnTap(new MapTapEventArgs { Position = coordinate });
}
protected virtual void OnTap(MapTapEventArgs e)
{
var handler = Tapped;
if (handler != null)
handler(this, e);
}
}
And in my IOS Project this code :
public class ExtMapRenderer : MapRenderer
{
private readonly UITapGestureRecognizer _tapRecogniser;
public ExtMapRenderer()
{
_tapRecogniser = new UITapGestureRecognizer(OnTap)
{
NumberOfTapsRequired = 1,
NumberOfTouchesRequired = 1
};
}
private void OnTap(UITapGestureRecognizer recognizer)
{
var cgPoint = recognizer.LocationInView(Control);
var location = ((MKMapView)Control).ConvertPoint(cgPoint, Control);
((ExtMap)Element).OnTap(new Position(location.Latitude, location.Longitude));
}
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
if (Control != null)
Control.RemoveGestureRecognizer(_tapRecogniser);
base.OnElementChanged(e);
if (Control != null)
{
var nativeMap = Control as MKMapView;
nativeMap.ShowsUserLocation = true;
Control.AddGestureRecognizer(_tapRecogniser);
}
}
}
In the simulator sometimes the event is raised, but I have to click randomly a lot of time in the map.
In my iPhone, the event is never raised.
In Android phone & Emulator, the event is working correctly so I suspect a bad implementation in IOS Project but I do not know how I can improve it.
I have an iOS map renderer where tap is working correctly.
My OnElementChanged is a bit different to yours:
private MKMapView Map => Control as MKMapView;
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
if (e.OldElement != null && Map != null)
{
Control?.RemoveGestureRecognizer(_tapRecogniser);
}
if (e.NewElement != null)
{
Control?.AddGestureRecognizer(_tapRecogniser);
}
}

How to create an Entry renderer in Xamarin?

I want to create a renderer for an entry field using Xamarin. What is the best way to get it? I have no idea how to get it, any help will be appreciate.
This is my entry field and I want to create font size renderer for that
<Entry x:Name="txtTest"/>
This is sample of Entry that set padding to 0 and can set TextSize property.
namespace projectname
{
public class BareEntry : Entry
{
public BareEntry ()
{
}
public static readonly BindableProperty TextSizeProperty =
BindableProperty.Create<BareEntry,int> (X => X.TextSize, 10);
public int TextSize
{
get {return (int)base.GetValue (TextSizeProperty);}
set {base.SetValue (TextSizeProperty, value);}
}
}
}
This part is on android platform
using Xamarin.Forms;
using projectname;
using projectname.Droid;
using Xamarin.Forms.Platform.Android;
using MocMSearch.Droid;
using Android.Support.V4.Content;
[assembly: ExportRenderer (typeof (BareEntry), typeof (BareEntryRenderer))]
namespace MocMSearch.Droid
{
public class BareEntryRenderer : EntryRenderer
{
public BareEntryRenderer ()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Entry> e)
{
base.OnElementChanged(e);
Recreate ();
}
void Recreate()
{
if (this.Control == null) return;
Control.SetPadding (0,0,0,0);
Control.SetTextSize (Android.Util.ComplexUnitType.Mm,(Element as BareEntry).TextSize);
}
protected override void OnElementPropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged (sender, e);
if (e.PropertyName == "TextSize")
{
Recreate ();
this.Invalidate ();
}
}
}
}

Resources