스크롤 위치 파악하는 법과 더보기 요청
- 문자 중간에 변수를 넣는 방법
- React와 같이 ${} 사이에 변수를 넣어주게 되면 된다.
- Text('좋아요 ${homeData[idx]['likes'].toString()}', style: TextStyle(fontSize: 15, fontWeight: FontWeight.*w700*),),
- 무한 스크롤 기능 구현
- 인스타나 페이스북과 같이 스크롤이 끝까지 내려가게 되면 서버에서 다시 데이터를 받아와서 끝없는 사용 경험을 줄 수 있도록 하기.
- 순서
- 스크롤바 높이 측정하기
- import 'package:flutter/rendering.dart'; ← 스크롤 관련 유용한 함수가 있음
- 현재 LiswView 위젯에 서버로부터 받아온 데이터를 뿌리고 있기에 LiswView의 높이를 측정하려 하는데
- 스크롤바 높이를 측정하기 위해선 StatefulWidget이어야 한다.
- 그래서 변경하게 되는데 부모에서 보낸 state의 등록은 첫 클래스에서 하고 사용은 두 번째 클래스에서 해야한다.
- 다만 두 번째 클래스에서 그냥 사용할 수는 없기에 widget을 앞에 붙여줘야 한다.
- ex) widget.homeData
class Home extends StatefulWidget { // <-- 첫 번째 클래스에서 등록 Home({super.key, this.homeData}); final homeData; @override State<Home> createState() => _HomeState(); } class _HomeState extends State<Home> { // <-- 두 번째 클래스에서 사용 @override Widget build(BuildContext context) { if (widget.homeData.isNotEmpty){ // <-- widget.homeData return ListView.builder( itemCount: widget.homeData.length, itemBuilder: (context, idx){ return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Image.network(widget.homeData[idx]['image']), Container( margin: EdgeInsets.fromLTRB(10, 20, 10, 20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text('좋아요 ${widget.homeData[idx]['likes'].toString()}', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w700),), ], ), Text(widget.homeData[idx]['date'].toString()), Text(widget.homeData[idx]['content'].toString()), ], ), ) ], ); }, ); } else { return Text('빈'); } } }
- 그리고 변수에 ScrollController() 를 담아주기
- ScrollController는 자료를 저장해주는 클래스로 스크롤 정보를 저장해준다.
- 이후 스크롤을 사용하는 위젯의 controller에 변수를 넣어주기!
class Home extends StatefulWidget { Home({super.key, this.homeData}); final homeData; @override State<Home> createState() => _HomeState(); } class _HomeState extends State<Home> { // ScrollController() 는 // 자료를 저장해주는 클래스로 스크롤 정보를 저장해준다. var scroll = ScrollController(); @override Widget build(BuildContext context) { if (widget.homeData.isNotEmpty){ return ListView.builder( controller: scroll, itemCount: widget.homeData.length, itemBuilder: (context, idx){ return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Image.network(widget.homeData[idx]['image']), Container( margin: EdgeInsets.fromLTRB(10, 20, 10, 20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text('좋아요 ${widget.homeData[idx]['likes'].toString()}', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w700),), ], ), Text(widget.homeData[idx]['date'].toString()), Text(widget.homeData[idx]['content'].toString()), ], ), ) ], ); }, ); } else { return Text('빈'); } } }
- 스크롤바 높이 측정하기
- 이제 무한 스크롤을 위해 스크롤 위치를 측정하면서 스크롤의 끝인지에 대해 판단을 할 수 있도록 하기
- 해당 기능을 하기 위해선 첫 로딩시부터 변경될 마다 계속 해줘야 하기에
- initstate를 생성 후 만들어 둔 변수 scroll에 리스너를 달아서 변수가 변경될 때 마다 실행되도록 하기
- 주의점으로 리스너는 더 이상 필요가 없다면 제거하는 것이 성능에 좋다고 한다.
class Home extends StatefulWidget { Home({super.key, this.homeData}); final homeData; @override State<Home> createState() => _HomeState(); } class _HomeState extends State<Home> { // ScrollController() 는 자료를 저장해주는 것으로, 클래스가 된다. 그래서 스크롤 정보를 저장해주는 것을 하는데 도움을 준다 var scroll = ScrollController(); @override void initState() { super.initState(); scroll.addListener(() { }); } @override Widget build(BuildContext context) { if (widget.homeData.isNotEmpty){ return ListView.builder( controller: scroll, itemCount: widget.homeData.length, itemBuilder: (context, idx){ return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Image.network(widget.homeData[idx]['image']), Container( margin: EdgeInsets.fromLTRB(10, 20, 10, 20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text('좋아요 ${widget.homeData[idx]['likes'].toString()}', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w700),), ], ), Text(widget.homeData[idx]['date'].toString()), Text(widget.homeData[idx]['content'].toString()), ], ), ) ], ); }, ); } else { return Text('빈'); } } }
- 그래서 우선 출력문으로 현재 위치를 알고자 한다면
- print(scroll.position.pixels)
- 스크롤 방향
- scroll.position.userScrollDirection
- 최대 스크롤 가능 높이는 아래와 같이 작성하면 알 수 있다.
- scroll.position.maxScrollExtent
- 이제 조건문을 사용해서 끝에 도달했다면이라는 조건을 준다면 아래와 같다
- @override void initState() { super.initState(); scroll.addListener(() { if (scroll.position.pixels == scroll.position.maxScrollExtent) { print('같당'); } }); }
숙제
무한 스크롤을 구현하기
그리고 응용 과제
- 처음으로 끝에 도달했을 땐 more1.json
- 두 번째로 끝에 도달했을 땐 more2.json 에 요청해서 게시글 가져오기
응용 과제로는 그냥 변수 하나를 more${변수} 에 담아서 요청하고 성공시에만 게시글 변수에 추가하는 함수를 실행시키도록 했음
import 'dart:js_interop';
import 'package:flutter/material.dart';
import './style.dart' as style;
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:flutter/rendering.dart';
void main() {
runApp(
MaterialApp(
theme: style.theme,
home: MyApp()
)
);
}
class MyApp extends StatefulWidget {
MyApp({super.key});
@override
State createState() => _MyAppState();
}
class _MyAppState extends State {
var homeData = [];
appendData(value){
setState(() {
homeData.add(value);
});
}
getData() async{
var result = await http.get(Uri.parse('<주소>'));
if (result.statusCode == 200) {
setState(() {
homeData = jsonDecode(result.body);
});
} else {
print('실패');
}
}
@override
void initState() {
super.initState();
getData();
}
// 0: home, 1: shop
var tab = 0;
changeTab(tabNumber){
setState(() {
tab = tabNumber;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Instagram'),
actions: [
IconButton(
onPressed: (){},
icon: Icon(Icons.add_box_outlined)
)
],
),
body: [Home(homeData:homeData, appendData:appendData),Text('shop')][tab],
bottomNavigationBar: BottomNavigationBar(
onTap: (i){
changeTab(i);
},
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home_outlined),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_bag_outlined),
label: 'Shopping',
),
],
showSelectedLabels: false, // 선택된 아이템의 레이블 숨김
showUnselectedLabels: false, // 선택되지 않은 아이템의 레이블 숨김
),
);
}
}
class Home extends StatefulWidget {
Home({super.key, this.homeData, this.appendData});
final homeData;
final appendData;
@override
State createState() => _HomeState();
}
class _HomeState extends State {
// ScrollController() 는 자료를 저장해주는 것으로, 클래스가 된다. 그래서 스크롤 정보를 저장해주는 것을 하는데 도움을 준다
var scroll = ScrollController();
var cnt = 0;
getAddData() async{
cnt ++;
print(cnt);
var data = await http.get(Uri.parse('<주소/more${cnt}.json>'));
if (data.statusCode == 200){
widget.appendData(jsonDecode(data.body));
} else {
print('더 이상 없어');
}
}
@override
void initState() {
super.initState();
scroll.addListener(() {
if (scroll.position.pixels == scroll.position.maxScrollExtent) {
getAddData();
}
});
}
@override
Widget build(BuildContext context) {
if (widget.homeData.isNotEmpty){
return ListView.builder(
controller: scroll,
itemCount: widget.homeData.length,
itemBuilder: (context, idx){
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(widget.homeData[idx]['image']),
Container(
margin: EdgeInsets.fromLTRB(10, 20, 10, 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text('좋아요 ${widget.homeData[idx]['likes'].toString()}', style: TextStyle(fontSize: 15, fontWeight: FontWeight.w700),),
],
),
Text(widget.homeData[idx]['date'].toString()),
Text(widget.homeData[idx]['content'].toString()),
],
),
)
],
);
},
);
} else {
return Text('빈');
}
}
}
'Flutter' 카테고리의 다른 글
[Flutter] 폰에 저장된 이미지 가져오기 (Image Picker) (0) | 2023.08.11 |
---|---|
[Flutter] 상세페이지 만들기 (Navigator, Routes) (0) | 2023.08.10 |
[Flutter] Future 다루기 & FutureBuilder (0) | 2023.08.09 |
[Flutter] 앱이 서버와 데이터 주고받는 법 (0) | 2023.08.09 |
[Flutter] 탭으로 페이지 나누는 법 (사진 추가, ListView) (0) | 2023.08.09 |