Never give up

Flutter - PageView with TabBar and Indicator 본문

Flutter

Flutter - PageView with TabBar and Indicator

대기만성 개발자 2021. 1. 3. 17:26
반응형

Pageview를 활용할 방법은 여러가지가 있습니다

 

그 중 tabbar를 이용해서 pageview의 page와 tabbar의 tab을 일치시키는 예제

 

그리고 indicator로 페이지를 표시해 주는 예제를 다뤄보겠습니다

 

tabbar예제

class _PageViewExampleState extends State<PageViewExample>
    with SingleTickerProviderStateMixin {
  int _page = 0;
  PageController _pController;
  TabController _tController;

  @override
  void initState() {
    super.initState();
    _pController = PageController();
    _tController = TabController(length: 3, vsync: this);
  }

  @override
  void dispose() {
    _pController?.dispose();
    _tController?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('PageView example'),
        bottom: TabBar(
          controller: _tController,
          onTap: (value) {
            _page = value;
            _pController.animateToPage(_page,
                duration: Duration(milliseconds: 300), curve: Curves.ease);
          },
          tabs: [
            Tab(icon: Icon(Icons.looks_one_rounded)),
            Tab(icon: Icon(Icons.looks_two_rounded)),
            Tab(icon: Icon(Icons.looks_3_rounded)),
          ],
        ),
      ),
      body: PageView(
        controller: _pController,
        scrollDirection: Axis.vertical,
        onPageChanged: (value) {
          _page = value;
          _tController.animateTo(_page,
              duration: Duration(milliseconds: 300), curve: Curves.ease);
        },
        children: [
          _container(1, Colors.red),
          _container(2, Colors.green),
          _container(3, Colors.blue),
        ],
      ),
    );
  }

  Container _container(int page, Color color){
    return Container(
        color: color,
        child: Center(
            child: Text(
              'Page $page',
              style: TextStyle(
                  color: Colors.white,
                  fontWeight: FontWeight.bold,
                  fontSize: 24),
            )));
  }
}

Pageview의 direction을 수직으로 설정해주면

 

위아래로 드래그를 통해 다른 페이지로 이동할 수 있게 되고

 

onPageChanged에서 TabController를 이용해서

 

현재 페이지(page 값)와 동일한 tab으로 이동시켜줍니다

 

그리고 tabbar에서 터치를 통해 다른 화면으로 이동할때는

 

onTap에서 PageController를 이용해서 해당 페이지로 이동시켜줍니다

 

 

indicator예제

  PageController _pController = PageController();
  StreamController _sController = StreamController<int>()..add(0);

  @override
  void dispose() {
    _sController?.close();
    _pController?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('PageView example 2')),
      body: Stack(
        children: [
          PageView(
            controller: _pController,
            scrollDirection: Axis.horizontal,
            onPageChanged: (value) {
              _sController.add(value);
            },
            children: [
              _container(1, Colors.red),
              _container(2, Colors.green),
              _container(3, Colors.blue),
            ],
          ),
          Align(
            alignment: Alignment.bottomCenter,
            child: SizedBox(
                height: 50,
                width: 50,
                child: StreamBuilder<int>(
                    stream: _sController.stream,
                    builder: (context, snapshot) {
                      if (snapshot.hasData) {
                        return ListView.builder(
                            scrollDirection: Axis.horizontal,
                            shrinkWrap: true,
                            itemCount: 3,
                            itemBuilder: (context, index) {
                              return Container(
                                margin: const EdgeInsets.symmetric(
                                    vertical: 8, horizontal: 4),
                                width: 9,
                                height: 9,
                                decoration: BoxDecoration(
                                    shape: BoxShape.circle,
                                    color: (snapshot.data == index)
                                        ? Colors.white
                                        : Colors.grey),
                              );
                            });
                      }
                      return Container();
                    })),
          ),
        ],
      ),
    );
  }

  Container _container(int page, Color color) {
    return Container(
        color: color,
        child: Center(
            child: Text(
          'Page $page',
          style: TextStyle(
              color: Colors.white, fontWeight: FontWeight.bold, fontSize: 24),
        )));
  }

위 예제와 거의 동일한데 여기서는 direction을 수평으로 해줬고

 

page의 이동에 따라 dot indicator로 움직임을 표현해 보는 예제를 만들어 봤습니다

 

Pageview의 onPageChanged부분에서 값을 StreamController를 이용해서 page값을 전달합니다

 

그리고 Streambuilder를 통해 ListView의 아이템 index와 page값이 동일할 때

 

아이템 색깔을 하얀색으로 동일하지 않을 때 회색으로 해서

 

현재 페이지가 어디에 있는지 그리고 총 페이지 수가 얼마나 되는지 표현할 수 있습니다

 

StreamBuilder를 사용하는대신 onPageChanged 부분에 setState로 페이지 변경을

 

notify해주는 방법도 있지만 나중에 Page부분에 데이터가 많아지면 rebuild할 때 문제가 발생할 수도 있으니

 

StreamBuilder를 사용하는 연습을 해보는것도 좋을거 같습니다

반응형
Comments