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](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

  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                     <TextBox  Text="自定义监听键盘上推事件" Name="textbox0"  Foreground="Black" VerticalAlignment="Bottom"  Width="300"/>
35                 </FlipViewItem>
36                 <FlipViewItem Background="Blue">
37                     <TextBox  Text="系统处理键盘上推事件" Name="textbox1"  Foreground="Black" VerticalAlignment="Bottom"  Width="300"/>
38                 </FlipViewItem>
39                 <FlipViewItem Background="Green">
40                     <TextBox  Text="自定义监听键盘上推事件" Name="textbox2" Foreground="Black" VerticalAlignment="Top"  Width="300"/>
41                 </FlipViewItem>
42             </FlipView>
43         </Grid>
44     </Grid>
45 </Page>
KeyboardPage.xaml

  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 }
KeyboardPage.xaml.cs

  测试用例中在FlipView的三个item中分别放置一个TextBox,其中textbox0和textbox2是自定义处理键盘上推事件,而textbox1是由系统处理,通过运行程序可以发现textbox1触发弹出键盘不会使页面上推。而textbox0触发弹出键盘有自定义处理,会使页面上推。

原文地址:https://www.cnblogs.com/huizhang212/p/Win8Keyboard.html