Snippets

Kevin Armstrong On-boarding - Exercise Example

Created by Kevin Armstrong
import 'package:flutter/material.dart';
import 'dart:math';

const double IMAGE_SIZE = 250.0;

class CircleWithImage extends StatelessWidget {
  final String image;

  CircleWithImage(this.image);

  Widget _centerCircle(double radius, double opacity){
    return new Positioned(
      width: radius,
      child: Container(
        width: radius,
        height: radius,
        decoration: BoxDecoration(
          shape:  BoxShape.circle,
          color: Colors.white.withOpacity(opacity),
        ),
      ),
    );
  }

  Widget _largeCircle(Size size){
    Random rnd = new Random();
    double top = rnd.nextDouble();
    double radius = rnd.nextDouble() * size.height;
    double opacity = rnd.nextDouble() * 0.1;

    return new Positioned(
      top: top,
      width: radius,
      child: Container(
        width: radius,
        height: radius,
        decoration: BoxDecoration(
          shape:  BoxShape.circle,
          color: Colors.white.withOpacity(opacity),
        ),
      ),
    );
  }

  Widget _smallCircle(Size size){
    Random rnd = new Random();
    double top = rnd.nextDouble() * size.height;
    double left = rnd.nextDouble() * size.width;
    double radius = rnd.nextDouble() * 15.0;
    double opacity = rnd.nextDouble() * 0.75;

    return new Positioned(
      top: top,
      left: left,
      width: radius,
      child: Container(
        width: radius,
        height: radius,
        decoration: BoxDecoration(
          shape:  BoxShape.circle,
          color: Colors.white.withOpacity(opacity),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final width = MediaQuery.of(context).size.width;
    List<Widget> widgets = [];
    List<Widget> smallCircles = List(10).map((_) => _smallCircle(MediaQuery.of(context).size)).toList();
    List<Widget> largeCircles = List(5).map((_) => _largeCircle(MediaQuery.of(context).size)).toList();
    List<Widget> centerCircles = [
      _centerCircle(width * 1.35, 0.07),
      _centerCircle(width * 1.25, 0.1),
      _centerCircle(width * 1.0, 0.15),
      _centerCircle(width * 0.40, 0.5),
    ];
    widgets.addAll(smallCircles);
    widgets.addAll(largeCircles);
    widgets.addAll(centerCircles);
    /*
    widgets.add(
      SizedBox(
        child: Image(
          image: AssetImage(image),
          fit: BoxFit.fitHeight,
        ),
        height: IMAGE_SIZE,
        width: IMAGE_SIZE,
      ),
    );
    */
    return Stack(
      children: widgets,
      alignment: FractionalOffset.center,
    );
  }
}
import 'dart:math';

import 'package:flutter/material.dart';

class DotsIndicator extends AnimatedWidget {
  DotsIndicator({
    this.controller,
    this.itemCount,
    this.onPageSelected,
    this.color: Colors.white,
  }) : super(listenable: controller);

  /// The PageController that this DotsIndicator is representing.
  final PageController controller;

  /// The number of items managed by the PageController
  final int itemCount;

  /// Called when a dot is tapped
  final ValueChanged<int> onPageSelected;

  /// The color of the dots.
  ///
  /// Defaults to `Colors.white`.
  final Color color;

  // The base size of the dots
  static const double _kDotSize = 8.0;

  // The increase in the size of the selected dot
  static const double _kMaxZoom = 2.0;

  // The distance between the center of each dot
  static const double _kDotSpacing = 25.0;

  Widget _buildDot(int index) {
    double selectedness = Curves.easeOut.transform(
      max(
        0.0,
        1.0 - ((controller.page ?? controller.initialPage) - index).abs(),
      ),
    );
    double zoom = 1.0 + (_kMaxZoom - 1.0) * selectedness;
    return new Container(
      width: _kDotSpacing,
      child: new Center(
        child: new Material(
          color: color,
          type: MaterialType.circle,
          child: new Container(
            width: _kDotSize * zoom,
            height: _kDotSize * zoom,
            child: new InkWell(
              onTap: () => onPageSelected(index),
            ),
          ),
        ),
      ),
    );
  }

  Widget build(BuildContext context) {
    return new Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: new List<Widget>.generate(itemCount, _buildDot),
    );
  }
}
import 'package:fluids/designs/onboarding/dots_indicator.dart';
import 'package:flutter/material.dart';
import './Page1.dart';
import './Page2.dart';
import './Page3.dart';

class _OnboardingMainPageState extends State<OnboardingMainPage> {
  final _controller = new PageController();
  final List<Widget> _pages = [
    Page1(),
    Page2(),
    Page3(),
  ];
  int page = 0;

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

  @override
  Widget build(BuildContext context) {
    bool isDone = page == _pages.length - 1;
    return new Scaffold(
      backgroundColor: Colors.transparent,
      body: new Stack(
        children: <Widget>[
          new Positioned.fill(
            child: new PageView.builder(
              physics: new AlwaysScrollableScrollPhysics(),
              controller: _controller,
              itemCount: _pages.length,
              itemBuilder: (BuildContext context, int index) {
                return _pages[index % _pages.length];
              },
              onPageChanged: (int p){
                setState(() {
                  page = p;
                });
              },
            ),
          ),
          new Positioned(
            top: 0.0,
            left: 0.0,
            right: 0.0,
            child: new SafeArea(
              child: AppBar(
                backgroundColor: Colors.transparent,
                elevation: 0.0,
                primary: false,
                title: Text('Onboarding Example'),
                actions: <Widget>[
                  FlatButton(
                    child: Text(isDone ? 'DONE' : 'NEXT', style: TextStyle(color: Colors.white),),
                    onPressed: isDone ? (){
                      Navigator.pop(context);
                    } : (){
                      _controller.animateToPage(page + 1, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
                    },
                  )
                ],
              ),
            ),
          ),
          new Positioned(
            bottom: 10.0,
            left: 0.0,
            right: 0.0,
            child: new SafeArea(
              child: new Column(
                children: <Widget>[
                  new Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: new DotsIndicator(
                      controller: _controller,
                      itemCount: _pages.length,
                      onPageSelected: (int page) {
                        _controller.animateToPage(
                          page,
                          duration: const Duration(milliseconds: 300),
                          curve: Curves.ease,
                        );
                      },
                    ),
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: <Widget>[
                      new Container(
                        width: 150.0,
                        height: 50.0,
                        decoration: BoxDecoration(
                          gradient: new LinearGradient(
                            colors: [
                              Colors.orange[600],
                              Colors.orange[900],
                            ],
                            begin: Alignment(0.5, -1.0),
                            end: Alignment(0.5, 1.0)
                          ),
                          borderRadius: new BorderRadius.circular(30.0),
                        ),
                        child: new Material(
                          child: MaterialButton(
                            child: Text('I\'M NEW',
                              style: Theme.of(context).textTheme.button.copyWith(color: Colors.white),
                            ),
                            onPressed: (){},
                            highlightColor: Colors.orange.withOpacity(0.5),
                            splashColor: Colors.orange.withOpacity(0.5),
                          ),
                          color: Colors.transparent,
                          borderRadius: new BorderRadius.circular(30.0),
                        ),
                      ),
                      new Container(
                        width: 150.0,
                        height: 50.0,
                        decoration: BoxDecoration(
                          borderRadius: new BorderRadius.circular(30.0),
                          border: Border.all(color: Colors.white, width: 1.0),
                          color: Colors.transparent,
                        ),
                        child: new Material(
                          child: MaterialButton(
                            child: Text('LOG IN',
                              style: Theme.of(context).textTheme.button.copyWith(color: Colors.white),
                            ),
                            onPressed: (){},
                            highlightColor: Colors.white30,
                            splashColor: Colors.white30,
                          ),
                          color: Colors.transparent,
                          borderRadius: new BorderRadius.circular(30.0),
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ),
        ],
      )
    );
  }
}

class OnboardingMainPage extends StatefulWidget {
  OnboardingMainPage({Key key}) : super(key: key);

  @override
  _OnboardingMainPageState createState() => new _OnboardingMainPageState();
}
import 'package:fluids/designs/onboarding/circles_with_image.dart';
import 'package:fluids/utils/assets.dart';
import 'package:flutter/material.dart';

class Page1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Container(
      height: double.infinity,
      width: double.infinity,
      decoration: new BoxDecoration(
        gradient: LinearGradient(
          colors: [
            Colors.green[400],
            Colors.blue[600],
            Colors.blue[900],
          ],
          begin: Alignment(0.5, -1.0),
          end: Alignment(0.5, 1.0)
        )
      ),
      child: Stack(
        children: <Widget>[
          new Positioned(
            child: new CircleWithImage(Assets.pose1),
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
          ),
          new Positioned.fill(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                SizedBox(
                  child: Image(
                    image: AssetImage(Assets.pose1),
                    fit: BoxFit.fitHeight,
                  ),
                  height: IMAGE_SIZE,
                  width: IMAGE_SIZE,
                ),
                new Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Text('Workout at home, outside or in the studio',
                    style: Theme.of(context).textTheme.display1.copyWith(color: Colors.white),
                    textAlign: TextAlign.center,
                  ),
                ),
                Text('Workout anywhere without any equipment!',
                  style: Theme.of(context).textTheme.body1.copyWith(color: Colors.white),
                  textAlign: TextAlign.center,
                )
              ],
            ),
          )
        ],
        alignment: FractionalOffset.center,
      ),
    );
  }
}
import 'package:fluids/designs/onboarding/circles_with_image.dart';
import 'package:fluids/utils/assets.dart';
import 'package:flutter/material.dart';

const double IMAGE_SIZE = 200.0;

class Page2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Container(
      height: double.infinity,
      width: double.infinity,
      decoration: new BoxDecoration(
        gradient: LinearGradient(
          colors: [
            Colors.pink[400],
            Colors.deepPurple[600],
            Colors.deepPurple[900],
          ],
          begin: Alignment(0.5, -1.0),
          end: Alignment(0.5, 1.0)
        )
      ),
      child: Stack(
        children: <Widget>[
          new Positioned(
            child: new CircleWithImage(Assets.pose2),
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
          ),
          new Positioned.fill(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                SizedBox(
                  child: Image(
                    image: AssetImage(Assets.pose2),
                    fit: BoxFit.fitHeight,
                  ),
                  height: IMAGE_SIZE,
                  width: IMAGE_SIZE,
                ),
                new Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Text('Varied Workouts\nBuilt Skills',
                    style: Theme.of(context).textTheme.display1.copyWith(color: Colors.white),
                    textAlign: TextAlign.center,
                  ),
                ),
                Text('Take your workouts to the next level\nand become a BEAST!',
                  style: Theme.of(context).textTheme.body1.copyWith(color: Colors.white),
                  textAlign: TextAlign.center,
                )
              ],
            ),
          )
        ],
        alignment: FractionalOffset.center,
      ),
    );
  }
}
import 'package:fluids/designs/onboarding/circles_with_image.dart';
import 'package:fluids/utils/assets.dart';
import 'package:flutter/material.dart';

