Search code examples
flutterexpansion-tile

Can someone show me what i am missing in my code? I am trying to display sub-category as a dropdown in category screen in flutter using extension tile


can someone help me figure out what i'm doing wrong? I have a category screen and I have a list-view of all my parent categories on the left and my main categories filling the remaining space as a drop-down widget to display the sub-categories but the expansion tile is not opening. Below is the code of my category screen

`

import 'package:buyfast/Widget/category/main_category_widget.dart';
import 'package:buyfast/models/category_model.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:firebase_ui_firestore/firebase_ui_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_iconly/flutter_iconly.dart';


class CategoryScreen extends StatefulWidget {
  const CategoryScreen({Key? key}) : super(key: key);

  @override
  State<CategoryScreen> createState() => _CategoryScreenState();
}

class _CategoryScreenState extends State<CategoryScreen> {
  String _title = 'Categories';
  String? selectedCategory;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        title: Text(
          selectedCategory==null ? _title : selectedCategory!,
          style: const TextStyle(color: Colors.black,fontSize: 16),),
        elevation: 0,
        backgroundColor: Colors.white,
        iconTheme: const IconThemeData(
          color: Colors.black54
        ),
        actions: [
          IconButton(
              onPressed: (){},
              icon: const Icon(IconlyLight.search),
          ),
          IconButton(
              onPressed: (){},
              icon: const Icon(IconlyLight.buy),
          ),
          IconButton(
              onPressed: (){},
              icon: const Icon(Icons.more_vert),
          ),
        ],
      ),
      body: Row(
        children: [
          Container(
            width: 80,
            color: Colors.grey.shade300,
            child: FirestoreListView<Category>(
              query: categoryCollection,
              itemBuilder: (context, snapshot) {
                Category category = snapshot.data();
                return InkWell(
                  onTap: (){
                    setState(() {
                      _title= category.catName!;
                      selectedCategory = category.catName;
                    });
                  },
                  child: Container(
                    height: 70,
                    color: selectedCategory == category.catName ? Colors.white : Colors.grey.shade300,
                    child: Center(
                      child: Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Column(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            SizedBox(
                              height: 30,
                              child: CachedNetworkImage(
                                  imageUrl: category.image!,
                                  color: selectedCategory == category.catName ? Theme.of(context).primaryColor:Colors.grey.shade700,
                              ),
                            ),
                            Text(
                              category.catName!,
                              style: TextStyle(
                                  fontSize: 10,
                                color: selectedCategory == category.catName ? Theme.of(context).primaryColor:Colors.grey.shade700,
                              ),
                              textAlign: TextAlign.center,
                            ),
                          ],
                        ),
                      ),
                    ),
                  ),
                );
              },
            ),
          ),
          MainCategoryWidget(
            selectedCat: selectedCategory,
          )
        ],
      ),
    );
  }
}

Now my category model to retrieve the categories from Firebase

import 'package:buyfast/firebase_service.dart';

class Category {

  Category({this.catName, this.image});
  Category.fromJson(Map<String, Object?> json)
      : this(
    catName: json['catName']! as String,
    image: json['image']! as String,
  );

  final String? catName;
  final String? image;

  Map<String, Object?> toJson() {
    return {
      'catName': catName,
      'image': image,
    };
  }


}
FirebaseService _service = FirebaseService();
final categoryCollection = _service.categories.where('active',isEqualTo: true).withConverter<Category>(
  fromFirestore: (snapshot, _) => Category.fromJson(snapshot.data()!),
  toFirestore: (category, _) => category.toJson(),
);


My category widget

import 'package:buyfast/models/category_model.dart';
import 'package:firebase_ui_firestore/firebase_ui_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_iconly/flutter_iconly.dart';

class CategoryWidget extends StatefulWidget {
  const CategoryWidget({Key? key}) : super(key: key);

  @override
  State<CategoryWidget> createState() => _CategoryWidgetState();
}

class _CategoryWidgetState extends State<CategoryWidget> {

  String? _selectedCategory;


  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: Column(
        children: [
          const SizedBox(height: 18,),
          const Padding(
            padding: EdgeInsets.all(8.0),
            child: Align(
              alignment: Alignment.centerLeft,
              child: Text(
                'Stores For You',
                style: TextStyle(
                    fontWeight: FontWeight.bold,
                    letterSpacing: 1,
                    fontSize: 20
                ),
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.fromLTRB(8,0,8,8),
            child: SizedBox(
              height: 40,
              child: Row(
                children: [
                  Expanded(
                    child:FirestoreListView<Category>(
                      scrollDirection: Axis.horizontal,
                      query: categoryCollection,
                      itemBuilder: (context, snapshot) {
                        Category category = snapshot.data();
                        return Padding(
                          padding: const EdgeInsets.only(right: 4),
                          child: ActionChip(
                            padding: EdgeInsets.zero,
                            shape: RoundedRectangleBorder(
                                borderRadius: BorderRadius.circular(2)
                            ),
                            backgroundColor: _selectedCategory  == category.catName ? Colors.blue.shade900 : Colors.grey,
                            label: Text(
                              category.catName!,
                              style: TextStyle(
                                fontSize: 12,
                                color: _selectedCategory==category.catName ? Colors.white : Colors.black
                            ),
                            ),
                            onPressed: () {
                              setState(() {
                                _selectedCategory = category.catName;
                              });
                            },
                          ),
                        );
                      },
                    ),
                  ),
                  Container(
                    decoration: BoxDecoration(
                      border: Border(left: BorderSide(color: Colors.grey.shade400),)
                    ),
                    child: IconButton(
                      onPressed: (){

                      },
                      icon: const Icon(IconlyLight.arrowDown),
                    ),
                  )
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

main category widget

import 'package:buyfast/Widget/category/sub_category_widget.dart';
import 'package:buyfast/models/main_category_model.dart';
import 'package:firebase_ui_firestore/firebase_ui_firestore.dart';
import 'package:flutter/material.dart';

class MainCategoryWidget extends StatefulWidget {
  final String? selectedCat;
  const MainCategoryWidget({this.selectedCat,Key? key}) : super(key: key);

  @override
  State<MainCategoryWidget> createState() => _MainCategoryWidgetState();
}

class _MainCategoryWidgetState extends State<MainCategoryWidget> {
  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: FirestoreListView<MainCategory>(
        query: mainCategoryCollection(widget.selectedCat),
        itemBuilder: (context, snapshot) {
          MainCategory mainCategory = snapshot.data();
          return ExpansionTile(
            title: Text(mainCategory.mainCategory!),
            children: [
              SubCategoryWidget(
                selectedSubCat: mainCategory.mainCategory,
              )
            ],
          );
        },
      ),
    );
  }
}

main category model

import 'package:buyfast/firebase_service.dart';

class MainCategory {

  MainCategory({this.category, this.mainCategory});
  MainCategory.fromJson(Map<String, Object?> json)
      : this(
    category: json['category']! as String,
    mainCategory: json['mainCategory']! as String,
  );

  final String? category;
  final String? mainCategory;

  Map<String, Object?> toJson() {
    return {
      'category': category,
      'mainCategory': mainCategory,
    };
  }


}
FirebaseService _service = FirebaseService();
mainCategoryCollection (selectedCat){
  return _service.mainCategories.where('approved',isEqualTo: true).where('category', isEqualTo: selectedCat).withConverter<MainCategory>(
      fromFirestore: (snapshot, _) => MainCategory.fromJson(snapshot.data()!),
  toFirestore: (category, _) => category.toJson(),);
}

`

