22

I am getting a "nullable expression" error. The problem is occurring in the following lines:

left: isSideBarOpenedAsync.data ? 0 : 0,
right: isSideBarOpenedAsync.data ? 0 : screenWidth - 35,

Where isSideBarOpenedAsync is type AsyncSnapshot<bool>

This is the error I'm getting

A nullable expression can't be used as a condition. Try checking that the value isn't null before using it as a condition.

Here's the full code for reference

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:solaris/constants.dart';
import 'package:rxdart/rxdart.dart';

class SideBar extends StatefulWidget {

  @override
  _SideBarState createState() => _SideBarState();
}

class _SideBarState extends State<SideBar> with SingleTickerProviderStateMixin<SideBar>{
  late AnimationController _animationController;
  late StreamController<bool> isSidebarOpenedStreamController;
  late Stream<bool> isSideBarOpenedStream;
  late StreamSink<bool> isSideBarOpenedSink;
  final _animationDuration = const Duration(milliseconds: 500);

  @override
  void initState(){
    super.initState();
    _animationController = AnimationController(vsync: this, duration: _animationDuration);
    isSidebarOpenedStreamController = PublishSubject<bool>();
    isSideBarOpenedStream = isSidebarOpenedStreamController.stream;
    isSideBarOpenedSink = isSidebarOpenedStreamController.sink;
  }
  @override
  void dispose(){
  _animationController.dispose();
  isSidebarOpenedStreamController.close();
  isSideBarOpenedSink.close();
  super.dispose();
  }

  void onIconPressed(){
    final animationStatus = _animationController.status;
    final isAnimationCompleted = animationStatus == AnimationStatus.completed;

    if(isAnimationCompleted){
      isSideBarOpenedSink.add(false);
      _animationController.reverse();
    }else{
      isSideBarOpenedSink.add(true);
      _animationController.forward();
    }
  }

  @override
  Widget build(BuildContext context) {
    final screenWidth = MediaQuery.of(context).size.width;

    return StreamBuilder<bool>(
      initialData: false,
      stream: isSideBarOpenedStream,
      builder: (context, isSideBarOpenedAsync){
        return AnimatedPositioned(
          duration: _animationDuration,
          top: 0,
          bottom: 0,
          left: isSideBarOpenedAsync.data ? 0 : 0,
          right: isSideBarOpenedAsync.data ? 0 : screenWidth - 35,
          child: Row(
            children: <Widget>[
              Expanded(
                child: Container(
                  color: red,
                ),
              ),
              Align(
                alignment: Alignment(0,-0.9),
                child: GestureDetector(
                  onTap: (){
                    onIconPressed();
                  },
                  child: Container(
                    width: 35,
                    height: 110,
                    color: blue,
                    alignment: Alignment.centerLeft,
                    child: AnimatedIcon(
                      progress: _animationController.view,
                      icon: AnimatedIcons.menu_close,
                      color: white,
                      size: 25,
                    ),
                  ),
                ),
              ),
            ],
          ),
        );
      },
    );
  }
}
mrgnhnt96
  • 3,562
  • 1
  • 17
  • 36
Tμrf
  • 404
  • 1
  • 3
  • 14

3 Answers3

29

If you know that isSideBarOpenedAsync.data will always have a value, you can use a ! to force the value to not be null.

isSideBarOpenedAsync.data!

This changes the value's type from bool? to bool.
Your ternary expressions will work with this logic.

Note: if isSideBarOpenedAsync.data is null using a ! will throw an error, bool cannot be type null.

Alternatively, you can provide a value to be used if the value is null

(isSideBarOpenedAsync.data ?? false)

If isSideBarOpenedAsync.data has a non-null value, it will be referenced. If the value is null, false will be used instead.

mrgnhnt96
  • 3,562
  • 1
  • 17
  • 36
  • ok, i've tried to change `right: isSideBarOpenedAsync.data ? 0 : screenWidth - 35,` in `right: (isSideBarOpenedAsync.data ?? 0 : screenWidth - 35),` but now it gives me this new error: **error: The argument type 'Object' can't be assigned to the parameter type 'double?' and also it expectes to find ')'.** – Tμrf May 28 '21 at 14:17
  • 1
    it should read `(isSideBarOpenedAsync.data ?? false) ? 0 : screenWidth - 35`. – mrgnhnt96 May 28 '21 at 18:01
  • I was hoping that we have the JavaScript approach which null treated as false, but your clarification helps a lot ... – HoseinGhanbari Aug 19 '21 at 09:28
  • 1
    Nice @mrgnhnt96 just put ! after the condition like this isSideBarOpenedAsync.data! and everthing worked fine! – linhadiretalipe Oct 06 '21 at 21:30
5

For more clarification about null safety issue just sharing some info here

There has 3 ways to handle null :

1. ?. Operator - value is Null or not by using simple syntax.

data?.variable;

2. ?? Operator - has Null value and we can also pass default value like

variable ?? "";
    

3. ??= Operator - variable is Null or not. If the variable is Null then it will assign a new value to it

int x = 5;
x ??= 2;
    

Note : I have solved my same issue using ?. operator against bang(!)

May it help someone. Thanks

mrgnhnt96
  • 3,562
  • 1
  • 17
  • 36
Mimu Saha Tishan
  • 2,402
  • 1
  • 21
  • 40
1

i was getting the same problem : even we are doing sample work from the same place in our code i solved the problem as follows

left: isSideBarOpenedAsync.data! ?  0:0, right:isSideBarOpenedAsync.data! ? 0: screenWidth -45, 

I solved the problem when I tried " data! ? "

Other solutions I tried:

left: isSideBarOpenedAsync.data != null && isSideBarOpenedAsync.data ? 0 : 0,

right: isSideBarOpenedAsync.data != null && isSideBarOpenedAsync.data ? 0 : screenWidth - 45,

left: isSideBarOpenedAsync.hasData && isSideBarOpenedAsync.data! ? 0 : 0,

right: isSideBarOpenedAsync.hasData && !isSideBarOpenedAsync.data! ? screenWidth - 45 : 0,

these had happened.