จะตรวจสอบการมองเห็นคีย์บอร์ดของซอฟต์แวร์ใน Android ได้อย่างไร?


516

ฉันต้องทำสิ่งที่ง่ายมาก - ตรวจสอบว่าแป้นพิมพ์ซอฟต์แวร์ปรากฏขึ้นหรือไม่ เป็นไปได้ใน Android?


9
แม้ว่าคำตอบของรูเบนสแครตตันนั้นดี แต่ดูเหมือนว่าจะแตกบนแท็บเล็ต ฉันแทนที่เช็ค diff> 128 ด้วย diff> screenHeight / 3
kingston

2
คำตอบของรูเบนสแครตตันเป็นสิ่งที่ดี แต่ฉันต้องการการปรับตัวของคาชิเพื่อใช้งานจริง
Cullan

1
เหตุใด Google จึงไม่สร้างวิธีการมาตรฐานในตัวสำหรับแอปแป้นพิมพ์ทั้งหมด
ผลไม้

4
มันยังคงเป็นพี่น้องกับฉันว่านี่ไม่ใช่ระบบทำงาน ...
ลองกอง

1
ก็อย่างว่าถั่ว API นี้ยังขาดหายไป10 ปีต่อมา ดีใจมากที่ฉันย้ายออกจาก Android
รูเบน Scratton

คำตอบ:


674

ใหม่คำตอบ เพิ่ม 25 มกราคม 2012

นับตั้งแต่ที่เขียนคำตอบด้านล่างมีบางคนบอกให้ฉันทราบถึงการมีอยู่ของViewTreeObserverและเพื่อน ๆ API ที่ซ่อนอยู่ใน SDK ตั้งแต่รุ่น 1

แทนที่จะต้องใช้ประเภทเลย์เอาต์ที่กำหนดเองโซลูชันที่ง่ายกว่าคือการให้รูทของกิจกรรมของคุณดู ID ที่รู้จักพูด@+id/activityRootตะขอ GlobalLayoutListener เข้าใน ViewTreeObserver และจากนั้นคำนวณขนาดที่แตกต่างระหว่างรูทมุมมองของกิจกรรมและขนาดหน้าต่าง:

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
        if (heightDiff > dpToPx(this, 200)) { // if more than 200 dp, it's probably a keyboard...
            // ... do something here
        }
     }
});

การใช้ยูทิลิตี้เช่น:

public static float dpToPx(Context context, float valueInDp) {
    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}

ง่าย!

หมายเหตุ: แอปพลิเคชันของคุณต้องตั้งค่าสถานะนี้ใน Android Manifest ไม่android:windowSoftInputMode="adjustResize"เช่นนั้นโซลูชันด้านบนจะไม่ทำงาน

คำตอบเดิม

ใช่มันเป็นไปได้ แต่มันยากกว่าที่ควรจะเป็น

ถ้าผมจำเป็นต้องดูแลเกี่ยวกับเมื่อปรากฏแป้นพิมพ์และหายไป (ซึ่งเป็นค่อนข้างบ่อย) onMeasure()แล้วสิ่งที่ฉันทำคือการปรับแต่งรูปแบบของฉันระดับระดับบนสุดซึ่งเป็นหนึ่งในการแทนที่ ตรรกะพื้นฐานคือถ้าเค้าโครงพบว่าตัวเองเติมน้อยกว่าพื้นที่ทั้งหมดของหน้าต่างแสดงว่าคีย์บอร์ดนุ่มนวลอาจแสดง

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 LinearLayoutThatDetectsSoftKeyboard extends LinearLayout {

    public LinearLayoutThatDetectsSoftKeyboard(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);       
    }

    }

จากนั้นในชั้นเรียนกิจกรรมของคุณ ...

public class MyActivity extends Activity implements LinearLayoutThatDetectsSoftKeyboard.Listener {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        LinearLayoutThatDetectsSoftKeyboard mainLayout = (LinearLayoutThatDetectsSoftKeyboard)findViewById(R.id.main);
        mainLayout.setListener(this);
        ...
    }


    @Override
    public void onSoftKeyboardShown(boolean isShowing) {
        // do whatever you need to do here
    }

    ...
}

62
สิ่งนี้ไม่ได้ผลสำหรับฉันจนกว่าฉันจะรู้ว่าคุณต้องตั้งค่าคุณลักษณะต่อไปนี้ในกิจกรรมของคุณ: android: windowSoftInputMode = "adjustResize"
ajh158

9
ดูเหมือนว่าจะทำเคล็ดลับ นอกจากนี้หากคุณไม่ทราบ ID ของรูทวิวต่อไปนี้เป็นวิธีที่คุณจะได้รับมุมมอง:((ViewGroup) findViewById(android.R.id.content)).getChildAt(0)
ช่างทอง

8
หากคุณลองทำโดยใช้มุมมองรูทที่แท้จริง ( android.R.id.content) คุณจะสามารถพูดได้อย่างมั่นใจมากขึ้นว่าSystemแทนที่จะใช้แอปพลิเคชันของคุณคือการเปลี่ยนเอนทิตี้ของความสูง จะปลอดภัยกว่ามากสำหรับทีม Android ที่จะให้เวลาพักกับเราและแจ้งให้เราทราบอย่างน้อยสิ่งพื้นฐานเกี่ยวกับอินพุต SoftKeyboard
แกรม

14
ระวังว่าheightDiffจะรวมความสูงของแถบการกระทำเสมอ ในคำตอบใหม่ที่ถูกละเว้นโดยการทดสอบว่าความสูงนั้นสูงกว่าค่าคงที่หรือไม่ แต่ 100 พิกเซลไม่เพียงพอสำหรับอุปกรณ์ xxhdpi เช่น Nexus 4 ลองพิจารณาการแปลงค่าเป็น DPs หากคุณต้องการใช้งานแฮ็คนี้ รอบ
Paul Lammertsma

8
ประกาศ: ไม่ทำงานกับ WindowManager.LayoutParams.FLAG_FULLSCREEN และมีธีมเต็มหน้าจอ
VAV

303

หวังว่านี่จะช่วยใครซักคน

