Полноэкранное приложение с DisplayCutout

Как сделать приложение с реальными полноэкранными возможностями, макет которого будет отображаться под выемкой?

Вот что я хочу:

Google Фото

Вот код того, что я пробовал:

class MainActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
//            window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)

            val attrib = window.attributes
            attrib.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS

            layout_main.setOnApplyWindowInsetsListener { _, windowInsets ->
                val inset = windowInsets.displayCutout
                Log.d("Tag", "Inset: $inset")
                windowInsets
            }
        }
    }
}

Расположение:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/layout_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#3000FFFF"
    android:fitsSystemWindows="true">

    <View
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="#FFFF0000"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="#FF00FF00"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="#FF0000FF"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <View
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="#FFFF00"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:gravity="center"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

Стиль:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>

    <item name="android:windowNoTitle">true</item>
    <item name="android:windowActionBar">false</item>
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowContentOverlay">@null</item>

    <item name="android:windowTranslucentStatus">true</item>
    <item name="android:windowTranslucentNavigation">true</item>
</style>

Вот манифест Android:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.app.testandroidp">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity
            android:name="com.app.testandroidp.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

</manifest>

Вот результат, который я получил до сих пор:

введите описание изображения здесь

Я пытался установить разные темы, установить флаг полноэкранного режима в XML/Kotlin, установить активность с изменяемым размером в манифесте, но активность просто не будет отображаться под надрезом.

Для справки, это исходный код проекта: https://gitlab.com/alvin.rusli/AndroidPTest


person Alvin Rusli    schedule 09.03.2018    source источник
comment
не уверен, где вы взяли window.attributes, мне пришлось использовать getWindow().getAttributes().   -  person Michael    schedule 04.01.2019
comment
@Michael Использование Kotlin автоматически удаляет get/set из методов getter/setter   -  person Alvin Rusli    schedule 07.01.2019


Ответы (9)


Установите эти свойства в своей теме:

<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
person Sofiane Majdoub    schedule 11.06.2019
comment
это простой и лучший ответ - person Samwinishere Here; 13.01.2020

Я наконец узнал, почему. По какой-то странной причине приложение не входит в условие if:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    // It never gets here
}

Я удалил это условие, и действие, наконец, правильно переходит в полноэкранный режим.

Активность под выемкой


Вот минимальные коды, необходимые для отображения действия в полноэкранном режиме.

Мероприятия:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // or add <item name="android:windowTranslucentStatus">true</item> in the theme
        window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)

        val attrib = window.attributes
        attrib.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
    }
}

Стили:

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>

    <!-- Adding fullscreen will just hide the status bar -->
    <!-- <item name="android:windowFullscreen">true</item> -->
</style>
person Alvin Rusli    schedule 12.03.2018
comment
Да, код версии, возвращаемый эмулятором, все еще 27. Lint дает вам неверные исправления, вам в основном нужно @SuppressLint(NewAPI) везде... - person rockgecko; 12.03.2018
comment
Я думаю, что LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS был заменен на LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES: developer.android.com/reference/ андроид/вид/ . Это правда? Это тот же смысл? Что он займет весь экран, включая небезопасные области? - person android developer; 13.06.2018
comment
@androiddeveloper Я протестировал обновление кода и изменение ВСЕГДА на новую работу SHORT_EDGES, как и раньше, но теперь мне интересно, что вам нужно сделать, чтобы сделать полный полноэкранный вид для этих двойных вырезов. - person Alvin Rusli; 26.06.2018
comment
@AlvinRusli Для этого у вас может быть 2 варианта: иммерсивный режим, как показано здесь: developer. android.com/training/system-ui/immersive . Или, если вы хотите показать панель навигации, используйте это: stackoverflow.com/a/29138275/878126 , включая это в коде: window.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS) - person android developer; 26.06.2018
comment
@androiddeveloper Понятно, window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION работает, спасибо! - person Alvin Rusli; 06.07.2018
comment
Я думаю, что MODE_SHORT_EDGES всегда будет вести себя так же, как MODE_ALWAYS, потому что на данный момент вырезы разрешены только на коротких краях устройств. Из документации DisplayCutout.getBoundingRects На коротком краю устройства будет не более одной нефункциональной области, а на длинных — ни одной. края в будущих версиях API, но пока мы в безопасности. - person Columbo; 25.07.2018
comment
Нет ли XML-эквивалента attrib.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS? - person Michael; 04.01.2019
comment
Это не сработает, если мы поддерживаем минимальный API ‹28, поэтому мы не можем удалить условие if. Как еще приложение узнает, использовать условие или нет? - person Subham Burnwal; 27.11.2019
comment
@AlvinRusli Как насчет ландшафтного режима, это исправлено? - person Ashraf Alshahawy; 14.10.2020