Subcategory model `

import 'package:buyfast/firebase_service.dart';

class SubCategory {

  SubCategory({this.mainCategory, this.subCatName, this.image});
  SubCategory.fromJson(Map<String, Object?> json)
      : this(
    mainCategory: json['mainCategory']! as String,
    subCatName: json['subCatName']! as String,
    image: json['image']! as String,
  );

  final String? mainCategory;
  final String? subCatName;
  final String? image;

  Map<String, Object?> toJson() {
    return {
      'mainCategory': mainCategory,
      'subCatName': subCatName,
      'image': image,
    };
  }


}
FirebaseService _service = FirebaseService();
subCategoryCollection({selectedSubCat}){
  return _service.subCategories.where('active',isEqualTo: true).where('mainCategory',isEqualTo: selectedSubCat).withConverter<SubCategory>(
      fromFirestore: (snapshot, _) => SubCategory.fromJson(snapshot.data()!),
  toFirestore: (category, _) => category.toJson(),
  );
}



` Subcategory widget

`

import 'package:buyfast/models/sub_category_model.dart';
import 'package:firebase_ui_firestore/firebase_ui_firestore.dart';
import 'package:flutter/material.dart';

class SubCategoryWidget extends StatelessWidget {
  final String? selectedSubCat;
  const SubCategoryWidget({this.selectedSubCat,Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: FirestoreQueryBuilder<SubCategory>(
        query: subCategoryCollection(
          selectedSubCat: selectedSubCat
        ),
        builder: (context, snapshot, _) {
          if (snapshot.isFetching) {
            return const Center(child: CircularProgressIndicator());
          }
          if (snapshot.hasError) {
            return Text('Something went wrong! ${snapshot.error}');
          }
          return GridView.builder(
            shrinkWrap: true,
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 3,
              childAspectRatio: snapshot.docs.length == 0 ? 1/.1 : 1/1.1,
            ),
            itemCount: snapshot.docs.length,
            itemBuilder: (context, index) {

              SubCategory subCat = snapshot.docs[index].data();
              return InkWell(
                onTap: (){
                  //move to product screen
                },
                child: Column(
                  children: [
                    SizedBox(
                      height: 60,
                      width: 60,
                      child: FittedBox(
                        fit: BoxFit.contain,
                          child: Image.network(subCat.image!)),
                    ),
                    Text(subCat.subCatName!,style: const TextStyle(fontSize: 12),
                     textAlign: TextAlign.center,
                    ),
                  ],
                ),
              );
            },
          );
        },
      ),
    );
  }
}

`


