Home > Mobile >  I want to change the height of the appbar using the value of json style file
I want to change the height of the appbar using the value of json style file

Time:03-01

I have a app_bar_base.dart file where i have an AppBar.



class AppBarBase extends StatelessWidget implements PreferredSizeWidget {
  late double appBarHeight = LoadAppStyle().loadAppStyle();


  AppBarBase({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return AppBar();
  }

  @override
  Size get preferredSize => Size.fromHeight(appBarHeight);
}

I am calling the method LoadAppStyle().loadAppStyle() from the file load_app_style:


class LoadAppStyle {
  loadAppStyle() async {
    String jsonData =
        await rootBundle.loadString('assets/config/app_style.json');
    Map<String, dynamic> data = jsonDecode(jsonData);
    var getHeight = double.parse(data["app_bar"]["app_bar_height"]);
    return getHeight;
  }
}

In the load_app_style.dart file i grab the value of app_bar_heigt from the app_style.json

in app_style.json i have key app_bar_height where i want to change the value manually to change the height of the App bar

{
  "app_bar":
  {
    "app_bar_height": 78
  },
  
}

But for some reason i get the error : type 'Future<dynamic>' is not a subtype of type 'double'

CodePudding user response:

You can add the type to your loadAppStyle method. Since your method is async it returns a Future.

Future<double> loadAppStyle() async {
   ...
   return getHeight;
  }

Now your error should be

type 'Future<double>' is not a subtype of type 'double'

Since your method returns a Future you have to use await to get the value.

loadAppStyle() // Future<double>
await loadAppStyle() // double

If you want to use a value of a Future inside a Widget, have a look at FutureBuilder.

For your case you could e.g. use the FutureBuilder to retrieve the height and then pass it to AppBarBase

FutureBuilder<double>(
  future: loadAppStyle(),
  builder: (context, snapshot) {
    if(snapshot.hasData) {
      return AppBarBase(height: snapshot.data);
    } else {
      return const Center(child: CirclularProgressIndicator));
    }
  }
)

And change your AppBarBase to the following.

class AppBarBase extends StatelessWidget implements PreferredSizeWidget {
  AppBarBase({
    Key? key,
    required this.height,
  }) : super(key: key);

  final double height;
  
  @override
  Widget build(BuildContext context) {
    return AppBar();
  }

  @override
  Size get preferredSize => Size.fromHeight(height);
}

CodePudding user response:

In your example, loadAppStyle() has no defined return type (dynamic) and it is marked as async (Future), hence the return type of this function is Future<dynamic>. Size.fromHeight function requires the double value, hence you get this error - the expected type is double, but Future<dynamic> was found here.

To resolve the type differences, you should set the return type of a function:

class LoadAppStyle {
  Future<double> loadAppStyle() async {
    String jsonData =
        await rootBundle.loadString('assets/config/app_style.json');
    Map<String, dynamic> data = jsonDecode(jsonData);
    var getHeight = double.parse(data["app_bar"]["app_bar_height"]);
    return getHeight;
  }
}

Now, since your function is async, you must wait for your Future to finish and only then you could retrieve the double value. It would look something like this:

class AppBarBase extends StatelessWidget implements PreferredSizeWidget {
  late double appBarHeight = await LoadAppStyle().loadAppStyle(); // Throws error

  AppBarBase({Key? key}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return AppBar();
  }

  @override
  Size get preferredSize => Size.fromHeight(appBarHeight);
}

However, this throws an error since you cannot use the asynchronous code when initialising a value this way. What could be a better way to do this is to wait for this value somewhere outside of your widget and pass the result via the constructor:

class AppBarBase extends StatelessWidget implements PreferredSizeWidget {
  final double appBarHeight;

  AppBarBase({
    required this.appBarHeight,
    Key? key,
  }) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return AppBar();
  }

  @override
  Size get preferredSize => Size.fromHeight(appBarHeight);
}

This way, you separate your UI code from the widget. Anyway, the way of keeping this UI-specific configuration inside the JSON file sounds way overengineered - consider just passing this value via constructor directly, like: AppBarBase(appBarHeight: 78).

  • Related