Я пробовал много вещей, но не добился успеха, затем я пробую следующий код, и он работает нормально.

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

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
        }

      ---
    }

Я надеюсь, что это полезно.

person Sanjay Chauhan    schedule 06.12.2019
comment
Благодарю вас! Работал отлично для меня! - person 0ne0rZer0; 07.04.2020

если ничего не работает, попробуйте этот один раз

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
                WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
    }
person Sai Gopi Me    schedule 12.07.2019
comment
Это единственный ответ, который работает на надрезных устройствах. - person Ravind Maurya; 04.09.2019
comment
идеальное решение с условием... :) - person VikaS GuttE; 09.02.2020

У меня такая же проблема при разработке приложения для устройства Notch, я решаю эту проблему, определяя стиль темы для устройств Android P и устанавливая режим, такой как режим по умолчанию, короткие края, никогда.

Шаг 1. Создайте новую папку values-v28 в каталоге res и скопируйте в нее файл styles.xml по умолчанию.

Шаг 2. В варианте values-28 файла styles.xml перейдите к теме своей деятельности или создайте новую, если вы использовали тему по умолчанию, и установите этот атрибут:

<style name="ActivityTheme">
  <item name="android:windowLayoutInDisplayCutoutMode">
    shortEdges
  </item>
</style>

Это все, что вам нужно сделать, чтобы получить более захватывающий опыт в вашем приложении и избежать почтовых ящиков, заставив окно приложения отображаться с обеих сторон выемки.

введите описание изображения здесь

Вот ссылка, чтобы узнать больше о разработке совместимого приложения для устройств Notch. Создание приложений, совместимых с Notch

person Asad Mukhtar    schedule 14.03.2019

Вот что сработало для меня:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
        getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
    }
person Tomov    schedule 23.10.2020
comment
Спасибо, это работает для меня - person Ashwin H; 18.06.2021

Это потому, что вы используете Android P, когда он еще не был официально выпущен. Вероятно, у вас есть предварительная версия для разработчиков, в которой есть проблемы с поставщиком. Если вы ищете свою систему в Google и попадаете на страницу XDA, вы, вероятно, сможете найти «Поставщик» среди ошибок вашей версии Android. Обычно предварительные версии для разработчиков сохраняют поставщика предыдущей версии Android, поэтому ваше приложение считает, что оно находится в Android Oreo, когда вы проверяете его в строке ниже:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
person Davide Cannizzo    schedule 11.09.2018

Попробуйте следовать стилю,

<style name="SplashTheme" parent="Theme.AppCompat.NoActionBar">
    <item name="windowNoTitle">true</item>
    <item name="android:windowFullscreen">true</item>
</style>
person Lucifer    schedule 09.03.2018
comment
Странно, не могли бы вы опубликовать код вашего manifest.xml? - person Lucifer; 09.03.2018
comment
Конечно, это совершенно пустой проект, и в нем ничего нет, я просто опубликую ссылку на gitlab по этому вопросу. - person Alvin Rusli; 09.03.2018
comment
@AlvinRusli, извините, но я тоже не смог ее решить. - person Lucifer; 10.03.2018

приведенный ниже код работал у меня, надеюсь, он сработает и у вас:

protected void onCreate(Bundle savedInstanceState) {
    requestWindowFeature(Window.FEATURE_NO_TITLE);//will hide the title
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); //show the activity in full screen
    setContentView(R.layout.activity_pdf_view);

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
        getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
    }
}
    
person n-y    schedule 13.07.2021