分类 推荐 下的文章

本系列文章共有三篇,计划分别从Flutter、Dart、工具三个方面介绍,快速形成对Flutter开发的一个综合概念。

本文主要介绍Flutter相关知识。

Flutter语言使用 Dart,开发IDE使用VSCode、Android Studio 或 IntelliJ IDEA,个人推荐使用VSCode。

Flutter概览

Flutter是由Google开发的开源移动应用开发框架,用于快速构建高性能、高保真度的跨平台移动应用。Flutter支持同一套代码在 iOS、Android、Web、桌面应用等多个平台上运行,使用自带的 Skia 图形引擎,可以直接绘制 UI 组件,这使得 Flutter 应用在性能方面表现出色,滚动流畅,响应迅速(目前正在使用 Impeller 替换 Skia)。

看一眼有个印象即可。


参考资料

三棵树

Flutter的渲染机制由三棵树组成:Widget Tree、Element Tree、Render Tree(渲染树)。

所有Widget组成Widget Tree。

通过调用Widget的createElement()方法,创建Element Tree,Wdiget Tree与Element Tree是一一对应的。

每个Element调用 createRenderObject()形成Render Tree,Render Tree负责渲染,注意Render Tree与Elemeng Tree并不是一一对应的,而是为最后渲染做准备。

StatelessWidget

// StatelessWidget 定义
abstract class StatelessWidget extends Widget {
  const StatelessWidget({ super.key });

  @override
  StatelessElement createElement() => StatelessElement(this);
  
  // 核心是 build 方法
  @protected
  Widget build(BuildContext context);
}

// 示例,Echo widget,核心是build方法构建UI
class Echo extends StatelessWidget  {
  const Echo({
    Key? key,  
    required this.text,
    this.backgroundColor = Colors.grey, //默认为灰色
  }):super(key:key);
    
  final String text;
  final Color backgroundColor;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        color: backgroundColor,
        child: Text(text),
      ),
    );
  }
}



// 在子树中获取父级widget的一个示例:
class ContextRoute extends StatelessWidget  {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Context测试"),
      ),
      body: Container(
        child: Builder(builder: (context) {
          // 在 widget 树中向上查找最近的父级`Scaffold`  widget
          Scaffold scaffold = context.findAncestorWidgetOfExactType<Scaffold>();
          // 直接返回 AppBar的title, 此处实际上是Text("Context测试")
          return (scaffold.appBar as AppBar).title;
        }),
      ),
    );
  }
}


StatefulWidget

StatefulWidget的核心就是有状态,可以修改重绘UI。


StatefulWidget重写了createElement方法,返回的是StatefulElement,StatefulElement可能会多次调用createState()来创建对象。

createState(),创建状态,修改UI必须通过修改状态来实现,一个StatefulElement对应一个State实例。

abstract class StatefulWidget extends Widget {
  const StatefulWidget({ Key key }) : super(key: key);
    
  @override
  StatefulElement createElement() => StatefulElement(this);
    
  @protected
  State createState();
}


添加插件

tutorial_coach_mark: 1.2.11

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

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget{
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) => MaterialApp(home: const HomePage());
}

