简体   繁体   中英

flutter how to create a TabBarView base on null condition

I have a JSON file like this:

[
  {
    "name": "A",
    "tabX": ["AX1","AX2"],
    "tabY": null
  },
  {
    "name": "B",
    "tabX": null,
    "tabY": ["BY1","BY2"]
  },
  {
    "name": "C",
    "tabX": ["CX1","CX2"],
    "tabY": ["CY1","CY2"]
  }
]

I want to create 3 TabView:

  1. The "All" tab shows all
  2. Tab "TabX" will show the elements that tabX has a value, if tabY == null will not include
  3. Tab "TabY" will show the elements that tabY has a value, if tabX == null will not include

在此处输入图像描述

So please help me, this is full code:

import 'package:flutter/material.dart';
import 'dart:convert';

List<Json> jsonFromJson(String str) => List<Json>.from(json.decode(str).map((x) => Json.fromJson(x)));

String jsonToJson(List<Json> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class Json {
  Json({
    this.name,
    this.tabX,
    this.tabY,
  });

  String name;
  List<String> tabX;
  List<String> tabY;

  factory Json.fromJson(Map<String, dynamic> json) => Json(
        name: json["name"] == null ? null : json["name"],
        tabX: json["tabX"] == null ? null : List<String>.from(json["tabX"].map((x) => x)),
        tabY: json["tabY"] == null ? null : List<String>.from(json["tabY"].map((x) => x)),
      );

  Map<String, dynamic> toJson() => {
        "name": name == null ? null : name,
        "tabX": tabX == null ? null : List<dynamic>.from(tabX.map((x) => x)),
        "tabY": tabY == null ? null : List<dynamic>.from(tabY.map((x) => x)),
      };
}

class JsonServices {
  static Future<List<Json>> getData() {
    String jsonString = '''
[
  {
    "name": "A",
    "tabX": ["AX1","AX2"],
    "tabY": null
  },
  {
    "name": "B",
    "tabX": null,
    "tabY": ["BY1","BY2"]
  },
  {
    "name": "C",
    "tabX": ["CX1","CX2"],
    "tabY": ["CY1","CY2"]
  }
]
    ''';

    return Future.value(jsonFromJson(jsonString));
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List<Json> _json = [];
  @override
  void initState() {
    super.initState();
    setState(() {
      JsonServices.getData().then((data) {
        setState(() {
          _json = data;
        });
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DefaultTabController(
        length: 3,
        child: Scaffold(
          appBar: AppBar(
            bottom: TabBar(
              tabs: [
                Tab(text: 'ALL'),
                Tab(text: 'TabX'),
                Tab(text: 'TabY'),
              ],
            ),
          ),
          body: TabBarView(children: [
            Tab(child: TabItemWidget(j: _json,),),
            Tab(text: 'TabX'), // pls help
            Tab(text: 'TabY'), // pls help
          ],),
        ),
      ),
    );
  }
}

class TabItemWidget extends StatelessWidget {
  final List<Json> j;

  const TabItemWidget({Key key, this.j}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Column(children: [
      for(Json j in j)
      Row(
        children: [
          Expanded(child: Text('${j.name}: ')),
          if(j.tabX != null) Expanded(child: Text(j.tabX.reduce((value, element) => '$value - $element'))),
          if(j.tabY != null) Expanded(child: Text(j.tabY.reduce((value, element) => '$value - $element')))
        ],
      )
    ],);
  }
}


You can filter the list before passing in:

// Only when tabX != null
_json.where((element) => element.tabX != null).toList()

// Only when tabY != null
_json.where((element) => element.tabY != null).toList()

To display only the appropriate value for that tab, we can use an enum and pass it in. It's always a good idea to use enum when we have more than 2 modes of display

enum DisplayMode { all, onlyX, onlyY }

The TabItemWidget would now be:

class TabItemWidget extends StatelessWidget {
  final List<Json> j;
  final DisplayMode mode;

  const TabItemWidget({Key key, this.j, this.mode = DisplayMode.all})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        for (Json j in j)
          Row(
            children: [
              Expanded(child: Text('${j.name}: ')),
              if (j.tabX != null && !(mode == DisplayMode.onlyY))
                Expanded(
                    child: Text(j.tabX
                        .reduce((value, element) => '$value - $element'))),
              if (j.tabY != null && !(mode == DisplayMode.onlyX))
                Expanded(
                    child: Text(
                        j.tabY.reduce((value, element) => '$value - $element')))
            ],
          )
      ],
    );
  }
}

The TabBarView would now be:

body: TabBarView(
    children: [
      Tab(
        child: TabItemWidget(
          j: _json,
        ),
      ),
      Tab(
        child: TabItemWidget(
          j: _json.where((element) => element.tabX != null).toList(),
          mode: DisplayMode.onlyX,
        ),
      ),
      // pls help
      Tab(
        child: TabItemWidget(
          j: _json.where((element) => element.tabY != null).toList(),
          mode: DisplayMode.onlyY,
        ),
      ),
      // pls help
    ],
  )

Result:
在此处输入图像描述

This code is not beautiful but it works (null safety):

import 'package:flutter/material.dart';
import 'dart:convert';

 List<Json> jsonFromJson(String str) => List<Json>.from(json.decode(str).map((x) =>                
 Json.fromJson(x)));

 String jsonToJson(List<Json> data) => json.encode(List<dynamic>.from(data.map((x) => 
 x.toJson())));

 class Json {
   Json({
     this.name,
     this.tabX,
     this.tabY,
   });

   String? name;
   List<String>? tabX;
   List<String>? tabY;

   factory Json.fromJson(Map<String, dynamic> json) => Json(
     name: json["name"] == null ? null : json["name"],
    tabX: json["tabX"] == null ? null : List<String>.from(json["tabX"].map((x) => 
     x)),
    tabY: json["tabY"] == null ? null : List<String>.from(json["tabY"].map((x) => x)),
   );

   Map<String, dynamic> toJson() => {
    "name": name == null ? null : name,
    "tabX": (tabX == null)? null : List<dynamic>.from(tabX!.map((x) => x)),
    "tabY": (tabY == null) ? null : List<dynamic>.from(tabY!.map((x) => x)),
  };
}

class JsonServices {
  static Future<List<Json>> getData() {
    String jsonString = '''
[
  {
    "name": "A",
    "tabX": ["AX1","AX2"],
    "tabY": null
  },
  {
    "name": "B",
   "tabX": null,
    "tabY": ["BY1","BY2"]
  },
  {
    "name": "C",
    "tabX": ["CX1","CX2"],
    "tabY": ["CY1","CY2"]
  }
]
    ''';

    return Future.value(jsonFromJson(jsonString));
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  List<Json> _json = [];
  @override
  void initState() {
    super.initState();
    setState(() {
      JsonServices.getData().then((data) {
        setState(() {
          _json = data;
        });
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DefaultTabController(
        length: 3,
        child: Scaffold(
          appBar: AppBar(
            bottom: TabBar(
              tabs: [
                Tab(text: 'ALL'),
                Tab(text: 'TabX'),
                Tab(text: 'TabY'),
              ],
            ),
          ),
          body: TabBarView(children: [
            Tab(child: TabItemWidget(j: _json,),),
            Tab(child: TabItemWidget2(j: _json,),), // pls help
            Tab(child: TabItemWidget3(j: _json,),), // pls help
          ],),
        ),
      ),
    );
  }
}

class TabItemWidget extends StatelessWidget {
  final List<Json> j;


  TabItemWidget({Key? key, required this.j}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(children: [
      for(Json j in j)
        Row(
          children: [
            Expanded(child: Text('${j.name}: ')),
            if(j.tabX != null) Expanded(child: Text(j.tabX!.reduce((value, element) => 
 '$value - $element'))),
            if(j.tabY != null) Expanded(child: Text(j.tabY!.reduce((value, element) => 
'$value - $element')))
          ],
        )
    ],);
  }
}
class TabItemWidget2 extends StatelessWidget {
  final List<Json> j;

  const TabItemWidget2({Key? key, required this.j}) : super(key: key);
  @override
  Widget build(BuildContext context) {

    print(j.where((element) => element.tabX != null).toString());
    var jForTabX = j.where((element) => element.tabX != null);

    return Column(children: [
      for(Json j in jForTabX)
        Row(
          children: [
            Expanded(child: Text('${j.name}: ')),
            if(j.tabX != null && j.tabY == null) Expanded(child: 
Text(j.tabX!.reduce((value, element) => '$value - $element'))),
            if(j.tabY != null) Expanded(child: Text(j.tabX!.reduce((value, element) => 
'$value - $element')))
          ],
        )
    ],);
  }
}

class TabItemWidget3 extends StatelessWidget {
  final List<Json> j;

  const TabItemWidget3({Key? key, required this.j}) : super(key: key);
  @override
  Widget build(BuildContext context) {

    var jForTabY = j.where((element) => element.tabY != null);

    return Column(children: [
      for(Json j in jForTabY)
        Row(
          children: [
            Expanded(child: Text('${j.name}: ')),
            if(j.tabX != null && j.tabX == null) Expanded(child: 
 Text(j.tabX!.reduce((value, element) => '$value - $element'))),
           if(j.tabY != null) Expanded(child: Text(j.tabY!.reduce((value, element) => 
 '$value - $element')))
          ],
        )
    ],);
  }
}

You can improve que quality of this code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM