web-dev-qa-db-ja.com

ソフトキーボードが表示された後、スティッキーイマーシブモードが無効になります

ほとんどの場合、全画面表示にする必要があるアプリがあります。アラートが表示されたり、他のウィンドウが表示されたりすると、アクティビティウィンドウの上部にある全画面が一時的に削除されることを知っています。残念ながら、EditTextなどにソフトキーボードが表示されている場合、ユーザーがキーボードを使い終えると、全画面没入モードは復元されません。

これをどのように達成できるか考えていますか?

31
jomalden

Googleによるこのサンプルアプリ から取得した場合、これをアクティビティの最後の最後の終了ブラケットの前に追加する必要があります。

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    // When the window loses focus (e.g. the action overflow is shown),
    // cancel any pending hide action. When the window gains focus,
    // hide the system UI.
    if (hasFocus) {
        delayedHide(300);
    } else {
        mHideHandler.removeMessages(0);
    }
}

private void hideSystemUI() {
    getWindow().getDecorView().setSystemUiVisibility(
        View.SYSTEM_UI_FLAG_LAYOUT_STABLE | 
        View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | 
        View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | 
        View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | 
        View.SYSTEM_UI_FLAG_FULLSCREEN | 
        View.SYSTEM_UI_FLAG_LOW_PROFILE | 
        View.SYSTEM_UI_FLAG_IMMERSIVE
    );
}

private void showSystemUI() {
    getWindow().getDecorView().setSystemUiVisibility(
        View.SYSTEM_UI_FLAG_LAYOUT_STABLE | 
        View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | 
        View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
    );
}

private final Handler mHideHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        hideSystemUI();
    }
};

private void delayedHide(int delayMillis) {
    mHideHandler.removeMessages(0);
    mHideHandler.sendEmptyMessageDelayed(0, delayMillis);
}

そして、あなたは良いはずです。 :)

14
r3pwn

AppCompatActivityを新しいクラス(ImmersiveAppCompatActivity)に拡張することをお勧めします。これにより、このクラスを使用して作成するアクティビティには、没入モードの処理が組み込まれます。

ソフトキーボードが表示された後、イマーシブモードをすばやく設定しようとすると、非表示になりません。

また、静的ハンドラーに切り替えることでハンドラーが改善されたことにも注意してください。これにより、GUIが非表示になる前にユーザーがアクティビティを離れた場合のリークが防止されます。

public abstract class ImmersiveAppCompatActivity extends AppCompatActivity {
    private HideHandler mHideHandler;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // create a handler to set immersive mode on a delay
        mHideHandler = new HideHandler(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        setToImmersiveMode();
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if(hasFocus) {
            mHideHandler.removeMessages(0);
            mHideHandler.sendEmptyMessageDelayed(0, 300);
        }
        else mHideHandler.removeMessages(0);
    }

    private void setToImmersiveMode() {
        // set to immersive
        getWindow().getDecorView().setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
    }

    private static class HideHandler extends Handler {
        private final WeakReference<ImmersiveAppCompatActivity> mActivity;

        HideHandler(ImmersiveAppCompatActivity activity) {
            mActivity = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            ImmersiveAppCompatActivity activity = mActivity.get();
            if(activity != null) activity.setToImmersiveMode();
        }
    }
}

Kotlinのバージョンは次のとおりです。

abstract class ImmersiveAppCompatActivity : AppCompatActivity() {
    override fun onResume() {
        super.onResume()

        setToImmersiveMode()
    }

    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)

        val runnable = Runnable { setToImmersiveMode() }

        val handler = Handler(Looper.getMainLooper())
        handler.postDelayed(runnable, 300)
    }

    private fun setToImmersiveMode() {
        window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                or View.SYSTEM_UI_FLAG_FULLSCREEN
                or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
    }
}

次に、このクラスを使用してアクティビティを作成します。

public class SettingsActivity extends ImmersiveAppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getFragmentManager().beginTransaction().replace(Android.R.id.content, new SettingsFragment()).commit();
    }
}

これをAndroid 5.1および7.0でテストして、アクションバーのないフルスクリーンアプリで動作するようにしました。

さらに、EditTextでキーボードを使用する場合は、imeOptionsに注意してください。横長モードでは、奇妙な全画面編集動作が発生する可能性があります。これは、クラスEditorInfoに含まれるimeOptionsフラグを設定することで無効にできます。

<EditText
    Android:layout_width="@dimen/pin_width"
    Android:layout_height="wrap_content"
    Android:inputType="numberPassword"
    Android:imeOptions="flagNoExtractUi"
    Android:ems="10"
    Android:id="@+id/editTextPIN"
    Android:textSize="@dimen/pin_large_text_size"/>

https://developer.Android.com/reference/Android/view/inputmethod/EditorInfo.html

2
Machine Commune

このコードをonCreate()に配置して、レイアウトの変更を監視します

getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {

        Rect rect = new Rect();
        getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
        int screenHeight = getWindow().getDecorView().getRootView().getHeight();

        int keyboardHeight = screenHeight - rect.bottom;

        if (keyboardHeight > screenHeight * 0.15) {
             setToImmersiveMode();
        }
    }
});


private void setToImmersiveMode() {
        // set to immersive
        getWindow().getDecorView().setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
    }
1

これは通常の動作です。ただし、次の2つの手順で修正できます。
1。キーボードが非表示になったときに確認する
2。没入型フルスクリーンモードを設定します(ここでも)

ステップ1は少しトリッキーです。ここで私の答えをチェックできます:
https://stackoverflow.com/a/27567074/2525452

ステップ2は簡単です。

public static void setImmersiveMode( Activity activity )
{
    // Get the Activity's content View
    ViewGroup content = (ViewGroup) activity.findViewById( Android.R.id.content );
    //
    // Set the immersive mode flags at the content View
    content.setSystemUiVisibility(
        View.SYSTEM_UI_FLAG_IMMERSIVE |
        View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
        View.SYSTEM_UI_FLAG_FULLSCREEN |
        View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
        View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
        View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
    );
}
1
fies