JHHK

欢迎来到我的个人网站
行者常至 为者常成

5 常用控件

目录

架子介绍

程序的入口函数,runApp() 相当于UIApplicationMain()方法

void main() {
  runApp(const MyApp());
}

Widget 小部件
有状态:Stateful 可变,比如颜色
无状态:Stateless 不可变
build方法 -> 渲染方法。build方法返回什么,就渲染什么

常用Widget

一、容器

相当于UIView

Container(
  width: 100,
  height: 100,
  color: Colors.blue,
);

二、文本

1、普通文本

Text(
  '这是一个文本',
  textAlign: TextAlign.center,
  style: TextStyle( color: Colors.white, fontSize: 20, fontWeight: FontWeight.w500,),
);

2、富文本

Text.rich(
  TextSpan(
    children: [
      const TextSpan(
        text: '同一个世界同一个世界同一个世界同一个世界同一个世界同一个世界同一个世界同一个世界同一个世界',
        style: TextStyle(fontSize: 14, color: Colors.white),
      ),

      WidgetSpan(
        alignment: PlaceholderAlignment.middle,
        child: Container(
          margin: const EdgeInsets.only(left: 6),
          padding: const EdgeInsets.only(left: 2, right: 6),
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.circular(2),
            border: Border.all(
              color: Colors.red,
              width: 1,
              style: BorderStyle.solid,
            ),
          ),
          child: const Text(
            '同一个梦想',
            style: TextStyle(fontSize: 12, color: Colors.red),
          ),
        ),
      ),
    ],
  ),
);

三、按钮

TextButton(
  style: ButtonStyle(
    // 在Flutter中,MaterialStateProperty是一种用于管理在不同状态下(例如按下、禁用等)小部件样式的类
    // MaterialStateProperty.all<Color>(Colors.blue),它的意思是将所有状态下的颜色都设置为蓝色。
    // 设置背景色
    backgroundColor: MaterialStateProperty.all<Color>(Colors.blue),
    // 调整按钮的最小尺寸
    minimumSize: MaterialStateProperty.all<Size>(const Size(10, 60)),
    // 移除点击效果
    overlayColor: MaterialStateProperty.resolveWith<Color>(
      (Set<MaterialState> states) {
        return Colors.transparent;
      },
    ),
  ),
  onPressed: () {
    debugPrint('点击了按钮');
  },
  child: const Text(
    '这是一个按钮',
    style: const TextStyle(color: Colors.black),
  ),
);

4、手势

GestureDetector(
  onTap: () {
    debugPrint('点击回调');
  },
  child: const Text(
    '手势测试',
    style: TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.normal),
  ),
);

重要Widget

一、常用

Material App
  title
  theme
  home
    scafford
      appBar
      body
ListView 相当于UITableView
	ListView.builder
		itemCount: datas.length,
		itemBuilder: _cellForRow,
Column 纵向布局
	children<widget>
Image.network( datas[index].imageUrl, ),
SizedBox( height: 10, ),

二、provider

ChangeNotifierProvider 和 ChangeNotifier 配合使用可以实现数据的共享使用

ChangeNotifier用来管理数据和发送通知

class FormNotifier extends ChangeNotifier {
  String _username = '';
  String get username => _username;
  set username(String newName) {
    _username = newName;
    notifyListeners();
  }

  String _password = '';
  String get password => _password;
  set password(String value) {
    _password = value;

    // 发送通知
    notifyListeners();
  }
}

ChangeNotifierProvider是一个widget创建时可以绑定一个notifier

let provider = ChangeNotifierProvider(
  create: (context) => FormNotifier(),
  child: const FormPage(),
);

在Provider的所有子组件下都可以获取到notifer并使用数据
当发送notifyListeners();所有子组件的build方法都会重新调用,达到自动更新数据的目的

// 获取绑定的notifier,并获取数据
final formNotifier = Provider.of<FormNotifier>(context);
let username = formNotifier.username;

