How to create flutter TabBar with a list and pass data to change tabView

957 Views Asked by At

I need to replace this list tiles and the navigation page with TabBar and Tab view.

Currently I am using a list to create this vertical scrolling CategoryTile to navigate to category page

CategoryTile UI


List<CategoryModel> getCategories(){
  List<CategoryModel> category = <CategoryModel>[];
  CategoryModel categoryModel = new CategoryModel();

  categoryModel.categoryName = "Business";
  category.add(categoryModel);
  categoryModel = new CategoryModel();

  categoryModel.categoryName = "Entertainment";
  category.add(categoryModel);
  categoryModel = new CategoryModel();

  categoryModel.categoryName = "General"; buils
  category.add(categoryModel);
  categoryModel = new CategoryModel();

  categoryModel.categoryName = "Health";
  category.add(categoryModel);
  categoryModel = new CategoryModel();

  categoryModel.categoryName = "Science";
  category.add(categoryModel);
  categoryModel = new CategoryModel();

  categoryModel.categoryName = "Sports";
  category.add(categoryModel);
  categoryModel = new CategoryModel();

  categoryModel.categoryName = "Technology";
  category.add(categoryModel);
  categoryModel = new CategoryModel();

  return category;
}

CategoryTile widget:

class CategoryTile extends StatelessWidget {
  final categoryName;
  CategoryTile({this.categoryName});

  @override
  Widget build(BuildContext context) {
    final vm = Provider.of<NewsArticleListViewModel>(context);
    return GestureDetector(
      onTap: () {
        vm.Category(categoryName.toLowerCase());
        print('tap');
        // Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryNews(category: categoryName.toLowerCase(),
        // )
        // ));
      },
      child: Container(
        alignment: Alignment.center,
        width: 120,
        height: 60,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(6),
          color: Colors.black26,
        ),
        child: Text(categoryName,
            style: TextStyle(
                color: Colors.white,
                fontSize: 14,
                fontWeight: FontWeight.w500)),
      ),
    );
  }
}

When I tap each tile it will pass the category name and open this category page which will change the content according to the tile I select.

Container(
  margin: const EdgeInsets.only(top: 16),
  child: ListView.builder(
      itemCount: articles.length,
      shrinkWrap: true,
      physics: ClampingScrollPhysics(),
      itemBuilder: (context, index) {
        return BlogTileList(
          imageUrl: articles[index].urlToImage ?? '',
          title: articles[index].title ?? '',
          desc: articles[index].description ?? '',
          url: articles[index].url ?? '',
        );
      }),
)

class BlogTileList extends StatelessWidget {
  final String imageUrl, title, desc, url;
  BlogTileList(
      {required this.imageUrl,
        required this.title,
        required this.desc,
        required this.url});

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        Navigator.push(
            context,
            MaterialPageRoute(
                builder: (context) => ArticleView(
                  blogUrl: url,
                )));
      },
      child: Padding(
        padding: const EdgeInsets.symmetric(vertical: 6.0),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Expanded(
              flex: 2,
              child: ClipRRect(
                child: Container(
                  padding: EdgeInsets.only(right: 10),
                  child: Image.network(
                    imageUrl ?? '',
                    width: 100,
                    height: 90,
                    fit: BoxFit.cover,
                  ),
                ),
              ),
            ),
            Expanded(
              flex: 3,
              child: Padding(
                padding: const EdgeInsets.fromLTRB(5.0, 0.0, 5.0, 0.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: <Widget>[
                    Text(title,
                        style: const TextStyle(
                            fontSize: 14, fontWeight: FontWeight.w500),
                        maxLines: 3),
                    const Padding(padding: EdgeInsets.symmetric(vertical: 2.0)),
                    Text(desc, style: TextStyle(fontSize: 12), maxLines: 2),
                  ],
                ),
              ),
            ),
            // const Icon(
            //   Icons.more_vert,
            //   size: 16.0,
            // ),
          ],
        ),
      ),
    );
  }
}

How to replace the category tile with TabBar and BlogTiles with TabView.

I know its possible to create multiple pages and bind them to each tabView but It should pass the category name by selecting a tab and change the tabView with that.

1

There are 1 best solutions below

0
On

You can use bottom TabBar of AppBar and don't forget to set scrollable property to true.

class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({super.key});

  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget>
    with TickerProviderStateMixin {
  late TabController _tabController;
  static const List<String> categories = [
    'Business',
    'Entertainment',
    'General',
    'Health',
    'Science',
    'Sports',
    'Technology'
  ];

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: categories.length, vsync: this);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('TabBar Widget'),
        bottom: TabBar(
            isScrollable: true,
            controller: _tabController,
            tabs: categories.map((e) => Text(e)).toList()),
      ),
      body: TabBarView(
        controller: _tabController,
        children: categories
            .map((e) => CategoryTabView(
                  name: e,
                ))
            .toList(),
      ),
    );
  }
}

class CategoryTabView extends StatelessWidget {
  const CategoryTabView({super.key});

final List<Article> articles;
//final other params
//final more params

 
 


  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.only(top: 16),
      child: ListView.builder(
          itemCount: articles.length,
          shrinkWrap: true,
          physics: const ClampingScrollPhysics(),
          itemBuilder: (context, index) {
            return BlogTileList(
                imageUrl: articles[index].urlToImage ?? '',
                title: articles[index].title ?? '',
                desc: articles[index].description ?? '',
                url: articles[index].url ?? '',
            );
          }),
    );
  }
}