【问题标题】:How to draw view on top of soft keyboard like WhatsApp?如何在 WhatsApp 等软键盘上绘制视图?
【发布时间】:2013-04-10 05:56:01
【问题描述】:

我想知道如何在 WhatsApp 和环聊等键盘顶部添加 View。在聊天屏幕中,他们在打开的软键盘顶部插入表情视图。

有谁知道如何实现这种行为?

【问题讨论】:

  • 我认为 WhatsApp 不会发生这种情况。我猜点击表情按钮只会关闭软键盘并打开笑脸片段。
  • 根据我的理解,它并没有关闭键盘,我认为它是在打开的键盘上绘制的
  • 这是关于如何创建自己的键盘的教程,这不是我要找的
  • 我可以确认它不会关闭软键盘,而是完美地绘制在它之上。在打开表情视图时可以看到输入法仍处于活动状态的通知。

标签: android view android-softkeyboard


【解决方案1】:

好吧,我已经创建了一个用于聊天的示例键盘here...

在这里,我使用弹出窗口来显示弹出窗口,弹出窗口的高度由键盘高度动态计算

// Initially defining default height of keyboard which is equal to 230 dip
        final float popUpheight = getResources().getDimension(
                R.dimen.keyboard_height);
        changeKeyboardHeight((int) popUpheight);

// Creating a pop window for emoticons keyboard
    popupWindow = new PopupWindow(popUpView, LayoutParams.MATCH_PARENT,
            (int) keyboardHeight, false);

并使用此函数计算高度:

/**
 * Checking keyboard height and keyboard visibility
 */
int previousHeightDiffrence = 0;
private void checkKeyboardHeight(final View parentLayout) {

    parentLayout.getViewTreeObserver().addOnGlobalLayoutListener(
            new ViewTreeObserver.OnGlobalLayoutListener() {

                @Override
                public void onGlobalLayout() {

                    Rect r = new Rect();
                    parentLayout.getWindowVisibleDisplayFrame(r);

                    int screenHeight = parentLayout.getRootView()
                            .getHeight();
                    int heightDifference = screenHeight - (r.bottom);

                    if (previousHeightDiffrence - heightDifference > 50) {                          
                        popupWindow.dismiss();
                    }

                    previousHeightDiffrence = heightDifference;
                    if (heightDifference > 100) {

                        isKeyBoardVisible = true;
                        changeKeyboardHeight(heightDifference);

                    } else {

                        isKeyBoardVisible = false;

                    }

                }
            });

}

使用所有这些东西,我可以制作出完美的重叠键盘......

然后我用 viewpager 和 gridview 为表情符号膨胀弹出窗口。

另外,我使用可扩展字符串在列表视图和聊天窗口中显示这些表情符号

【讨论】:

  • 我很想看看你的项目是如何工作的,但我无法使用我的 Android Studio 克隆它。
【解决方案2】:

经过大量的研究和试错,我找到了另一种类似于上述 Chirag Jain 的解决方案,但使用的是自定义对话框。

    mDialogKeyboard = new Dialog(this,android.R.style.Theme_NoTitleBar);
    mDialogKeyboard.setContentView(R.layout.your_custom_layout);
    mDialogKeyboard.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
    mDialogKeyboard.getWindow().setFlags(WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
    mDialogKeyboard.getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
    mDialogKeyboard.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);

    WindowManager.LayoutParams lp=mDialogKeyboard.getWindow().getAttributes();    
    lp.width=WindowManager.LayoutParams.MATCH_PARENT;
    lp.height=mSoftKeyboardHeight;
    lp.gravity=Gravity.BOTTOM | Gravity.LEFT;
    lp.dimAmount=0;

尽管 Chirag Jain 的答案似乎更简洁,但我将在此处发布此内容以获得替代方法。

【讨论】:

  • 如果 customlayout 是一个片段并且您正在使用此对话框在 FragmentActivity 中对它进行膨胀,如何执行此操作.. 它会给您二进制膨胀错误。不是吗?
【解决方案3】:

据我所知,您可以利用其他应用程序,是的。我自己设计了这样一个应用程序。至于在诸如键盘之类的应用程序或任何其他特定应用程序上绘图,我想,您必须定义一个高度与键盘完全相同的布局。因此,这会因设备而异。所以,这是不可能的。

我仍然坚持我的观点,即 WhatsApp 只是在按下笑脸按钮时关闭软键盘并将其称为自己的片段。

如果您仍想这样做,以下是您在其他应用程序上绘制“窗口”的方法。这些应该是它的布局参数。

params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
                PixelFormat.TRANSLUCENT);

尽管如此,您的宽度将更改为绝对像素值,因为您希望 Activity 仅在键盘上方。

如果我误解了这个问题,请纠正我。

【讨论】:

  • 感谢您的重播,我认为这种方法比 WhatsApp 做的要贵一点,因为它需要权限 android:name="android.permission.SYSTEM_ALERT_WINDOW" 而 WhatsApp 没有您的这个权限
  • 没错,所以他们没有在键盘上绘制笑脸片段 :) 这只是一个简单的关闭命令。
  • 不确定,因为他们关闭了那个键盘,并且原生键盘没有动画就进入了,更不用说当表情键盘打开时活动继续缩小视图
  • 您可以随时调整其余活动的大小以适应表情标签。我敢肯定这只是设计。
  • 好的,感谢您的反馈,我会调查这种方法,并进行必要的更新
【解决方案4】:

