👻

Flutterでウォークスルー的なものを作る

4 min read
/// lib/views/screens/start_screen.dart

import 'package:flutter/material.dart';

import '../components/start/page_view_dots.dart';
import '../components/start/start_screen_page_view.dart';

class StartScreen extends StatefulWidget {
  const StartScreen();

  
  _StartScreenState createState() => _StartScreenState();
}

class _StartScreenState extends State<StartScreen> {
  int _currentPageIndex = 0;

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        bottom: false,
        child: Stack(
          alignment: Alignment.bottomCenter,
          children: <Widget>[
            _buildPageView,
            SafeArea(
              child: _buildButtonAndDotsArea,
            ),
          ],
        ),
      ),
    );
  }

  Widget get _buildPageView {
    return StartScreenPageView(
      onPageChanged: _onPageChanged,
    );
  }

  void _onPageChanged(int index) {
    setState(() => _currentPageIndex = index);
  }

  Widget get _buildButtonAndDotsArea {
    return Column(
      mainAxisAlignment: MainAxisAlignment.end,
      children: <Widget>[
        const SizedBox(height: 16),
        _buildDots,
        const SizedBox(height: 26),
      ],
    );
  }

  Widget get _buildDots {
    return PageViewDots(
      pageCount: pageItems.length,
      currentPageIndex: _currentPageIndex,
    );
  }
}

/// lib/views/components/start/start_screen_page_view.dart

import 'package:flutter/material.dart';

import '../../../constants/image_paths.dart' as image_paths;

class _PageItem {
  const _PageItem({
    required this.bgImagePath,
  });

  final String bgImagePath;
}

const pageItems = <_PageItem>[
  _PageItem(
    bgImagePath: image_paths.bg1,
  ),
  _PageItem(
    bgImagePath: image_paths.bg2,
  ),
  _PageItem(
    bgImagePath: image_paths.bg3,
  ),
];

class StartScreenPageView extends StatelessWidget {
  const StartScreenPageView({
    required this.onPageChanged,
  });

  final Function(int index) onPageChanged;

  
  Widget build(BuildContext context) {
    return PageView.builder(
      onPageChanged: onPageChanged,
      itemCount: pageItems.length,
      itemBuilder: (_, index) => _buildPage(pageItems[index]),
    );
  }

  Widget _buildPage(_PageItem item) {
    return SizedBox(
      height: double.infinity,
      width: double.infinity,
      child: _buildBGImage(item.bgImagePath),
    );
  }

  Widget _buildBGImage(String imagePath) {
    return Image.asset(
      imagePath,
      fit: BoxFit.fill,
    );
  }
}

/// lib/views/components/start/page_view_dots.dart

import 'package:flutter/material.dart';

import 'page_view_dots/page_view_dot.dart';

class PageViewDots extends StatelessWidget {
  const PageViewDots({
    required this.pageCount,
    required this.currentPageIndex,
  });

  final int pageCount;
  final int currentPageIndex;

  static const _spacing = 11.2;
  static const _dotDiameter = 8.0;

  
  Widget build(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        for (var i = 0; i < pageCount; i++)
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: _spacing / 2),
            child: _buildDot(i),
          ),
      ],
    );
  }

  Widget _buildDot(int index) {
    final isActive = index == currentPageIndex;
    return PageViewDot(
      isActive: isActive,
      diameter: _dotDiameter,
    );
  }
}

/// lib/views/components/start/page_view_dots/page_view_dot.dart

import 'package:flutter/material.dart';

class PageViewDot extends StatelessWidget {
  const PageViewDot({
    required this.isActive,
    required this.diameter,
  });

  final bool isActive;
  final double diameter;

  
  Widget build(BuildContext context) {
    return Container(
      width: diameter,
      height: diameter,
      decoration: _decoration,
    );
  }

  Decoration get _decoration {
    return BoxDecoration(
      color: isActive ? _activeColor : _deActiveColor,
      shape: BoxShape.circle,
    );
  }

  Color get _activeColor => const Color(0xffFFC700);
  Color get _deActiveColor => const Color.fromARGB(179, 255, 255, 255);
}