I'm attempting to disable the "long press" animation that seems to come by default on Android devices using Xamarin Forms. I have a custom renderer written (that properly works, I can change the background, etc.. and the changes are resounded in the listview). Here is the core of my renderer:
protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
{
base.OnElementChanged(e);
if (Control != null) {
Control.LongClickable = false;
}
}
I have also tried Control.SetOnLongClickListener (null). Neither of the above controls seem to affect the long press behavior of the listview. Any suggestions would be greatly appreciated :)
Related
I am a newbie in xamarin forms app development, currently, I am facing an issue in overriding the toolbar back button onclick. In ios, I am able to achieve but in android its not working can anyone help me out on how to achieve this in my project.
By default it works on iOS and on Android physical back button only. If you want to also support the navigation bar button, you need to use custom platform logic. Take a look on this blog post: Let’s Override Navigation Bar back button click in Xamarin For. He creates a common content page with custom action for back button:
public class CoolContentPage : ContentPage
{
/// <summary>
/// Gets or Sets the Back button click overriden custom action
/// </summary>
public Action CustomBackButtonAction { get; set; }
public static readonly BindableProperty EnableBackButtonOverrideProperty =
BindableProperty.Create(
nameof(EnableBackButtonOverride),
typeof(bool),
typeof(CoolContentPage),
false);
/// <summary>
/// Gets or Sets Custom Back button overriding state
/// </summary>
public bool EnableBackButtonOverride
{
get
{
return (bool)GetValue(EnableBackButtonOverrideProperty);
}
set
{
SetValue(EnableBackButtonOverrideProperty, value);
}
}
}
And then he calls CustomBackAction inside OnOptionsItemSelected method in Anroid code.
Best way to intercept Back Navigation ( Navigation in general ) would be by adding your NavigationPageRenderer so you can control the events and cancel or redirect them, look at my answer How to intercept Navigation Bar Back Button Clicked in Xamarin Forms?
I came to this post with same question about Xamarin forms navigation back button and later discovered that since Xamarin.Forms Shell this is done easily by overriding the OnNavigating method in the AppShell.xaml.cs file as I have done here:
protected override void OnNavigating(ShellNavigatingEventArgs e)
{
// Make sure it's safe to examine the current page
if ((Shell.Current != null) &&
(Shell.Current.CurrentPage != null))
{
Console.WriteLine($"{e.Source} {Shell.Current.Title}");
if (
// Detect Back Navigation
e.Source == ShellNavigationSource.Pop &&
// Cancel or Not, based on (for example) the Title of the current page.
(Shell.Current.Title != "My Main Page"))
{
e.Cancel();
Shell.Current.GoToAsync("..");
}
}
base.OnNavigating(e);
}
In case anyone else stumbles upon, I put a sample on GitHub of what worked for me for Android and iOS both.
I'm new to Xamarin.Forms and mobile app development, so patience & kindness is appreciated! Am building a barcode scanner app with Xamarin.Forms PCL, trying to use MVVM. The scanner is an EXTERNAL bluetooth device (so can't use ZXing).
This project has a fixed requirement to use the scanner as a keyboard-type input and for the user to be able to quickly swap out one bluetooth device for another brand (so no device-specific APIs can be used). A second requirement is for the user to never be allowed to type anything directly into the Entry control. Input should come from the scanner and only the scanner, so therefore we don't ever want the keyboard showing on the scanning page.
There are other pages that have Entry controls where the user WILL need access to the keyboard, and the scanner should be able to stay connected to bluetooth even when a non-scanning screen is displayed. Therefore, I need a reliable way to set the soft keyboard to never be displayed on the scanning page (there is only one input control on this page, and it's intended for scanner use only), but to allow the keyboard to be accessed on other pages.
When on the scanning page, we want focus to always be set on the scanner's Entry control, so when the control gets a Completed event, we do stuff with the value received, then clear out the control and re-set focus on it to prepare for the next scan.
I have been stumbling around writing custom controls and android renderers, and with setting up dependencies (preferred), both with partial success. Either way, there's a timing issue related to how soon focus is set on the control. If there's not enough of a delay before focus is set, the soft keyboard stays visible. In the code sample provided, I added a short sleep delay, which mostly works to keep the keyboard hidden. However, the keyboard still "flashes" on the screen briefly with each scan, which looks terrible. Would really prefer a solution that is less hacky and ugly.
Is there a good, simple way to remove the soft keyboard entirely for a page, while still allowing an input control to receive focus, so that a scanned barcode can be received? And/or any other suggestions that will allow me to still meet the requirements?
(PS: the scanning page does not currently use MVVM binding. Just trying to get the keyboard to go away first, then will work on binding.)
Below is one way I tried to solve it. There were others as well. NOTE: Ultimately I went with a completely different approach which I'll post as an answer.
The custom control (in PCL):
using Xamarin.Forms;
namespace MyPCL.Views
{
//See ScanEntryRenderer in the Android project.
public class ScanEntryControl : Entry
{
public ScanEntryControl() { }
}
}
The Xaml page (notice InputTransparent = "True" on the custom control. This is so the user cannot directly enter input on the android device. All input must come from the bluetooth scanner).
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyPCL.Views"
x:Class="MyPCL.Views.ScanTestPage"
Title="Scan Test Page" >
<ContentPage.Content>
<StackLayout>
<Label Text="Scanner Test" />
<local:ScanEntryControl x:Name="BarcodeEntry"
Completed="BarcodeEntryCompleted"
InputTransparent="True"/>
<Label x:Name="ResultLabel" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
The code behind for the form:
using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace MyPCL.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ScanTestPage : ContentPage
{
public ScanTestPage()
{
InitializeComponent();
BarcodeEntry.Focus();
}
protected override void OnAppearing()
{
base.OnAppearing();
BarcodeEntry.Focus();
}
private void BarcodeEntryCompleted(object sender, EventArgs e)
{
if (!string.IsNullOrWhiteSpace(BarcodeEntry.Text))
{
ResultLabel.Text = "You entered: " + BarcodeEntry.Text;
BarcodeEntry.Text = string.Empty;
}
BarcodeEntry.Focus();
}
}
}
The Android renderer:
using Android.Content;
using Xamarin.Forms;
using MyPCL.Views;
using MyPCL.Droid;
using Xamarin.Forms.Platform.Android;
using Android.Views.InputMethods;
[assembly: ExportRenderer(typeof(ScanEntryControl), typeof(ScanEntryRenderer))]
namespace MyPCL.Droid
{
public class ScanEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
((ScanEntryControl)e.NewElement).PropertyChanging += OnPropertyChanging;
}
if (e.OldElement != null)
{
((ScanEntryControl)e.OldElement).PropertyChanging -= OnPropertyChanging;
}
// Disable the Keyboard on Focus
this.Control.ShowSoftInputOnFocus = false;
}
private void OnPropertyChanging(object sender, PropertyChangingEventArgs propertyChangingEventArgs)
{
// Check if the view is about to get Focus
if (propertyChangingEventArgs.PropertyName == VisualElement.IsFocusedProperty.PropertyName)
{
// Dismiss the Keyboard
InputMethodManager imm = (InputMethodManager)this.Context.GetSystemService(Context.InputMethodService);
imm.HideSoftInputFromWindow(this.Control.WindowToken, 0);
}
}
}
}
I have been stumbling around writing custom controls and android renderers, and with setting up dependencies (preferred), both with partial success.
You can use EditText.ShowSoftInputOnFocus to achieve it in your scanning page, then the keyboard will not appear when your entry gets the focus:
using Android.Content;
using Android.Views.InputMethods;
using Edi;
using Edi.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(ScanEntryControl), typeof(ScanEntryRenderer))]
namespace Edi.Droid
{
public class ScanEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
((ScanEntryControl)e.NewElement).PropertyChanging += OnPropertyChanging;
}
if (e.OldElement != null)
{
((ScanEntryControl)e.OldElement).PropertyChanging -= OnPropertyChanging;
}
// Disable the Keyboard on Focus
this.Control.ShowSoftInputOnFocus = false;
}
private void OnPropertyChanging(object sender, PropertyChangingEventArgs propertyChangingEventArgs)
{
// Check if the view is about to get Focus
if (propertyChangingEventArgs.PropertyName == VisualElement.IsFocusedProperty.PropertyName)
{
// incase if the focus was moved from another Entry
// Forcefully dismiss the Keyboard
InputMethodManager imm = (InputMethodManager)this.Context.GetSystemService(Context.InputMethodService);
imm.HideSoftInputFromWindow(this.Control.WindowToken, 0);
}
}
}
}
In other pages you can still use Entry, so the keyboard will be appear.
UPDATE:
ScanEntryControl class in PCL:
using Xamarin.Forms;
namespace Edi
{
public class ScanEntryControl : Entry
{
}
}
.xaml file:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Edi"
x:Class="Edi.MainPage">
<ContentPage.Content>
<StackLayout>
<local:ScanEntryControl Text="ScanEntryControl"/>
<Entry Text="Entry"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
This answer does not solve the original issue directly, in the sense that it does not involve an Entry control. However, it was the only thing that worked for me, and ended up being a more elegant solution:
The Bluetooth scanner was in HID mode (Human Interface Device) by default, meaning the only way it could interact with the app was by imitating key presses, thereby necessitating an Entry (EditText) control, or similar. I switched the scanner to SPP mode (Serial Port Profile) and adapted the code from this page (see also the GitHub repo here, and for more info on HID vs SPP see this document).
The resulting code activates the scanner and then "listens" for input. When input is received, it is displayed in a Label rather than an Entry control.
There were other problems with the Entry control that I didn't mention prior: often it would add a repeat character to the front of the barcode and/or chop off one or more characters from the end. The SPP solution solved all that as well. If anyone wants the code I came up with, let me know. It will take some work to put together in a generic example, so not posting it at the moment.
I was facing the same problem. I had found one sample over in the Xamarin forums that IMHO contained the key solution:
You must override Focus() and must not call the base method. This gives you full control over the virtual keyboard. In all other solutions I have seen the virtual keyboard appears sometimes.
Of course your custom Entry needs methods to show/hide the keyboard. You would call them in your OnFocus() method. My sample control (see below) also has a bindable property that allows you to show the virtual keyboard automatically on Focus. So you may decide for every field if the keyboard should appear automatically or not.
In addition I have included another object that informs you if the virtual keyboard is currently visible and its size in case you need to size your layout accordingly.
Since this is quite a common question in several different forums I have decided to create a sample control and a small app to show the features.
In addition I wrote a detailed Readme that explains all crucial points of the implementation.
You will find it here: https://github.com/UweReisewitz/XamarinAndroidEntry
protected override void OnAppearing()
{
base.OnAppearing();
txtLotID.Focus();
}
private void OnLoad()
{
Init();
swScanMode.IsToggled = Global.IsScannable;
txtLotID.EnableKeyboard = !Global.IsScannable;
txtLotID.OnEntryScanned += BtnSearch_Clicked;
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
if (txtLotID.IsReadOnly)
{
txtLotID.Text = "";
**txtLotID.IsReadOnly = false;**
txtLotID.GetFocus();
}
return true;
});
}
So know how to set up a custom renderer (only partially apparently) with an OnElementChanged method. I followed this (http://forums.xamarin.com/discussion/17654/tabbedpage-icons-not-visible-android)
protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
{
base.OnElementChanged(e);
_activity = this.Context as Activity;
}
This gets hit, but it never displays the page afterwards.
Anyone have any ideas?
It is showing up now. I had to use the base class of TabbedRender rather than TabbedPageRenderer. I also had to add this.SetWillNotDraw(false) in the CustomRenderer constructor.
Here you can find a full TabbedPageRenderer ready to be modified. It comes directly from Xamarin.Forms Android.
Still I'm trying to set a different Font Size...
I'm having an issue with the ActionBar in my app; In certain scenarios the ActionBar appears to go "under" the notifications/title bar. It's reproducible each time and i can't figure out why it's happening. I use the ZXING application with Intents to scan barcodes and return them to my app, and it's at some point during this process the issue occurs.
I thought it'd be best to show you the issue with pictures.
1: The app home screen, all is normal.
2: Use the menu item to scan a barcode. This appears as expected.
3: The product page for the scanned item appears normal. If i click 'Cancel' however...
4: The ActionBar has now gone under the notifications/title bar.
The only other mention of a bug such of this (that i can find) is in this GitHub issue for ActionBarSherlock (which i'm using): https://github.com/JakeWharton/ActionBarSherlock/issues/602
I have checked and i'm not doing anything weird with configChanges as Jake mentions.
This issue is seen on my 4.2.2 device, i'm unable to test on a pre-ICS device unfortunately.
Any thoughts or suggestions are welcome!
I'm guessing it not getting reset back when you come back from the zxing screen. In your Activity for "Best Before", try reseting the window flags for fullscreen something like:
#Override
protected void onResume() {
super.onResume();
//getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
setSystemUiVisibility(this, View.SYSTEM_UI_FLAG_VISIBLE /* SYSTEM_UI_FLAG_VISIBLE=0 */);
}
private static void setSystemUiVisibility(final Activity activity, final int newValue){
if (activity.getWindow() != null){
View v = activity.getWindow().getDecorView();
if (v != null) {
try {
Method methodSetSystemUIVisibility = v.getClass().getMethod("setSystemUiVisibility", int.class);
methodSetSystemUIVisibility.invoke(v, newValue);
} catch (Exception noop) {
}
}
}
}
I'd like to gray out a button so it appears disabled to the user, but still listen for clicks so that I can display a message to the user that explains why the button isn't applicable.
I'd like to ensure that the Android API is the one configuring whatever is the appropriate standard disabled appearance as opposed to manually setting the button color to gray, etc. What's the best way to do this?
Related: Android - Listen to a disabled button
this is custom button which expose the event of touch when disabled
it working for sure, and tested. designed specific to you
public class MyObservableButton extends Button
{
public MyObservableButton(Context context, AttributeSet attrs)
{
super(context, attrs);
}
private IOnClickWhenEnabledListner mListner;
public void setOnClickWhenEnabledListener(IOnClickWhenEnabledListner listener) {
mListner = listener;
}
private interface IOnClickWhenEnabledListner {
public void onClickWhenEnabled();
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (!isEnabled() && mListner != null) {
mListner.onClickWhenEnabled();
}
}
return super.onTouchEvent(event);
}
}
this is the right way to accomplish what you want from my point of view as android developer.
there is no problem extanding all android's views, and use them on the xml files, and source instead..
good luck
You could also manually set the background of your Button to the default one for disabled. But leave the button enabled and handle the click events in the normal fashion
something like this should do it:
mBtn.setBackgroundResource(android.R.drawable.btn_default_normal_disabled);
I am not an Android expert, so there could be better ways, but what about disabling the button and overlaying a transparent view that will catch the events?
You could have the view always there laying below the button so you just need to change a z-index, or create it dynamically when needed.
If your button is on the newer types that controls color via backgroundTint rather then background, this is what you should do:
if (enabled) {
ViewCompat.setBackgroundTintList(btn, getResources().getColorStateList(R.color.button_states)); // either use a single color, or a state_list color resource
} else {
ViewCompat.setBackgroundTintList(btn, ColorStateList.valueOf(Color.GRAY));
}
// make sure we're always clickable
btn.setEnabled(true);
btn.setClickable(true);
You could also set the Button's style to look grayed out (for both pressed and non-pressed states), then setOnClickListener() as normal, but have the onClick() method give the message that it isn't clickable.
Since button extends textview. You may use the methods in textview such as .setTextColor() or .setBackgroundColor() .
Now for the the display you have 2 options:
AlertDialog - displays an alert but doesn't self close unless specified.
Toast - displays a text over a given time and self closes.
take your pick.