Beautiful application experience comes from the processing of details, but also from the self-requirements and efforts of code farmers, of course, also need the young flexible thinking of code farmers, not limited to thinking, not limited to language restrictions, is the highest realm of programming.

  • Beautiful musical beats take you through the coding process of this effect
  • Insist on every day, is the pursuit of every ideal youth
  • Follow in the footsteps of young people, and maybe your answer is right here

The effect achieved in this article is shown in the figure below:

A single file in the Flutter project defines the startup test entry

void main(a) {
  // Start root directory
  runApp(MaterialApp(
    // The default page
    home: Example820(),
  ));
}
Copy the code
2 Page initialization

Waves also wave, so let’s start with the following build of an animation controller Example820:

class Example820 extends StatefulWidget {
  @override
  State<StatefulWidget> createState(a) {
    return_ExampleState(); }}class _ExampleState extends State with SingleTickerProviderStateMixin {
  /// Animation controller
  AnimationController _animationController;

  @override
  void initState(a) {
    super.initState();
    // Create the animation controller
    _animationController = AnimationController(
      // Default initial value
      value: 0.0.// Execution time
      duration: Duration(seconds: 10),
      // Range of values
      upperBound: 1,
      lowerBound: -1,
      vsync: this,);// Repeat the execution
    _animationController.repeat();
  }

  @override
  void dispose(a) {
    / / destroy
    _animationController.dispose();
    super.dispose(); }... }Copy the code

3. Build the main UI of the page

The Scaffold Scaffold is used to build the main page. The code is as follows:

  @override
  Widget build(BuildContext context) {
    // Get the current component size
    Size size = MediaQuery
        .of(context)
        .size;
    return Scaffold(
      // Allows the keyboard to pop layout files up
      resizeToAvoidBottomPadding: true,
      body: Container(
        / / fill
        width: size.width,
        height: size.height,
        / / cascade
        child: Stack(
          children: <Widget>[
            // The first part of the water ripple background
            buildFirstAnimation(size),
            // Text at the top of part 2
            buildTopText(size),
            // The button at the bottom of section 3
            buildBottomButton(size),
          ],
        ),
      ),
    );
  }
Copy the code
3.1 Hello World

There are three layers in the Stack. Let’s start with the simplest text, which looks like this:

  /// Listing 8-31 for the text aligned at the top
  /// 
  Positioned buildTopText(Size size) {
    return Positioned(
      top: size.height * 0.2,
      left: 0,
      right: 0,
      child: Text(
        "Hello World",
        textAlign: TextAlign.center,
        style: TextStyle(
            fontSize: 33, color: Colors.white, fontWeight: FontWeight.bold),
      ),
    );
  }
Copy the code

3.2 Text input area at the bottom

Build with a linear layout Column as follows:

 /// Bottom aligned input box
  Positioned buildBottomButton(Size size) {
    return Positioned(
      bottom: 60,
      left: 0,
      right: 0,
      child: Column(
        // Wrap the child Widget
        mainAxisSize: MainAxisSize.min,
        // Align the bottom of the main directional sub-widget (Column vertical)
        mainAxisAlignment: MainAxisAlignment.end,
        // Center the sub-directional widgets (Column horizontal)
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Container(
            width: size.width * 0.8,
            margin: EdgeInsets.only(top: 18),
            child: buildInputWidget('Please enter your account number'),
          ),
          Container(
            width: size.width * 0.8,
            margin: EdgeInsets.only(top: 18),
            child: buildInputWidget('Please enter your password', isPass: true),
          ),
          Container(
            margin: EdgeInsets.only(top: 20),
            padding: EdgeInsets.only(bottom: 60),
            width: size.width * 0.7,
            child: ElevatedButton(
              onPressed: () {},
              child: Text(
                'login',
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 20() (() [() [() [() [() [() }}Copy the code

Because the text input field here is relatively similar, so also made a wrapper call, the code is as follows:

/// 
Widget buildInputWidget(String hint, {bool isPass = false}) {
  return TextField(
    // Whether to hide the text
    obscureText: isPass,
    // Text border decoration
    decoration: InputDecoration(
      // Prompt text
      hintText: hint,
      // Prompt the style of the text
      hintStyle: TextStyle(color: Color(0xFFACACAC), fontSize: 14),
      // The inside margin of the input
      contentPadding: EdgeInsets.only(top: 20, bottom: 20, left: 38),
      // The border style of the input box when it is available
      enabledBorder: OutlineInputBorder(
        borderSide: BorderSide(color: Colors.lightBlueAccent),
        borderRadius: BorderRadius.all(Radius.circular(30.0))),// Input box gets the border style of the input focus
      focusedBorder: OutlineInputBorder(
        borderSide: BorderSide(color: Colors.green),
        borderRadius: BorderRadius.all(Radius.circular(30.0)),),),); }Copy the code

4 Wavy style background construction

Set the gradient background using the BoxDecoration of the Container, then ClipPath, and AnimatedBuilder and AnimationController.

  /// Build AnimatedBuilder with clipping water ripples
  /// 
  AnimatedBuilder buildFirstAnimation(Size size) {
    return AnimatedBuilder(
      // Bind the animation controller
      animation: _animationController,
      builder: (BuildContext context, Widget child) {
        // Clipping the component
        return ClipPath(
          // Customize the clipping path
          clipper: HeaderClipper(_animationController.value),
          // Clipped child Widget
          child: Container(
            / / height
            height: size.height * 0.5.// Linear gradient color style
            decoration: BoxDecoration(
              gradient: LinearGradient(
                // Direction of linear gradient
                  begin: Alignment.bottomLeft,
                  end: Alignment.topRight,
                  colors: [Color(0xFFE0647B), Color(0xFFFCDD89)]),),),); }); }Copy the code

ClipPath is used to crop custom images, defined as follows:

/// Listing 8-34 Custom Clipper
/// 
class HeaderClipper extends CustomClipper<Path> {
  /// The value ranges from -1 to 1.0
  double moveFlag = 0;

  HeaderClipper(this.moveFlag);

  @override
  Path getClip(Size size) {
    / / create the Path
    Path path = Path();
    // Move to point P0 is also the beginning of the curve
    path.lineTo(0, size.height * 0.8);
    // Calculate the coordinates of control point P1
    double xCenter = size.width * 0.5 +
        (size.width * 0.6 + 1) * sin(moveFlag * pi);
    double yCenter = size.height * 0.8 + 69 * cos(moveFlag*pi);
    // Construct the second-order Bezier curve
    path.quadraticBezierTo(xCenter, yCenter, size.width, size.height * 0.8);

    path.lineTo(size.width, 0);
    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    / / refresh
    return true; }}Copy the code

Second-order Bezier curve is used, and the occupying analysis diagram is as follows:

Second-order Bezier curve:

PI is also used:

PI, cos, and sin are provided in the Flutter Sdk dart.math class.


[X1] Daily reminder of wechat public account at any time, daily accumulation, free to follow the bottom of the article scan code attention

【 X2 】 Various series of free open source video tutorials focus on you won’t get lost

【 X3 】 series article millions of Demo copy and paste use at any time

[X4] Short video is not the same experience

[x5] must have source code


Not limited to thinking, not limited to language restrictions, is the highest realm of programming.

With xiaobian character, must be to record a set of video, and then upload

If you are interested, you can check out the watermelon video – early risers