คำตอบใหม่ที่รูเบนสแครตตันให้ไว้นั้นยอดเยี่ยมและมีประสิทธิภาพจริงๆ แต่จะใช้ได้เฉพาะเมื่อคุณตั้งค่า windowSoftInputMode เพื่อปรับขนาด หากคุณตั้งค่าเป็น adjustPan คุณจะไม่สามารถตรวจพบว่ามีแป้นพิมพ์ปรากฏอยู่หรือไม่โดยใช้ข้อมูลโค้ดของเขา เพื่อหลีกเลี่ยงปัญหานี้ฉันได้ทำการปรับเปลี่ยนรหัสเล็กน้อยด้านบนนี้

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
    Rect r = new Rect();
    //r will be populated with the coordinates of your view that area still visible.
    activityRootView.getWindowVisibleDisplayFrame(r);

    int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
    if (heightDiff > 0.25*activityRootView.getRootView().getHeight()) { // if more than 25% of the screen, its probably a keyboard...
        ... do something here
    }
 }
}); 

1
นี่คือสิ่งที่เหมาะกับฉัน ฉันพยายามตรวจสอบสถานะแป้นพิมพ์จากแบบกำหนดเองTwoDScrollerViewคล้ายกับstackoverflow.com/a/5224088/530513แม้ว่าจะมีการซูมด้วย เด็กที่ไม่ได้เป็นที่เรียบง่ายImageViewแต่รูปแบบที่กำหนดเอง (ขยายRelativeLayout) android:windowSoftInputMode="adjustResize"แต่ก็ไม่สามารถที่จะตรวจสอบแป้นพิมพ์โดยใช้วิธีการแก้ปัญหาที่แนะนำแม้จะมีการตั้งค่า ขอบคุณ!
David O'Meara

1
ขอบคุณขอบคุณขอบคุณ! AdjustResize เพียงใช้ไม่ได้กับแอปของฉันและโซลูชันของคุณทำงานได้อย่างสมบูรณ์
dwemthy

1
ทำงานร่วมกับและActionBar ActionBarSherlockขอบคุณมาก! โดยวิธีการที่มีวิธีr.height():)
Dmitry Zaytsev

1
ฉันจะแนบค่าหัวที่นี่ภายใน 23 ชั่วโมงเพื่อทำเครื่องหมายคำตอบอย่างใด
Dmitry Zaytsev

9
heightDiff > root.getRootView().getHeight() / 4คุ้มค่าที่จะทำงานกับอุปกรณ์ความละเอียดสูง 100px สั้น ใน Nexus 5 ที่มี 1080x1920 res, 1920 - (996-75)>? 100 = 999 1920 - (1776-75)>? 100 = 219 // แป้นพิมพ์ขึ้นใน galaxy s2 ที่มีความละเอียด 480x800, 800 - (800-38)>? 100 = 38 800 - (410-38)>? 100 = 428 // แป้นพิมพ์ขึ้นไปจำนวนมายากล 100px ไม่ดีพอ
Flask_KR

55

มันมีมานานแล้วในแง่ของคอมพิวเตอร์ แต่คำถามนี้ยังมีความเกี่ยวข้องอย่างไม่น่าเชื่อ!

ดังนั้นฉันจึงได้คำตอบข้างต้นและรวมเข้าด้วยกันและทำให้ดีขึ้นเล็กน้อย ...

public interface OnKeyboardVisibilityListener {


    void onVisibilityChanged(boolean visible);
}

public final void setKeyboardListener(final OnKeyboardVisibilityListener listener) {
    final View activityRootView = ((ViewGroup) getActivity().findViewById(android.R.id.content)).getChildAt(0);

    activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

        private boolean wasOpened;

        private final int DefaultKeyboardDP = 100;

        // From @nathanielwolf answer...  Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff
        private final int EstimatedKeyboardDP = DefaultKeyboardDP + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? 48 : 0);

        private final Rect r = new Rect();

        @Override
        public void onGlobalLayout() {
            // Convert the dp to pixels.
            int estimatedKeyboardHeight = (int) TypedValue
                    .applyDimension(TypedValue.COMPLEX_UNIT_DIP, EstimatedKeyboardDP, activityRootView.getResources().getDisplayMetrics());

            // Conclude whether the keyboard is shown or not.
            activityRootView.getWindowVisibleDisplayFrame(r);
            int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
            boolean isShown = heightDiff >= estimatedKeyboardHeight;

            if (isShown == wasOpened) {
                Log.d("Keyboard state", "Ignoring global layout change...");
                return;
            }

            wasOpened = isShown;
            listener.onVisibilityChanged(isShown);
        }
    });
}

ได้ผลสำหรับฉัน :)

หมายเหตุ: หากคุณสังเกตเห็นว่าDefaultKeyboardDPไม่เหมาะกับอุปกรณ์ของคุณเล่นกับค่าและโพสต์ความคิดเห็นสำหรับทุกคนที่จะรู้ว่าสิ่งที่ควรค่า ... ในที่สุดเราจะได้รับค่าที่ถูกต้องเพื่อให้พอดีกับอุปกรณ์ทั้งหมด!

สำหรับรายละเอียดเพิ่มเติมดูการใช้งานในCyborg


2
+1 ขอบคุณมาก !! ฉันพยายามคำตอบอื่น ๆ แต่พวกเขาไม่ทำงาน จากนั้นฉันก็พบคุณและมันก็ใช้งานได้อย่างมีเสน่ห์ รหัสที่ยอดเยี่ยม! : D
Kevin van Mierlo

ใช้งานได้เฉพาะในกรณีที่คุณเพิ่ม: android: windowSoftInputMode = "stateHidden | adjustPan" หรือ android: windowSoftInputMode = "stateHidden | adjustResize" ขอบคุณ !!!!
Lena Bru

คุณแน่ใจไหม? ถ้าเซิร์ฟเวอร์หน่วยความจำฉันได้รับเหตุการณ์อย่างถูกต้องเช่นกันเมื่อ android: windowSoftInputMode มีค่าเริ่มต้น ... สิ่งเดียวที่ไม่ได้ผลคือพฤติกรรมของหน้าจอดังนั้นฉันจึง
ย่อ

2
การแก้ไขเล็กน้อย: ส่วนตัวสุดท้าย int EstimatedKeyboardDP = DefaultKeyboardDP + (Build.VERSION.SDK_INT> = Build.VERSION_CODES.LOLLIPOP 48: 0);
binaryKarmic