Solution

  • I solved it by wrapping the Expanded widget in the sub_category_widget.dart file with a SizeBox and give it a height of 100. Like below.

       import 'package:buyfast/models/sub_category_model.dart';
    import 'package:firebase_ui_firestore/firebase_ui_firestore.dart';
    import 'package:flutter/material.dart';
    
    class SubCategoryWidget extends StatelessWidget {
      final String? selectedSubCat;
      const SubCategoryWidget({this.selectedSubCat,Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return SizeBox(height: 100,
         Expanded(
          child: FirestoreQueryBuilder<SubCategory>(
            query: subCategoryCollection(
              selectedSubCat: selectedSubCat
            ),
            builder: (context, snapshot, _) {
              if (snapshot.isFetching) {
                return const Center(child: CircularProgressIndicator());
              }
              if (snapshot.hasError) {
                return Text('Something went wrong! ${snapshot.error}');
              }
              return GridView.builder(
                shrinkWrap: true,
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 3,
                  childAspectRatio: snapshot.docs.length == 0 ? 1/.1 : 1/1.1,
                ),
                itemCount: snapshot.docs.length,
                itemBuilder: (context, index) {
    
                  SubCategory subCat = snapshot.docs[index].data();
                  return InkWell(
                    onTap: (){
                      //move to product screen
                    },
                    child: Column(
                      children: [
                        SizedBox(
                          height: 60,
                          width: 60,
                          child: FittedBox(
                            fit: BoxFit.contain,
                              child: Image.network(subCat.image!)),
                        ),
                        Text(subCat.subCatName!,style: const TextStyle(fontSize: 12),
                         textAlign: TextAlign.center,
                        ),
                      ],
                    ),
                  );
                },
              );
            },
          ),
         ),
        );
      }
    }