Windows 8 键盘上推自定义处理
在Windows 8 应用程序中,当TextBox控件获得焦点时,输入面板会弹出,如果TextBox控件处于页面下半部分,则系统会将页面上推是的TextBox不被输入面板盖住,但是当TextBox是在FlipView控件中时,系统不会将页面上推,所以这种情况下输入框被输入面板盖住。具体原因不清楚,不知道是不是系统bug。当输入面板弹出,页面上推的操作可以通过监听InputPane的Showing和Hiding事件来处理,既然当TextBox在FlipView控件时,系统没有很好的处理页面上推,那么开发者可以通过监听InputPane的事件来自己处理上推操作。
Windows 8 的一个实例代码Responding to the appearance of the on-screen keyboard sample中介绍了如果监听处理InputPane的相关操作,参考此实例以FlipView中的TextBox控件为例并对实例代码进行简化处理。
实例中的InputPaneHelper是对InputPane的事件处理的封装,直接拿来使用,InputPaneHelper代码如下:
1 using System;
2 using System.Collections.Generic;
3 using Windows.UI.ViewManagement;
4 using Windows.UI.Xaml;
5 using Windows.Foundation;
6 using Windows.UI.Xaml.Media.Animation;
7
8 namespace HuiZhang212.Keyboard
9 {
10 public delegate void InputPaneShowingHandler(object sender, InputPaneVisibilityEventArgs e);
11 public delegate void InputPaneHidingHandler(InputPane input, InputPaneVisibilityEventArgs e);
12 public class InputPaneHelper
13 {
14 private Dictionary<UIElement, InputPaneShowingHandler> handlerMap;
15 private UIElement lastFocusedElement = null;
16 private InputPaneHidingHandler hidingHandlerDelegate = null;
17
18 public InputPaneHelper()
19 {
20 handlerMap = new Dictionary<UIElement, InputPaneShowingHandler>();
21 }
22
23 public void SubscribeToKeyboard(bool subscribe)
24 {
25 InputPane input = InputPane.GetForCurrentView();
26 if (subscribe)
27 {
28 input.Showing += ShowingHandler;
29 input.Hiding += HidingHandler;
30 }
31 else
32 {
33 input.Showing -= ShowingHandler;
34 input.Hiding -= HidingHandler;
35 }
36 }
37
38 public void AddShowingHandler(UIElement element, InputPaneShowingHandler handler)
39 {
40 if (handlerMap.ContainsKey(element))
41 {
42 throw new System.Exception("A handler is already registered!");
43 }
44 else
45 {
46 handlerMap.Add(element, handler);
47 element.GotFocus += GotFocusHandler;
48 element.LostFocus += LostFocusHandler;
49 }
50 }
51
52 private void GotFocusHandler(object sender, RoutedEventArgs e)
53 {
54 lastFocusedElement = (UIElement)sender;
55 }
56
57 private void LostFocusHandler(object sender, RoutedEventArgs e)
58 {
59 if (lastFocusedElement == (UIElement)sender)
60 {
61 lastFocusedElement = null;
62 }
63 }
64
65 private void ShowingHandler(InputPane sender, InputPaneVisibilityEventArgs e)
66 {
67 if (lastFocusedElement != null && handlerMap.Count > 0)
68 {
69 handlerMap(lastFocusedElement, e);
70 }
71 lastFocusedElement = null;
72 }
73
74 private void HidingHandler(InputPane sender, InputPaneVisibilityEventArgs e)
75 {
76 if (hidingHandlerDelegate != null)
77 {
78 hidingHandlerDelegate(sender, e);
79 }
80 lastFocusedElement = null;
81 }
82
83 public void SetHidingHandler(InputPaneHidingHandler handler)
84 {
85 this.hidingHandlerDelegate = handler;
86 }
87
88 public void RemoveShowingHandler(UIElement element)
89 {
90 handlerMap.Remove(element);
91 element.GotFocus -= GotFocusHandler;
92 element.LostFocus -= LostFocusHandler;
93 }
94 }
95 }
InputPaneHelper代码比较容易理解,简单的说就是用一个Hash表存储所有需要监听处理键盘上推事件的UIElement(一般情况下应该是TextBox控件),并且通过监听UIElement的焦点事件来判断弹出输入面板是通过那个UIElement触发的,并且通过监听InputPane的Showing和Hiding事件来对键盘上推进行处理。
测试页面KeyboardPage.xaml代码如下:
1 <Page
2 x:Class="HuiZhang212.Keyboard.KeyboardPage"
3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5 xmlns:local="using:HuiZhang212.Keyboard"
6 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
7 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
8 mc:Ignorable="d">
9
10 <!--键盘上推和隐藏动画-->
11 <Page.Resources>
12 <Storyboard x:Name="MoveMiddleOnShowing">
13 <DoubleAnimationUsingKeyFrames Duration="0:0:0.733" Storyboard.TargetName="MiddleTranslate" Storyboard.TargetProperty="Y">
14 <SplineDoubleKeyFrame x:Name="ShowingMoveSpline" KeyTime="0:0:0.733" KeySpline="0.10,0.90, 0.20,1">
15 </SplineDoubleKeyFrame>
16 </DoubleAnimationUsingKeyFrames>
17 </Storyboard>
18
19 <Storyboard x:Name="MoveMiddleOnHiding">
20 <DoubleAnimationUsingKeyFrames Duration="0:0:0.367" Storyboard.TargetName="MiddleTranslate" Storyboard.TargetProperty="Y">
21 <SplineDoubleKeyFrame KeyTime="0:0:0.367" KeySpline="0.10,0.90, 0.20,1" Value="0">
22 </SplineDoubleKeyFrame>
23 </DoubleAnimationUsingKeyFrames>
24 </Storyboard>
25 </Page.Resources>
26
27 <Grid x:Name="LayoutRoot" Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
28 <Grid.RenderTransform>
29 <TranslateTransform x:Name="MiddleTranslate" />
30 </Grid.RenderTransform>
31 <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
32 <FlipView Margin="100">
33 <FlipViewItem Background="Yellow">
34 <TextBoxText="自定义监听键盘上推事件" Name="textbox0"Foreground="Black" VerticalAlignment="Bottom"Width="300"/>
35 </FlipViewItem>
36 <FlipViewItem Background="Blue">
37 <TextBoxText="系统处理键盘上推事件" Name="textbox1"Foreground="Black" VerticalAlignment="Bottom"Width="300"/>
38 </FlipViewItem>
39 <FlipViewItem Background="Green">
40 <TextBoxText="自定义监听键盘上推事件" Name="textbox2" Foreground="Black" VerticalAlignment="Top"Width="300"/>
41 </FlipViewItem>
42 </FlipView>
43 </Grid>
44 </Grid>
45 </Page>
MoveMiddleOnShowing和MoveMiddleOnHiding分别是定义的键盘上推和隐藏时的动画,此动画作用在Grid上,当输入面板显示和隐藏时对Grid做此两种动画偏远而达到键盘上推的效果。
测试代码KeyboardPage.xaml.cs如下:
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using Windows.Foundation;
6 using Windows.Foundation.Collections;
7 using Windows.UI.ViewManagement;
8 using Windows.UI.Xaml;
9 using Windows.UI.Xaml.Controls;
10 using Windows.UI.Xaml.Controls.Primitives;
11 using Windows.UI.Xaml.Data;
12 using Windows.UI.Xaml.Input;
13 using Windows.UI.Xaml.Media;
14 using Windows.UI.Xaml.Navigation;
15
16 // “空白页”项模板在 http://go.microsoft.com/fwlink/?LinkId=234238 上有介绍
17
18 namespace HuiZhang212.Keyboard
19 {
20 /// <summary>
21 /// 可用于自身或导航至 Frame 内部的空白页。
22 /// 参考Responding to the appearance of the on-screen keyboard sample
23 /// FlipView控件中放置的TextBox控件 不会上推
24 /// </summary>
25 public sealed partial class KeyboardPage : Page
26 {
27 public KeyboardPage()
28 {
29 this.InitializeComponent();
30
31 AddInputPanelElement(textbox0);
32 AddInputPanelElement(textbox2);
33 }
34
35
36 protected override void OnNavigatedFrom(NavigationEventArgs e)
37 {
38 RemoveInputPanelElement(textbox0);
39 RemoveInputPanelElement(textbox2);
40 }
41
42 #region 键盘上推处理
43 private double displacement = 0;
44 private InputPaneHelper inputPaneHelper = new InputPaneHelper();
45
46 public void AddInputPanelElement(FrameworkElement element)
47 {
48 inputPaneHelper.SubscribeToKeyboard(true);
49 inputPaneHelper.AddShowingHandler(element, new InputPaneShowingHandler(CustomKeyboardHandler));
50 inputPaneHelper.SetHidingHandler(new InputPaneHidingHandler(InputPaneHiding));
51 }
52
53 public void RemoveInputPanelElement(FrameworkElement element)
54 {
55 inputPaneHelper.SubscribeToKeyboard(false);
56 inputPaneHelper.RemoveShowingHandler(element);
57 inputPaneHelper.SetHidingHandler(null);
58 }
59
60 private void CustomKeyboardHandler(object sender, InputPaneVisibilityEventArgs e)
61 {
62 // Keep in mind that other elements could be shifting out of your control. The sticky app bar, for example
63 // will move on its own. You should make sure the input element doesn't get occluded by the bar
64 FrameworkElement element = sender as FrameworkElement;
65 Point poppoint = element.TransformToVisual(this).TransformPoint(new Point(0, 0));
66 displacement = e.OccludedRect.Y - (poppoint.Y + element.ActualHeight + 10);
67 //bottomOfList = MiddleScroller.VerticalOffset + MiddleScroller.ActualHeight;
68
69
70 // Be careful with this property. Once it has been set, the framework will
71 // do nothing to help you keep the focused element in view.
72 e.EnsuredFocusedElementInView = true;
73
74 if (displacement > 0)
75 {
76 displacement = 0;
77 }
78
79 ShowingMoveSpline.Value = displacement;
80 MoveMiddleOnShowing.Begin();
81 }
82
83 private void InputPaneHiding(InputPane sender, InputPaneVisibilityEventArgs e)
84 {
85 if (displacement != 0.0)
86 {
87 MoveMiddleOnShowing.Stop();
88
89 if (displacement < 0)
90 {
91 MoveMiddleOnHiding.Begin();
92 }
93 }
94 }
95 #endregion
96 }
97 }
测试用例中在FlipView的三个item中分别放置一个TextBox,其中textbox0和textbox2是自定义处理键盘上推事件,而textbox1是由系统处理,通过运行程序可以发现textbox1触发弹出键盘不会使页面上推。而textbox0触发弹出键盘有自定义处理,会使页面上推。
页:
[1]