【Flutter】タブをページの途中で使う方法

file

タブを上じゃなくてページの途中で使いたくて書きました。

呼び出し側はこんな感じ
InnerTabController(
  initailIndex: 0,
  tebSpaceFlex: 3,
  freeSpaceFlex: 2,
  tabs: [
    Tab(child: Text('title1')),
    Tab(child: Text('title2')),
  ],
  bodys: [Text('test3'), Text('test2')],
),

いろいろ書きましたが、ちょっと変なことしてます。

TabControllerを使うときにTabBarViewで高さを指定する必要があったので、
一度描画してサイズを取得してそのあとに
サイズを指定して、TabBarViewを表示するということをしてます。

実装
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';

class InnerTabController extends StatefulWidget {
  final int initailIndex;
  final List<Widget> tabs;
  final List<Widget> bodys;
  final int tebSpaceFlex; // タブを左寄せする場合の割合幅
  final int freeSpaceFlex; // タブを左寄せする場合の右側の割合幅
  const InnerTabController({
    Key? key,
    required this.initailIndex,
    required this.tabs,
    required this.bodys,
    this.tebSpaceFlex = 1,
    this.freeSpaceFlex = 0,
  }) : super(key: key);

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

class InnerTabControllerState extends State<InnerTabController>
    with SingleTickerProviderStateMixin {
  List<GlobalKey> keys = [];
  List<double?> bodyHeights = [];
  late TabController tabController;
  @override
  void initState() {
    tabController = TabController(
        vsync: this,
        length: widget.tabs.length,
        initialIndex: widget.initailIndex);

    for (int i = 0; i < widget.tabs.length; i++) {
      bodyHeights.add(null);
      keys.add(GlobalKey());
    }
    SchedulerBinding.instance.addPostFrameCallback((_) {
      setState(() {
        for (int i = 0; i < widget.tabs.length; i++) {
          bodyHeights[i] = keys[i].currentContext?.size?.height;
        }
      });
    });
    super.initState();
  }

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

  @override
  Widget build(BuildContext context) {
    if (widget.tabs.length != widget.bodys.length) {
      throw Exception('tabsとbodysとbodySizesの配列の数を同じにして下さい。');
    }
    return Column(
      children: [
        Row(
          children: [
            Flexible(
              flex: widget.tebSpaceFlex,
              child: TabBar(
                controller: tabController,
                tabs: widget.tabs,
                indicatorColor: kDefColor,
                indicatorSize: TabBarIndicatorSize.label,
              ),
            ),
            Flexible(
              flex: widget.freeSpaceFlex,
              child: const SizedBox(),
            ),
          ],
        ),
        const Divider(height: 0),
        if (bodyHeights[tabController.index] == null)
          Container(
            key: keys[tabController.index],
            alignment: Alignment.centerLeft,
            child: widget.bodys[tabController.index],
          )
        else
          SizedBox(
            height: bodyHeights[tabController.index],
            child: TabBarView(
              controller: tabController,
              children: widget.bodys,
            ),
          ),
      ],
    );
  }
}

NestedScrollViewheaderSliverBuilderとかに
SliverToBoxAdapterを使う方法もある。


Flutter開発で知らないと損すること Flutter開発で知らないと損すること

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です