具有动态高度和填充的 TabBarView

问题描述

enter image description here

我有 3 个具有动态 gridview 的选项卡,但我的问题是,当我在物理设备上测试它时,其中一个 gridview 的末端看起来完整,但在另一个较小的设备 (720 x 1280) 中gridview的最后一行文字不可见,所以我的想法是在底部添加一个填充,但当然,在小设备上它看起来不错

enter image description here

并将此填充添加到 GridView.Builder...:

padding: EdgeInsets.only(right: 20.0,left: 20.0,bottom: 100),

enter image description here

但在其他更高分辨率的设备中,这使得底部的填充看起来不一样,这里的填充更大"

enter image description here

如何进行这种动态填充,使其相同并且网格视图在所有设备上都完全可见?

另外,我想补充一点,我的 TabBarViews 在一个 500 高度的容器内,我不知道这是否有问题,因为我觉得它是静态的,我不喜欢任何东西,我想要容器只从头开始(在选项卡下方)直到屏幕结束,我也不知道该怎么做。

另外,我看到测试总是指出安全区域和脚手架下的列有“hasSize”问题,我在尝试修复它时总是遇到许多高度异常,在 shop_scree_page.dart 中,我不不太了解设计,也许我把事情搞错了。

shop_scree_page.dart

import 'package:Flutter/material.dart';
import 'package:Flutter/services.dart';
import 'package:plantsapp/screens/all_tab.dart';
import 'package:plantsapp/screens/indoor_page.dart';
import 'package:plantsapp/screens/outdoor_tab.dart';
import 'package:plantsapp/screens/top_tab.dart';
import 'package:plantsapp/services/authentication_service.dart';

class ShopScreen extends StatefulWidget {
  @override
  _ShopScreenState createState() => _ShopScreenState();
}

