inblog logo
|
keepgoing
    Flutter

    [Flutter] ScrollController로 Container 제어하기

    김호정's avatar
    김호정
    Oct 03, 2024
    [Flutter] ScrollController로 Container 제어하기
    Contents
    선생님 공유구글링 참고
     
    6장인가 7장인가 그 로그인쪽에 스크롤 적용!!!!
     
    textformfield는 터치했을때 스크롤 조금씩 내려오도록 해야한다.
     
    안그러면 불편해서 사용자가 안쓴다.
     
     

    선생님 공유

    https://getinthere.notion.site/ScrollController-Container-bb0cbd7ff70b47f4b3f410d7eba9952b
     
     

    구글링 참고

    Flutter에서 특정 위젯 위치로 스크롤 이동하기
    안녕하세요. 이번 포스팅에서는 이벤트(버튼 클릭 등) 발생 시 특정 위젯이 위치한 위치로 스크롤 이동하는 방법에 대해서 알아보겠습니다. 웹에서 url에 Fragment(#)를 이용해서 Fragment id에 해당하는 HTMLElement를 보이게 하는것과 동일한 동작이라고 보면 됩니다. 방법은 아주 간단합니다. 특정 위젯에 대한 정보를 알기 위한 key 값을 등록하고 Scrollable.ensureVisible을 이용하면 됩니다. 먼저 특정 Widget에 key를 등록해줍니다. ... final GlobalKey _widgetKey = GlobalKey(); @override Widget build(BuildContext context) { @override Widget build(BuildContext..
    Flutter에서 특정 위젯 위치로 스크롤 이동하기
    https://dev-bak.tistory.com/55
    Flutter에서 특정 위젯 위치로 스크롤 이동하기
     
     
     
    선생님 코드 보고 하나씩 해보는데
     
    notion image
     
    HomePage 를 StatefulWidget으로 뺏다.
     
     
    일단 stl 로 만들고 나서 stf 로 alt enter 해서 바꿈
     
     
    notion image
     
    stf 로 바꾸면 상태를 만드는 createSatete 가 자동으로 오버라이딩 되고,
    ScrollController 를 불러내서 이벤트리스너를 달아줌 ( addListener )
     
    addListener 로 들어가보니 void 여서 return을 안하니까 () {} 이렇게 익명함수로 써줌
     
    그리고 어떤 함수가 실행되면 listen 하게 할건지 설정하고
     
    scrollListener 함수를 만들어줌
     
    notion image
     
    여기까지 해주고 스크롤링을 web에서 하면 print가 찍힌다.
     
    이제 스크롤할 때, 위의 good 컨테이너의 크기가 줄어들도록 offset을 활용해보자
     
    notion image
    notion image
     
    스크롤을 내릴수록 offset이 커진다.
     
    offset이 300 보다 작은 경우 ( 페이지 상단에 있을 때 )
     
    Container 의 높이를 줄이는 효과를 적용해야 한다.
    height = 300 - currentOffset; // Container의 height 가 동적으로 변한다
     
    현재 offset을 기준으로 Container의 height를 조금씩 작게 줄인다.
    height = 56; // Container 가 소멸되지않게? 최소 높이 설정
     
    Container 가 너무 작아지지 않게 최소 높이를 설정해준다.
     
     
    notion image
     
     
    default가 0 인 prev 랑 curentOffset 을 이용해서
     
    스크롤이 위로 올라가는지 아래로 내려가는지 감지하고,
     
    가장 상단, 가장 하단에 닿은 것도 감지한다.
     
    → 막줄에 prev = currentOffset 을 넣어줘야지
     
    직전의 offset 과 지금 변화하는 currentOffset 을 if 문으로 비교해서
     
    효과를 줄 수 있다.
     
    notion image
     
    이렇게 잘 찍히고,
     
    notion image
     
    상단 Container의 크기도 아래로 스크롤 하면
     
    notion image
     
    이렇게 작아진다 ( 최소 높이 56 )
     
     
    import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: HomePage(), ); } } class HomePage extends StatefulWidget { const HomePage({super.key}); @override State<HomePage> createState() => _HomePageState(); // 상태를 만듦 } class _HomePageState extends State<HomePage> { final ScrollController _controller = ScrollController(); double prev = 0; double height = 300; @override void initState() { _controller.addListener((){ scrollListener(); }); // 익명 super.initState(); } void scrollListener(){ print("스크롤 동작중"); double currentOffset = _controller.offset; //bool keepScrollOffset = _controller.keepScrollOffset; print("currentOffset : $currentOffset"); //print("keepScrollOffset : $keepScrollOffset"); // 실습 if(currentOffset < 300) { setState(() { height = 300 - currentOffset; // Container의 height 가 동적으로 변한다 if(height < 56) { height = 56; // Container 가 소멸되지않게? 최소 높이 설정 } }); } // 301 0 if(currentOffset > prev) { print("아래로 내려가요"); } // if(currentOffset < prev) { print("위로 올라가요"); } if(currentOffset == _controller.position.maxScrollExtent){ print("가장 하단"); } if(currentOffset == _controller.position.minScrollExtent){ print("가장 상단"); } prev = currentOffset; } @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: Column( children: [ Container( color: Colors.red, height: height, width: double.infinity, child: Center( child: Text( "Good", style: TextStyle(color: Colors.white, fontSize: height / 3), ), ), ), Expanded( child: ListView.builder( controller: _controller, itemCount: 100, itemBuilder: (context, index) => Text("제목 $index"), ), ), ], ), ), ); } }
     
     
     
     
     
     
    notion image
     
    스크롤 할 때 상단의 Container를 투명하게 만들고 싶으면
    opacity 도 같이 계산해서 Container의 color 매개변수로 넣어준다.
     
    notion image
    currentOffset이 100인 경우 → 2 / 3 , 200인 경우 → 1 / 3
     
    내려갈수록 0 에 가까워져서 투명해진다.
     
    opacity : 0~1.0 사이의 값을 가지고 불투명도를 지정하는데
    0일 경우 가장 투명하고, 1일 경우 가장 불투명하게 보인다.
    notion image
     
    Container 의 color를 지정할 때, opacity 도 같이 줄려면
     
    Colors 말고 Color.fromRGBO 를 사용해서 Red 컬러 + opacity (동적으로 변경됨) 를 같이 준다.
     
    import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: HomePage(), ); } } class HomePage extends StatefulWidget { const HomePage({super.key}); @override State<HomePage> createState() => _HomePageState(); // 상태를 만듦 } class _HomePageState extends State<HomePage> { final ScrollController _controller = ScrollController(); double prev = 0; double height = 300; // 추가 double op = 1.0; @override void initState() { _controller.addListener((){ scrollListener(); }); // 익명 super.initState(); } void scrollListener(){ print("스크롤 동작중"); double currentOffset = _controller.offset; //bool keepScrollOffset = _controller.keepScrollOffset; print("currentOffset : $currentOffset"); //print("keepScrollOffset : $keepScrollOffset"); // 실습 if(currentOffset < 300) { setState(() { height = 300 - currentOffset; // Container의 height 가 동적으로 변한다 op = (300 - currentOffset) / 300; // co가 100이면 2 / 3 , 200 이면 1 / 3 -> 내려갈수록 0 에 가까워져서 투명해진다. if(height < 56) { height = 56; // Container 가 소멸되지않게? 최소 높이 설정 } }); } // 301 0 if(currentOffset > prev) { print("아래로 내려가요"); } // if(currentOffset < prev) { print("위로 올라가요"); } if(currentOffset == _controller.position.maxScrollExtent){ print("가장 하단"); } if(currentOffset == _controller.position.minScrollExtent){ print("가장 상단"); } prev = currentOffset; } @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: Column( children: [ Container( color: Color.fromRGBO(255, 0, 0, op), height: height, width: double.infinity, child: Center( child: Text( "Good", style: TextStyle(color: Colors.white, fontSize: height / 3), ), ), ), Expanded( child: ListView.builder( controller: _controller, itemCount: 100, itemBuilder: (context, index) => Text("제목 $index"), ), ), ], ), ), ); } }
     
    notion image
     
    가장 위에 있을 땐 255, 0, 0, 1 (opacity 1.0임) 의 real red 색
     
    notion image
     
    조금 내리면 height 도 변경되고,
     
    opacity도 만약 currentOffset이 100 이라 치면,
     
    2 / 3 ⇒ 0.6
     
    255, 0, 0, 0,6 이 되어서 조금 더 투명해졌다.
     
    op = (300 - currentOffset) / 300;
     
    으로 설정해두었기 때문에,
     
    currentOffset이 300 이상으로 넘어가면
     
    op = 0 이 되어서
     
    최대치로 투명해진다.
     
    notion image
     
    끝
     
    Share article
    Contents
    선생님 공유구글링 참고

    keepgoing

    RSS·Powered by Inblog