按下后退时 EditText 不会触发更改

Posted

技术标签:

【中文标题】按下后退时 EditText 不会触发更改【英文标题】:EditText does not trigger changes when back is pressed 【发布时间】:2011-08-02 20:43:07 【问题描述】:

在带有购物车的应用程序中,我提供了通过 EditText 更改商品数量的选项,该选项只允许输入数字。 一切正常,除非用户更改字段然后按后退键隐藏软键盘。在这种情况下,该字段显示更改的值,但我不知道如何检测到此更改并对其做出反应。等待切换到另一个活动不是一种选择。 当用户使用“完成”按钮确认时,我可以使用“OnEditorActionListener”来处理它。但是后退键呢?

更新: 事实证明,使用返回键关闭软键盘时,编辑字段上的 onKeyDown / onBackPressed 和 OnKeyListener 都不会触发。

【问题讨论】:

【参考方案1】:

我在前段时间编写的应用程序中遇到了同样的问题。它现在已停产,但这不是你的问题 xD。

事实上,没有选项可以跟踪这样的操作,但我找到了一个很好的(或多或少)解决方案来添加这样的功能。这在理论上很简单,但我认为它也是一个“黑客”。

因此,您需要一个包含您的应用程序或特殊区域的自定义线性布局。之后,您必须为其添加一个侦听器。这仅适用于纵向模式。

所以这里是代码:(对不起,我不记得出处了)

自定义布局:

LinearLayoutThatDetactsSoftwarekeyboard.java(这是布局 xD 的原始名称)

package com.tundem.people.Layout;

import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.LinearLayout;

/*
 * LinearLayoutThatDetectsSoftKeyboard - a variant of LinearLayout that can detect when 
 * the soft keyboard is shown and hidden (something Android can't tell you, weirdly). 
 */

public class LinearLayoutThatDetectSoftkeyboard extends LinearLayout 

    public LinearLayoutThatDetectSoftkeyboard(Context context, AttributeSet attrs) 
        super(context, attrs);
    

    public interface Listener 
        public void onSoftKeyboardShown(boolean isShowing);
    

    private Listener listener;

    public void setListener(Listener listener) 
        this.listener = listener;
    

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
        int height = MeasureSpec.getSize(heightMeasureSpec);
        Activity activity = (Activity) getContext();
        Rect rect = new Rect();
        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
        int statusBarHeight = rect.top;
        int screenHeight = activity.getWindowManager().getDefaultDisplay().getHeight();
        int diff = (screenHeight - statusBarHeight) - height;
        if (listener != null) 
            listener.onSoftKeyboardShown(diff > 128); // assume all soft
                                                        // keyboards are at
                                                        // least 128 pixels high
        
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    


以及如何添加监听器:

final LinearLayoutThatDetectSoftkeyboard lltodetectsoftkeyboard = (LinearLayoutThatDetectSoftkeyboard) findViewById(R.id.LinearLayout_SoftKeyboard);
    lltodetectsoftkeyboard.setListener(new Listener() 

        public void onSoftKeyboardShown(boolean isShowing) 
            if (actMode == MODE_SMS && isShowing) 
                findViewById(R.id.LinearLayout_bottomnavigationbar).setVisibility(View.GONE);
             else 
                findViewById(R.id.LinearLayout_bottomnavigationbar).setVisibility(View.VISIBLE);
            
        
    );

LinearLayout 添加了一个监听器,每当 layoutheight 改变至少 128 像素时都会调用该监听器。这是一个技巧,它不适用于小于 128 像素的键盘(但我认为每个键盘都有这样的高度) 如果 LayoutHeight 已更改,您将收到通知是否现在显示。

希望我的回答有用。也许您再次在 *** 上找到了真正的来源。所以我不会偷别人的天才。学分归未知人所有;)

【讨论】:

我还没有尝试过这个解决方案,但是看看代码我很确定它可以工作。我从没想过这个看似微不足道的问题需要这样的黑客攻击。感谢您的代码(即使不是自己编写的)!【参考方案2】:

这是 @mikepenz 答案的修改版本,因为它不适用于具有 windowSoftInputMode="adjustPan" 模式的 Android 8

语言是 kotlin。 将此视图用作根视图并设置keyboardListener:

class KeyboardAwareConstraintLayout(context: Context?, attrs: AttributeSet?) : ConstraintLayout(context, attrs)


  var keyboardListener: KeyboardListener? = null

  constructor(context: Context?) : this(context, null)


  override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int)
  
    val rect = Rect()
    getWindowVisibleDisplayFrame(rect)
    val statusBarHeight = rect.top
    val keyboardHeight = rootView.height - (rect.bottom - rect.top) - statusBarHeight
    // R.dimen.keyboard_min_height has set to 120dp, 
    // as a reasonable minimum height of a soft keyboard
    val minKeyboardHeight = resources.getDimensionPixelSize(R.dimen.keyboard_min_height)

    keyboardListener?.onKeyboardShown(keyboardHeight > minKeyboardHeight)

    super.onMeasure(widthMeasureSpec, heightMeasureSpec)
  


interface KeyboardListener

  fun onKeyboardShown (shown: Boolean)

【讨论】:

【参考方案3】:

您可以在活动中覆盖 onBackPressed(伪代码 - 被警告):

@Override
public void onBackPressed() 
    if(userHasChangedAnything) 
        revertChanges();
     else 
        super.onBackPressed();
    

【讨论】:

我也想过这一点,但是(假设它有效)这将是一个很大的 hack,因为 EditText 位于 Fragment 中,而不是 Activity 中,因此处理此问题的代码将分散在各处。没有更好的解决方案? 这也不起作用(就像 onKeyDown 一样)。关闭键盘时,它不会触发。【参考方案4】:

由于代码的新信息位于片段中,我建议在文本框中添加一个关键侦听器。此代码未经测试,但应该可以工作。

((EditText) findViewById(R.id.button)).setOnKeyListener(new OnKeyListener()  
    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) 
         if ((keyCode == KeyEvent.KEYCODE_BACK)) 
              Log.d(this.getClass().getName(), "back button pressed");
              return true;
         
         return false;
    
)

【讨论】:

【参考方案5】:

如果这不相关,请原谅,但我曾经遇到过这个问题,忘记了我添加了一个 OnKeyListener 来捕获我的 dialogFragment 的背面按下。 我重写了监听器如下。添加了 Top 条件来解决问题。

getDialog().setOnKeyListener(new DialogInterface.OnKeyListener() 
    @Override
    public boolean onKey(DialogInterface dialogInterface, int i, KeyEvent keyEvent) 
        if(keyEvent.getKeyCode() == KeyEvent.KEYCODE_DEL) 
            return false;
        
        if(keyEvent.getAction() == KeyEvent.ACTION_DOWN && keyEvent.getKeyCode() == KeyEvent.KEYCODE_BACK) 
            if(iYoutubePickerDialog != null) 
                iYoutubePickerDialog.closeYoutubeDialog(getDialog());
            
        
        return true;
    
);

【讨论】:

以上是关于按下后退时 EditText 不会触发更改的主要内容,如果未能解决你的问题,请参考以下文章

Android:为EditText打开键盘时处理后退按钮单击

Android:按下后退按钮时提示用户保存更改

按下后退按钮未触发

当资源不是本地的(使用 http)时,不会触发 Cordova android 4.x 后退按钮事件

表单组值更改时不会触发更改检测

软键盘仅在 EditText 焦点上显示一次