首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

Windows 8 應用開發:虛擬鍵盤遮擋問題解決方案 - InputPane 自訂處理

     編輯:關於.NET

前言

Windows 8 中,TextBox 獲得焦點時會自動彈出輸入面板 (虛擬鍵盤)。系統會嘗試將頁面上推以確保輸入框可見,但 FlipView 等容器內的 TextBox 往往失效。本文提供基於 InputPane 事件的完整自訂解決方案。

問題場景

  • TextBox 位於頁面下半部 → 系統自動上推 ✓
  • TextBox 位於 FlipViewItem 內 → 系統不上推,輸入框被遮擋 ✗
  • 原因不明,可能為系統 Bug 或佈局邏輯限制

核心解決方案:InputPaneHelper 封裝類別

using System;
using System.Collections.Generic;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.Foundation;
using Windows.UI.Xaml.Media.Animation;

namespace HuiZhang212.Keyboard
{
    public delegate void InputPaneShowingHandler(object sender, InputPaneVisibilityEventArgs e);
    public delegate void InputPaneHidingHandler(InputPane input, InputPaneVisibilityEventArgs e);

    public class InputPaneHelper
    {
        private Dictionary handlerMap;
        private UIElement lastFocusedElement = null;
        private InputPaneHidingHandler hidingHandlerDelegate = null;

        public InputPaneHelper()
        {
            handlerMap = new Dictionary();
        }

        public void SubscribeToKeyboard(bool subscribe)
        {
            InputPane input = InputPane.GetForCurrentView();
            if (subscribe)
            {
                input.Showing += ShowingHandler;
                input.Hiding += HidingHandler;
            }
            else
            {
                input.Showing -= ShowingHandler;
                input.Hiding -= HidingHandler;
            }
        }

        public void AddShowingHandler(UIElement element, InputPaneShowingHandler handler)
        {
            if (handlerMap.ContainsKey(element))
                throw new Exception("A handler is already registered!");
            
            handlerMap.Add(element, handler);
            element.GotFocus += GotFocusHandler;
            element.LostFocus += LostFocusHandler;
        }

        private void GotFocusHandler(object sender, RoutedEventArgs e)
        {
            lastFocusedElement = (UIElement)sender;
        }

        private void LostFocusHandler(object sender, RoutedEventArgs e)
        {
            if (lastFocusedElement == (UIElement)sender)
                lastFocusedElement = null;
        }

        private void ShowingHandler(InputPane sender, InputPaneVisibilityEventArgs e)
        {
            if (lastFocusedElement != null && handlerMap.Count > 0)
            {
                handlerMap[lastFocusedElement](lastFocusedElement, e);
            }
            lastFocusedElement = null;
        }

        private void HidingHandler(InputPane sender, InputPaneVisibilityEventArgs e)
        {
            if (hidingHandlerDelegate != null)
                hidingHandlerDelegate(sender, e);
            lastFocusedElement = null;
        }

        public void SetHidingHandler(InputPaneHidingHandler handler)
        {
            hidingHandlerDelegate = handler;
        }

        public void RemoveShowingHandler(UIElement element)
        {
            handlerMap.Remove(element);
            element.GotFocus -= GotFocusHandler;
            element.LostFocus -= LostFocusHandler;
        }
    }
}

運作原理

  1. 註冊追蹤:以 Dictionary 儲存需處理的 UIElement (通常是 TextBox) 與對應處理器
  2. 焦點偵測:監聽 GotFocus/LostFocus 判斷觸發輸入面板的元素
  3. 事件轉發:InputPane.Showing 時,呼叫對應元素的自訂處理器
  4. 動畫配合:處理器內執行頁面位移動畫 (TranslateTransform)

測試頁面實作

XAML 定義動畫資源

<Page.Resources>
    <Storyboard x:Name="MoveMiddleOnShowing">
        <DoubleAnimationUsingKeyFrames Duration="0:0:0.733" 
            Storyboard.TargetName="MiddleTranslate" Storyboard.TargetProperty="Y">
            <SplineDoubleKeyFrame x:Name="ShowingMoveSpline" KeyTime="0:0:0.733" KeySpline="0.10,0.90,0.20,1"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
    
    <Storyboard x:Name="MoveMiddleOnHiding">
        <DoubleAnimationUsingKeyFrames Duration="0:0:0.367" 
            Storyboard.TargetName="MiddleTranslate" Storyboard.TargetProperty="Y">
            <SplineDoubleKeyFrame KeyTime="0:0:0.367" KeySpline="0.10,0.90,0.20,1" Value="0"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</Page.Resources>

<Grid x:Name="LayoutRoot">
    <Grid.RenderTransform>
        <TranslateTransform x:Name="MiddleTranslate" />
    </Grid.RenderTransform>
    
    <FlipView Margin="100">
        <FlipViewItem Background="Yellow">
            <TextBox Name="textbox0" Text="自訂監聽鍵盤上推事件" VerticalAlignment="Bottom" Width="300"/>
        </FlipViewItem>
        <FlipViewItem Background="Blue">
            <TextBox Name="textbox1" Text="系統處理鍵盤上推事件" VerticalAlignment="Bottom" Width="300"/>
        </FlipViewItem>
        <FlipViewItem Background="Green">
            <TextBox Name="textbox2" Text="自訂監聽鍵盤上推事件" VerticalAlignment="Top" Width="300"/>
        </FlipViewItem>
    </FlipView>
</Grid>

後端程式碼整合

private InputPaneHelper _inputPaneHelper;

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    _inputPaneHelper = new InputPaneHelper();
    _inputPaneHelper.SubscribeToKeyboard(true);
    
    // 為需要自訂處理的 TextBox 註冊處理器
    _inputPaneHelper.AddShowingHandler(textbox0, OnInputPaneShowing);
    _inputPaneHelper.AddShowingHandler(textbox2, OnInputPaneShowing);
    
    _inputPaneHelper.SetHidingHandler(OnInputPaneHiding);
}

private void OnInputPaneShowing(object sender, InputPaneVisibilityEventArgs e)
{
    // 計算需要上推的距離:鍵盤高度 - 元素底部到頁面底部的距離
    double offset = e.OccludedRect.Height - (/* 元素底部座標計算 */);
    ShowingMoveSpline.Value = -offset; // 負值向上移動
    MoveMiddleOnShowing.Begin();
}

private void OnInputPaneHiding(InputPane sender, InputPaneVisibilityEventArgs e)
{
    MoveMiddleOnHiding.Begin();
}

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    _inputPaneHelper.SubscribeToKeyboard(false);
    _inputPaneHelper.RemoveShowingHandler(textbox0);
    _inputPaneHelper.RemoveShowingHandler(textbox2);
}

關鍵技術點

  • InputPane.GetForCurrentView():取得當前視圖的輸入面板實例
  • InputPaneVisibilityEventArgs.OccludedRect:鍵盤遮擋區域 (高度即為鍵盤高度)
  • TranslateTransform:整頁位移不影響內部佈局
  • SplineDoubleKeyFrame:緩動動畫曲線,提升使用者體驗
  • 頁面離開時必須取消訂閱,避免記憶體洩漏與事件殘留

參考資源

Microsoft 官方範例:Responding to the appearance of the on-screen keyboard sample

查看本欄目

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved