스마트시대

VIDEO TIMELINE 7.1 Infinite Scrolling 7.2 PageController 7.3 Video Player 7.4 VisibilityDetector 본문

Programing/Flutter

VIDEO TIMELINE 7.1 Infinite Scrolling 7.2 PageController 7.3 Video Player 7.4 VisibilityDetector

스마트시대 2023. 5. 14. 01:03
728x90

7.1 Infinite Scrolling

stf_screen.dart관련 데이터 다 지우고

 

main_navigation_screen.dart

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // // 선택된 탭의 페이지만 보여주기: 항상 새로운 페이지로써 표시됨
      // body: screens.elementAt(_selectedIndex),
      // offStage: 해당 위젯을 안 보이게 하면서 계속 존재하게 해주는 위젯
      body: Stack(
        children: [
        
        ---------------------
          Offstage(
            offstage: _selectedIndex != 0,
            child: const VideoTimelineScreen(),
               ---------------------
               
               
          ),
          Offstage(
            offstage: _selectedIndex != 1,
            child: Container(),
          ),

video_timeline_screen.dart 새로 만들기

import 'package:flutter/material.dart';

class VideoTimelineScreen extends StatefulWidget {
  const VideoTimelineScreen({super.key});

  @override
  State<VideoTimelineScreen> createState() => _VideoTimelineScreenState();
}

class _VideoTimelineScreenState extends State<VideoTimelineScreen> {
  @override
  Widget build(BuildContext context) {
    return PageView(
      children: [
        Container(
          color: Colors.blue,
        ),
        Container(
          color: Colors.teal,
        ),
        Container(
          color: Colors.yellow,
        ),
        Container(
          color: Colors.pink,
        ),
      ],
    );
  }
}

 

참고 property

    // 유용한 새 위젯
    return PageView(
    --------------
      // 자석 같이 화면이 딱딱 달라붙는 효과
      pageSnapping: false,
          --------------
          
      children: [
        Container(

 

    // 유용한 새 위젯
    return PageView(
      // 자석 같이 화면이 딱딱 달라붙는 효과 property
      //pageSnapping: false,
      
      -------------
      
      // 위로 스크롤 할 수 있는 property
      scrollDirection: Axis.vertical,
            -------------
            
      children: [
        Container(
          color: Colors.blue,
        ),

 

하지만 위 코드로 하면 퍼포먼스가 너무 떨어진다. 컨테이너 하나하나 데이터 처리하기 떄문에.

그래서 사용할게 Pageview.builder(itemBuilder: ) 이다.

import 'package:flutter/material.dart';

class VideoTimelineScreen extends StatefulWidget {
  const VideoTimelineScreen({super.key});

  @override
  State<VideoTimelineScreen> createState() => _VideoTimelineScreenState();
}

class _VideoTimelineScreenState extends State<VideoTimelineScreen> {
  List<Color> colors = [
    Colors.blue,
    Colors.red,
    Colors.yellow,
    Colors.teal,
  ];

  @override
  Widget build(BuildContext context) {
    // 유용한 새 위젯
    return PageView.builder(
      // 자석 같이 화면이 딱딱 달라붙는 효과 property
      //pageSnapping: false,
      // 위로 스크롤 할 수 있는 property
      scrollDirection: Axis.vertical,
      itemCount: 4,
      itemBuilder: (context, index) => Container(
        color: colors[index],
      ),
    );
  }
}

페이지 무한으로 증식하게 해주는 세팅

import 'package:flutter/material.dart';

class VideoTimelineScreen extends StatefulWidget {
  const VideoTimelineScreen({super.key});

  @override
  State<VideoTimelineScreen> createState() => _VideoTimelineScreenState();
}

class _VideoTimelineScreenState extends State<VideoTimelineScreen> {


------------------
  int _itemCount = 4;

  void _onPageChanged(int page) {
    if (page == _itemCount - 1) {
      _itemCount = _itemCount + 4;
      colors.addAll([
        Colors.blue,
        Colors.red,
        Colors.yellow,
        Colors.teal,
      ]);
      setState(() {});
    }
  }
------------------


  List<Color> colors = [
    Colors.blue,
    Colors.red,
    Colors.yellow,
    Colors.teal,
  ];

  @override
  Widget build(BuildContext context) {
    // 유용한 새 위젯
    return PageView.builder(
      // 자석 같이 화면이 딱딱 달라붙는 효과 property
      //pageSnapping: false,
      // 위로 스크롤 할 수 있는 property
      scrollDirection: Axis.vertical,
      
      ------------------
      onPageChanged: _onPageChanged,
      itemCount: _itemCount,
      ------------------

      itemBuilder: (context, index) => Container(
        color: colors[index],
        
              ------------------
        child: Center(
          child: Text(
            "Screen $index",
            style: const TextStyle(fontSize: 68),
                  ------------------
          ),
        ),
      ),
    );
  }
}

 

7.2 PageController 

끝에 자석효과 없애고 그냥 확확 넘어가게 해주는 설정

import 'package:flutter/material.dart';

class VideoTimelineScreen extends StatefulWidget {
  const VideoTimelineScreen({super.key});

  @override
  State<VideoTimelineScreen> createState() => _VideoTimelineScreenState();
}

class _VideoTimelineScreenState extends State<VideoTimelineScreen> {
-----------------
  int _itemCount = 4;

//스크린 넘어갈 때 느려지는 효과 없애는 함수:Pageview.builder를 컨트롤 하는 파라미터
  final PageController _pageController = PageController();
-----------------

  void _onPageChanged(int page) {
  
  -----------------
    //스크린 넘어갈 때 느려지는 효과 없애는 함수
    //curve:애니메이션의 종류
    _pageController.animateToPage(
      page,
      duration: const Duration(microseconds: 100),
      curve: Curves.linear,
    );
    -----------------
    
    
    if (page == _itemCount - 1) {
      //페이지 무한으로 증식하게 해주는 함수
      _itemCount = _itemCount + 4;
      colors.addAll([
        Colors.blue,
        Colors.red,
        Colors.yellow,
        Colors.teal,
      ]);
      setState(() {});
    }
  }


  @override
  Widget build(BuildContext context) {
    // 유용한 새 위젯
    
    return PageView.builder(
    -----------------
      //스크린 넘어갈 때 느려지는 효과 없애는 파라미터
      controller: _pageController,
-----------------

      // 자석 같이 화면이 딱딱 달라붙는 효과 property
      //pageSnapping: false,

 

7.3 Video Player

여기다가 샘플 비디오 넣어주고

 

puvspec.yaml에서 변경

 

video_post.dart

import 'package:flutter/material.dart';

class VideoPost extends StatefulWidget {
  const VideoPost({super.key});

  @override
  State<VideoPost> createState() => _VideoPostState();
}

class _VideoPostState extends State<VideoPost> {
  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Positioned.fill(
          child: Container(
            color: Colors.teal,
          ),
        ),
      ],
    );
  }
}



 

import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';

class VideoPost extends StatefulWidget {
  const VideoPost({super.key});

  @override
  State<VideoPost> createState() => _VideoPostState();
}

class _VideoPostState extends State<VideoPost> {

--------------
  //VideoPlayerController이용하기 위한 함수
  final VideoPlayerController _videoPlayerController =
      VideoPlayerController.asset("assets/videos/video.mp4");

  //VideoPlayerController이용하기 위한 함수
  void _initVideoPlayer() async {
    await _videoPlayerController.initialize();
    _videoPlayerController.play();
    setState(() {});
  }

  @override
  //VideoPlayerController이용하기 위한 함수1
  void initState() {
    super.initState();
    _initVideoPlayer();
  }

  //VideoPlayerController이용하기 위한 함수2
  @override
  void dispose() {
    _videoPlayerController.dispose();
  }
--------------

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
 
 --------------
        Positioned.fill(
          child: _videoPlayerController.value.isInitialized
              ? VideoPlayer(_videoPlayerController)
              : Container(
                  color: Colors.black,
 --------------                 
                ),
        ),
      ],
    );
  }
}

여기에서 _pageController관련 파라메터따로 분리해주고 _onPageChanged _onVideoFinished 함수에 파라메터 적용해주기

//스크린 넘어갈 때 느려지는 효과 없애는 함수:Pageview.builder를 컨트롤 하는 파라미터
  final PageController _pageController = PageController();
-----------------
  //_pageController관련 파라메터
  final Duration _scrollDuration = const Duration(microseconds: 150);
  final Curve _scrollCurve = Curves.linear;
-----------------



  void _onPageChanged(int page) {
    //스크린 넘어갈 때 느려지는 효과 없애는 함수
    //curve:애니메이션의 종류
    _pageController.animateToPage(
      page,
   -----------------   
      duration: _scrollDuration,
      curve: _scrollCurve,
  -----------------    
    );
    if (page == _itemCount - 1) {
 
 
 
 
-----------------
  // 비디오가 끝나면 어떻게 처리할지의 함수
  void _onVideoFinished() {
    _pageController.nextPage(
      duration: _scrollDuration,
      curve: _scrollCurve,
    );
  }
-----------------

 

여기서 이 처리해주고

 

      //페이지 무한으로 증식하게 해주는 파라미터
      onPageChanged: _onPageChanged,
      itemCount: _itemCount,
      
      --------------
      itemBuilder: (context, index) => VideoPost(
          onVideoFinished:
              _onVideoFinished), //VideoPost로 넘기고 onVideoFinished 처리(다음 비디오로 넘어가기)
      //->VideoPost의 statefulwidget으로 넘겨줌(state한테가 아니라)
            --------------
    );
  }

여기서 이 처리 해줌

class VideoPost extends StatefulWidget {

-----------------
  //onVideoFinished 처리해주기 위한 property,statefulWideget은 여기 있는데 작업은 state에서 해줄 필요
  final Function onVideoFinished;

  //onVideoFinished 처리해주기 위한 property의 costructor->이거는 State<VideoPost>로 접근
  //위젯 자체에 접근하게 해주는 것 밑에 만들어줄 필요,statefulWideget은 여기 있는데 작업은 state에서 해줄 필요
  const VideoPost({
    super.key,
    required this.onVideoFinished,
  });
-----------------

  @override
  State<VideoPost> createState() => _VideoPostState();
}


  //VideoPlayerController이용하기 위한 함수2, 보고 있지 않을 때도 캐쉬 살려두기 위함
  @override
  void dispose() {
    _videoPlayerController.dispose();

-----------------
    //위젯 자체에 접근하게 해주는 것,statefulWideget은 위 있는데 작업은 state에서 해줄 필요
    widget.onVideoFinished();
  }
  -----------------

 

영상이 끝났을 때를 알기 위한 event listener 작성

listener가 영상이 바뀌는 시간, 길이, 끝나는 시간 등을 모두 알려줄 수 있음

  final VideoPlayerController _videoPlayerController =
      VideoPlayerController.asset("assets/videos/video.mp4");
-------------------
  //VideoPlayerController를 어떻게 처리해줄 지 지정하는 listener에 넣어줄 파라메터
  //_videoPlayerController.value.duration(비디오길이)가 10초이고 _videoPlayerController.value.position(현재영상내의위치)이 10초이면 영상 끝냄처리
  void _onVideoChange() {
    if (_videoPlayerController.value.isInitialized) {
      if (_videoPlayerController.value.duration ==
          _videoPlayerController.value.position) {
        //위젯 자체에 접근하게 해주는 것,statefulWideget은 위 있는데 작업은 state에서 해줄 필요
        widget.onVideoFinished();
      }
    }
  }
-------------------


  //VideoPlayerController이용하기 위한 함수
  void _initVideoPlayer() async {





//VideoPlayerController이용하기 위한 함수
  void _initVideoPlayer() async {
    await _videoPlayerController.initialize();
    _videoPlayerController.play();
    setState(() {});
-------------------
    //VideoPlayerController를 어떻게 처리해줄 지 지정하는 listener
    _videoPlayerController.addListener(_onVideoChange);
    -------------------
  }

 

 

import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';

class VideoPost extends StatefulWidget {
  //onVideoFinished 처리해주기 위한 property,statefulWideget은 여기 있는데 작업은 state에서 해줄 필요
  final Function onVideoFinished;

  //onVideoFinished 처리해주기 위한 property의 costructor->이거는 State<VideoPost>로 접근
  //위젯 자체에 접근하게 해주는 것 밑에 만들어줄 필요,statefulWideget은 여기 있는데 작업은 state에서 해줄 필요
  const VideoPost({
    super.key,
    required this.onVideoFinished,
  });

  @override
  State<VideoPost> createState() => _VideoPostState();
}

class _VideoPostState extends State<VideoPost> {
  //VideoPlayerController이용하기 위한 함수
  final VideoPlayerController _videoPlayerController =
      VideoPlayerController.asset("assets/videos/video.mp4");

  //VideoPlayerController를 어떻게 처리해줄 지 지정하는 listener에 넣어줄 파라메터
  //_videoPlayerController.value.duration(비디오길이)가 10초이고 _videoPlayerController.value.position(현재영상내의위치)이 10초이면 영상 끝냄처리
  void _onVideoChange() {
    if (_videoPlayerController.value.isInitialized) {
      if (_videoPlayerController.value.duration ==
          _videoPlayerController.value.position) {
        //위젯 자체에 접근하게 해주는 것,statefulWideget은 위 있는데 작업은 state에서 해줄 필요
        widget.onVideoFinished();
      }
    }
  }

  //VideoPlayerController이용하기 위한 함수
  void _initVideoPlayer() async {
    await _videoPlayerController.initialize();
    _videoPlayerController.play();
    setState(() {});

    //VideoPlayerController를 어떻게 처리해줄 지 지정하는 listener
    _videoPlayerController.addListener(_onVideoChange);
  }

  @override
  //VideoPlayerController이용하기 위한 함수1
  void initState() {
    super.initState();
    _initVideoPlayer();
  }

  //VideoPlayerController이용하기 위한 함수2, 보고 있지 않을 때도 캐쉬 살려두기 위함
  @override
  void dispose() {
    _videoPlayerController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Positioned.fill(
          child: _videoPlayerController.value.isInitialized
              ? VideoPlayer(_videoPlayerController)
              : Container(
                  color: Colors.black,
                ),
        ),
      ],
    );
  }
}

 

import 'package:flutter/material.dart';
import 'package:tiktok_clone/features/videos/widgets/video_post.dart';

class VideoTimelineScreen extends StatefulWidget {
  const VideoTimelineScreen({super.key});
  @override
  State<VideoTimelineScreen> createState() => _VideoTimelineScreenState();
}

class _VideoTimelineScreenState extends State<VideoTimelineScreen> {
  int _itemCount = 4;

//스크린 넘어갈 때 느려지는 효과 없애는 함수:Pageview.builder를 컨트롤 하는 파라미터
  final PageController _pageController = PageController();

  //_pageController관련 파라메터
  final Duration _scrollDuration = const Duration(milliseconds: 250);
  final Curve _scrollCurve = Curves.linear;

  void _onPageChanged(int page) {
    //스크린 넘어갈 때 느려지는 효과 없애는 함수
    //curve:애니메이션의 종류
    _pageController.animateToPage(
      page,
      duration: _scrollDuration,
      curve: _scrollCurve,
    );
    if (page == _itemCount - 1) {
      //페이지 무한으로 증식하게 해주는 함수
      _itemCount = _itemCount + 4;

      setState(() {});
    }
  }

  // 비디오가 끝나면 어떻게 처리할지의 함수
  void _onVideoFinished() {
    _pageController.nextPage(
      duration: _scrollDuration,
      curve: _scrollCurve,
    );
  }

// 비디오가 끝나면 어떻게 처리할지의 함수,보고 있지 않을 때도 캐쉬 살려두기 위함
  @override
  void dispose() {
    _pageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // 유용한 새 위젯
    return PageView.builder(
      //스크린 넘어갈 때 느려지는 효과 없애는 파라미터
      controller: _pageController,

      // 자석 같이 화면이 딱딱 달라붙는 효과 property
      //pageSnapping: false,
      // 위로 스크롤 할 수 있는 property
      scrollDirection: Axis.vertical,

      //페이지 무한으로 증식하게 해주는 파라미터
      onPageChanged: _onPageChanged,
      itemCount: _itemCount,
      itemBuilder: (context, index) => VideoPost(
          onVideoFinished:
              _onVideoFinished), //VideoPost로 넘기고 onVideoFinished 처리(다음 비디오로 넘어가기)
      //->VideoPost의 statefulwidget으로 넘겨줌(state한테가 아니라)
    );
  }
}

 

7.4 VisibilityDetector

한쪽에서만 영상 재생되도록 해주는 설정

 

      //페이지 무한으로 증식하게 해주는 파라미터
      onPageChanged: _onPageChanged,
      itemCount: _itemCount,
      itemBuilder: (context, index) =>
      
      
      -------------------
          //VideoPost로 넘기고 onVideoFinished 처리(다음 비디오로 넘어가기)->VideoPost의 statefulwidget으로 넘겨줌(state한테가 아니라)
          //index로 어느 페이지 보고 있는지 체크
          VideoPost(onVideoFinished: _onVideoFinished, index: index),
    );
  }
}
      -------------------

 

    _videoPlayerController.dispose();
    super.dispose();
  }

