일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 오픈소스
- Firebase
- ASMR
- recyclerview
- 명언모음
- Flutter
- Android
- Freesound
- 좋은글필사하기
- jetpack compose
- DART
- 코틀린
- 1인개발자
- 명심보감
- Streaming
- bash
- 소울칼리버6
- 벤자민플랭클린
- 이모지
- androidx
- FSM
- 넷플릭스
- 공자명언
- Coroutine
- 장자명언
- 파이썬
- 공부집중
- 이모지메모
- kotlin
- Linux
Archives
- Today
- Total
Vintage appMaker의 Tech Blog
[Flutter] ScrollView에서 이동시 item 위치찾기 본문
Source code or Tip/Flutter & Dart
[Flutter] ScrollView에서 이동시 item 위치찾기
VintageappMaker 2022. 8. 12. 10:38
Android와 같은 native 앱을 개발하다보면 list관련 view들은 스크롤이 변할 시, 리스트 item의 인덱스 정보를 넘겨주는 경향이 있다. 그래서 Flutter에서도 Scroll 변경시 처리하는 listener에서 index를 찾아보았지만 찾을 수 없었다. 단지 Flutter는 위젯의 키값을 사용하여 스크롤될 때의 위치를 계산하면서 파악할 수 밖에 없었다.
1. GlobalKey()를 사용해야 한다. 정보를 알고자 하는 위젯에 키값을 대입한다.
2. Scroll관련 listener에서 key값으로 위젯을 가져온다.
3. 이때, context의 findRenderObject를 사용하여 RenderBox 정보를 가져온다.
4. 그 값이 보여지는 위치의 상단을 기준으로 0값인지 -값인지를 비교한다(-이면 지나간 것임)
다음은 전체소스이다.
import 'dart:ui';
import 'package:flutter/material.dart';
void main() {
runApp(const MainApp());
}
class MainApp extends StatelessWidget {
const MainApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
scrollBehavior: DeskScrollBehavior(),
title: 'list(grid) in ScrollView',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MainPage(title: 'list(grid) in ScrollView'),
);
}
}
class MainPage extends StatefulWidget {
const MainPage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
final _pageController = PageController(viewportFraction: 0.8);
int _index = 0;
String sMessage = "";
List<GlobalKey> keys = <GlobalKey>[GlobalKey(), GlobalKey(), GlobalKey()];
final ScrollController _scrollController = ScrollController();
// y값 가져오기
double getWidgetPosition(GlobalKey key) {
if (key.currentContext != null) {
final RenderBox renderBox =
key.currentContext!.findRenderObject() as RenderBox;
var position = renderBox.localToGlobal(Offset.zero);
return position.dy - renderBox.size.height; //
}
return 0;
}
@override
void initState() {
super.initState();
_scrollController.addListener(() {
print('offset = ${_scrollController.offset}');
var y1 = getWidgetPosition(keys[0]);
var y2 = getWidgetPosition(keys[1]);
var y3 = getWidgetPosition(keys[2]);
print("y1 : ${y1}, y2 : ${y2}, y3 : ${y3}");
if (y1 < 0 && y2 > 0 && y3 > 0) {
setState(() {
sMessage = "section 1";
});
} else if (y1 < 0 && y2 < 0 && y3 > 0) {
setState(() {
sMessage = "section 2";
});
} else if (y1 < 0 && y2 < 0 && y3 < 0) {
setState(() {
sMessage = "section 3";
});
} else {
setState(() {
sMessage = "영역밖임";
});
}
});
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_buildHeader(sMessage),
SizedBox(height: 30),
Expanded(
child: SingleChildScrollView(
controller: _scrollController,
physics: AlwaysScrollableScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildTitle("GridSection", keys[0], Colors.blue),
_buildGridView(),
_buildTitle("PageViewSection", keys[1], Colors.blue),
_buildPageView(),
_buildTitle("ListSection", keys[2], Colors.blue),
_buildListView(),
]),
),
),
],
),
);
}
Widget _buildHeader(String s) {
return Container(
width: double.infinity,
height: 100,
color: Color.fromARGB(255, 20, 2, 64),
child: Center(
child: Text(
s,
style: TextStyle(fontSize: 40, color: Colors.white),
)));
}
Widget _buildTitle(String s, Key k, [Color c = Colors.red]) {
return Container(
key: k,
width: double.infinity,
height: 100,
color: c,
child: Center(
child: Text(
s,
style: TextStyle(fontSize: 40, color: Colors.white),
)));
}
Container _buildGridView() {
return Container(
child: GridView.builder(
physics: NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 1,
crossAxisSpacing: 1,
),
itemCount: 10,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
var url = getUrl(index);
return Container(child: Image.network(url));
}),
);
}
Widget _buildPageView() {
return Container(
height: 200,
child: PageView.builder(
itemCount: 10,
controller: _pageController,
itemBuilder: (BuildContext context, int index) {
return Transform.scale(
scale: index == _index ? 1 : 0.98,
child: Container(
color: (index % 2 == 0)
? Color.fromARGB(255, 70, 70, 70)
: Color.fromARGB(255, 0, 0, 0),
child: SizedBox(
width: 100,
child: Center(
child:
Container(child: Image.network(getUrl(index))))),
));
},
onPageChanged: (int index) => setState(() => _index = index)),
);
}
Container _buildListView() {
return Container(
child: ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: const EdgeInsets.all(8),
itemCount: 30,
itemBuilder: (BuildContext context, int index) {
return Center(child: Container(child: Image.network(getUrl(index))));
},
),
);
}
String getUrl(int index) {
return (index % 2 == 0)
? "https://cdn.cloudflare.steamstatic.com/steam/apps/108710/capsule_616x353.jpg?t=1616438999"
: "https://cdn-ext.fanatical.com/production/product/1280x720/674039a7-bdf2-4b0a-856c-624b8d4b1c8e.jpeg";
}
}
// 웹과 desktop에서 모바일처럼 터치 스크롤 지원하기 위함
class DeskScrollBehavior extends MaterialScrollBehavior {
@override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
};
}
[전체소스]
'Source code or Tip > Flutter & Dart' 카테고리의 다른 글
[Flutter] Layoutbuilder를 이용한 반응형 UI (0) | 2022.08.15 |
---|---|
[Flutter] stickyheader 구현(CustomScrollView, SliverAppBar, SliverList) (0) | 2022.08.13 |
[Flutter] InteractiveViewer를 listView안에 넣기 (0) | 2022.08.11 |
[Flutter link] Flutter 개발자 필수 사이트 정리 (0) | 2022.08.11 |
[dart] dart에서 list 항목 비교하여 새로운 list 만들기 (0) | 2022.08.08 |
Comments