반응형

이번에는 전자 액자 앱을 만들어 보자!!

여러 이미지를 슬라이딩하여 볼 수 있는 전자 액자이다.

Layout

 - 위젯을 좌우로 스와이프 할 수 있는 PageView 하나로 구성

 

1. 앱에서 사용할 이미지를 가져온다.

 - [프로젝트 디렉토리]/asset/img 폴더 아래에 이미지를 복사한다.

    √ [프로젝트 디렉토리]/asset/img/image_1.jpeg

    √ [프로젝트 디렉토리]/asset/img/image_2.jpeg

    √ [프로젝트 디렉토리]/asset/img/image_3.jpeg

    √ [프로젝트 디렉토리]/asset/img/image_4.jpeg

    √ [프로젝트 디렉토리]/asset/img/image_5.jpeg

 

2. 추가된 이미지(에셋)을 pubspec.yaml 에 등록한다.

 - [프로젝트 디렉토리]/pubspec.yaml

....

# The following section is specific to Flutter packages.
flutter:

  # The following line ensures that the Material Icons font is
  # included with your application, so that you can use the icons in
  # the material Icons class.
  uses-material-design: true

  assets:
    - asset/img/
 
 ....

 

3. 앱의 기본 홈 화면으로 사용할 HomeScreen 위젯을 생성한다.

 - [프로젝트 디렉토리]/lib/screen/home_screen.dart

import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Text('Home Screen'),
    );
  }
}

 

4. 앱 실행 시 HomeScreen 을 사용하도록 한다.

 - [프로젝트 디렉토리]/lib/main.dart

import 'package:[프로젝트 이름]/screen/home_screen.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HomeScreen(),
    ),
  );
}

 

5. PageView 구현

 - PageView 는 여러개의 위젯을 독립적인 페이지로 생성하고 가로 또는 세로 스와이프로 페이지를 넘길 수 있게 하는 위젯이다.

 - PageView 는 material 패키지에서 기본으로 제공

 - children 변수에 페이지로 생성하고 싶은 위젯을 넣어준다.

 - 핸드폰 크기와 이미지의 크기가 달라서 위아래로 흰색 여백이 생길수 있다. 핸드폰 화면 비율에 따라 위아래 대신 좌우가 남거나 운좋게 딱 맞을 수 도 있다. 여러 비율의 화면에 대응할 수 있게 이미지 fit 을 조절해줘서 항상 전체 화면을 차지하도록 설정한다.(fit: BoxFit.cover)

import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      body: PageView(
        controller: pageController,
        // ➊ PageView 추가
        children: [1, 2, 3, 4, 5] // ➋ 샘플 리스트 생성
            .map(
              // ➌ 위젯으로 매핑
              (number) => Image.asset(
                'asset/img/image_$number.jpeg',
                fit: BoxFit.cover,
              ),
            )
            .toList(),
      ),
    );
  }
}

 - BoxFit 관련해서는 Flutter 설명 페이지를 참고.

 

BoxFit enum - painting library - Dart API

How a box should be inscribed into another box. See also: applyBoxFit, which applies the sizing semantics of these values (though not the alignment semantics). Inheritance Constructors BoxFit() const Values fill → const BoxFit Fill the target box by dist

api.flutter.dev

 

6. 상태 바 변경

 - 상태바 : 앱 실행중에 배터리, 시간, 와이파이 연결 상태 등을 보여주는 영역

 - 상태바의 글자 및 아이콘 색상이 검정색이라 잘 안보여 흰색으로 변경.

 - SystemChrome 클래스 : 시스템 UI 의 그래픽 설정을 변경하는 기능 제공.

 - 상태바 변경 : SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);

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

class HomeScreen extends StatelessWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
  
 	// 상태바가 이미 흰색이면 light 대신 dark 로 설정하여 검정색으로 변경.
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);

    return Scaffold(
      body: PageView(
        controller: pageController,
        children: [1, 2, 3, 4, 5]
            .map(
              (number) => Image.asset(
                'asset/img/image_$number.jpeg',
                fit: BoxFit.cover,
              ),
            )
            .toList(),
      ),
    );
  }
}

 

 