2
ยอดเยี่ยม !! ไม่ว่า "windowSoftInputMode" ถูกตั้งค่าเป็น "adjustPan" / "adjustResize" / "adjustPan | stateHidden" / "adjustResize | stateHidden" หรือแม้กระทั่งโดยไม่มีตัวเลือกนี้ ทดสอบกับ XiaoMi 8
Zhou Hongbo

52

ขออภัยสำหรับคำตอบที่ล่าช้า แต่ฉันได้สร้างคลาสผู้ช่วยเล็กน้อยเพื่อจัดการกับเหตุการณ์เปิด / ปิดด้วยการแจ้งให้ผู้ฟังและสิ่งที่มีประโยชน์อื่น ๆ อาจเป็นคนที่เห็นว่าเป็นประโยชน์:

import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;

import java.util.LinkedList;
import java.util.List;

public class SoftKeyboardStateWatcher implements ViewTreeObserver.OnGlobalLayoutListener {

    public interface SoftKeyboardStateListener {
        void onSoftKeyboardOpened(int keyboardHeightInPx);
        void onSoftKeyboardClosed();
    }

    private final List<SoftKeyboardStateListener> listeners = new LinkedList<SoftKeyboardStateListener>();
    private final View activityRootView;
    private int        lastSoftKeyboardHeightInPx;
    private boolean    isSoftKeyboardOpened;

    public SoftKeyboardStateWatcher(View activityRootView) {
        this(activityRootView, false);
    }

    public SoftKeyboardStateWatcher(View activityRootView, boolean isSoftKeyboardOpened) {
        this.activityRootView     = activityRootView;
        this.isSoftKeyboardOpened = isSoftKeyboardOpened;
        activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @Override
    public void onGlobalLayout() {
        final Rect r = new Rect();
        //r will be populated with the coordinates of your view that area still visible.
        activityRootView.getWindowVisibleDisplayFrame(r);

        final int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
        if (!isSoftKeyboardOpened && heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
            isSoftKeyboardOpened = true;
            notifyOnSoftKeyboardOpened(heightDiff);
        } else if (isSoftKeyboardOpened && heightDiff < 100) {
            isSoftKeyboardOpened = false;
            notifyOnSoftKeyboardClosed();
        }
    }

    public void setIsSoftKeyboardOpened(boolean isSoftKeyboardOpened) {
        this.isSoftKeyboardOpened = isSoftKeyboardOpened;
    }

    public boolean isSoftKeyboardOpened() {
        return isSoftKeyboardOpened;
    }

    /**
     * Default value is zero {@code 0}.
     *
     * @return last saved keyboard height in px
     */
    public int getLastSoftKeyboardHeightInPx() {
        return lastSoftKeyboardHeightInPx;
    }

    public void addSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
        listeners.add(listener);
    }

    public void removeSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
        listeners.remove(listener);
    }

    private void notifyOnSoftKeyboardOpened(int keyboardHeightInPx) {
        this.lastSoftKeyboardHeightInPx = keyboardHeightInPx;

        for (SoftKeyboardStateListener listener : listeners) {
            if (listener != null) {
                listener.onSoftKeyboardOpened(keyboardHeightInPx);
            }
        }
    }

    private void notifyOnSoftKeyboardClosed() {
        for (SoftKeyboardStateListener listener : listeners) {
            if (listener != null) {
                listener.onSoftKeyboardClosed();
            }
        }
    }
}

ตัวอย่างการใช้งาน:

final SoftKeyboardStateWatcher softKeyboardStateWatcher 
    = new SoftKeyboardStateWatcher(findViewById(R.id.activity_main_layout);

// Add listener
softKeyboardStateWatcher.addSoftKeyboardStateListener(...);
// then just handle callbacks

2
ชั้นไม่ได้เป็นเพียงเล็กน้อย แต่การใช้งานก็แน่นอน :) ขอบคุณฉันจะลอง :) :)
Atul O Holic

1
Ping ฉันถ้าคุณมีปัญหากับมัน :) ฉันใช้มันสำเร็จใน 2 โปรเจค
Artem Zinnatullin

หลังจากลองหลายตัวอย่างด้านบนและพบปัญหาเล็กน้อยหนึ่งอันนี้เป็นสิ่งที่ดีที่สุดสำหรับฉันในอุปกรณ์ต่าง ๆ มากมาย (รวมถึง xxhdpi) นอกจากนี้ยังอยู่ในระดับที่สามารถนำกลับมาใช้ใหม่ได้เอง ฉันแปลงมันเพื่อใช้ในโมโน droid
kheit

บางคีย์บอร์ดบางครั้งมีแถวของคีย์ที่กำหนดเองเพิ่มเติมด้านบน (ตัวอย่างเช่นคำที่คาดคะเน) เห็นได้ชัดว่าไม่ได้เป็นส่วนหนึ่งของแป้นพิมพ์เหล่านี้เนื่องจากการใช้getLastKeyboardHeightInPx()ไม่รวมความสูงของแถวนั้น คุณรู้วิธีนำมาพิจารณาด้วยหรือไม่
ygesher

ใช้งานได้ก็ต่อเมื่อคุณพร้อมที่จะยอมให้ความสูงของเลย์เอาท์เปลี่ยนไปเมื่อแป้นพิมพ์ปรากฏขึ้น ขวา?
M. Usman Khan

33

