Never give up

Flutter - Listview with ScrollController 본문

Flutter

Flutter - Listview with ScrollController

대기만성 개발자 2020. 8. 3. 16:19
반응형

Listview를 사용하다보면 스크롤이 맨 위 혹은 아래에 도달했을때

특정 동작을 해야되는 경우가 있는데, ScrollController를 이용하면 간단하게 해결 가능합니다

(해당 소스코드는 맨 아래에 도달했을 때 FAB을 숨기는 동작을 함)

 

메인

class ListTestScreen extends StatefulWidget {
  @override
  _ListTestScreenState createState() => _ListTestScreenState();
}

class _ListTestScreenState extends State<ListTestScreen> {
  ScrollController _controller;

  @override
  void initState() {
    super.initState();
    _controller = ScrollController();
    _controller.addListener(_scrollListener);
  }

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

  _scrollListener() {
    var _data = Provider.of<VisibilityData>(context, listen: false);
    if (_controller.offset >= _controller.position.maxScrollExtent &&
        !_controller.position.outOfRange) {
      _data.setVisible(false);
    } else {
      _data.setVisible(true);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Consumer<VisibilityData>(builder: (context, value, child) {
      return Scaffold(
        appBar: AppBar(title: Text('Scroll test')),
        body: ListView.builder(
            controller: _controller,
            itemCount: 20,
            itemBuilder: (context, index) {
              return ListTile(
                leading: CircleAvatar(
                  child: Text('${index + 1}'),
                ),
                title: Text('2 x $index = ${index * 2}'),
              );
            }),
        floatingActionButton: Visibility(
          visible: value.getVisible,
          child: FloatingActionButton(
            child: Icon(Icons.add),
            onPressed: () {},
          ),
        ),
      );
    });
  }
}

 

데이터

class VisibilityData extends ChangeNotifier {
  bool _visible = true;

  bool get getVisible => _visible;

  void setVisible(bool value) {
    _visible = value;
    notifyListeners();
  }
}

 

하지만 위와 같이 else 부분에서 처리를 해버리면 성능상 단점이 생길 수 있습니다

 

실제로 print를 해보면 setVisible이 1번 이상 불리게 되고

 

notifyListeners() 또한 여러번 불리게 되어 성능 하락 및 에러를 발생시킬 수 있습니다

 

그래서 조금 더 개선을 시켜보면

_scrollListener() {
    var _data = Provider.of<VisibilityData>(context, listen: false);
    if (_controller.offset >= _controller.position.maxScrollExtent &&
        !_controller.position.outOfRange) {
      _data.setVisible(false);
    } else if(_controller.offset < _controller.position.maxScrollExtent &&
        !_data.getVisible){
      _data.setVisible(true);
    }
}

 

다음과 같이 표현할 수 있습니다

 

offset이 화면 최하단보다 위에 있고, visible false 상태일 때만 visible true를 설정하면 더 좋을거 같습니다

 

추가로 setState되는 과정에서 Listview가 갱신되는 구조로 코딩을 하셨다면

 

해당 부분은 StreamBuilder를 이용해서 처리하면 될거 같습니다

반응형
Comments