const double IMAGE_SIZE = 300.0;

class Page3 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Container(
      height: double.infinity,
      width: double.infinity,
      decoration: new BoxDecoration(
        gradient: LinearGradient(
          colors: [
            Colors.orange[400],
            Colors.red[600],
            Colors.red[900],
          ],
          begin: Alignment(0.5, -1.0),
          end: Alignment(0.5, 1.0)
        )
      ),
      child: Stack(
        children: <Widget>[
          new Positioned(
            child: new CircleWithImage(Assets.pose3),
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
          ),
          new Positioned.fill(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                SizedBox(
                  child: Image(
                    image: AssetImage(Assets.pose3),
                    fit: BoxFit.fitHeight,
                  ),
                  height: IMAGE_SIZE,
                  width: IMAGE_SIZE,
                ),
                new Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Text('Learn the secret techniques',
                    style: Theme.of(context).textTheme.display1.copyWith(color: Colors.white),
                    textAlign: TextAlign.center,
                  ),
                ),
                Text('Our programs have been tested\nby professional instructors & athletes.',
                  style: Theme.of(context).textTheme.body1.copyWith(color: Colors.white),
                  textAlign: TextAlign.center,
                )
              ],
            ),
          )
        ],
        alignment: FractionalOffset.center,
      ),
    );
  }
}

Comments (3)

  1. Nkansah Rexford

    import 'package:fluids/utils/assets.dart';

    Where's the assets.dartfile? what’s in it?

  2. Kevin Armstrong

    Nkansah, the assets.dart file is what I use to easily access the list of assets for my app. If I include assets in the pubspec.yaml as such...

        - assets/images/exercise/pose1.png
        - assets/images/exercise/pose2.png
        - assets/images/exercise/pose3.png
    

    …I then include an assets.dart file that looks like…

    class Assets {
      static final String pose1 = 'assets/images/exercise/pose1.png';
      static final String pose2 = 'assets/images/exercise/pose2.png';
      static final String pose3 = 'assets/images/exercise/pose3.png';
    }
    

    …this makes it easy to update asset locations without affecting the code.

  3. Nkansah Rexford

    Ooh cool. Thanks.

    I just put the image strings in there directly without the assets, and it works too. Thanks.

    That’s a really good snippet there.