การปรับปรุงบางอย่างเพื่อหลีกเลี่ยงการตรวจจับการมองเห็นของคีย์บอร์ดอ่อนบนอุปกรณ์ที่มีความหนาแน่นสูงอย่างไม่ถูกต้อง:

  1. เกณฑ์ของความแตกต่างความสูงควรได้รับการกำหนดให้เป็น128 DPไม่128 พิกเซล
    อ้างถึงเอกสารการออกแบบของ Google เกี่ยวกับ Metrics และ Gridขนาด48 dpนั้นสะดวกสบายสำหรับวัตถุแบบสัมผัสและ32 dpนั้นน้อยที่สุดสำหรับปุ่ม คีย์บอร์ดนุ่มทั่วไปควรมีปุ่มแถว 4 แถวดังนั้นความสูงของแป้นพิมพ์ขั้นต่ำควรเป็น: 32 dp * 4 = 128 dpซึ่งหมายความว่าขนาดเกณฑ์ควรถ่ายโอนเป็นพิกเซลด้วยความหนาแน่นของอุปกรณ์คูณ สำหรับอุปกรณ์ xxxhdpi (ความหนาแน่น 4) ขีดจำกัดความสูงของคีย์บอร์ดอ่อนควรเป็น 128 * 4 = 512 พิกเซล

  2. ความแตกต่างของความสูงระหว่างมุมมองรูทและพื้นที่ที่มองเห็นได้:
    ความสูงของมุมมองรูท - ความสูงของแถบสถานะ - ความสูงของเฟรมที่มองเห็น = ด้านล่างของมุมมองรูท - ด้านล่างของเฟรมที่มองเห็นเนื่องจากความสูงของแถบสถานะ

    private final String TAG = "TextEditor";
    private TextView mTextEditor;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_editor);
        mTextEditor = (TextView) findViewById(R.id.text_editor);
        mTextEditor.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                isKeyboardShown(mTextEditor.getRootView());
            }
        });
    }
    
    private boolean isKeyboardShown(View rootView) {
        /* 128dp = 32dp * 4, minimum button height 32dp and generic 4 rows soft keyboard */
        final int SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD = 128;
    
        Rect r = new Rect();
        rootView.getWindowVisibleDisplayFrame(r);
        DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
        /* heightDiff = rootView height - status bar height (r.top) - visible frame height (r.bottom - r.top) */
        int heightDiff = rootView.getBottom() - r.bottom;
        /* Threshold size: dp to pixels, multiply with display density */
        boolean isKeyboardShown = heightDiff > SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD * dm.density;
    
        Log.d(TAG, "isKeyboardShown ? " + isKeyboardShown + ", heightDiff:" + heightDiff + ", density:" + dm.density
                + "root view height:" + rootView.getHeight() + ", rect:" + r);
    
        return isKeyboardShown;
    }

4
นี่สมควรที่จะเป็นคำตอบที่ได้รับการยอมรับ การเพิกเฉยต่อความหนาแน่นทำให้ฉันได้ผลลัพธ์ที่แตกต่างกันมากบนอุปกรณ์ที่มีฟอร์มแฟคเตอร์ต่างกัน แต่ขนาดพิกเซลใกล้เคียงกัน ขอบคุณ!
Ginger McMurray

2
ขอบคุณ ... นี่เป็นเงื่อนไขที่ดีกว่า!
TacB0sS

1
ยอดเยี่ยม isKeyboardShown () วิธีการเป็นสิ่งที่เราต้องการ ขอบคุณ
Danylo Volokh

มันทำงานในปี 2020 เช่นกัน คำตอบที่สมบูรณ์แบบ ฉันลองใช้รหัสทั้งหมด แต่ใช้งานได้อย่างสมบูรณ์แบบ
Mitesh Jain

8

ฉันใช้เวลาเล็กน้อยในการคิดสิ่งนี้ ... ฉันใช้งาน CastExceptions บางส่วน แต่คิดว่าคุณสามารถแทนที่ LinearLayout ใน layout.xml ด้วยชื่อคลาสได้

แบบนี้:

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"
    xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/llMaster">

<com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard android:background="@drawable/metal_background"
    android:layout_width="fill_parent" android:layout_height="fill_parent"
    android:id="@+id/rlMaster" >
    <LinearLayout android:layout_width="fill_parent"
        android:layout_height="1dip" android:background="@drawable/line"></LinearLayout>

          ....

</com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard>    


</LinearLayout>

ด้วยวิธีนี้คุณจะไม่พบปัญหาใด ๆ

... และหากคุณไม่ต้องการทำสิ่งนี้ในทุก ๆ หน้าฉันแนะนำให้คุณใช้ "MasterPage ใน Android" ดูลิงค์ได้ที่นี่: http://jnastase.alner.net/archive/2011/01/08/ldquomaster-pagesrdquo-in-android.aspx


โปรดระวังการวางสิ่งนี้ลงใน XML ของคุณหากคุณไม่มีชื่อแพ็คเกจ / คลาสเดียวกัน Eclipse เพิ่งตัดสินใจที่จะหยุดและคุณต้องปิดมัน ช่างเป็นผลิตภัณฑ์ระดับมืออาชีพ / s
Spencer Ruport

5
@SpencerRuport นั่นเป็นเหตุผลว่าทำไมมันฟรี
โคดี

@DoctorOreo - รับ IntelliJ ฟรีและไม่ดูด
ทำเครื่องหมาย

@ Mark - ไม่กี่เดือนหลังจากที่ฉันโพสต์สิ่งนี้ฉันได้ลอง IntelliJ มันดีกว่า IMO มากกว่า Eclipse ผลิตภัณฑ์ทั้งหมดของพวกเขา (ส่วนใหญ่) ฉันคิดว่ายอดเยี่ยม ฉันเคยซื้อมาบ้าง
โคดี้

ขออภัยสำหรับการฟื้นเธรดความคิดเห็นเก่า ๆ ฉันดีใจที่คุณใช้มันและสนุกกับมัน ฉันชอบใช้ IntelliJ รวมถึง AppCode สำหรับ iOS และ PyCharm สำหรับ Python ไชโย!
Mark

7

การตรวจสอบความสูงขององค์ประกอบไม่น่าเชื่อถือเนื่องจากคีย์บอร์ดบางรุ่นเช่น WifiKeyboard มีความสูงเป็นศูนย์

คุณสามารถใช้ผลลัพธ์การโทรกลับของ showSoftInput () และ hideSoftInput () แทนเพื่อตรวจสอบสถานะของคีย์บอร์ด รายละเอียดและรหัสตัวอย่างที่

https://rogerkeays.com/how-to-check-if-the-software-keyboard-is-shown-in-android


5

แนวคิดคือถ้าคุณต้องการซ่อนแป้นพิมพ์และตรวจสอบสถานะอินพุตแบบซอฟต์พร้อมกันให้ใช้วิธีแก้ไขปัญหาต่อไปนี้:

public boolean hideSoftInput() {
    InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
    return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
}

เมธอดนี้ส่งคืนค่าจริงหากคีย์บอร์ดถูกแสดงก่อนซ่อน


นี่คือสิ่งที่ใช้ได้โดยไม่ต้องใช้ความสูงและทั้งหมด ... ขอบคุณ ... คุณประหยัดเวลาของฉัน ...
Vji

4