------------------
// 비디오가 보여지는 영역을 계산하고 한쪽에서만 영상 재생되도록 해주는 파라메터
  void _onVisibilityChanged(VisibilityInfo info) {
    if (info.visibleFraction == 1 && !_videoPlayerController.value.isPlaying) {
      _videoPlayerController.play();
    }
  }
  ------------------
  
  
    @override
  Widget build(BuildContext context) {
  
    ------------------
    // 비디오가 보여지는 영역을 계산하고 한쪽에서만 영상 재생되도록 해주는 위젯
    return VisibilityDetector(
      key: Key("${widget.index}"),
      onVisibilityChanged: _onVisibilityChanged,
        ------------------
        
        
      child: Stack(
        children: [
          Positioned.fill(

      _videoPlayerController.play();
    }
  }
  
  
-----------------
//토글하면 화면 멈추기 파라메터
  void _onTogglePause() {
    if (_videoPlayerController.value.isPlaying) {
      _videoPlayerController.pause();
    } else {
      _videoPlayerController.play();
    }
  }
-----------------

  @override
  Widget build(BuildContext context) {
  
  
  
  

child: Stack(
        children: [
          Positioned.fill(
            child: _videoPlayerController.value.isInitialized
                ? VideoPlayer(_videoPlayerController)
                : Container(
                    color: Colors.black,
                  ),
          ),
          
          ---------------
          //토글하면 화면 멈추기
          Positioned.fill(
            child: GestureDetector(
              onTap: _onTogglePause,
            ),
                    ---------------

 

          //토글하면 화면 멈추기
          Positioned.fill(
            child: GestureDetector(
              onTap: _onTogglePause,
            ),
          ),
          
          -------------------
          const Positioned.fill(
            //아이콘을 GestureDetector로 또 감싸는게 아닌 IgnorePointer로 _onTogglePause 이벤트리스너 듣게 하기
            child: IgnorePointer(
              child: Center(
                child: FaIcon(
                  FontAwesomeIcons.play,
                  color: Colors.white,
                  size: Sizes.size52,
                ),
              ),
            ),
                      -------------------

 

 

import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:tiktok_clone/constants/sizes.dart';
import 'package:video_player/video_player.dart';
import 'package:visibility_detector/visibility_detector.dart';

class VideoPost extends StatefulWidget {
  //onVideoFinished 처리해주기 위한 property,statefulWideget은 여기 있는데 작업은 state에서 해줄 필요
  final Function onVideoFinished;

  //index로 어느 페이지 보고 있는지 체크
  final int index;

  //onVideoFinished 처리해주기 위한 property의 costructor->이거는 State<VideoPost>로 접근
  //위젯 자체에 접근하게 해주는 것 밑에 만들어줄 필요,statefulWideget은 여기 있는데 작업은 state에서 해줄 필요
  //index로 어느 페이지 보고 있는지 체크
  const VideoPost({
    super.key,
    required this.onVideoFinished,
    required this.index,
  });

  @override
  State<VideoPost> createState() => _VideoPostState();
}

//animation을 커스터마이즈하는 하기 위해 클래스에 with이하 추가
class _VideoPostState extends State<VideoPost>
    with SingleTickerProviderStateMixin {
  //VideoPlayerController이용하기 위한 함수
  final VideoPlayerController _videoPlayerController =
      VideoPlayerController.asset("assets/videos/video.mp4");

  final Duration _animationDuration = const Duration(milliseconds: 200);

  //animation을 커스터마이즈하는 함수
  late final AnimationController _animationController;

  bool _isPaused = false;

  //VideoPlayerController를 어떻게 처리해줄 지 지정하는 listener에 넣어줄 파라메터
  //_videoPlayerController.value.duration(비디오길이)가 10초이고 _videoPlayerController.value.position(현재영상내의위치)이 10초이면 영상 끝냄처리

  void _onVideoChange() {
    if (_videoPlayerController.value.isInitialized) {
      if (_videoPlayerController.value.duration ==
          _videoPlayerController.value.position) {
        //위젯 자체에 접근하게 해주는 것,statefulWideget은 위 있는데 작업은 state에서 해줄 필요
        widget.onVideoFinished();
      }
    }
  }

  //VideoPlayerController이용하기 위한 함수
  void _initVideoPlayer() async {
    await _videoPlayerController.initialize();

    //autoplay
    // _videoPlayerController.play();

    //VideoPlayerController를 어떻게 처리해줄 지 지정하는 listener
    _videoPlayerController.addListener(_onVideoChange);
    setState(() {});
  }

  @override
  //VideoPlayerController이용하기 위한 함수1
  void initState() {
    super.initState();
    _initVideoPlayer();

    //animation을 커스터마이즈하는 parameter
    _animationController = AnimationController(
      vsync: this,
      lowerBound: 1.0,
      upperBound: 1.5,
      value: 1.5, //디폴트 표시
      duration: _animationDuration,
    );
    // 위의 중간값을 애니메이션 처리해주는(밑에 build 매소드가 중간값 읽기위한) 이벤트 리스너1
    _animationController.addListener(() {
      setState(() {});
    });
  }

  //VideoPlayerController이용하기 위한 함수2, 보고 있지 않을 때도 캐쉬 살려두기 위함
  @override
  void dispose() {
    _videoPlayerController.dispose();
    super.dispose();
  }

// 비디오가 보여지는 영역을 계산하고 한쪽에서만 영상 재생되도록 해주는 파라메터
  void _onVisibilityChanged(VisibilityInfo info) {
    if (info.visibleFraction == 1 && !_videoPlayerController.value.isPlaying) {
      _videoPlayerController.play();
    }
  }

//토글하면 화면 멈추기 파라메터
  void _onTogglePause() {
    if (_videoPlayerController.value.isPlaying) {
      _videoPlayerController.pause();
      //정지 누르면 재생아이콘 lowerBound: 1.0된다.
      _animationController.reverse();
    } else {
      _videoPlayerController.play();
      //플레이 누르면 재생아이콘 upperBound: 1.5,된다.
      _animationController.forward();
    }
    setState(() {
      _isPaused = !_isPaused;
    });
  }

  @override
  Widget build(BuildContext context) {
    // 비디오가 보여지는 영역을 계산하고 한쪽에서만 영상 재생되도록 해주는 위젯
    return VisibilityDetector(
      key: Key("${widget.index}"),
      onVisibilityChanged: _onVisibilityChanged,
      child: Stack(
        children: [
          Positioned.fill(
            child: _videoPlayerController.value.isInitialized
                ? VideoPlayer(_videoPlayerController)
                : Container(
                    color: Colors.black,
                  ),
          ),
          //토글하면 화면 멈추기
          Positioned.fill(
            child: GestureDetector(
              onTap: _onTogglePause,
            ),
          ),
          Positioned.fill(
            //아이콘을 GestureDetector로 또 감싸는게 아닌 IgnorePointer로 _onTogglePause 이벤트리스너 듣게 하기
            child: IgnorePointer(
              child: Center(
                //animation을 커스터마이즈하는 parameter 2
                // child: AnimatedBuilder(
                //   animation: _animationController,
                //   builder: (context, child) {
                //     return Transform.scale(
                //       scale: _animationController.value,
                //       child: child,
                //     );
                //   },

                //animation을 커스터마이즈하는 parameter 1
                child: Transform.scale(
                  scale: _animationController.value,
                  child: AnimatedOpacity(
                    opacity: _isPaused ? 1 : 0,
                    duration: _animationDuration,
                    child: const FaIcon(
                      FontAwesomeIcons.play,
                      color: Colors.white,
                      size: Sizes.size52,
                    ),
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}
import 'package:flutter/material.dart';
import 'package:tiktok_clone/features/videos/widgets/video_post.dart';

class VideoTimelineScreen extends StatefulWidget {
  const VideoTimelineScreen({super.key});
  @override
  State<VideoTimelineScreen> createState() => _VideoTimelineScreenState();
}

class _VideoTimelineScreenState extends State<VideoTimelineScreen> {
  int _itemCount = 4;

//스크린 넘어갈 때 느려지는 효과 없애는 함수:Pageview.builder를 컨트롤 하는 파라미터
  final PageController _pageController = PageController();

  //_pageController관련 파라메터
  final Duration _scrollDuration = const Duration(milliseconds: 250);
  final Curve _scrollCurve = Curves.linear;

  void _onPageChanged(int page) {
    //스크린 넘어갈 때 느려지는 효과 없애는 함수
    //curve:애니메이션의 종류
    _pageController.animateToPage(
      page,
      duration: _scrollDuration,
      curve: _scrollCurve,
    );
    if (page == _itemCount - 1) {
      //페이지 무한으로 증식하게 해주는 함수
      _itemCount = _itemCount + 4;

      setState(() {});
    }
  }

  // 비디오가 끝나면 어떻게 처리할지의 함수
  void _onVideoFinished() {
    _pageController.nextPage(
      duration: _scrollDuration,
      curve: _scrollCurve,
    );
  }

// 비디오가 끝나면 어떻게 처리할지의 함수,보고 있지 않을 때도 캐쉬 살려두기 위함
  @override
  void dispose() {
    _pageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // 유용한 새 위젯
    return PageView.builder(
      //스크린 넘어갈 때 느려지는 효과 없애는 파라미터
      controller: _pageController,

      // 자석 같이 화면이 딱딱 달라붙는 효과 property
      //pageSnapping: false,
      // 위로 스크롤 할 수 있는 property
      scrollDirection: Axis.vertical,

      //페이지 무한으로 증식하게 해주는 파라미터
      onPageChanged: _onPageChanged,
      itemCount: _itemCount,
      itemBuilder: (context, index) =>
          //VideoPost로 넘기고 onVideoFinished 처리(다음 비디오로 넘어가기)->VideoPost의 statefulwidget으로 넘겨줌(state한테가 아니라)
          //index로 어느 페이지 보고 있는지 체크
          VideoPost(onVideoFinished: _onVideoFinished, index: index),
    );
  }
}
728x90
반응형
Comments