7. 타이머 추가

 - 일정 시간이 지나면 자동으로 페이지가 변경되도록 Timer 클래스를 사용하여 자동 롤링 기능 추가.

※ Timer 를 추가하려면 HomeScreen 위젯을 StatelessWidget 이 아닌 StatefulWidget 으로 변경해야 한다. StatelessWidget 위젯을 사용하면 Timer 를 build() 에서 등록해야 하는데 이럴경우 위젯이 새로 생성될 때마다 매번 새로운 Timer 가 생성된다. 이렇게 구현하면 Memory leak 이 발생한다.

 - 따라서, StatefulWidget 위젯을 사용하여 initState() 에서 한번만 Timer 를 등록하여 구현하면 된다.

 - Timer 를 사용하기 위해 async 패키지를 import 한다.

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async'; // ❶ async 패키지

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

// ❷ State 정의
class _HomeScreenState extends State<HomeScreen> {

  @override
  void initState() {
    super.initState(); // ➌ 부모 initState() 실행

    Timer.periodic(
      // ➍ Timer.periodic() 등록
      Duration(seconds: 3),
      (timer) {
        print('실행!');
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);

    return Scaffold(
      body: PageView(
        controller: pageController,
        children: [1, 2, 3, 4, 5]
            .map(
              (number) => Image.asset(
                'asset/img/image_$number.jpeg',
                fit: BoxFit.cover,
              ),
            )
            .toList(),
      ),
    );
  }
}

① Timer 를 사용하기 위해 async 패키지를 import 한다.

② initState() 함수를 override 하면 StatefulWidget 생명주기에서의 initState() 함수를 사용할 수 있다.

③ 모든 initState() 함수는 부모의 initState() 함수를 호출해야 한다.

④ 3초마다 실행되는 Timer 등록.

 

8. PageController 사용

 - PageView 를 조작하기 위해 PageController 사용.

 - PageController 를 State 에 선언하고 PageView 에 매개변수로 입력

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  // ❶ PageController 생성
  final PageController pageController = PageController();

  @override
  void initState() {
    super.initState();

    Timer.periodic(
      Duration(seconds: 3),
      (timer) {
      
        // ➌ 현재 페이지 가져오기.
        int? nextPage = pageController.page?.toInt();

        // 페이지 값이 없을 때 예외 처리
        if (nextPage == null) {
          return;
        }
        
        // 첫페이지와 마지막 페이지 분기 처리
        if (nextPage == 4) {
          nextPage = 0;
        } else {
          nextPage++;
        }
        pageController.animateToPage(
          // ➍ 페이지 변경
          nextPage,
          duration: Duration(milliseconds: 500),
          curve: Curves.ease,
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.light);

    return Scaffold(
      body: PageView(
      // ❷ PageController 등록
        controller: pageController,
        children: [1, 2, 3, 4, 5]
            .map(
              (number) => Image.asset(
                'asset/img/image_$number.jpeg',
                fit: BoxFit.cover,
              ),
            )
            .toList(),
      ),
    );
  }
}

PageController 사용을 위한 생성.

PageView 에 매개변수로 PageController  등록

③ pageController.page Getter 를 사용하여 PageView 의 현재 페이지를 가져올 수 있다. 페이지가 변경 중인 경우 소수점으로 표현돼서 double 로 값이 반환된다. animateToPage() 함수 실행시 정수값을 넣어줘야해서 toInt() 로 변환한다.

④ animateToPage() 함수를 이용해서 PageView 의 현재 페이지를 변경할 수 있다. curve 매개변수는 페이지가 변경되는 애니메이션의 작동 방식을 정의한다.  공식 홈페이지에서 애니메이션을 확인할 수 있다.

 

Curves class - animation library - Dart API

A collection of common animation curves. See also: Curve, the interface implemented by the constants available from the Curves class. Properties hashCode → int The hash code for this object. read-onlyinherited runtimeType → Type A representation of the

api.flutter.dev

 

이제 모든 코드 작성이 끝났다.

열심히 만든 앱을 실행 시켜보자.

짜잔~~~ 나만의 액자 앱이 잘~~ 만들어 진 것을 확인할 수 있다!!

반응형

+ Recent posts