ฉันพบว่าการรวมกันของวิธีการของ @ Reuben_Scratton พร้อมกับวิธีการของ @ Yogesh นั้นทำงานได้ดีที่สุด การรวมวิธีการของพวกเขาจะให้ผลดังนี้:

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
  @Override
  public void onGlobalLayout() {
    if (getResources().getConfiguration().keyboardHidden == Configuration.KEYBOARDHIDDEN_NO) { // Check if keyboard is not hidden
       // ... do something here
    }
  }
});

กำหนดค่าเสมอ KEYBOARDHIDDEN_NO
fantouch

4

คุณสามารถสังเกตการซ่อนซอฟต์คีย์บอร์ดได้โดยใช้ decorView ของกิจกรรม

public final class SoftKeyboardUtil {
    public static final String TAG = "SoftKeyboardUtil";
    public static void observeSoftKeyBoard(Activity activity , final OnSoftKeyBoardHideListener listener){
        final View decorView = activity.getWindow().getDecorView();
        decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect rect = new Rect();
                decorView.getWindowVisibleDisplayFrame(rect);
                int displayHight = rect.bottom - rect.top;
                int hight = decorView.getHeight();
                boolean hide = (double)displayHight / hight > 0.8 ;
                if(Log.isLoggable(TAG, Log.DEBUG)){
                    Log.d(TAG ,"DecorView display hight = "+displayHight);
                    Log.d(TAG ,"DecorView hight = "+ hight);
                    Log.d(TAG, "softkeyboard visible = " + !hide);
                }

                listener.onSoftKeyBoardVisible(!hide);

            }
        });
    }



    public interface OnSoftKeyBoardHideListener{
        void onSoftKeyBoardVisible(boolean visible);
    }
}

4

แทนที่จะสมมติว่ารหัสต่างกันฉันทำอะไรแบบนี้เพราะฉันมีตัวเลือกเมนูในแอปพลิเคชันของฉัน

final View root= findViewById(R.id.myrootview); 
root.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
    public void onGlobalLayout() {
        int heightDiff = root.getRootView().getHeight() - root.getHeight();

        Rect rectgle= new Rect();
        Window window= getWindow();
        window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
        int contentViewTop=                     
          window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
        if(heightDiff <= contentViewTop){
            //Soft KeyBoard Hidden
        }else{
            //Soft KeyBoard Shown
        }
     }
});

มันไม่ทำงานสำหรับ android: windowSoftInputMode = "adjustPan" ฉันต้องการให้หน้าจอของฉันไม่ควรถูกลดขนาดหลังจากที่คีย์บอร์ดนุ่มปรากฏขึ้น คุณช่วยบอกการแก้ไขใด ๆ เพื่อให้มันทำงานได้แม้สำหรับ adjustPan
Shirish Herwade

4

นอกจากนี้ยังมีวิธีแก้ปัญหาด้วยการแทรกของระบบ แต่ใช้งานได้เฉพาะกับAPI >= 21( Android L) สมมติว่าคุณมีBottomNavigationViewซึ่งเป็นลูกของLinearLayoutคุณจำเป็นต้องซ่อนมันเมื่อแป้นพิมพ์ปรากฏขึ้น:

> LinearLayout
  > ContentView
  > BottomNavigationView

สิ่งที่คุณต้องทำคือการขยายLinearLayoutในลักษณะเช่นนี้:

public class KeyboardAwareLinearLayout extends LinearLayout {
    public KeyboardAwareLinearLayout(Context context) {
        super(context);
    }

    public KeyboardAwareLinearLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public KeyboardAwareLinearLayout(Context context,
                                     @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public KeyboardAwareLinearLayout(Context context, AttributeSet attrs,
                                     int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
        int childCount = getChildCount();
        for (int index = 0; index < childCount; index++) {
            View view = getChildAt(index);
            if (view instanceof BottomNavigationView) {
                int bottom = insets.getSystemWindowInsetBottom();
                if (bottom >= ViewUtils.dpToPx(200)) {
                    // keyboard is shown
                    view.setVisibility(GONE);
                } else {
                    // keyboard is hidden
                    view.setVisibility(VISIBLE);
                }
            }
        }
        return insets;
    }
}

แนวคิดก็คือเมื่อมีการแสดงแป้นพิมพ์ระบบจะเปลี่ยน.bottomค่าที่ค่อนข้างใหญ่


4

มีวิธีที่ซ่อนอยู่สามารถช่วยInputMethodManager.getInputMethodWindowVisibleHeightได้ แต่ฉันไม่รู้ว่าทำไมมันถึงซ่อนอยู่

import android.content.Context
import android.os.Handler
import android.view.inputmethod.InputMethodManager

class SoftKeyboardStateWatcher(private val ctx: Context) {
  companion object {
    private const val DELAY = 10L
  }

  private val handler = Handler()
  private var isSoftKeyboardOpened: Boolean = false

  private val height: Int
    get() {
      val imm = ctx.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
      val method = imm.javaClass.getMethod("getInputMethodWindowVisibleHeight")
      method.isAccessible = true
      return method.invoke(imm) as Int
    }

  private val task: Runnable by lazy {
    Runnable {
      start()
      if (!isSoftKeyboardOpened && height > 0) {
        isSoftKeyboardOpened = true
        notifyOnSoftKeyboardOpened(height)
      } else if (isSoftKeyboardOpened && height == 0) {
        isSoftKeyboardOpened = false
        notifyOnSoftKeyboardClosed()
      }
    }
  }

  var listener: SoftKeyboardStateListener? = null

  interface SoftKeyboardStateListener {
    fun onSoftKeyboardOpened(keyboardHeightInPx: Int)
    fun onSoftKeyboardClosed()
  }

  fun start() {
    handler.postDelayed(task, DELAY)
  }

  fun stop() {
    handler.postDelayed({
      if (!isSoftKeyboardOpened) handler.removeCallbacks(task)
    }, DELAY * 10)
  }

  private fun notifyOnSoftKeyboardOpened(keyboardHeightInPx: Int) {
    listener?.onSoftKeyboardOpened(keyboardHeightInPx)
  }