class _ShopScreenState extends State<ShopScreen>
    with SingleTickerProviderStateMixin {
  TabController _tabController;
  PageController _pageController;
  GlobalKey<ScaffoldState> _drawerKey = GlobalKey();

  @override
  void initState() {
    super.initState();
    _tabController = TabController(initialIndex: 0,length: 4,vsync: this);
    _pageController = PageController(initialPage: 0,viewportFraction: 0.8);
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    List<Widget> containers = [
      new TopTab(),new OutdoorTab(),new IndoorTab(),new AllTab(),];

    AuthenticationService authServ = new AuthenticationService();
    return Scaffold(
      key: _drawerKey,drawer: new Drawer(),floatingActionButton: FloatingActionButton(
        child: Icon(Icons.logout),backgroundColor: Colors.black,onpressed: () {
          //context.read<AuthenticationService>()
          authServ.signOut();
        },),drawerEnableOpenDragGesture: false,body: SafeArea(
        child: Column(
          children: <Widget>[
            //ICONOS MENU Y CART
            Container(
              margin: EdgeInsets.only(top: 20),child: Padding(
                padding: EdgeInsets.symmetric(horizontal: 30.0),child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[
                    IconButton(
                      icon: Icon(Icons.menu,size: 30.0,color: Colors.grey),onpressed: (() => _drawerKey.currentState.openDrawer()),Spacer(),IconButton(
                        icon: Icon(Icons.add),color: Colors.black,iconSize: 32,onpressed: () {
                          Navigator.pushNamed(context,'createplantpost');
                        }),IconButton(
                        icon: Icon(Icons.shopping_cart),onpressed: () {}),],SizedBox(height: 20.0),//TITULO "TOP PICKS"
            Expanded(
              child: Container(
                width: double.infinity,child: SingleChildScrollView(
                  child: Column(
                    children: [
                      Container(
                        alignment: Alignment.centerLeft,child: Padding(
                          padding: EdgeInsets.only(left: 20.0),child: Text(
                            'Top Picks',style: TextStyle(
                                fontSize: 24.0,fontWeight: FontWeight.w600),_tabs(),_tabsView(containers),);
  }

 Widget _tabs() {
    return TabBar(
      controller: _tabController,indicatorColor: Colors.transparent,labelColor: Colors.black,unselectedLabelColor: Colors.grey.withOpacity(0.6),labelPadding: EdgeInsets.symmetric(horizontal: 35.0),isScrollable: true,tabs: <Widget>[
        Tab(
            child: Text('Top',style: TextStyle(
                  fontSize: 16.0,fontWeight: FontWeight.w600,))),Tab(
            child: Text('Outdoor',Tab(
            child: Text('Indoor',Tab(
            child: Text('All',);
  }

  Widget _tabsView(containers) {
    final size = MediaQuery.of(context).size;
    return  Container(
      height: 500,child: TabBarView(
            physics: NeverScrollableScrollPhysics(),controller: _tabController,children: containers
      ),);
  }
}

outdoor_tab.dart

import 'package:Flutter/material.dart';
import 'package:plantsapp/models/plant_model.dart';
import 'package:plantsapp/providers/products_provider.dart';
import 'package:plantsapp/screens/plant_screen.dart';
import 'package:plantsapp/widgets/snapshots_alerts.dart';

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

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

class _OutdoorTabState extends State<OutdoorTab> {
  @override
  Widget build(BuildContext context) {
    ProductsProvider productsProvider = new ProductsProvider();

    return Scaffold(
      body: streamBuilderCards(productsProvider),);
  }

  Widget streamBuilderCards(ProductsProvider productsProvider) {
    final size = MediaQuery.of(context).size;
    return StreamBuilder(
      stream: productsProvider.getPostOutdoor(context),builder:
          (BuildContext context,AsyncSnapshot<List<PlantModel>> snapshot) {
        if (snapshot.hasError) {
          return snapshotMsgError(snapshot);
        }
        if (!snapshot.hasData) {
          return snapshotCircularProgressIndicator();
        }
        List<PlantModel> posts = snapshot.data;

        return GridView.builder(
          padding: EdgeInsets.only(
              right: 20.0,itemCount: posts.length,gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 2,mainAxisspacing: 20,crossAxisspacing: 20,childAspectRatio: 0.60),itemBuilder: (context,index) => ItemCard(plants: posts[index]),);
      },);
  }
}

class ItemCard extends StatelessWidget {
  final PlantModel plants;
  final Function press;

  const ItemCard({
    Key key,this.press,this.plants,}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        Navigator.push(
          context,MaterialPageRoute(
            builder: (_) => PlantScreen(plant: plants),child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,children: [
          Container(
              height: 198,width: 175,decoration: Boxdecoration(
                  //color: Colors.blueAccent,borderRadius: BorderRadius.circular(16)),child: Hero(
                tag: plants.imageUrl,child: ClipRRect(
                  borderRadius: BorderRadius.circular(16),child: (plants.imageUrl == null)
                      ? Image(
                          image: Assetimage('assets/images/no-image.png'),fit: BoxFit.cover)
                      : FadeInImage(
                          image: NetworkImage(plants.imageUrl),placeholder:
                              Assetimage('assets/images/image-loading.gif'),fit: BoxFit.cover,/*Image(
                  image: NetworkImage(plants.imageUrl),)*/
                ),) //Image.asset(plants.imageUrl),Padding(
            padding: const EdgeInsets.symmetric(vertical: 4.0),child: Text(
              plants.name,style: TextStyle(color: Colors.grey),overflow: TextOverflow.ellipsis,Text(
            '\$${plants.price}',style: TextStyle(fontWeight: FontWeight.bold),)
        ],);
  }
}

解决方法

您可以通过屏幕尺寸动态填充来实现这一点。对于经验:

var screenHeight = MediaQuery.of(context).size.height;
var screenWidth = MediaQuery.of(context).size.width;

padding: EdgeInsets.only(right: screenWidth * 0.2,left: screenWidth * 0.2,bottom: screenHeight * 0.15)