ساخت کیبورد سفارشی برای اندروید با Xamarin Forms — از صفر تا صد
در برخی موارد هنگام اجرای پروژهها نیاز به کیبوردهایی داریم که بعضی امکانات خاص دارند که کیبورد معمولی اندروید فاقد آن است. در این مقاله روش ساخت کیبورد سفارشی اندروید با Xamarin Forms را توضیح خواهیم داد.
نخستین گزینهای که در این موارد به ذهن میرسد، این است که یک Entry غیر فعال با یک GestureRecognizer اضافه کنیم که یک کنترل به همراه یک انیمیشن نمایش میدهد تا ظاهر شدن کیبورد را شبیهسازی کند، اما به سرعت متوجه میشویم که این ایده قابلیت اجرای مجدد ندارد و لذا آن را کنار میگذاریم.
بهترین گزینه این است که مسیر native را پی بگیریم، اما اغلب این مسیرها در نهایت به ایجاد یک سرویس منتهی میشوند. بدیهی است که کاربران ما علاقه چندانی به این ندارند که یک کیبورد را جداگانه دانلود کنند تا صرفاً در اپلیکیشن مورد استفاده قرار دهند و باید توجه داشته باشیم که ما از Xamarin Forms استفاده میکنیم. از آنجا که میخواهیم این کیبورد سفارشی را در Xamarin Forms پیادهسازی کنیم، بهترین گزینه ممکن یک Custom Renderer (+) برای کنترل Entry است که از EditText به عنوان مبنایی برای کنترل native استفاده میکند. تلاش میکنیم تا همه دانشی که در نتیجه بررسی گزینههای مختلف به دست آمده است را در مورد این کیبورد سفارشی اندروید پیادهسازی کنیم.
کدنویسی
توجه کنید که به منظور پیادهسازی کیبورد سفارشی اندروید باید Xamarin Forms با نسخه 3.6.0.135200-pre1 یا بالاتر استفاده کنید، زیرا به متد OnFocusChangeRequest نیاز داریم که در این نسخهها موجود است. ابتدا یک کنترل سفارشی میسازیم که یک مشخصه «اتصالپذیر» bindable دارد.
در این مشخصه، خصوصیتی به نام EnterCommand و با نوع ICommand وجود دارد که برای اتصال به اکشن فشرده شدن کلید Enter استفاده میشود. اینک کنترل سفارشی ما به صورت زیر است:
1namespace CustomKeyboard
2{
3 public class EntryWithCustomKeyboard : Entry
4 {
5 public static readonly BindableProperty EnterCommandProperty = BindableProperty.Create(
6 nameof(EnterCommand),
7 typeof(ICommand),
8 typeof(EntryWithCustomKeyboard),
9 default(ICommand),
10 BindingMode.OneWay
11 );
12
13 public ICommand EnterCommand
14 {
15 get => (ICommand)GetValue(EnterCommandProperty);
16 set => SetValue(EnterCommandProperty, value);
17 }
18 }
19}
سپس به پروژه اندروید میرویم و آنجا کار میکنیم. در ادامه دوباره به پروژه Xamarin Forms خود بازمیگردیم. پیش از ادامه باید مطمئن شویم که همه پکیجهای اندروید مورد نیاز را داریم:
سپس باید MainActivity اندروید خود را ویرایش کنیم تا از نمایش کیبورد نیتیو جلوگیری کنیم. به این منظور از خصوصیت SoftInputMode.StateAlwaysHidden استفاده میکنیم:
1namespace CustomKeyboard.Droid
2{
3 [Activity(
4 Label = "CustomKeyboard",
5 Icon = "@mipmap/icon",
6 Theme = "@style/MainTheme",
7 MainLauncher = true,
8 ScreenOrientation = ScreenOrientation.Portrait,
9 ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
10 WindowSoftInputMode = SoftInput.StateAlwaysHidden,
11 LaunchMode = LaunchMode.SingleTask)]
12 public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
13 {
14 protected override void OnCreate(Bundle savedInstanceState)
15 {
16 TabLayoutResource = Resource.Layout.Tabbar;
17 ToolbarResource = Resource.Layout.Toolbar;
18
19 base.OnCreate(savedInstanceState);
20 global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
21
22 LoadApplication(new App());
23
24 Window.SetSoftInputMode(SoftInput.StateAlwaysHidden);
25 }
26 }
27}
کار بعدی که انجام میدهیم آغاز تعریف کیبورد سفارشی است.
درون پوشه Resource/layout یک لیآوت اندروید به نام CustomKeyboard و از نوع InputMethodService.Keyboard ایجاد میکنیم.
1<?xml version="1.0" encoding="utf-8"?>
2<android.inputmethodservice.Keyboard
3 xmlns:android="http://schemas.android.com/apk/res/android"
4 android:id="@+id/keyboard"
5 android:layout_width="match_parent"
6 android:layout_height="wrap_content"
7 android:layout_alignParentBottom="true"
8 android:keyPreviewLayout="@null"
9 android:keyBackground="@drawable/keyboard_background"
10 android:textColor="@android:color/white"
11 android:background="@android:color/white" />
قبل از هر چیز مشخصه alignParentBottom را به صورت true تنظیم میکنیم، زیرا میخواهیم کیبورد از سمت پایین صفحه ظاهر شود. سپس مشخصه keyPreviewLayout را به صورت null تنظیم میکنیم، زیرا در این نمونه نمیخواهیم وقتی کلیدی فشرده شد، لیآوت واکنشی داشته باشد.
چنان که میبینید مشخصه keyBackground به یک drawable به نام keyboard_background اشاره میکند که وجود ندارد، بنابراین باید آن را درون پوشه Drawable به صورت یک فایل xml بسازیم. در این بخش یک سلکتور حالت برای دو حالت کلید یعنی normal (بدون فشرده شدن) و pressed (فشرده شدن) تعریف میکنیم.
1<?xml version="1.0" encoding="UTF-8" ?>
2<selector xmlns:android="http://schemas.android.com/apk/res/android">
3 <item
4 android:state_focused="false"
5 android:state_selected="false"
6 android:state_pressed="false"
7 android:drawable="@drawable/normal" />
8 <item
9 android:state_pressed="true"
10 android:drawable="@drawable/pressed" />
11</selector>
چنان که میبینید میخواهیم دو xml دیگر درون پوشه Drawable بسازیم که در آنها حس و ظاهر کیبورد خود را تعریف میکنیم تا با قالب اپلیکیشن هماهنگ باشد.
فایل normal.xml
1<?xml version="1.0" encoding="UTF-8" ?>
2<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
3 <item android:left="2dp" android:right="2dp">
4 <shape android:shape="rectangle">
5 <solid android:color="#FFFFFF" />
6 </shape>
7 </item>
8
9 <item android:bottom="2dp">
10 <shape android:shape="rectangle">
11 <solid android:color="#FF6A00" />
12 </shape>
13 </item>
14</layer-list>
فایل pressed.xml
1<?xml version="1.0" encoding="UTF-8" ?>
2<shape xmlns:android="http://schemas.android.com/apk/res/android">
3 <solid android:color="#FF8C00" />
4</shape>
اینک درون پوشه values یک فایل xml به نام ids ایجاد میکنیم که در ادامه مورد استفاده قرار خواهد گرفت:
1<?xml version="1.0" encoding="UTF-8" ?>
2<resources>
3 <item
4 name="customKeyboard"
5 type="id" />
6</resources>
سپس درون پوشه Resources یک پوشه به نام xml میسازیم. درون آن یک فایل xml ایجاد میکنیم که کلیدهای کیبورد خاص خود را در آن تعریف میکنیم.
\در این مورد کیبورد به نام special_keyboard خوانده میشود و از نوع Keyboard خواهد بود که در آن اندازه افقی و عمودی کلیدها، مشخصههای horizontalGap و verticalGap که به فاصلهبندی اشاره میکنند و همچنین نوع ابعاد %p را تعریف میکنیم که نوعی از درصد مرتبط با نمای والد است.
هر ردیف از کلیدها درون بخشهایی قرار میگیرد که با تگهای <Row></Row> از هم جدا میشوند. ردیف نخست با یک خط جداکننده اشغال شده است که محدوده کیبورد را نشان میدهد. تگ ردیف دارای ارتفاع 4dp است و بخش فوقانی کیبورد را از طریق مشخصه rowEdgeFlags نشان میدهد. سپس یک خط به صورت یک key درون تگهای Row اضافه میکنیم که عرض کامل کیبورد را اشغال میکند. جداکننده ما یک Xml دیگر است که درون پوشه Drawable ایجاد خواهیم کرد.
فایل kb_separator_line.xml
1<?xml version="1.0" encoding="utf-8"?>
2<shape xmlns:android="http://schemas.android.com/apk/res/android"
3 android:shape="rectangle" >
4 <stroke android:width="1dp" />
5 <size android:height="2dp" />
6</shape>
هر Key دو مشخصه صراحتاً ضروری به نامهای codes و keyLabel دارد. code عددی است که به سیستم عامل اعلام میکند که کلید به کدام حرف یا نماد مربوط است. کیبوردهای سفارشی مختلف از کدهای گوناگونی برای اشاره به نماد یا کلیدها استفاده میکنند؛ اما بهترین فرست کدها که اغلب نیازها را تأمین میکند Android Keycodes (+) است. میتوانید مستندات رسمی اندروید (+) و یا حتی مستندات اندروید زامارین (+) را نیز ببینید، اما هیچ کدام از آنها با دقت کار نمیکنند.
keyLabel رشتهای است که قرار است در کلید ما نمایش یابد. قرار دادن این مشخصه حتی در صورتی که قصد نمایش هیچ متنی روی کلید ندارید، حائز اهمیت بالایی است. در آن حالت میتوانید از ""=keyLabel استفاده کنید.
در مورد استایل در ابتدا و انتهای هر ردیف یک کلید با کد معادل 0 اضافه میکنیم. این کلیدها دارای مشخصه keyEdgeFlags با مقادیر left یا right مناسب هستند. کد کامل کیبورد به صورت زیر است:
فایل special_keyboard.xml
1<?xml version="1.0" encoding="UTF-8" ?>
2<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
3 android:keyWidth="8%p"
4 android:keyHeight="50dp"
5 android:horizontalGap="1%p"
6 android:verticalGap="1%p">
7
8 <Row android:keyHeight="4dp" android:rowEdgeFlags="top" android:verticalGap="1%p">
9 <Key android:codes="0" android:keyWidth="100%p" android:keyIcon="@drawable/kb_separator_line" />
10 </Row>
11
12 <Row>
13 <Key android:codes="0" android:keyWidth="0dp" android:horizontalGap="2%p" android:keyEdgeFlags="left" />
14 <Key android:codes="29" android:keyLabel="A" android:keyWidth="18%p" />
15 <Key android:codes="30" android:keyLabel="B" android:keyWidth="18%p" />
16 <Key android:codes="31" android:keyLabel="C" android:keyWidth="18%p" />
17 <Key android:codes="32" android:keyLabel="D" android:keyWidth="18%p" />
18 <Key android:codes="33" android:keyLabel="E" android:keyWidth="18%p" />
19 <Key android:codes="0" android:keyWidth="0dp" android:horizontalGap="2%p" android:keyEdgeFlags="right" />
20 </Row>
21
22 <Row>
23 <Key android:codes="0" android:keyWidth="0dp" android:horizontalGap="2%p" android:keyEdgeFlags="left" />
24 <Key android:codes="8" android:keyLabel="1" android:keyWidth="18%p" />
25 <Key android:codes="9" android:keyLabel="2" android:keyWidth="18%p" />
26 <Key android:codes="10" android:keyLabel="3" android:keyWidth="18%p" />
27 <Key android:codes="11" android:keyLabel="4" android:keyWidth="18%p" />
28 <Key android:codes="12" android:keyLabel="5" android:keyWidth="18%p" />
29 <Key android:codes="0" android:keyWidth="0dp" android:horizontalGap="2%p" android:keyEdgeFlags="right" />
30 </Row>
31
32 <Row>
33 <Key android:codes="0" android:keyWidth="0dp" android:horizontalGap="2%p" android:keyEdgeFlags="left" />
34 <Key android:codes="13" android:keyLabel="6" android:keyWidth="18%p" />
35 <Key android:codes="14" android:keyLabel="7" android:keyWidth="18%p" />
36 <Key android:codes="15" android:keyLabel="8" android:keyWidth="18%p" />
37 <Key android:codes="16" android:keyLabel="9" android:keyWidth="18%p" />
38 <Key android:codes="7" android:keyLabel="0" android:keyWidth="18%p" />
39 <Key android:codes="0" android:keyWidth="0dp" android:horizontalGap="2%p" android:keyEdgeFlags="right" />
40 </Row>
41
42 <Row>
43 <Key android:codes="0" android:keyWidth="0dp" android:horizontalGap="2%p" android:keyEdgeFlags="left" />
44 <Key android:codes="67" android:keyLabel="DELETE" android:keyWidth="37%p" />
45 <Key android:codes="66" android:keyLabel="ENTER" android:keyWidth="56%p" />
46 <Key android:codes="0" android:keyWidth="0dp" android:horizontalGap="2%p" android:keyEdgeFlags="right" />
47 </Row>
48</Keyboard>
در نهایت پیش از کار روی رندر کننده پوشه دیگری درون Resources به نام anim ایجاد میکنیم که در آن یک فایل xml به نام slide_in_bottom می سازیم. انیمیشن ظاهرشدن کیبورد ما روی صفحه در این فایل قرار میگیرد:
1<?xml version="1.0" encoding="UTF-8" ?>
2<set xmlns:android="http://schemas.android.com/apk/res/android">
3 <translate android:fromYDelta="150%p" android:toYDelta="0" android:duration="200"/>
4 <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="200" />
5</set>
اکنون یک پوشه جدید به نام Renderers روی پروژه اندروید ایجاد میکنیم و درون آن رندر کننده خود را که EntryWithCustomKeyboardRenderer نام دارد و از EntryRenderer بسط یافته و اینترفیس IOnKeyboardActionListener را پیادهسازی میکند تعریف میکنیم. همچنین درون رندر کننده سفارشی یک کلاس خصوصی به نام NullListener ایجاد میکنیم که قرار است از Java.Lang.Object بسط یابد و اینترفیس IOnKeyboardActionListener را پیادهسازی کند که در رندر کننده خود مورد استفاده قرار میدهیم تا از استثناهای null جلوگیری کنیم.
1[assembly: ExportRenderer(typeof(EntryWithCustomKeyboard), typeof(EntryWithCustomKeyboardRenderer))]
2namespace CustomKeyboard.Droid.Renderers
3{
4 public class EntryWithCustomKeyboardRenderer : EntryRenderer, IOnKeyboardActionListener
5 {
6 private Context context;
7
8 private EntryWithCustomKeyboard entryWithCustomKeyboard;
9
10 private Android.InputMethodServices.KeyboardView mKeyboardView;
11 private Android.InputMethodServices.Keyboard mKeyboard;
12
13 private InputTypes inputTypeToUse;
14
15 private bool keyPressed;
16
17 public EntryWithCustomKeyboardRenderer(Context context) : base(context)
18 {
19 this.context = context;
20 }
21
22 protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
23 {
24 base.OnElementChanged(e);
25
26 var newCustomEntryKeyboard = e.NewElement as EntryWithCustomKeyboard;
27 var oldCustomEntryKeyboard = e.OldElement as EntryWithCustomKeyboard;
28
29 if (newCustomEntryKeyboard == null && oldCustomEntryKeyboard == null)
30 return;
31
32 if (e.NewElement != null)
33 {
34 this.entryWithCustomKeyboard = newCustomEntryKeyboard;
35 this.CreateCustomKeyboard();
36
37 this.inputTypeToUse = this.entryWithCustomKeyboard.Keyboard.ToInputType() | InputTypes.TextFlagNoSuggestions;
38
39 // Here we set the EditText event handlers
40 this.EditText.FocusChange += Control_FocusChange;
41 this.EditText.TextChanged += EditText_TextChanged;
42 this.EditText.Click += EditText_Click;
43 this.EditText.Touch += EditText_Touch;
44 }
45
46 // Dispose control
47 if (e.OldElement != null)
48 {
49 this.EditText.FocusChange -= Control_FocusChange;
50 this.EditText.TextChanged -= EditText_TextChanged;
51 this.EditText.Click -= EditText_Click;
52 this.EditText.Touch -= EditText_Touch;
53 }
54 }
55
56 protected override void OnFocusChangeRequested(object sender, VisualElement.FocusRequestArgs e)
57 {
58 e.Result = true;
59
60 if (e.Focus)
61 this.Control.RequestFocus();
62 else
63 this.Control.ClearFocus();
64 }
65
66 // Event handlers
67 private void Control_FocusChange(object sender, FocusChangeEventArgs e)
68 {
69 // Workaround to avoid null reference exceptions in runtime
70 if (this.EditText.Text == null)
71 this.EditText.Text = string.Empty;
72
73 if (e.HasFocus)
74 {
75 this.mKeyboardView.OnKeyboardActionListener = this;
76
77 if (this.Element.Keyboard == Keyboard.Text)
78 this.CreateCustomKeyboard();
79
80 this.ShowKeyboardWithAnimation();
81 }
82 else
83 {
84 // When the control looses focus, we set an empty listener to avoid crashes
85 this.mKeyboardView.OnKeyboardActionListener = new NullListener();
86
87 this.HideKeyboardView();
88 }
89 }
90
91 private void EditText_TextChanged(object sender, Android.Text.TextChangedEventArgs e)
92 {
93 // Ensure no key is pressed to clear focus
94 if (this.EditText.Text.Length != 0 && !this.keyPressed)
95 {
96 this.EditText.ClearFocus();
97 return;
98 }
99 }
100
101 private void EditText_Click(object sender, System.EventArgs e)
102 {
103 ShowKeyboardWithAnimation();
104 }
105
106 private void EditText_Touch(object sender, TouchEventArgs e)
107 {
108 this.EditText.InputType = InputTypes.Null;
109
110 this.EditText.OnTouchEvent(e.Event);
111
112 this.EditText.InputType = this.inputTypeToUse;
113
114 e.Handled = true;
115 }
116
117 // Keyboard related section
118
119 // Method to create our custom keyboard view
120 private void CreateCustomKeyboard()
121 {
122 var activity = (Activity)this.context;
123
124 var rootView = activity.Window.DecorView.FindViewById(Android.Resource.Id.Content);
125 var activityRootView = (ViewGroup)((ViewGroup)rootView).GetChildAt(0);
126
127 this.mKeyboardView = activityRootView.FindViewById<Android.InputMethodServices.KeyboardView>(Resource.Id.customKeyboard);
128
129 // If the previous line fails, it means the keyboard needs to be created and added
130 if (this.mKeyboardView == null)
131 {
132 this.mKeyboardView = (Android.InputMethodServices.KeyboardView)activity.LayoutInflater.Inflate(Resource.Layout.CustomKeyboard, null);
133 this.mKeyboardView.Id = Resource.Id.customKeyboard;
134 this.mKeyboardView.Focusable = true;
135 this.mKeyboardView.FocusableInTouchMode = true;
136
137 this.mKeyboardView.Release += (sender, e) => { };
138
139 var layoutParams = new Android.Widget.RelativeLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.WrapContent);
140 layoutParams.AddRule(LayoutRules.AlignParentBottom);
141 activityRootView.AddView(this.mKeyboardView, layoutParams);
142 }
143
144 this.HideKeyboardView();
145
146 this.mKeyboard = new Android.InputMethodServices.Keyboard(this.context, Resource.Xml.special_keyboard);
147
148 this.SetCurrentKeyboard();
149 }
150
151 private void SetCurrentKeyboard()
152 {
153 this.mKeyboardView.Keyboard = this.mKeyboard;
154 }
155
156 // Method to show our custom keyboard
157 private void ShowKeyboardWithAnimation()
158 {
159 // First we must ensure that keyboard is hidden to
160 // prevent showing it multiple times
161 if (this.mKeyboardView.Visibility == ViewStates.Gone)
162 {
163 // Ensure native keyboard is hidden
164 var imm = (InputMethodManager)this.context.GetSystemService(Context.InputMethodService);
165 imm.HideSoftInputFromWindow(this.EditText.WindowToken, 0);
166
167 this.EditText.InputType = InputTypes.Null;
168
169 var animation = AnimationUtils.LoadAnimation(this.context, Resource.Animation.slide_in_bottom);
170 this.mKeyboardView.Animation = animation;
171
172 this.mKeyboardView.Enabled = true;
173
174 // Show custom keyboard with animation
175 this.mKeyboardView.Visibility = ViewStates.Visible;
176 }
177 }
178
179 // Method to hide our custom keyboard
180 private void HideKeyboardView()
181 {
182 this.mKeyboardView.Visibility = ViewStates.Gone;
183 this.mKeyboardView.Enabled = false;
184
185 this.EditText.InputType = InputTypes.Null;
186 }
187
188 // Implementing IOnKeyboardActionListener interface
189 public void OnKey([GeneratedEnum] Keycode primaryCode, [GeneratedEnum] Keycode[] keyCodes)
190 {
191 if (!this.EditText.IsFocused)
192 return;
193
194 // Ensure key is pressed to avoid removing focus
195 this.keyPressed = true;
196
197 // Create event for key press
198 long eventTime = JavaSystem.CurrentTimeMillis();
199
200 var ev = new KeyEvent(eventTime, eventTime, KeyEventActions.Down, primaryCode, 0, 0, 0, 0,
201 KeyEventFlags.SoftKeyboard | KeyEventFlags.KeepTouchMode);
202
203 // Ensure native keyboard is hidden
204 var imm = (InputMethodManager)this.context.GetSystemService(Context.InputMethodService);
205 imm.HideSoftInputFromWindow(this.EditText.WindowToken, HideSoftInputFlags.None);
206
207 this.EditText.InputType = this.inputTypeToUse;
208
209 switch(ev.KeyCode)
210 {
211 case Keycode.Enter:
212 // Sometimes EditText takes long to update the HasFocus status
213 if (this.EditText.HasFocus)
214 {
215 // Close the keyboard, remove focus and launch command asociated action
216 this.HideKeyboardView();
217
218 this.ClearFocus();
219
220 this.entryWithCustomKeyboard.EnterCommand?.Execute(null);
221 }
222
223 break;
224 }
225
226 // Set the cursor at the end of the text
227 this.EditText.SetSelection(this.EditText.Text.Length);
228
229 if (this.EditText.HasFocus)
230 {
231 this.DispatchKeyEvent(ev);
232
233 this.keyPressed = false;
234 }
235 }
236
237 public void OnPress([GeneratedEnum] Keycode primaryCode)
238 {
239 }
240
241 public void OnRelease([GeneratedEnum] Keycode primaryCode)
242 {
243 }
244
245 public void OnText(ICharSequence text)
246 {
247 }
248
249 public void SwipeDown()
250 {
251 }
252
253 public void SwipeLeft()
254 {
255 }
256
257 public void SwipeRight()
258 {
259 }
260
261 public void SwipeUp()
262 {
263 }
264
265 private class NullListener : Java.Lang.Object, IOnKeyboardActionListener
266 {
267 public void OnKey([GeneratedEnum] Keycode primaryCode, [GeneratedEnum] Keycode[] keyCodes)
268 {
269 }
270
271 public void OnPress([GeneratedEnum] Keycode primaryCode)
272 {
273 }
274
275 public void OnRelease([GeneratedEnum] Keycode primaryCode)
276 {
277 }
278
279 public void OnText(ICharSequence text)
280 {
281 }
282
283 public void SwipeDown()
284 {
285 }
286
287 public void SwipeLeft()
288 {
289 }
290
291 public void SwipeRight()
292 {
293 }
294
295 public void SwipeUp()
296 {
297 }
298 }
299 }
300}
در نهایت به پروژه Xamarin Forms باز میگردیم و کیبورد خاص خود را پیادهسازی میکنیم:
فایل MainPage.xaml
1<?xml version="1.0" encoding="utf-8"?>
2<ContentPage
3 xmlns="http://xamarin.com/schemas/2014/forms"
4 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
5 xmlns:local="clr-namespace:CustomKeyboard"
6 x:Class="CustomKeyboard.MainPage">
7 <ScrollView>
8 <StackLayout
9 Orientation="Vertical">
10
11 <local:EntryWithCustomKeyboard
12 x:Name="entry1"
13 HorizontalOptions="FillAndExpand"
14 Margin="0, 0, 0, 20"
15 Keyboard="Text"
16 TextColor="Black"
17 Placeholder="Custom Keyboard entry..." />
18
19 <local:EntryWithCustomKeyboard
20 x:Name="entry2"
21 HorizontalOptions="FillAndExpand"
22 Keyboard="Text"
23 TextColor="Black"
24 Placeholder="Custom Keyboard entry 2..." />
25
26 </StackLayout>
27 </ScrollView>
28</ContentPage>
همچنین در کد قبلی خود EnterCommand را که پیشتر ساختیم پیادهسازی میکنیم. بدین ترتیب اکشنی که میخواهیم هنگام فشردن کلید اینتر کیبورد سفارشی انجام یابد را تعریف میکنیم:
فایل MainPage.cs
1namespace CustomKeyboard
2{
3 public partial class MainPage : ContentPage
4 {
5 public MainPage()
6 {
7 InitializeComponent();
8
9 // Here we implement the action of the Enter button on our custom keyboard
10 this.entry1.EnterCommand = new Command(() => this.entry2.Focus());
11 this.entry2.EnterCommand = new Command(() => this.entry1.Focus());
12 }
13 }
14}
نتیجه نهایی به صورت زیر است:
بدین ترتیب به پایان راهنما میرسیم. برای مشاهده کد کامل این پروژه به این ریپوی گیتهاب (+) مراجعه کنید.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای پروژهمحور برنامهنویسی اندروید
- مجموعه آموزشهای برنامهنویسی
- آموزش برنامهنویسی اندروید (Android) – پیشرفته
- روشهای اجرای اپلیکیشنهای اندروید در ویندوز — راهنمای کاربردی
- نکات کلیدی اندروید ۱۰ برای توسعهدهندگان — راهنمای کاربردی
==
درود استاد
بنده یکم گیج شدم اگه میشه لطف کنید فیلم همین کارو بذارین که راحت تر بتونم بفهممش…
مورد ضروری دمتون گرم لطفاً کمک کنید🙏🏻
سلام
آموزش ساخت کیبورد واقعا خیلی خوب بود ممنون
خیلی زیبا آموزش دادین ، خیلی ممنون برای این آموزشتون
دمتون گرم عالی
سلام لطفا اگر کسی برنانکه نویسی کیبورد سفارشی بلده بسازه به ایمیل من پیام بده بهم یاد بده خیلی ازش ممنون میشم