  private fun notifyOnSoftKeyboardClosed() {
    listener?.onSoftKeyboardClosed()
  }
}

หากใครบางคนต้องการสิ่งนี้ - มันใช้งานได้ใน Xamarin เช่นกันชื่อของวิธีการนั้นเหมือนกันทุกประการและจำเป็นต้องเข้าถึงในลักษณะเดียวกัน - ผ่านคุณสมบัติ Class บน InputMethodManager
Konstantin Severy

ระวังการใช้สิ่งนี้มันเป็น API ที่ไม่รองรับ (มันถูกซ่อนไว้ด้วยเหตุผล) และสำหรับการเริ่มมันไม่ทำงานกับ KitKat
Daniele Ricci

3

วิธีแก้ปัญหาเหล่านี้จะไม่สามารถใช้กับ Lollipop ได้ ใน Lollipop activityRootView.getRootView().getHeight()รวมถึงความสูงของแถบปุ่มในขณะที่การวัดมุมมองไม่ได้ ฉันได้ปรับแก้ปัญหาที่ดีที่สุด / ง่ายที่สุดข้างต้นเพื่อทำงานกับ Lollipop

    final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
  @Override
  public void onGlobalLayout() {
    Rect r = new Rect();
    //r will be populated with the coordinates of your view that area still visible.
    activityRootView.getWindowVisibleDisplayFrame(r);

    int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
    Resources res = getResources();
    // The status bar is 25dp, use 50dp for assurance
    float maxDiff =
        TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, res.getDisplayMetrics());

    //Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
      float buttonBarHeight =
          TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, res.getDisplayMetrics());
      maxDiff += buttonBarHeight;
    }
    if (heightDiff > maxDiff) { // if more than 100 pixels, its probably a keyboard...
      ...do something here
    }
  }
});

เหตุใดโซลูชันที่คล้ายกันจากstackoverflow.com/a/18992807/2914140 จึงใช้งานไม่ได้สำหรับคุณและโซลูชันของคุณแตกต่างกันอย่างไร
CoolMind

3

ฉันเพิ่งพบข้อผิดพลาดขณะใช้โซลูชันส่วนใหญ่ด้านบนที่แนะนำให้เพิ่มหมายเลขคงที่

S4 นั้นมี dpi สูงซึ่งส่งผลให้ความสูงของแถบการนำทางอยู่ที่ 100px ทำให้แอปของฉันคิดว่าแป้นพิมพ์เปิดอยู่ตลอดเวลา

ดังนั้นด้วยโทรศัพท์ความละเอียดสูงใหม่ทั้งหมดที่มีการเปิดตัวฉันเชื่อว่าการใช้ค่าที่เข้ารหัสยากไม่ใช่ความคิดที่ดีในระยะยาว

วิธีที่ดีกว่าที่ฉันพบหลังจากการทดสอบบนหน้าจอและอุปกรณ์ต่าง ๆ คือใช้เปอร์เซ็นต์ รับความแตกต่างระหว่างเนื้อหาแอพ decorView และ ur และหลังจากนั้นตรวจสอบว่าเปอร์เซ็นต์ของความแตกต่างนั้นคืออะไร จากสถิติที่ฉันได้รับแถบนำทาง (โดยไม่คำนึงถึงขนาดความละเอียด ฯลฯ ) ส่วนใหญ่จะใช้ระหว่าง 3% ถึง 5% ของหน้าจอ โดยที่ราวกับว่าคีย์บอร์ดเปิดอยู่มันใช้เวลาระหว่าง 47% ถึง 55% ของหน้าจอ

โดยสรุปแล้วทางออกของฉันคือการตรวจสอบว่าส่วนต่างนั้นมีค่ามากกว่า 10% หรือไม่จากนั้นฉันถือว่าแป้นพิมพ์นั้นเปิดอยู่


3

ฉันใช้คำตอบของ Reuban เล็กน้อยซึ่งพิสูจน์แล้วว่ามีประโยชน์มากขึ้นในบางสถานการณ์โดยเฉพาะกับอุปกรณ์ความละเอียดสูง

final View activityRootView = findViewById(android.R.id.content);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(
        new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                int heightView = activityRootView.getHeight();
                int widthView = activityRootView.getWidth();
                if (1.0 * widthView / heightView > 3) {
                    //Make changes for Keyboard not visible
                } else {
                    //Make changes for keyboard visible
                }
            }
        });

R.id.activityRoot นี้คืออะไร
ranjith

2
แทนที่จะสร้างและใช้R.id.activityRootคุณสามารถใช้android.R.id.contentสิ่งที่คุณต้องการ
Marcin Orlowski

3

มันมีมานานแล้วในแง่ของคอมพิวเตอร์ แต่คำถามนี้ยังมีความเกี่ยวข้องอย่างไม่น่าเชื่อ! ดังนั้นฉันจึงได้คำตอบข้างต้นและรวมเข้าด้วยกันและทำให้ดีขึ้นเล็กน้อย ...

public interface OnKeyboardVisibilityListener {
    void onVisibilityChanged(boolean visible);
}

public final void setKeyboardListener(final OnKeyboardVisibilityListener listener) {
    final View activityRootView = ((ViewGroup) getActivity().findViewById(android.R.id.content)).getChildAt(0);
    activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

        private boolean wasOpened;

    private final Rect r = new Rect();

        @Override
        public void onGlobalLayout() {
            activityRootView.getWindowVisibleDisplayFrame(r);

            int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
            boolean isOpen = heightDiff > 100;
            if (isOpen == wasOpened) {
                logDebug("Ignoring global layout change...");
                return;
            }

            wasOpened = isOpen;
            listener.onVisibilityChanged(isOpen);
        }
    });
}

มันใช้งานได้สำหรับฉัน


3

ลองสิ่งนี้:

final View activityRootView = getWindow().getDecorView().getRootView();
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        Rect r = new Rect();
        //r will be populated with the coordinates of your view that area still visible.
        activityRootView.getWindowVisibleDisplayFrame(r);

        int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
        if (heightDiff < activityRootView.getRootView().getHeight() / 4 ) { // if more than 100 pixels, its probably a keyboard...
             // ... do something here ... \\
        }
    }
});

2

คำตอบของฉันนั้นโดยทั่วไปเหมือนกับคำตอบของ Kachi แต่ฉันห่อไว้ในคลาสผู้ช่วยที่ดีเพื่อทำความสะอาดวิธีการใช้งานตลอดทั้งแอพของฉัน

import android.app.Activity;
import android.app.Fragment;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;

/**
 * Detects Keyboard Status changes and fires events only once for each change
 */
public class KeyboardStatusDetector {
    KeyboardVisibilityListener visibilityListener;

