Изменение цвета панели системы с областью безопасности

#flutter

#flutter

Вопрос:

Я пытаюсь добавить SafeArea виджет для приложения flutter с раскрашенными системными панелями, но почему-то они всегда становятся черными.

   @override
  Widget build(BuildContext context) {
    SystemChrome.setSystemUIOverlayStyle(
      SystemUiOverlayStyle.light.copyWith(
        systemNavigationBarIconBrightness: Brightness.dark,
        systemNavigationBarColor: kSurfaceColor,
        statusBarIconBrightness: Brightness.dark,
        statusBarColor: Colors.red, // Note RED here
      ),
    );

    return SafeArea(
      child: Scaffold(
        backgroundColor: kWhiteColor,
        appBar: _buildAppBar(context), // Title and Avatar are built here
        body: _buildBody(), // This function just returns blank Container for now
        floatingActionButton: _buildFAB(context),
        floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
      ),
    );
  }
  

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

Если я оберну SafeArea внутри свойства, для Container которого color установлено значение white, это сработает, но значки системной панели также станут белыми введите описание изображения здесь

Ответ №1:

Основываясь на ответе @david-carrilho, я создал этот простой виджет

 import 'package:flutter/material.dart';

class ColoredSafeArea extends StatelessWidget {
  final Widget child;
  final Color color;

  const ColoredSafeArea({Key key, @required this.child, this.color})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: color ?? Theme.of(context).colorScheme.primaryVariant,
      child: SafeArea(
        child: child,
      ),
    );
  }
}
  

