티스토리 뷰

728x90
반응형

[1] 용어

보통 Marquee 라고 부르는 것은 두가지 타입이 있습니다.

 

1) 계속 한 방향으로 흘러가는 Marquee

 

 

 

 

2) 왼쪽 갔다가 오른쪽 갔다가(?) 를 계속 반복하는 Marquee

 

 

이 두개를 각각 나눠 말하는 일반적인 용어를 찾고 싶었는데 못찾았습니다,,,

보통은(특히 웹에서) 1번 타입을 Marquee라고 많이 부르고 있기는 합니다,,  (marquee는 현수막이라는 뜻이에요)

 

 

그러면 2번을 PingpongMarquee 라고 네이밍해서 일단 만들어보겠습니다. (이름이 잘 안떠오르네요,,😳)

 

 

===> (추가)  여기 블로그 에서 봤는데 html에서는 1번을 scroll, 2번을 alternate 속성이라고 부른다고 합니다

 

 

[2] PingpongMarquee 만들기 

 

# Step 1. 

 

우선 statefulWidget을 만들고 items를 받게 만들어줍니다. 

 

 

import 'package:flutter/cupertino.dart';
class PingpongMarquee extends StatefulWidget {
final List<Widget> items;
PingpongMarquee({
Key key,
@required this.items,
}): super(key: key);
@override
_PingpongMarqueeState createState() => _PingpongMarqueeState();
}
class _PingpongMarqueeState extends State<PingpongMarquee> {
@override
Widget build(BuildContext context) {
return Container();
}
}

 

 

 

# Step 2.

 

그 다음 SingleChildScrollView를 사용해줍니다. 

주입받은 items를 스크롤뷰로 감싸줍니다.

사용자가 스크롤할 수 있는 것을 막기 위해 NeverScrollableScrollPhysics 를 설정해줍니다.

 

 

import 'package:flutter/cupertino.dart';
class PingpongMarquee extends StatefulWidget {
final List<Widget> items;
PingpongMarquee({
Key key,
@required this.items,
}): super(key: key);
@override
_PingpongMarqueeState createState() => _PingpongMarqueeState();
}
class _PingpongMarqueeState extends State<PingpongMarquee> {
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(children: widget.items),
physics: NeverScrollableScrollPhysics(), // not allow the user to scroll.
);
}
}

 

 

 

# Step 3. 

 

그 다음 scroll을 직접 컨트롤해주고 싶으니까 scrollController를 넣어줍니다.

 

 

class _PingpongMarqueeState extends State<PingpongMarquee> {
ScrollController _scrollController;
@override
void initState() {
_scrollController = ScrollController();
super.initState();
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(children: widget.items),
controller: _scrollController,
physics: NeverScrollableScrollPhysics(),// not allow the user to scroll.
);
}
@override
void dispose(){
_scrollController.dispose();
super.dispose();
}
}

 

 

 

# Step 4. 

 

그 다음 addPostFrameCallback 을 등록해줍니다.

build 메소드가 끝난 후, 한번 불리는 콜백입니다.  보통 위젯들 setup이 다 끝난 후 처음 해줘야하는 작업에 사용합니다. (참고)

 

 

그리고 여기 콜백(FrameCallback)으로 Future.doWhile 을 넘겨줄 건데,

False가 반환될 때까지 작업을 반복적으로 수행해준다고 합니다. 

 

 

 

반복시킬 작업으로는 스크롤 시키는 것을 넣을 것이기 때문에 

위젯 setup이 끝나고 작업이 시작되도록  addPostFrameCallback 를 사용한 것입니다!  

(안그러면 scrollController가 scrollView에 아직 안붙었다~~ 이런 에러 나더라구요!)

 

 

이렇게 하면 

true를 반환하니까 계속 작업이 무한반복됩니다.

 

class _PingpongMarqueeState extends State<PingpongMarquee> {
ScrollController _scrollController;
@override
void initState() {
_scrollController = ScrollController();
WidgetsBinding.instance.addPostFrameCallback((_) async {
print("addPostFrameCallback");
Future.doWhile(_scroll);
});
super.initState();
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(children: widget.items),
controller: _scrollController,
physics: NeverScrollableScrollPhysics(),// not allow the user to scroll.
);
}
@override
void dispose(){
_scrollController.dispose();
super.dispose();
}
Future<bool> _scroll() async {
print("scroll");
return true;
}
}

 

 

App에서 Marquee를 만들어서 테스트해보겠습니다.

 

import 'package:flutter/cupertino.dart';
import 'pingpongmarquee.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoApp(
home: _RootWidget()
);
}
}
class _RootWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return PingpongMarquee(items: []);
}
}
view raw app_test_1.dart hosted with ❤ by GitHub

 

 

이렇게 출력 결과가 나오는 것을 볼 수 있습니다. (scroll이 계속 프린트 됩니다)

addPostFrameCallback
scroll
scroll
scroll
scroll
...

 

 

 

# Step 5.

 

이제 테스트를 위해 넣었던 print문을 빼고

scrollView을 left, right 끝으로 scroll 시켜주는 코드를 넣습니다.  

 