    boolean keyboardVisible = false;

    public void registerFragment(Fragment f) {
        registerView(f.getView());
    }

    public void registerActivity(Activity a) {
        registerView(a.getWindow().getDecorView().findViewById(android.R.id.content));
    }

    public KeyboardStatusDetector registerView(final View v) {
        v.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();
                v.getWindowVisibleDisplayFrame(r);

                int heightDiff = v.getRootView().getHeight() - (r.bottom - r.top);
                if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
                    /** Check this variable to debounce layout events */
                    if(!keyboardVisible) {
                        keyboardVisible = true;
                        if(visibilityListener != null) visibilityListener.onVisibilityChanged(true);
                    }
                } else {
                    if(keyboardVisible) {
                        keyboardVisible = false;
                        if(visibilityListener != null) visibilityListener.onVisibilityChanged(false);
                    }
                }
            }
        });

        return this;
    }

    public KeyboardStatusDetector setVisibilityListener(KeyboardVisibilityListener listener) {
        visibilityListener = listener;
        return this;
    }

    public static interface KeyboardVisibilityListener {
        public void onVisibilityChanged(boolean keyboardVisible);
    }
}

คุณสามารถใช้สิ่งนี้เพื่อตรวจจับการเปลี่ยนแปลงของแป้นพิมพ์ได้ทุกที่ในแอปเช่นนี้

    new KeyboardStatusDetector()
            .registerFragment(fragment)  //register to a fragment 
            .registerActivity(activity)  //or register to an activity
            .registerView(view)          //or register to a view
            .setVisibilityListener(new KeyboardVisibilityListener() {
                @Override
                public void onVisibilityChanged(boolean keyboardVisible) {
                    if(keyboardVisible) {
                       //Do stuff for keyboard visible
                    }else {
                       //Do stuff for keyboard hidden
                    }
                }
            });

หมายเหตุ: ใช้หนึ่งในสาย "ลงทะเบียน" เท่านั้น พวกเขาทั้งหมดทำงานเหมือนกันและมีเพื่อความสะดวกเท่านั้น


2

คุณสามารถลองสิ่งนี้ทำงานได้ดีสำหรับฉัน:

InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);

if (imm.isAcceptingText()) {
    //Software Keyboard was shown..
} else {
    //Software Keyboard was not shown..
}

1
อย่าใช้สิ่งนี้มันจะกลับมาเป็นจริงถ้าคีย์บอร์ดถูกซ่อนไว้โดยใช้ด้านหลัง แต่มุมมองนั้นมีจุดโฟกัสอย่างน้อยใน Marshmallow
Maragues

2
ตอบกลับที่มองเห็นได้เสมอ
jose920405

2

ฉันมีปัญหาในการรักษาสถานะแป้นพิมพ์เมื่อเปลี่ยนการวางแนวของชิ้นส่วนภายใน viewpager ฉันไม่แน่ใจว่าทำไม แต่ดูเหมือนจะเฉื่อยชาและทำหน้าที่แตกต่างจากกิจกรรมมาตรฐาน

เพื่อรักษาสถานะแป้นพิมพ์ในกรณีนี้ก่อนอื่นคุณควรเพิ่มandroid:windowSoftInputMode = "stateUnchanged"ของคุณAndroidManifest.xmlที่คุณคุณอาจสังเกตเห็นว่าสิ่งนี้ไม่ได้แก้ปัญหาทั้งหมดจริง ๆ - แป้นพิมพ์ไม่เปิดให้ฉันถ้ามันถูกเปิดก่อนหน้านี้ก่อนที่จะเปลี่ยนการวางแนว ในกรณีอื่น ๆ พฤติกรรมดูเหมือนจะถูกต้อง

จากนั้นเราต้องใช้วิธีแก้ไขปัญหาที่กล่าวถึงที่นี่ สิ่งที่สะอาดที่สุดที่ฉันพบคือ George Maisuradze's - ใช้การติดต่อกลับบูลีนจาก hideSoftInputFromWindow:

InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);

ฉันเก็บค่านี้ในonSaveInstanceStateวิธีส่วนของฉันและดึงมันonCreateมา จากนั้นฉันบังคับให้แสดงแป้นพิมพ์ในonCreateViewกรณีที่มีค่าเป็นtrue(มันจะกลับมาจริงถ้าแป้นพิมพ์สามารถมองเห็นได้ก่อนที่จะซ่อนตัวจริงก่อนที่จะทำลายชิ้นส่วน)


1

นี่คือทางออกของฉันและใช้งานได้ แทนที่จะมองหาขนาดพิกเซลเพียงตรวจสอบว่าความสูงของมุมมองเนื้อหาเปลี่ยนไปหรือไม่:

// Scroll to the latest comment whenever the keyboard is shown
commentsContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

        private int oldHeight;

        @Override
        public void onGlobalLayout() {
            int newHeight = commentsContent.getMeasuredHeight();
            if (newHeight < oldHeight) {
                // Check for the keyboard showing in case the height difference
                // is a result of orientation change
                if (isSoftKeyboardShowing(CommentsActivity.this)) {
                    // Keyboard is showing so scroll to the latest comment
                    scrollToLatestComment();
                }
            }
            oldHeight = newHeight;
        }

    });


public static boolean isSoftKeyboardShowing(Activity activity) {
    InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
    return inputMethodManager.isActive();
}

inputMethodManager.isActive () มักจะกลับมาจริงสำหรับฉันโดยไม่คำนึงว่าแป้นพิมพ์จะขึ้นหรือไม่
EionRobb

1

อย่าทำรหัสยาก ๆ วิธีที่ดีที่สุดคือคุณต้องปรับขนาดมุมมองของคุณในขณะที่รับโฟกัสบน EditText ด้วย KeyBord Show คุณสามารถเพิ่มคุณสมบัติการปรับขนาดในกิจกรรมลงในไฟล์ Manifest โดยใช้รหัสด้านล่าง

android:windowSoftInputMode="adjustResize"


1

มีวิธีการโดยตรงเพื่อหาสิ่งนี้ และไม่ต้องการการเปลี่ยนแปลงเค้าโครงใด ๆ
ดังนั้นมันจะทำงานในโหมดเต็มหน้าจอแบบเต็มจอด้วยเช่นกัน

