I know the Xamarin.Android code, but how about Xamarin.IOS?
Xamarin.Android code:
public class CustomNumEntry : EntryRenderer
{
public CustomNumEntry(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (this.Control != null)
{
Control.SetPadding(10, 0, 0, 15);
Control.InputType = Android.Text.InputTypes.ClassNumber | Android.Text.InputTypes.NumberFlagSigned | Android.Text.InputTypes.NumberFlagDecimal;
Control.TextAlignment = Android.Views.TextAlignment.Center;
}
if (e.OldElement == null)
{
var nativeEditText = (global::Android.Widget.EditText)Control;
nativeEditText.SetSelectAllOnFocus(true);
}
}
}
for Xamarin iOS:
nativeTextField.EditingDidBegin += (object sender, EventArgs eIos) =>
{
nativeTextField.PerformSelector(new Selector("selectAll"), null, 0.0f);
};
for Xamarin.Forms using custom renderer for iOS(which you are looking for):
public class CustomNumEntry : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
var nativeTextField = (UITextField)Control;
nativeTextField.EditingDidBegin += (object sender, EventArgs eIos) =>
{
nativeTextField.PerformSelector(new ObjCRuntime.Selector("selectAll"), null, 0.0f);
};
}
}
}
Solution:
You can implement it in method EditingStarted.Refer the following code
namespace xxx.iOS
{
public class MyEntryRenderer:EntryRenderer,IUITextFieldDelegate
{
public MyEntryRenderer()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
Control.WeakDelegate = this;
}
}
[Export("textFieldDidBeginEditing:")]
public void EditingStarted(UITextField textField)
{
textField.PerformSelector(new Selector("selectAll:"), null, 0.0f);
}
}
}
Here is the solution via this post:
private void Entry_Focused(object sender, FocusEventArgs e)
{
myEntry.CursorPosition = 0;
myEntry.SelectionLength = entryItem.Text.Length;
}
Example shows selection of all text on focused but you can do the same on demand too.
Related
I am implementing code for SwitchRenderer in Android but it appears that there is an issue with the code as I get a warning:
'SwitchRender.SwitchRender()' is obsolete; 'This constuctor is
obsolets as of version 2.5. Please use SwitchRender(Context) instead.'
Does anyone have any ideas how I can resolve this problem:
using Japanese.Android;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Japanese;
[assembly: ExportRenderer(typeof(ExtSwitch), typeof(ExtSwitchRenderer))]
namespace Japanese.Android
{
public class ExtSwitchRenderer : SwitchRenderer
{
private ExtSwitch view;
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Switch> e)
{
base.OnElementChanged(e);
if (e.OldElement != null || e.NewElement == null)
return;
view = (ExtSwitch)Element;
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.JellyBean)
{
if (this.Control != null)
{
if (this.Control.Checked)
{
this.Control.TrackDrawable.SetColorFilter(view.SwitchOnColor.ToAndroid(), PorterDuff.Mode.SrcAtop);
}
else
{
this.Control.TrackDrawable.SetColorFilter(view.SwitchOffColor.ToAndroid(), PorterDuff.Mode.SrcAtop);
}
this.Control.CheckedChange += this.OnCheckedChange;
UpdateSwitchThumbImage(view);
}
//Control.TrackDrawable.SetColorFilter(view.SwitchBGColor.ToAndroid(), PorterDuff.Mode.Multiply);
}
}
private void UpdateSwitchThumbImage(CustomSwitch view)
{
if (!string.IsNullOrEmpty(view.SwitchThumbImage))
{
view.SwitchThumbImage = view.SwitchThumbImage.Replace(".jpg", "").Replace(".png", "");
int imgid = (int)typeof(Resource.Drawable).GetField(view.SwitchThumbImage).GetValue(null);
Control.SetThumbResource(Resource.Drawable.icon);
}
else
{
Control.ThumbDrawable.SetColorFilter(view.SwitchThumbColor.ToAndroid(), PorterDuff.Mode.Multiply);
// Control.SetTrackResource(Resource.Drawable.track);
}
}
private void OnCheckedChange(object sender, CompoundButton.CheckedChangeEventArgs e)
{
if (this.Control.Checked)
{
this.Control.TrackDrawable.SetColorFilter(view.SwitchOnColor.ToAndroid(), PorterDuff.Mode.SrcAtop);
}
else
{
this.Control.TrackDrawable.SetColorFilter(view.SwitchOffColor.ToAndroid(), PorterDuff.Mode.SrcAtop);
}
}
protected override void Dispose(bool disposing)
{
this.Control.CheckedChange -= this.OnCheckedChange;
base.Dispose(disposing);
}
}
}
Check out the answer here. The new way to do Android custom renderers would be this:
public class ExtSwitchRenderer : SwitchRenderer
{
private ExtSwitch view;
public ExtSwitchRenderer(Context context) : base(context) { }
....
}
Then if you actually need to use the Android context in your custom renderer, you would use the one passed in through the constructor, instead of Forms.Context for example.
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!
Is there a way to detect a long tap on an image control in Xamarin Forms?
I'm using the carousel view to display images and would like to give the option to delete them by selecting with a long tap.
Based on your suggestions in the comments this is what I did:
(The purpose of the control is to be able to select an Image with a LongTap)
I defined my own Image control in the PCL:
IsSelected BindableProperty.
LongTap event.
public class MyImage:Image
{
private BindableProperty IsSelectedProperty = BindableProperty.Create("IsSelected", typeof(bool), typeof(MyImage), false);
public bool IsSelected {
get {
return (bool)GetValue(IsSelectedProperty);
}
set {
SetValue(IsSelectedProperty, value);
}
}
public event EventHandler LongClick;
public void OnLongClick()
{
IsSelected = !IsSelected;
if(IsSelected)
{
Opacity = 0.5;
}
else
{
Opacity = 1;
}
if (LongClick != null)
{
LongClick(this, EventArgs.Empty);
}
}
}
And this is my custom renderer: (Defined in the Android project)
[assembly: ExportRenderer(typeof(MyImage), typeof(MyImageRenderer))]
namespace PRISMCarouselView.Droid.Renderes
{
public class MyImageRenderer : ImageRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
{
base.OnElementChanged(e);
if (Control != null)
{
ImageView androidSource = Control as ImageView;
MyImage myImage = e.NewElement as MyImage;
androidSource.LongClick += (object sender, LongClickEventArgs ee) =>
{
myImage.OnLongClick();
};
}
}
}
}
Edit 1:
Here's a slightly updated version, I use the BindingPropertyChangedDelegate to change the opacity of the image:
public class SelectableImage : Image
{
public SelectableImage()
{
}
private static BindableProperty IsSelectedProperty = BindableProperty.Create("IsSelected",
typeof(bool),
typeof(SelectableImage),
false, BindingMode.Default, null, (sender, o1, o2) => {
SelectableImage imageControl = sender as SelectableImage;
if(imageControl != null)
{
if(imageControl.IsSelected)
{
imageControl.Opacity = 0.5;
}else
{
imageControl.Opacity = 1;
}
}
});
public bool IsSelected {
get {
return (bool)GetValue(IsSelectedProperty);
}
set {
SetValue(IsSelectedProperty, value);
}
}
}
And the renderer:
[assembly: ExportRenderer(typeof(SelectableImage), typeof(SelectableImageRenderer))]
namespace Muserma.Apps.Droid.Renderer
{
public class SelectableImageRenderer : ImageRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
{
base.OnElementChanged(e);
if (Control != null)
{
ImageView androidSource = Control as ImageView;
SelectableImage selectableImage = e.NewElement as SelectableImage;
androidSource.LongClick += (object sender, LongClickEventArgs ee) =>
{
selectableImage.IsSelected = !selectableImage.IsSelected;
};
}
}
}
}
I'm trying to implement the functionality of the android button through a ButtonRender. The problem occurs when I try to join ".LongClick" and ".touch", since it does not launch the long click event.
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
{
this.SetBackgroundResource(Resource.Drawable.button);
base.OnElementChanged(e);
Android.Widget.Button thisButton = Control as Android.Widget.Button;
thisButton.LongClickable = true;
thisButton.LongClick += delegate
{
string s = "";
};
thisButton.Touch += (object sender, Android.Views.View.TouchEventArgs e2) =>
{
if (e2.Event.Action == MotionEventActions.Down)
{
.
.
.
}
else if (e2.Event.Action == MotionEventActions.Up)
{
.
.
.
}
else if (e2.Event.Action == MotionEventActions.HoverExit || e2.Event.Action == MotionEventActions.Cancel)
{
.
.
.
}
else if (e2.Event.Action == MotionEventActions.Move)
{
.
.
.
}
};
}
To invoke the event of native control, we need to create event handlers in our custom control, and together an interface which inherits from IViewController in order to set values from renderers.
Here is my demo, first of all, create a custom button:
public class MyButton : Xamarin.Forms.Button, IMyButtonController
{
public event EventHandler Touched;
void IMyButtonController.SendTouched()
{
Touched?.Invoke(this, EventArgs.Empty);
}
public event EventHandler LongClicked;
void IMyButtonController.SendLongClicked()
{
LongClicked?.Invoke(this, EventArgs.Empty);
}
public event EventHandler Released;
void IMyButtonController.SendReleased()
{
Released?.Invoke(this, EventArgs.Empty);
}
}
The IMyButtonController inherits from IViewController like this:
public interface IMyButtonController : IViewController
{
void SendTouched();
void SendLongClicked();
void SendReleased();
}
Then in android project, implement the ButtonRenderer and IMyButtonController like this:
[assembly: ExportRenderer(typeof(MyButton), typeof(MyButtonRenderer))]
namespace ProjectNameSpace.Droid
{
public class MyButtonRenderer : Xamarin.Forms.Platform.Android.ButtonRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
if (Control != null)
{
Control.SetOnTouchListener(ButtonTouchListener.Instance.Value);
Control.LongClickable = true;
Control.SetOnLongClickListener(ButtonLongClickListener.Instance.Value);
}
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (Control != null)
{
Control.SetOnTouchListener(null);
Control.SetOnLongClickListener(null);
}
}
base.Dispose(disposing);
}
private class ButtonTouchListener : Java.Lang.Object, Android.Views.View.IOnTouchListener
{
public static readonly Lazy<ButtonTouchListener> Instance = new Lazy<ButtonTouchListener>(() => new ButtonTouchListener());
public bool OnTouch(Android.Views.View v, Android.Views.MotionEvent e)
{
var renderer = v.Tag as ButtonRenderer;
if (renderer != null)
{
var buttonController = renderer.Element as IMyButtonController;
if (e.Action == Android.Views.MotionEventActions.Down)
{
buttonController?.SendTouched();
}
else if (e.Action == Android.Views.MotionEventActions.Up)
{
buttonController?.SendReleased();
}
}
return false;
}
}
private class ButtonLongClickListener : Java.Lang.Object, Android.Views.View.IOnLongClickListener
{
public static readonly Lazy<ButtonLongClickListener> Instance = new Lazy<ButtonLongClickListener>(() => new ButtonLongClickListener());
public bool OnLongClick(Android.Views.View v)
{
var renderer = v.Tag as ButtonRenderer;
((IMyButtonController)renderer?.Element)?.SendLongClicked();
return true;
}
}
}
}
The keyboard hides when I create the page, but when I change the focus to another entry I call the same function but the soft keyboard didn't hide?
ConfigService.cs
public void HideKeyboard()
{
var inputMethodManager = Xamarin.Forms.Forms.Context.GetSystemService(Context.InputMethodService) as InputMethodManager;
if (inputMethodManager != null && Xamarin.Forms.Forms.Context is Activity)
{
var activity = Xamarin.Forms.Forms.Context as Activity;
var focusedView = activity.CurrentFocus;
var token = focusedView == null ? null : focusedView.WindowToken;
inputMethodManager.HideSoftInputFromWindow(token, HideSoftInputFlags.None);
}
}
VerplaatsingPage.xaml.cs
namespace SI_Foodware.View
{
public partial class VerplaatsingPage : ContentPage
{
VerplaatsingPageViewModel vm;
public VerplaatsingPage (SubMenu subMenu)
{
InitializeComponent ();
vm = new VerplaatsingPageViewModel(this, subMenu);
BindingContext = vm;
}
public void OnClickDestination(object o, EventArgs e)
{
}
public void OnClickSelect(object o, EventArgs e)
{
}
public void OnClickCancel(object o, EventArgs e)
{
}
protected override void OnAppearing()
{
base.OnAppearing();
ent_drager.Focus();
IConfigService configService = DependencyService.Get<IConfigService>();
configService.HideKeyboard();
}
}
}
VerplaatsingPageViewModel.cs
public void Keyboard()
{
IConfigService configService = DependencyService.Get<IConfigService>();
configService.HideKeyboard();
}
public void OnScan(string scanProperty)
{
var list = db.GetAllItems<ContainerLine>();
Artikel = list[0].ItemNo;
Description = list[0].Description;
LotNo = list[0].LotNo;
NumberOfContainer = list[0].Quantity;
KiloDrager = list[0].KgQuantity;
UnitOfMeasure = list[0].UnitofMeasureCode;
LocationFrom = list[0].BinCode;
cp.FindByName<Entry>("ent_destination").Focus();
Keyboard(); <-- Doesn't Work
}
I solved my problem by using
inputMethodManager.ToggleSoftInputFromWindow(token, ShowSoftInputFlags.None, HideSoftInputFlags.None);
instead of
inputMethodManager.HideSoftInputFromWindow(token, HideSoftInputFlags.None);