class _PingpongMarqueeState extends State<PingpongMarquee> {
ScrollController _scrollController;
@override
void initState() {
_scrollController = ScrollController();
WidgetsBinding.instance.addPostFrameCallback((_) async {
Future.doWhile(_scroll);
});
super.initState();
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(children: widget.items),
controller: _scrollController,
physics: NeverScrollableScrollPhysics(),// not allow the user to scroll.
);
}
@override
void dispose(){
_scrollController.dispose();
super.dispose();
}
Future<bool> _scroll() async {
var pauseDuration = Duration(seconds: 1);
var animationDuration = Duration(seconds: 1);
var backDuration = Duration(seconds: 1);
await Future.delayed(pauseDuration);
_scrollController.animateTo(_scrollController.position.maxScrollExtent, duration: animationDuration, curve: Curves.easeOut);
await Future.delayed(pauseDuration);
_scrollController.animateTo(_scrollController.position.minScrollExtent, duration: backDuration, curve: Curves.easeOut);
return true;
}
}

 

 

 

# Step 6.

 

마지막으로 duration도 주입 가능하게 바꿔주면 끝! 

 

import 'package:flutter/cupertino.dart';
class PingpongMarquee extends StatefulWidget {
final List<Widget> items;
final Duration animationDuration, backDuration, pauseDuration;
PingpongMarquee({
Key key,
@required this.items,
this.animationDuration = const Duration(seconds: 1),
this.backDuration = const Duration(seconds: 1),
this.pauseDuration = const Duration(seconds: 1),
}): super(key: key);
@override
_PingpongMarqueeState createState() => _PingpongMarqueeState();
}
class _PingpongMarqueeState extends State<PingpongMarquee> {
ScrollController _scrollController;
@override
void initState() {
_scrollController = ScrollController();
WidgetsBinding.instance.addPostFrameCallback((_) async {
Future.doWhile(_scroll);
});
super.initState();
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(children: widget.items),
controller: _scrollController,
physics: NeverScrollableScrollPhysics(),// not allow the user to scroll.
);
}
@override
void dispose(){
_scrollController.dispose();
super.dispose();
}
Future<bool> _scroll() async {
await Future.delayed(widget.pauseDuration);
_scrollController.animateTo(_scrollController.position.maxScrollExtent, duration: widget.animationDuration, curve: Curves.easeOut);
await Future.delayed(widget.pauseDuration);
_scrollController.animateTo(_scrollController.position.minScrollExtent, duration: widget.backDuration, curve: Curves.easeOut);
return true;
}
}

 

 

 

# 테스트 

 

아래의 코드로 테스트해볼 수 있습니다!

이미지는 여기에서 가져왔고 (>_<..)

카카오 폰트체를 사용하였습니다. 

 

 

import 'package:flutter/cupertino.dart';
import 'pingpongmarquee.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoApp(
home: _RootWidget()
);
}
}
class _RootWidget extends StatelessWidget {
var _textStyle = TextStyle(fontFamily: "Kakao", color: CupertinoColors.white, fontSize: 100);
@override
Widget build(BuildContext context) {
return SafeArea(
right: false, // 가로모드에서는 bottom이 아니라 right를 false로 해줘야함,,
child: PingpongMarquee(
items: [
Image.asset("images/joon1.png", width: 100, height: 100),
Text(" 카페사장 ", style: _textStyle),
Image.asset("images/joon2.png", width: 100, height: 100),
Text(" 최준 ", style: _textStyle),
Image.asset("images/joon1.png", width: 100, height: 100),
Text(" ☕️ ", style: _textStyle),
Image.asset("images/joon2.png", width: 100, height: 100),
],
animationDuration: Duration(seconds: 2),
backDuration: Duration(seconds: 2),
pauseDuration: Duration(seconds: 2),
)
);
}
}

 

 

 

 

 

Reference

pub.dev/packages/marquee

 

marquee | Flutter Package

⏩ A Flutter widget that scrolls text infinitely. Provides many customizations including custom scroll directions, durations, curves as well as pauses after every round.

pub.dev

stackoverflow.com/questions/51772543/how-to-make-a-text-widget-act-like-marquee-when-the-text-overflows-in-flutter

 

How to make a Text widget act like marquee when the text overflows in Flutter

I'm looking for a way to implement Marquee style on a Text widget so that it automatically start scrolling when the text is overflowed from the screen. Is there a way to do it. I've tried all the

stackoverflow.com

 

 

Resource

much-merch.com/product/최준-귀여워-핀자석-버튼-3개-세트-발렌타인-한정/768/category/213/display/1/

 

최준 귀여워 핀/자석 버튼 3개 세트 (발렌타인 한정)

PLEASE SELECT THE DESTINATION COUNTRY AND LANGUAGE : SHIPPING TO : 가나(GHANA) SHIPPING TO : 가봉(GABON) SHIPPING TO : 가이아나(GUYANA) SHIPPING TO : 감비아(GAMBIA) SHIPPING TO : 과테말라(GUATEMALA) SHIPPING TO : 그레나다(GRENADA) SHIPPI

much-merch.com

 

- 카카오 폰트 (링크를 못찾았어요)

 

 

 

반응형
댓글

eungding님의
글이 좋았다면 응원을 보내주세요!