ChangeNotifierProvider 的使用场景:
1、共享数据:
父 - 子 - 孙 之间共享数据,配合ChangeNotifier实现自动刷新,而不需要在 父 中 调用setState()来刷新。

- 子1
- 子2
- 子3
在兄弟之间共享数据,配合ChangeNotifier实现自动刷新

2、绑定表单数据
本质还是数据的共享,只是数据来源于表单输入

如果你的应用需要更复杂的状态管理,你还可以考虑其他状态管理库,如 Provider、Bloc、GetX 等。

场景一:共享数据

// 创建一个继承自ChangeNotifier的类
class FormNotifier extends ChangeNotifier {
  String _username = '';
  String get username => _username;
  set username(String newName) {
    _username = newName;
    notifyListeners();
  }

  String _password = '';
  String get password => _password;
  set password(String value) {
    _password = value;

    // 发送通知
    notifyListeners();
  }
}



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

  @override
  Widget build(BuildContext context) {

    // 绑定一个notifier
    return ChangeNotifierProvider(
      create: (context) => FormNotifier(),
      child: const FormPage(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    // 只要发送通知就会重新调用build方法
    debugPrint('调用了build方法');

    // 获取绑定的notifier,并获取数据
    final formNotifier = Provider.of<FormNotifier>(context);

    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          TextFormField(
            onChanged: (value) {
              formNotifier.username = value;
            },
            decoration: const InputDecoration(labelText: 'Username'),
          ),
          const SizedBox(height: 16),
          TextFormField(
            onChanged: (value) {
              formNotifier.password = value;
            },
            decoration: const InputDecoration(labelText: 'Password'),
          ),
          const SizedBox(height: 32),
          Text('Username: ${formNotifier.username}'),
          Text('Password: ${formNotifier.password}'),
        ],
      ),
    );
  }
}

三、InheritedWidget

也可以在 父 - 子 - 孙 传递数据

DataWidget继承自InheritedWidget,它有一个属性data,这是共享的数据

class DataWidget extends InheritedWidget {
  const DataWidget({this.data, required Widget child, Key? key}) : super(key: key, child: child);

  final int? data; //需要在子Widget中共享的数据!

  //提供一个方法让子Widget访问的共享数据!
  static DataWidget? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<DataWidget>();
  }

  // 是否需要发送更新通知
  @override
  bool updateShouldNotify(DataWidget oldWidget) {
    debugPrint('oldWidget.data = ${oldWidget.data}, data = $data');
    // return oldWidget.data != data;
    return true;
  }
}

让DataWidget作为顶层的父控件,它的子控件都可以访问到共享的数据

class InheritedDemo extends StatefulWidget {
  InheritedDemo({Key? key}) : super(key: key);
  @override
  _InheritedDemoState createState() => _InheritedDemoState();
}

class _InheritedDemoState extends State<InheritedDemo> {
  // DataWidget 捕获的数据
  int count = 1;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('InheritedWidget')),
      body: DataWidget(
        data: count,
        child: Column(
          children: <Widget>[
            GestureDetector(
              onTap: () {
                setState(() { count++;});
              },
              child: const Center(child: Text('我是按钮')),
            ),
            const SizedBox(height: 20),
            Test1(),
          ],
        ),
      ),
    );
  }
}

子控件通过 DataWidget.of(context)!.data 来访问数据

class Test1 extends StatelessWidget {
  Test1({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Test2();
  }
}

class Test2 extends StatelessWidget {
  Test2({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Test3();
  }
}

class Test3 extends StatefulWidget {
  Test3({Key? key}) : super(key: key);
  @override
  _Test3State createState() => _Test3State();
}

class _Test3State extends State<Test3> {
  @override
  Widget build(BuildContext context) {
    return Text(DataWidget.of(context)!.data.toString());
  }

  //依赖的InheritedWidget发生变化之后,方法也会调用!
  @override
  void didChangeDependencies() {
    debugPrint('_Test3State - didChangeDependencies');
    super.didChangeDependencies();
  }
}

行者常至,为者常成!





R
Valine - A simple comment system based on Leancloud.