Forum Xamarin.Forms

Announcement:

The Xamarin Forums have officially moved to the new Microsoft Q&A experience. Microsoft Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

To create new threads and ask questions head over to Microsoft Q&A for .NET and get involved today.

How do I keep the keyboard always visible in a page?

isayasisayas Member ✭✭
edited February 2 in Xamarin.Forms

I am implementing a phone dialler-like functionality in my app. The dialler page will have an entry field to show the entered phone number. I want the keyboard to be always visible when users open the dialler page instead of getting hidden when the Entry loses focus. How can I achieve this?

Listening to unfocus events and returning the focus to the entry is not an option as users could see the keyboard start to disappear and then reappear again.

Answers

  • jezhjezh Member, Xamarin Team Xamurai

    You do not need to achieve the system's keyboard always on, just achieve a custom keboard like following code.

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
                 xmlns:local="clr-namespace:App32"
                 x:Class="App32.Page2">
        <ContentPage.Content>
            <StackLayout>
                <Grid HorizontalOptions="Center"
              VerticalOptions="Center">
                    <Grid.BindingContext>
                        <local:KeypadViewModel />
                    </Grid.BindingContext>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="80" />
                        <ColumnDefinition Width="80" />
                        <ColumnDefinition Width="80" />
                    </Grid.ColumnDefinitions>
                    <!-- Internal Grid for top row of items -->
                    <Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>
                        <Frame Grid.Column="0"
                           >
                            <Label Text="{Binding DisplayText}" />
                        </Frame>
                        <Button Text="&#x21E6;"
                        Command="{Binding DeleteCharCommand}"
                        Grid.Column="1"
                        BorderWidth="0" />
                    </Grid>
                    <Button Text="1"
                    Command="{Binding AddCharCommand}"
                    CommandParameter="1"
                    Grid.Row="1" Grid.Column="0" />
                    <Button Text="2"
                    Command="{Binding AddCharCommand}"
                    CommandParameter="2"
                    Grid.Row="1" Grid.Column="1" />
                    <Button Text="3"
                    Command="{Binding AddCharCommand}"
                    CommandParameter="3"
                    Grid.Row="1" Grid.Column="2" />
                    <Button Text="4"
                    Command="{Binding AddCharCommand}"
                    CommandParameter="4"
                    Grid.Row="2" Grid.Column="0" />
                    <Button Text="5"
                    Command="{Binding AddCharCommand}"
                    CommandParameter="5"
                    Grid.Row="2" Grid.Column="1" />
                    <Button Text="6"
                    Command="{Binding AddCharCommand}"
                    CommandParameter="6"
                    Grid.Row="2" Grid.Column="2" />
                    <Button Text="7"
                    Command="{Binding AddCharCommand}"
                    CommandParameter="7"
                    Grid.Row="3" Grid.Column="0" />
                    <Button Text="8"
                    Command="{Binding AddCharCommand}"
                    CommandParameter="8"
                    Grid.Row="3" Grid.Column="1" />
                    <Button Text="9"
                    Command="{Binding AddCharCommand}"
                    CommandParameter="9"
                    Grid.Row="3" Grid.Column="2" />
                    <Button Text="*"
                    Command="{Binding AddCharCommand}"
                    CommandParameter="*"
                    Grid.Row="4" Grid.Column="0" />
                    <Button Text="0"
                    Command="{Binding AddCharCommand}"
                    CommandParameter="0"
                    Grid.Row="4" Grid.Column="1" />
                    <Button Text="#"
                    Command="{Binding AddCharCommand}"
                    CommandParameter="#"
                    Grid.Row="4" Grid.Column="2" />
                </Grid>
            </StackLayout>
        </ContentPage.Content>
    </ContentPage>
    

    Here is KeypadViewModel.cs

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Text;
    using System.Windows.Input;
    using Xamarin.Forms;
    namespace App32
    {
        class KeypadViewModel : INotifyPropertyChanged
        {
            string inputString = "";
            string displayText = "";
            char[] specialChars = { '*', '#' };
            public event PropertyChangedEventHandler PropertyChanged;
            // Constructor
            public KeypadViewModel()
            {
                AddCharCommand = new Command<string>((key) =>
                {
                    // Add the key to the input string.
                    InputString += key;
                });
                DeleteCharCommand = new Command(() =>
                {
                    // Strip a character from the input string.
                    InputString = InputString.Substring(0, InputString.Length - 1);
                },
                    () =>
                    {
                        // Return true if there's something to delete.
                        return InputString.Length > 0;
                    });
            }
            // Public properties
            public string InputString
            {
                protected set
                {
                    if (inputString != value)
                    {
                        inputString = value;
                        OnPropertyChanged("InputString");
                        DisplayText = FormatText(inputString);
                        // Perhaps the delete button must be enabled/disabled.
                        ((Command)DeleteCharCommand).ChangeCanExecute();
                    }
                }
                get { return inputString; }
            }
            public string DisplayText
            {
                protected set
                {
                    if (displayText != value)
                    {
                        displayText = value;
                        OnPropertyChanged("DisplayText");
                    }
                }
                get { return displayText; }
            }
            // ICommand implementations
            public ICommand AddCharCommand { protected set; get; }
            public ICommand DeleteCharCommand { protected set; get; }
            string FormatText(string str)
            {
                bool hasNonNumbers = str.IndexOfAny(specialChars) != -1;
                string formatted = str;
                if (hasNonNumbers || str.Length < 4 || str.Length > 10)
                {
                }
                else if (str.Length < 8)
                {
                    formatted = String.Format("{0}-{1}",
                                              str.Substring(0, 3),
                                              str.Substring(3));
                }
                else
                {
                    formatted = String.Format("({0}) {1}-{2}",
                                              str.Substring(0, 3),
                                              str.Substring(3, 3),
                                              str.Substring(6));
                }
                return formatted;
            }
            protected void OnPropertyChanged(string propertyName)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
    

    Hope it can help you.


    Xamarin forums are migrating to a new home on Microsoft Q&A!
    We invite you to post new questions in the Xamarin forums’ new home on Microsoft Q&A!
    For more information, please refer to this sticky post.

  • isayasisayas Member ✭✭

    Thank you for the reply @jezh. I have tried this solution, but the problem is it needs a lot of customization to make the keyboard look like the default keyboard that the users' are accustomed to. It also feels like I am reinventing the wheel.

    What I actually want to do is, I want to show the TelephoneKeyboard when the entry is focused, but I want the keyboard to be always visible even if the user clicks on other elements on the page. So, I am basically looking for a way to make they entry to never lose focus, or make the keyboard always visible irrespective of what element is selected on the page.

  • jezhjezh Member, Xamarin Team Xamurai

    What I actually want to do is, I want to show the TelephoneKeyboard when the entry is focused, but I want the keyboard to be always visible even if the user clicks on other elements on the page.

    I don't think it is a good idea to make the keyboard to be always visible even if user clicks on other elements on the page,which will affect the user experience. So I don't recommend it.

    But if you really want to do that, in xamarin android, you can try to use CustomRenderer to achieve this.

    You can refer to the following code:

    [assembly: ExportRenderer(typeof(Entry), typeof(MyEntryCustomRenderer))]
    namespace App32.Droid
    {
        public class MyEntryCustomRenderer : EntryRenderer
        {
            public MyEntryCustomRenderer(Context context) : base(context)
            {
            }
            protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
            {
                base.OnElementChanged(e);
    
            }
        }
    }
    

    And add the following code to MainActivity.cs:

        private bool _lieAboutCurrentFocus;
        public override bool DispatchTouchEvent(MotionEvent ev)
        {
            var focused = CurrentFocus;
            bool customEntryRendererFocused = focused != null && focused.Parent is YourCustomEditorRenderer;
    
            _lieAboutCurrentFocus = customEntryRendererFocused;
            var result = base.DispatchTouchEvent(ev);
            _lieAboutCurrentFocus = false;
    
            return result;
        }
    
        public override Android.Views.View CurrentFocus
        {
            get
            {
                if (_lieAboutCurrentFocus)
                {
                    return null;
                }
    
                return base.CurrentFocus;
            }
        }
    

    Refer: https://forums.xamarin.com/discussion/56523/entry-cell-loses-focus-on-button-press-in-android-but-not-ios-work-around

Sign In or Register to comment.