Windows 8 键盘上推自定义处理

原文: 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触发弹出键盘有自定义处理,会使页面上推。

你可能感兴趣的:(windows)