frcd 发表于 2014-1-17 09:04:12

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]
查看完整版本: Windows 8 键盘上推自定义处理