เคล็ดลับคือคุณพยายามซ่อนหรือแสดงคีย์บอร์ดอ่อนและจับผลลัพธ์ของการลอง
ไม่ต้องตกใจนี่ไม่ได้แสดงหรือซ่อนคีย์บอร์ดจริงๆ เราแค่ขอให้รัฐ

หากต้องการติดตามข้อมูลล่าสุดคุณสามารถดำเนินการซ้ำได้อย่างง่ายดายเช่นทุกๆ 200 มิลลิวินาทีโดยใช้ตัวจัดการ

คุณพบการใช้งานที่นี่: https://stackoverflow.com/a/27567074/2525452


1

ฉันคิดว่าวิธีนี้จะช่วยให้คุณค้นพบว่ามีปุ่มกดปรากฏให้เห็นหรือไม่

 public Boolean isSoftKeyBoardVisible(){
    InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);

    if (imm.isAcceptingText()) {
        Log.d(TAG,"Software Keyboard was shown");
        return true;
    } else {
        Log.d(TAG,"Software Keyboard was not shown");
        return false;
    }

}

ตอบกลับที่มองเห็นได้เสมอ
jose920405

0

คำตอบใหม่ของ Reuben Scratton (คำนวณ HeightDiff int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight(); ) จะไม่ทำงานหากคุณตั้งโหมดแถบสถานะโปร่งแสง

ถ้าคุณใช้แถบสถานะโปร่งแสง activityRootView.getHeight()จะไม่เปลี่ยนสภาพอากาศเมื่อมองเห็นคีย์บอร์ดนุ่ม มันจะคืนความสูงของกิจกรรมและแถบสถานะเสมอ

ตัวอย่างเช่น Nexus 4, Android 5.0.1 ตั้งค่าandroid:windowTranslucentStatusเป็นจริงมันจะคืนค่า 1184 ตลอดกาลแม้ ime จะมี opend หากตั้งไว้android:windowTranslucentStatusเป็นเท็จมันจะคืนค่าความสูงได้อย่างถูกต้องหาก ime มองไม่เห็นมันส่งคืน 1134 (ไม่รวมแถบสถานะ) 。ปิดค่า ime ค่านั้นจะคืน 5xx อาจขึ้นอยู่กับความสูงของ ime

ฉันไม่ทราบว่าสภาพอากาศนี้เป็นจุดบกพร่องฉันลองใช้ 4.4.4 และ 5.0.1 ผลลัพธ์เหมือนกัน

ดังนั้นถึงตอนนี้คำตอบที่ได้รับการยอมรับมากเป็นอันดับสองคำตอบของ Kachi จะเป็นวิธีที่ปลอดภัยที่สุดในการคำนวณความสูงของค่า ime นี่คือสำเนา:

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new        OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);

int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
    ... do something here
    }
 }
}); 

0

วิธีการที่ไม่ต้องการ LayoutListener

ในกรณีของฉันฉันต้องการบันทึกสถานะของแป้นพิมพ์ก่อนที่จะเปลี่ยนชิ้นส่วนของฉัน ฉันเรียกเมธอด hideSoftInputFromWindowจากonSaveInstanceStateซึ่งจะปิดแป้นพิมพ์และส่งคืนฉันว่าแป้นพิมพ์นั้นสามารถมองเห็นได้หรือไม่

วิธีนี้ตรงไปตรงมา แต่อาจเปลี่ยนสถานะของแป้นพิมพ์ของคุณ


0

ฉันรู้ว่านี่เป็นโพสต์เก่า แต่ฉันคิดว่านี่เป็นวิธีที่ง่ายที่สุดที่ฉันรู้และอุปกรณ์ทดสอบของฉันคือ Nexus 5 ฉันไม่ได้ลองในอุปกรณ์อื่น หวังว่าคนอื่นจะแบ่งปันแนวทางของพวกเขาหากพวกเขาพบว่ารหัสของฉันไม่ดี :)

public static boolean isKeyboardShown(Context context, View view) {
        if (context == null || view == null) {
            return false;
        }
        InputMethodManager imm = (InputMethodManager) context
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        return imm.hideSoftInputFromWindow(view.getWindowToken(), 0); 
}

imm.hideSoftInputFromWindow ส่งคืนบูลีน

ขอบคุณ


0
if (keyopen())
{
                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY,0);            
}

ฟังก์ชั่นด้านบนเป็นสิ่งที่ฉันใช้ตรวจสอบว่ามีแป้นพิมพ์ปรากฏอยู่หรือไม่ ถ้าเป็นเช่นนั้นฉันจะปิดมัน

ด้านล่างแสดงวิธีการสองวิธีที่จำเป็น

ก่อนอื่นให้กำหนดความสูงของหน้าต่างที่สามารถทำงานได้ใน onCreate

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

//  add to onCreate method
    Rect rectgle= new Rect();
    Window window= getWindow();
    window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
    sheight= rectgle.bottom;
//

} 

จากนั้นเพิ่มเมธอดบูลีนที่รับค่าความสูงหน้าต่างในอินสแตนซ์นั้น หากไม่ตรงกับต้นฉบับ (สมมติว่าคุณไม่ได้เปลี่ยนไปตามทาง ... ) แสดงว่าแป้นพิมพ์เปิดอยู่

public boolean keyopen()
{
    Rect rectgle= new Rect();
    Window window= getWindow();
    window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
    int curheight= rectgle.bottom;

    if (curheight!=sheight)
    {
        return true;
    }
    else
    {
        return false;
    }
}

Frotz!


0

ฉันรู้ว่าคุณสามารถระบุได้อย่างแม่นยำว่าแป้นพิมพ์ถูกซ่อนอยู่หรือไม่

public int getStatusBarHeight() {
    int result = 0;
    int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0) {
        result = getResources().getDimensionPixelSize(resourceId);
    }
    return result;
}

public int getNavigationBarHeight() {
    int result = 0;
    int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
    if (resourceId > 0) {
        result = getResources().getDimensionPixelSize(resourceId);
    }
    return result;
}

public boolean isKeyboardHidden() {
    int delta = mRootView.getRootView().getHeight() - mRootView.getHeight() - getNavigationBarHeight() - getStatusBarHeight()
            - getSupportActionBar().getHeight();
    return delta <= 0;
}

ใช้งานได้กับแท็บเล็ต เมื่อแถบนำทางถูกแสดงในแนวนอน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.