스마트시대

VIDEO TIMELINE 7.5 AnimationController 7.6 AnimatedBuilder 7.7 SingleTickerProviderStateMixin 7.8 Video UI 7.9 RefreshIndicator 본문

Programing/Flutter

VIDEO TIMELINE 7.5 AnimationController 7.6 AnimatedBuilder 7.7 SingleTickerProviderStateMixin 7.8 Video UI 7.9 RefreshIndicator

스마트시대 2023. 5. 16. 10:50
728x90

7.5 AnimationController 

animation을 커스터마이즈하는 요소 아래와 같이 써주기

1. 이벤트 리스너를 사용하는 방법

// 위의 중간값을 애니메이션 처리해주는(밑에 build 매소드가 중간값 읽기위한) 이벤트 리스너1
_animationController.addListener(() {
setState(() {});
});
}
      VideoPlayerController.asset("assets/videos/video.mp4");
-----------
  //animation을 커스터마이즈하는 함수
  final Duration _animationDuration = const Duration(milliseconds: 200);
  late final AnimationController _animationController;
  bool _isPaused = false;
  -----------
  
    //VideoPlayerController이용하기 위한 함수
  void _initVideoPlayer() async {
    await _videoPlayerController.initialize();

    //autoplay
    // _videoPlayerController.play();


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

    -----------
    //animation을 커스터마이즈하는 parameter
    _animationController = AnimationController(
      vsync: this,
      lowerBound: 1.0,
      upperBound: 1.5,
      value: 1.5, //디폴트 표시
      duration: _animationDuration,
    );
    // 위의 중간값을 애니메이션 처리해주는(밑에 build 매소드가 중간값 읽기위한) 이벤트 리스너1
    _animationController.addListener(() {
      setState(() {});
    });
  }
      -----------
      
      
      //토글하면 화면 멈추기 파라메터
  void _onTogglePause() {
    if (_videoPlayerController.value.isPlaying) {
      _videoPlayerController.pause();
      
      
            -----------
      //정지 누르면 재생아이콘 lowerBound: 1.0된다.
      _animationController.reverse();
            -----------
            
            
    } else {
      _videoPlayerController.play();
      
            -----------
      //플레이 누르면 재생아이콘 upperBound: 1.5,된다.
      _animationController.forward();
    }
    setState(() {
      _isPaused = !_isPaused;
    });
  }
        -----------
                      onTap: _onTogglePause,
            ),
          ),
          
                  -----------
          Positioned.fill(
            //아이콘을 GestureDetector로 또 감싸는게 아닌 IgnorePointer로 _onTogglePause 이벤트리스너 듣게 하기
            child: IgnorePointer(
              child: Center(
                        //animation을 커스터마이즈하는 parameter 1
                child: Transform.scale(
                  scale: _animationController.value,
                                    -----------

 

7.6 AnimatedBuilder 

2. 위젯을 사용하는 방법

                  animation: _animationController,


--------------
                  //builder라는 함수는 animationController의 값이 변할 때마다 실행됨
                  //그럴 때마다 AnimatedBuilder는 밑의 메서드를 실행한다.
                  builder: (context, child) {
                    return Transform.scale(
                      scale: _animationController.value,
                      child: child, //여기서의 : child는 AnimatedOpacity
                    );
                  },
                  --------------

 

7.7 SingleTickerProviderStateMixin

 

class _VideoPostState extends State<VideoPost> with SingleTickerProviderStateMixin {

//animation을 커스터마이즈하는 하기 위해 클래스에 with이하 추가 //마이크로초보다 더빠른 시계로(ticker가 tick하는)매 프레임마다 callback호출함->그니까vsync로 제약둘 필요

 

    //animation을 커스터마이즈하는 parameter
    _animationController = AnimationController(
      //offscreen의 불필요한 리소스 사용막기:위젯이 안보일때는 애니 작동안함
      //this:_VideoPostState class
      vsync: this,
      lowerBound: 1.0,
      upperBound: 1.5,
      //디폴트 표시
      value: 1.5,
      duration: _animationDuration,
    );

 

7.8 Video UI 

video_timeline_screen.dart

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

 

video_post.dart

  //VideoPlayerController이용하기 위한 함수
  void _initVideoPlayer() async {
    await _videoPlayerController.initialize();
          
          -----------------
    //한 영상 반복되게 해주는 파라메터
    await _videoPlayerController.setLooping(true);
          
          -----------------
          
          
    //autoplay
    // _videoPlayerController.play();

    //VideoPlayerController를 어떻게 처리해줄 지 지정하는 listener
    _videoPlayerController.addListener(_onVideoChange);
    setState(() {});
    
    
    
FontAwesomeIcons.play,
                      color: Colors.white,
                      size: Sizes.size52,
                    ),
                  ),
                ),
              ),
            ),
          ),
          
          
          
          -----------------
          Positioned(
            bottom: 30,
            left: 30,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: const [
                Text(
                  "@jun",
                  style: TextStyle(
                    fontSize: Sizes.size20,
                    color: Colors.white,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                Gaps.v10,
                Text(
                  "This is my!!",
                  style: TextStyle(
                    fontSize: Sizes.size16,
                    color: Colors.white,
                              
          -----------------
                  ),
                )
              ],
            ),
          ),
        ],
      ),
    );
  }
}

          Positioned(
            bottom: 20,
            right: 10,
            child: Column(
              children: const [
                CircleAvatar(
                  radius: 25,
                  backgroundColor: Colors.black,
                  foregroundColor: Colors.white,
                  foregroundImage: NetworkImage(
                      "https://cdn.buymeacoffee.com/uploads/profile_pictures/2023/04/OX84VPRnUx1KYSpk.png@300w_0e.webp"),
                  child: Text("joon"),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

반복 사용을 위해 아래 위젯 따로 보관

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

class VideoButton extends StatelessWidget {
  final IconData icon;
  final String text;

  const VideoButton({
    super.key,
    required this.icon,
    required this.text,
  });

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        FaIcon(
          icon,
          color: Colors.white,
          size: Sizes.size36,
        ),
        Gaps.v5,
        Text(
          text,
          style: const TextStyle(
            color: Colors.white,
            fontWeight: FontWeight.bold,
          ),
        ),
      ],
    );
  }
}
                  child: Text("joon"),
                ),
                
                ---------------
                Gaps.v24,
                VideoButton(
                  icon: FontAwesomeIcons.solidHeart,
                  text: "2.9M",
                ),
                Gaps.v24,
                VideoButton(
                  icon: FontAwesomeIcons.solidComment,
                  text: "33K",
                ),
                Gaps.v24,
                VideoButton(
                  icon: FontAwesomeIcons.share,
                  text: "Share",
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

 

7.9 RefreshIndicator 

// 비디오가 끝나면 어떻게 처리할지의 함수,보고 있지 않을 때도 캐쉬 살려두기 위함
  @override
  void dispose() {
    _pageController.dispose();
    super.dispose();
  }
---------------------
  //유저가 당겨서 타임라인을 새로고침하는 함수
  Future<void> _onRefresh() {
    return Future.delayed(
      const Duration(seconds: 5),
    );
  }
---------------------
  @override
  Widget build(BuildContext context) {
  
  ---------------------
    //유저가 당겨서 타임라인을 새로고침하는 위젯
    return RefreshIndicator(
      onRefresh: _onRefresh,
---------------------


      // 유용한 새 위젯
      child: PageView.builder(
        //스크린 넘어갈 때 느려지는 효과 없애는 파라미터
        controller: _pageController,

하지만 문제는

1.아이폰 노치가 새로고침 마크 막고 있음

2.돌아갈 때 살짝 가려져있음

  Widget build(BuildContext context) {
    //유저가 당겨서 타임라인을 새로고침하는 위젯
    return RefreshIndicator(
      onRefresh: _onRefresh,
      
      
      ----------------
      displacement: 50,
      edgeOffset: 20,
      color: Theme.of(context).primaryColor,
            ----------------
      // 유용한 새 위젯
      child: PageView.builder(

그래서 위치와 색깔도 바꾸고

 

main_navigation_screen의 build scaffold가 디폴트는 흰색이니까 이렇게 바꾸자

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

 

 

여기서 아래 조건문 추가하기

"삭제"가 된 컨트롤러(VideoPlayerController)를 호출해서 생긴 에러가 생겼을 떄  "이미 삭제가 되어있는 상태" 가 생기는 걸 방지하기 위해

 

위젯이 트리에 있어서 mount되면 true를 반환할거니까 visibility에 변화가 있더라도, mount된 상태가 아니라면 아무것도 하지 않게 하는 조건문

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

// 비디오가 보여지는 영역을 계산하고 한쪽에서만 영상 재생되도록 해주는 파라메터
  void _onVisibilityChanged(VisibilityInfo info) {
  
  
  -------------------
    // mounted property: 위젯이 마운트되었는지 아닌지 알려줌
    if (!mounted) return;
  -------------------
  
  
    if (info.visibleFraction == 1 &&
        !_isPaused &&
        !_videoPlayerController.value.isPlaying) {
      _videoPlayerController.play();
    }
728x90
반응형
Comments