Затем, где бы я ни использовал SafeArea , я использую свой маленький виджет-оболочку ColoredSafeArea .

 class MyExampleView extends StatelessWidget {
  const MyExampleView({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ColoredSafeArea(
      child: Center(
        child: Text('Nice color bar'),
      ),
    );
  }
}
  

Причина, по которой это работает, заключается в том, что это создает контейнер за вашим содержимым с указанным цветом, а затем SafeArea просто добавляет необходимое заполнение в зависимости от устройства.

Комментарии:

1. Спасибо. Цвет работает, но сейчас я не вижу системных значков. Как их отобразить?

2. У меня такой же вопрос, как и у Kakyo. Может ли кто-нибудь поделиться подсветкой на нем?

Ответ №2:

Я знаю, что это старый вопрос, но после прочтения документации я придумал более полное решение.

В моем ответе учитывается следующее:

  1. Не помещайте каркасы в безопасные области;
  2. [iOS] покрасьте свой каркас в правильный цвет;
  3. [Android] программно настраивает системные панели.

1. Правильное использование SafeArea

SafeArea это виджет, который выполняет MediaQuery добавление некоторого надлежащего заполнения в ваше приложение. Это должно происходить внутри body вашего Scaffold приложения. Что-то подобное приведет к коду, который позже не будет неожиданно прерываться:

 return Scaffold(
  // ...
  body: SafeArea(                // your SafeArea should stay here
    child: YourWidget(),
  ),
);
  

2. Заметка для iOS

Как уже говорилось в других ответах, вам просто нужно покрасить свой каркас так, чтобы вы получили нужный цвет. Ваш каркас должен включать backgroundColor свойство (и панель приложений тоже, если она у вас есть).

 return Scaffold(
  // ...
  backgroundColor: yourColor,    // the RED you need
  appBar: AppBar(                // if any
    backgroundColor: yourColor,  // maybe RED here, also
    // a system overlay option is included here, too, see 3.
    // ...
  ),
  body: SafeArea(                // your SafeArea should stay here
    child: YourWidget(),
  ),
);
  

3. Системный интерфейс Android

Как и в OP, вам нужно SystemChrome.setSystemUIOverlayStyle() обратиться к системным цветам панели, связанным с Android.

Однако, в документации говорится, что этот метод следует вызывать программно всякий раз, когда открывается новая страница / новый маршрут, если у вас разные Route цвета.

Предположим, у вас есть версия 2.0 Router ; затем вы должны написать ее build метод следующим образом:

 Widget build(BuildContext context) {
    Color overlayColor = ... your color ...;
    final systemBarColors = SystemUiOverlayStyle(
      systemNavigationBarColor: overlayColor,
      statusBarColor: overlayColor,
    );
    SystemChrome.setSystemUIOverlayStyle(systemBarColors);

    return AnnotatedRegion<SystemUiOverlayStyle>(
      value: systemBarColors,
      child: Navigator(
        key: navigatorKey,
        pages: _stack,
        onPopPage: _onPopPage,
      ),
    );
}
  

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

Ответ №3:

 Container(
   color ...
      ),
      child: SafeArea(
        child: Scaffold(
          body: 
            AnnotatedRegion<SystemUiOverlayStyle>(
               value: SystemUiOverlayStyle.light,
               child: ...
  

Комментарии:

1. Добро пожаловать в stackoverflow. В дополнение к предоставленному вами ответу, пожалуйста, рассмотрите возможность предоставления краткого объяснения того, почему и как это устраняет проблему.

2. Я отклонил это. Не используйте это решение, SafeArea они всегда должны находиться внутри каркаса. Это приводит к тому, что навигационные и системные панели становятся черными без причины.

Ответ №4:

В вашем случае просто перенос SafeArea() на верхний виджет, который будет отображаться на экране (пример: ваш текстовый виджет «Сегодня»), должен избегать черного цвета на системной панели.

Полный пример.

 Scaffold(
        body: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            SafeArea(
              child: Text('Today'),
            ),
            Text('Tomorrow')
          ]
      );
  

У меня это сработало!

Ответ №5:

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

 SystemChrome.setSystemUIOverlayStyle(
  SystemUiOverlayStyle.dark.copyWith(statusBarColor: Colors.white));
  

Ответ №6:

установить только основной класс

   SystemChrome.setSystemUIOverlayStyle(
          SystemUiOverlayStyle.light.copyWith(
            systemNavigationBarIconBrightness: Brightness.dark,
            systemNavigationBarColor: Colors.white,
            statusBarIconBrightness: Brightness.light,
            statusBarColor: HexColor(HexColor.primarycolor), // Note RED here
          ),
        );  

  
  

мой пример кода

 import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    import 'package:loader_overlay/loader_overlay.dart';
    
    
    import 'HexColor.dart';
    
    class CityListActiviy extends StatefulWidget {
      // Initially password is obscure
      @override
      State<CityListActiviy> createState() => _CityListActiviyState();
    }
    
    class _CityListActiviyState extends State<CityListActiviy> {
      TextEditingController userid_Controller = new TextEditingController();
      bool userid_validate = false;
    
      final String requiredNumber = '123456';
    
      @override
      void initState() {
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        SystemChrome.setSystemUIOverlayStyle(
          SystemUiOverlayStyle.light.copyWith(
            systemNavigationBarIconBrightness: Brightness.dark,
            systemNavigationBarColor: Colors.white,
            statusBarIconBrightness: Brightness.light,
            statusBarColor: HexColor(HexColor.primarycolor), // Note RED here
          ),
        );
    
        return MaterialApp(
          debugShowCheckedModeBanner: true,
          home: LoaderOverlay(
            child:SafeArea(
            child: Scaffold(
                backgroundColor: HexColor(HexColor.gray_activity_background),
                body: SingleChildScrollView(
                  child: Column(
                      crossAxisAlignment: CrossAxisAlignment.stretch,
                      children: [
    
                        Stack(
                          children: [
                            Container(
                                height: 60,
                                padding: new EdgeInsets.all(20.0),
                                decoration: BoxDecoration(
                                  color: HexColor(HexColor.white),
                                ),
                                width: MediaQuery.of(context).size.width,
                                child: Text("Select Your Location",
                                    textAlign: TextAlign.center,
                                    style: TextStyle(
                                      fontSize: 16,
                                      color: Colors.grey,
                                      fontFamily: 'montserrat_medium',
                                      decoration: TextDecoration.none,
                                    ))),
    
                          ],
                        )
                      ]),
                )),
            )
          ),
        );
      }
    }