[flutter] scrolling to widget focus 특정 위치로 스크롤링 포커싱

💜Dabo (개발자 다보)·2021년 3월 31일
12

Flutter Widget

목록 보기
10/11
post-thumbnail

focusNode를 list 형태로 만들어서 똑같이 onTap으로 FocusScope.of(context).requestFocus(focusNodes[index+1]), 이렇게 해줘도 가능하긴 합니당

이번에는 focusNode가 아닌 GlobalKey의 globalKeys[questionIndex + 1].currentContext를 가져와서 스크롤링 처리되게 해보겠습니다😊



⛔️ 시작하기전! 잠깐!

21.04.01 update
cf. https://stackoverflow.com/questions/49153087/flutter-scrolling-to-a-widget-in-listview

다음 서술된 방식은 화면 내에서 보이는 globalKey를 이용해 context를 찾아 포커싱 해주는 작업입니다.

Scrollable.ensureVisible(
      _globalKey.currentContext,
    );

여기서 ListView.builder()ListView를 이용하면, 아무리 globalKey가 선언되어있다고 해도 currentContext는 화면에 있지 않으면 렌더링을 하지않아 null로 return이 됩니다, 그러면 포커싱은 자연스럽게 안되겠죠!?

이럴 땐 SingleChildScrollView로 감싼 Column로 진행해주시면 됩니다!



1. GlobalKey를 이용하여 화면 작성

class SkinfoldMCQScreen extends StatelessWidget {
  final globalKeys = <GlobalKey>[];
  ...
  
  
  Widget build(BuildContext context) {
    return Column(
      children: [
      	...
        Expanded(
          child: SingleChildScrollView(
            child: Column(
              children: _buildQuetsionBoxs(questions),
            ),
          ),
        ),
      ],
    );
    
    ...
    
    List<Widget> _buildQuetsionBoxs(List<Question> questions) {
    final lists = <Widget>[];
    
    for (var i = 0; i < questions.length; i++) {
      final question = questions[i];
      questionGlobalKeys[question.questionId] = GlobalKey();

        lists.add(
          CustomWidgetBox(),
        );
      }
    }
    return lists;
  }
  
   ... 
}
  
class CustomWidgetBox extends StatelessWidget {
  const CustomWidgetBox({
    Key key,
     this.questionIndex,
     this.globalKeys,
  }) : super(key: key);
  final int questionIndex;
  final List<GlobalKey> globalKeys;
  ...
  
  
  Widget build(BuildContext context) {
    return Container(
      key: globalKeys[questionIndex],
      ...
    );
  }
}

2. Scrollable.ensureVisible 이용하여 특정 context 위치로 스크롤링 / 포커싱

Scrollable.ensureVisible(context)를 이용하면 쉽게 해결이 가능합니다 :)

return InkWell(
  onTap: () {
    Scrollable.ensureVisible(
      globalKeys[questionIndex + 1].currentContext,
      duration: Duration(milliseconds: 600),
      curve: Curves.easeInOut,
    );
    print('focus');
	},
	child: ...
)

3. Result



profile
𝙸 𝚊𝚖 𝚊 𝚌𝚞𝚛𝚒𝚘𝚞𝚜 𝚍𝚎𝚟𝚎𝚕𝚘𝚙𝚎𝚛 𝚠𝚑𝚘 𝚎𝚗𝚓𝚘𝚢𝚜 𝚍𝚎𝚏𝚒𝚗𝚒𝚗𝚐 𝚊 𝚙𝚛𝚘𝚋𝚕𝚎𝚖. 🇰🇷👩🏻‍💻

5개의 댓글

comment-user-thumbnail
2021년 8월 17일

항상 좋은 정보 감사합니다 :)

답글 달기
comment-user-thumbnail
2021년 12월 2일

어떤분이 질문 댓글 남겨주셨는데! focusNode 주입 방법은
아래 링크 참고해주시면 됩니당 :D
https://docs.flutter.dev/cookbook/forms/focus

답글 달기
comment-user-thumbnail
2022년 1월 18일

항상 좋은 정보 감사합니다 다보님:-)

답글 달기
comment-user-thumbnail
2022년 5월 19일

안녕하세요! 잘봤습니다 :)

Build가 완료 된 후 동작하는 WidgetsBinding.instance.addPostFrameCallback을 활용하면 ListView에서도 활용 가능하더라구요!

WidgetsBinding.instance.addPostFrameCallback((_) {
        if (globalKey.currentContext != null) {
          Scrollable.ensureVisible(globalKey.currentContext!);
        }
});
답글 달기
comment-user-thumbnail
2022년 7월 29일

좋은 글 감사합니다!

답글 달기