class HomePage extends StatefulWidget{
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage>{
  late TutorialCoachMark tutorial;
  final _keyAdd = GlobalKey(),
      _keySearch = GlobalKey(),
      _keyProfile = GlobalKey();

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) => _showTutorial());
  }

  void _showTutorial() {
    tutorial = TutorialCoachMark(
      targets: _createTargets(),
      colorShadow: Colors.black54,
      opacityShadow: 0.7,
      paddingFocus: 8,
      textSkip: '跳过',
      onFinish: () => print('完成'),
      onSkip: () {
        print('跳过');
        return true;
      },
    )..show(context: context);
  }

  List<TargetFocus> _createTargets() => [
        TargetFocus(
          identify: 'add',
          keyTarget: _keyAdd,
          contents: [
            TargetContent(
              align: ContentAlign.bottom,
              builder: (_, __) =>
                  const Text('点击这里添加任务', style: TextStyle(color: Colors.white)),
            )
          ],
        ),
        TargetFocus(
          identify: 'search',
          keyTarget: _keySearch,
          contents: [
            TargetContent(
              align: ContentAlign.top,
              builder: (_, __) =>
                  const Text('快速搜索内容', style: TextStyle(color: Colors.white)),
            )
          ],
        ),
        TargetFocus(
          identify: 'profile',
          keyTarget: _keyProfile,
          contents: [
            TargetContent(
              align: ContentAlign.left,
              builder: (_, __) =>
                  const Text('进入个人中心', style: TextStyle(color: Colors.white)),
            )
          ],
        ),
      ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('局部高亮教程')),
      floatingActionButton: FloatingActionButton(
        key: _keyProfile,
        onPressed: () => _showTutorial(),
        child: const Icon(Icons.person),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              key: _keyAdd,
              onPressed: () {},
              child: const Text('添加'),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              key: _keySearch,
              onPressed: () {},
              child: const Text('搜索'),
            ),
            const SizedBox(height: 40),
            OutlinedButton(
              onPressed: _showTutorial,
              child: const Text('再看一次'),
            ),
          ],
        ),
      ),
    );
  }
}


<?php
// 检查是否有表单提交
if ($_SERVER["REQUEST_METHOD"] == "POST") {
    // 获取用户输入的名字
    $name = htmlspecialchars($_POST['name']);
} else {
    $name = "";
}
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Simple PHP Page</title>
</head>
<body>
    <h1>Welcome to My PHP Page</h1>
    <p>Current Time: <?php echo date('Y-m-d H:i:s'); ?></p>

    <form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>">
        <label for="name">Enter your name:</label>
        <input type="text" id="name" name="name" value="<?php echo $name; ?>">
        <input type="submit" value="Submit">
    </form>

    <?php
    if (!empty($name)) {
        echo "<p>Welcome, $name!</p>";
    }
    ?>
</body>
</html>

哈哈哈哈哈

import random

def guess_number():
    # 生成一个1到100之间的随机数
    number_to_guess = random.randint(1, 100)
    attempts = 0

    print("欢迎来到猜数字游戏!")
    print("我已经想好了一个1到100之间的数字。")

    while True:
        try:
            # 获取用户输入
            user_guess = int(input("请输入你的猜测(1-100):"))
            attempts += 1

            # 检查用户输入是否正确
            if user_guess < 1 or user_guess > 100:
                print("请输入1到100之间的数字!")
            elif user_guess < number_to_guess:
                print("太小了!再试一次。")
            elif user_guess > number_to_guess:
                print("太大了!再试一次。")
            else:
                print(f"恭喜你!你猜对了数字 {number_to_guess}!")
                print(f"你总共尝试了 {attempts} 次。")
                break
        except ValueError:
            print("请输入一个有效的数字!")

if __name__ == "__main__":
    guess_number()

测试

import java.util.Scanner;

public class SimpleCalculator {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.println("欢迎使用简单计算器");
        System.out.print("请输入第一个数字: ");
        double num1 = scanner.nextDouble();

        System.out.print("请输入运算符 (+, -, *, /): ");
        char operator = scanner.next().charAt(0);

        System.out.print("请输入第二个数字: ");
        double num2 = scanner.nextDouble();

        double result;

        switch (operator) {
            case '+':
                result = num1 + num2;
                break;
            case '-':
                result = num1 - num2;
                break;
            case '*':
                result = num1 * num2;
                break;
            case '/':
                if (num2 != 0) {
                    result = num1 / num2;
                } else {
                    System.out.println("错误:除数不能为0");
                    return;
                }
                break;
            default:
                System.out.println("错误:无效的运算符");
                return;
        }

        System.out.println("结果: " + num1 + " " + operator + " " + num2 + " = " + result);
    }
}

测试显示效果代码链接