我的想法是他们为微笑创建了自己的键盘,单击微笑图标或键盘图标时,他们会隐藏微笑键盘并显示普通键盘。 whats app case 有两种情况 1)如果你不关注第一次editext然后你看不到显示键盘按钮,并且微笑键盘的高度与普通键盘完全相同,我们将只获得键盘高度在我们的视图布局更改后,意味着只有在显示键盘之后,这意味着他们正在创建自己的键盘.. 2)如果您关注编辑文本并单击微笑按钮,那么它将显示显示键盘按钮的选项请纠正我如果我对此不正确

【讨论】:

    【解决方案5】:

    我最近不得不实现一个位于软键盘上方的视图。 @Chirag Jain 的解决方案几乎是正确的,但它不计入屏幕底部的系统按钮!这会使 NEXUS 6 等某些设备上的键盘高度不正确。此解决方案应该适用于所有设备:

    1) 创建包含您的视图的布局

    <RelativeLayout
            android:id="@+id/keyboard_info_container"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:layout_alignParentBottom="true"
            android:background="@color/C12"
            android:padding="10dp"
            android:visibility="invisible">
    
               ....
    
        </RelativeLayout>
    

    2) 绑定视图

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootview = inflater.inflate(R.layout.notifications_email_settings_fragment, container, false);
    
        ButterKnife.bind(this, rootview);
    
        checkKeyboardHeight(rootview);
    

    3) 键盘检查和查看边距设置

    private void checkKeyboardHeight(final View parentLayout) {
    
        parentLayout.getViewTreeObserver().addOnGlobalLayoutListener(
                new ViewTreeObserver.OnGlobalLayoutListener() {
    
                    int previousHeightDiffrence = 0;
                    int systemBarHigh = 999999;
    
                    @Override
                    public void onGlobalLayout() {
    
    
                        Rect r = new Rect();
                        parentLayout.getWindowVisibleDisplayFrame(r);
    
                        int screenHeight = parentLayout.getRootView()
                                .getHeight();
                        int keyboardHeight = screenHeight - (r.bottom);
    
                        if(systemBarHigh > keyboardHeight) {
                            systemBarHigh = keyboardHeight;
                        }
    
                        if (keyboardHeight > 250) {
    
                            int keyboardHightWithoutSystemBar = keyboardHeight - systemBarHigh;
                            // no need to update when the keyboard goes down
                            if (previousHeightDiffrence != keyboardHightWithoutSystemBar) { // if (Math.abs(previousHeightDiffrence - keyboardHeight) > 10) {
                                adjustKeyboard(keyboardHightWithoutSystemBar);
                            }
    
                            keyboardInfoContainer.setVisibility(View.VISIBLE);
                            isKeyBoardVisible = true;
                            previousHeightDiffrence = keyboardHightWithoutSystemBar;
    
                        } else {
                            isKeyBoardVisible = false;
                            if (keyboardInfoContainer != null) {
                                keyboardInfoContainer.setVisibility(View.INVISIBLE);
                            }
                        }
                    }
                });
    }
    
    private void adjustKeyboard(int keyboardHeight) {
        RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) keyboardInfoContainer.getLayoutParams();
        lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
        lp.bottomMargin = keyboardHeight;
        keyboardInfoContainer.requestLayout();
    }
    

    【讨论】:

      【解决方案6】:

      @jirkarrr,你为什么不像这样添加keyboardInfoContainer:

      WindowManager wm = getWindowManager();
      WindowManager.LayoutParams lps = new WindowManager.LayoutParams();
      lps.x = 0; lps.y = keyboardHeight;
      wm.addView(keyboardInfoContainer, lps);
      

      我按照你的代码做,但它不能显示keyboardInfoContainer。

      【讨论】:

        【解决方案7】:

        我使用弹出窗口将视图放在键盘上:

        public void showPopUpKeyboard() {
                mIsPopupVisible = true;
                // Initialize a new instance of LayoutInflater service
                LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
        
                // Inflate the custom layout/view
                View customView = inflater.inflate(R.layout.popup_in_keyboard, null);
        
        
                mScrollView = (ScrollView) customView.findViewById(R.id.keyboard_layout_view);
                // Initialize a new instance of popup window
                mPopupWindow = new PopupWindow(
                        customView,
                        RelativeLayout.LayoutParams.MATCH_PARENT,
                        RelativeLayout.LayoutParams.MATCH_PARENT
                );
        
        
                setSizeForSoftKeyboard();
        
                // Get a reference for the custom view close button
                Button closeButton = (Button) customView.findViewById(R.id.ib_close);
        
                // Set a click listener for the popup window close button
                closeButton.setOnClickListener((View view) -> {
                        // Dismiss the popup window
                        mIsPopupVisible = false;
                        mPopupWindow.dismiss();
                });
                mPopupWindow.showAtLocation(mParentLayout, Gravity.CENTER, 0, 0);
        
            }
        

        然后我尝试知道键盘的高度:

        mParentLayout.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
                        Rect r = new Rect();
        
                        mParentLayout.getWindowVisibleDisplayFrame(r);
        
                        int heightDiff = mParentLayout.getRootView().getHeight() - (r.bottom - r.top);
                        if (heightDiff > 100) {
                            //enter your code here
                            if (mIsPopupVisible) {
                                keepKeyboard();
                                mIsPopupVisible = false;
                                mPopupWindow.dismiss();
                            }
                        } else {
                            //enter code for hid
                        }
                }); 
        

        您可以查看此tutorial 和此example in GitHub

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-12-03
          • 1970-01-01
          • 2016-01-08
          • 1970-01-01
          • 2015-11-23
          • 2016-04-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多