키보드 높이 만큼 페이지 이동(동적스크롤링)

pages / login_page.dart

CustomTextFormField에 scrollAnimate 함수 넘겨줌

// statefulwidget으로 변경
class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  final _formKey = GlobalKey<FormState>();
  //scrollController 생성
  late ScrollController scrollController;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    //초기화
    scrollController = new ScrollController();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: ListView(
          controller: scrollController,
          children: [
            SizedBox(height: 100),
            Logo("Login"),
            SizedBox(height: 50),
            buildLoginForm(),
            SizedBox(height: 50),
            TextButton(
              onPressed: () {
                if (_formKey.currentState!.validate()) {
                  Navigator.pushNamed(context, "/home");
                }
              },
              child: Text("Login"),
            ),
            SizedBox(height: 10),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text("New Here? "),
                GestureDetector(
                  onTap: () {
                    print("Join 클릭");
                  },
                  child: Text(
                    "Join",
                    style: TextStyle(
                      fontWeight: FontWeight.bold,
                      decoration: TextDecoration.underline,
                    ),
                  ),
                )
              ],
            ),
          ],
        ),
      ),
    );
  }

  Widget buildLoginForm() {
    return Form(
      key: _formKey,
      child: Column(
        children: [
          CustomTextFormField("Email", scrollAnimate),
          CustomTextFormField("Password", scrollAnimate),
        ],
      ),
    );
  }

  void scrollAnimate() {
    print("탭 클릭됨");
    // 6초 후에 실행
    Future.delayed(Duration(milliseconds: 600), () {
      // MediaQuery.of(context).viewInsets.bottom 하단 inset(사용못하는영역)크기 리턴
      // 사용못하는 영역만큼 1초 동안 easeIn으로 이동
      scrollController.animateTo(MediaQuery.of(context).viewInsets.bottom,
          duration: Duration(milliseconds: 100), curve: Curves.easeIn);
    });
  }
}

components / custom_text_form_field.dart

import 'package:flutter/material.dart';

class CustomTextFormField extends StatelessWidget {
  final String subtitle;
  //scrollAnimate 함수 받아오기
  final Function scrollAnimate;
  const CustomTextFormField(this.subtitle, this.scrollAnimate, {Key? key})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(subtitle),
        SizedBox(height: 5),
        TextFormField(
          onTap: () {
          // text field tab할때 실행
            scrollAnimate();
          },
          validator: (value) =>
              value!.isEmpty ? "Please Enter some text" : null,
          decoration: InputDecoration(
            hintText: "Enter $subtitle",
            focusedBorder: OutlineInputBorder(
              borderRadius: BorderRadius.circular(20),
            ),
            enabledBorder: OutlineInputBorder(
              borderRadius: BorderRadius.circular(20),
            ),
            errorBorder: OutlineInputBorder(
              borderRadius: BorderRadius.circular(20),
            ),
            focusedErrorBorder: OutlineInputBorder(
              borderRadius: BorderRadius.circular(20),
            ),
          ),
        ),
        SizedBox(height: 10),
      ],
    );
  }
}

 

728x90

2021.03.21 - [Usage/ReactJS] - Table of Contents 스크롤 메뉴 구현

 

Table of Contents 스크롤 메뉴 구현

createContext를 사용하여 provider, context 생성 Toc.js 생성 메뉴에서 이동 시킬 위치를 각각의 컴포넌트에서 pos로 받아와서 저장 시킬 예정 import React from "react"; import { createContext, useState }..

mugon-devlog.tistory.com

이전 포스트의 확장판입니다.

ToC 스크롤 메뉴가 구현되어 있다는 가정하에 시작하겠습니다.

스크롤의 현재 위치, 동적으로 구현하고픈 페이지의 상단과 하단 위치의 절대 값

//현재 위치가 이곳에 왔을때 active true
const [active, setActive] = useState(false);
const element = useRef(null);

useEffect(() => {
  const onScroll = () => {
    const scrollTop = window.pageYOffset + 100; //현재 위치
    //현재 페이지 상단
    const pagePosTop =
    element.current.getBoundingClientRect().top + window.pageYOffset;
    //현재 페이지 하단
    const pagePosBot =
    element.current.getBoundingClientRect().bottom + window.pageYOffset;
    if (pagePosTop < scrollTop && scrollTop < pagePosBot) {
      setActive(true);
    } else {
      setActive(false);
    }
  };
  if (loc !== 0) {
  	window.addEventListener("scroll", onScroll);
  }
  return () => {
  	window.removeEventListener("scroll", onScroll);
  };
}, [active]);

-------
return(
 <Page id="fourth" ref={element}>
 {* *}
 </Page>
)

스크롤이 페이지 영역에 들어왔을때 나타나게끔 css

styled-components를 이용해 active값을 받아 구현

const IconStyle = styled.img`
  width: 40rem;
  height: 15rem;
  animation: ${(props) => (props.active ? "fadein 3s" : "fadeout 3s")};
  @keyframes fadein {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }
  @keyframes fadeout {
    from {
      opacity: 1;
    }
    to {
      opacity: 0;
    }
  }
`;
--------
return (
	<IconStyle src="./icon.png" active={active} />
);

 

 

728x90

+ Recent posts