Home > Mobile >  Adjust TabBar Items to fill entire screen width but have different proportions?
Adjust TabBar Items to fill entire screen width but have different proportions?

Time:07-24

I'm trying to get into Flutter development, and I've been following along some tutorials that matched an app I'm trying to make. Now, I'm mainly a web developer, so I thought this would be as easy a task as it is with CSS, but for some reason a very simple task I'm trying to achieve has proven to be more of a challenge than I hoped to.

I have an AppBar item, appended with a TabBar item, with two text items in it, them being "Chats" and "Me". As the names imply, the Chats tab will hold the chat window, and the Me tab will hold quick options relative to the current user, and as such, I'd like for the Chats window to take precedent, making it also a bigger item. I've tried setting the TabBar to Scrollable, but all it does is set the tab items to their content's width and center it. I can then adjust their width, but the size loses it's responsiveness.

Is there any way to make an item occupy, say, 90% of the TabBar and another 10%? Below is a few snippets to illustrate what I'm talking about. Top one is what I currently have working, bottom one is my desired proportions.

TabBar as I currently have it working

TabBar as I wish for it to be

And if the window's width changes, the width of the items adjusts to keep the proportions intact

And here is the code I have in Flutter

return Scaffold(
  appBar: AppBar(
    backgroundColor: Theme.of(context).primaryColor,
    title: const Text("AppName"),
    elevation: 0.7,
    bottom: TabBar(
        controller: _tabController,
        indicatorColor: Theme.of(context).accentColor,
        tabs: [
          Container(
              padding: EdgeInsets.symmetric(horizontal: 80.0),
              child: Tab(text: "Chats")),
          Container(child: Tab(text: "Me")),
        ]),
  ),
);

CodePudding user response:

I am using PreferredSize bottom. For animation you can choose other widget too, for now you can test it with AnimatedSize instead of AnimatedContainer because it will overlap some color transaction,

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
  late final TabController _tabController;

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text("AppName"),
          bottom: PreferredSize(
            preferredSize:
                Size(MediaQuery.of(context).size.width, kToolbarHeight),
            child: Container(
                child: Row(
              children: [
                GestureDetector(
                  onTap: () {
                    _tabController.animateTo(0);
                    setState(() {});
                  },
                  child: AnimatedSize(
                    key: const ValueKey("animatedTan 0"),
                    duration: Duration(milliseconds: 333),
                    child: Container(
                      alignment: Alignment.center,
                      height: kToolbarHeight,
                      color: _tabController.index == 0
                          ? Colors.purple
                          : Colors.transparent,
                      width: MediaQuery.of(context).size.width *
                          (_tabController.index == 0 ? .9 : .1),
                      child: Text("Chats"),
                    ),
                  ),
                ),
                GestureDetector(
                  onTap: () {
                    _tabController.animateTo(1);
                    setState(() {});
                  },
                  child: AnimatedSize(
                      key: const ValueKey("animatedTan 1"),
                      duration: Duration(milliseconds: 333),
                      child: Container(
                          alignment: Alignment.center,
                          height: kToolbarHeight,
                          color: _tabController.index == 1
                              ? Colors.purple
                              : Colors.transparent,
                          width: MediaQuery.of(context).size.width *
                              (_tabController.index == 1 ? .9 : .1),
                          child: Text("Me"))),
                )
              ],
            )),
          ),
        ),
        body: LayoutBuilder(
          builder: (context, constraints) {
            return Text(" ${_tabController.index}");
          },
        ));
  }
}

enter image description here

CodePudding user response:

just set the attribute isScrollable to true, and set labelPadding in horizontal axis to 0:

    @override
  Widget build(BuildContext context) {
    final double width = MediaQuery.of(context).size.width;
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).primaryColor,
        title: const Text("AppName"),
        elevation: 0.7,
        bottom: TabBar(
            controller: _tabController,
            indicatorColor: Theme.of(context).colorScheme.secondary,
            labelPadding: const EdgeInsets.symmetric(horizontal: 0),
            isScrollable: true,
            tabs: [
              Container(
                  width: width * 0.85,
                  color: Colors.orange,
                  // padding: const EdgeInsets.symmetric(horizontal: 80.0),
                  child: const Tab(text: "Chats")),
              Container(
                  width: width * 0.15,
                  color: Colors.red,
                  child: const Tab(text: "Me")),
            ]),
      ),
    );
  }

enter image description here

  • Related