- 静态:Icon --> 动态: IconButton
加入交互式,需要两个类,1.是stateful widget,该widget调用自己的构造方法以及创造一个state类,createstate 2.是State对象,里面存储一些变量等信息可以动态的改变,通过调用动态组件,可以捕获点击状态,从而改变变量的状态,改变渲染的数值的大小。
下面这段代码基于以前的静态代码博客
代码:
class FavoriteWidget extends StatefulWidget {
const FavoriteWidget({Key? key}) : super(key: key);
@override
State<FavoriteWidget> createState() => _FavoriteWidgetState();
}
class _FavoriteWidgetState extends State<FavoriteWidget> {
bool _isFavorited = true;
int _favoriteCount = 41;
void _toggleFavorite(){
//可以改变外观
setState(() {
if(_isFavorited){
_isFavorited = false;
_favoriteCount -= 1;
}
else{
_isFavorited = true;
_favoriteCount += 1;
}
});
}
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: const EdgeInsets.all(8),
child: IconButton(
padding: const EdgeInsets.all(0),
alignment: Alignment.centerRight,
icon:(//这一步就是对图标的选择,选择的条件是开设一个变量,进行真假变换
_isFavorited? const Icon(Icons.star):const Icon(Icons.star_border)
),
color: Colors.red[500],
onPressed: _toggleFavorite,
)
),
SizedBox(
width: 18,
child:Text('$_favoriteCount')//变量动态改变页面
)
],
);
}
}
嵌入到静态代码,直接就是:const FavoriteWidget();即可
ManageState
管理对象的方式有自己管理对象,适用于美术类的场景,比如动画。或者是父widget管理对象,适用于和用户的数据打交道的场景
自己管理状态
class interactive4 extends StatelessWidget {
const interactive4({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter app",
home: Scaffold(
appBar: AppBar(
title: const Text("Flutter Demo"),
),
body: Center(child: Tapbox()),
),
);
}
}
class Tapbox extends StatefulWidget {
const Tapbox({Key? key}) : super(key: key);
@override
State<Tapbox> createState() => _TapboxState();
}
class _TapboxState extends State<Tapbox> {
bool state1 = false;
void changeState1(){
setState(() {
state1 = !state1;
});
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: changeState1,
child: Container(
width: 200,
height: 200,
decoration: BoxDecoration(
color: state1?Colors.green:Colors.black12,
),
child: Center(
child:Text(
state1?"Active":"Inactive",
style: TextStyle(fontSize: 50),
),
)
),
);
}
}
父widget管理状态
import 'package:flutter/material.dart';
// ParentWidget manages the state for TapboxB.
//------------------------ ParentWidget --------------------------------
class ParentWidget extends StatefulWidget {
const ParentWidget({super.key});
@override
State<ParentWidget> createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
bool _active = false;
void _handleTapboxChanged(bool newValue) {
setState(() {
_active = newValue;
});
}
@override
Widget build(BuildContext context) {
return SizedBox(
child: TapboxB(
active: _active,
onChanged: _handleTapboxChanged,
),
);
}
}
//------------------------- TapboxB ----------------------------------
class TapboxB extends StatelessWidget {
const TapboxB({
super.key,
this.active = false,
required this.onChanged,
});
final bool active;
final ValueChanged<bool> onChanged;
void _handleTap() {
onChanged(!active);
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: _handleTap,
child: Container(
width: 200.0,
height: 200.0,
decoration: BoxDecoration(
color: active ? Colors.lightGreen[700] : Colors.grey[600],
),
child: Center(
child: Text(
textDirection: TextDirection.ltr,
active ? 'Active' : 'Inactive',
style: const TextStyle(fontSize: 32.0, color: Colors.white),
),
),
),
);
}
}
二者的区别:
共同点是状态的管理都是通过一个变量,在这个例子中都是Bool变量。
自己控制状态:
- 自己是一个stateful widget
- 控制状态的变量声明在自己的state中
- 改变变量的setState也是在自己的state 类中
父widget空置状态: - 自己是一个stateless widget
- 控制状态的变量声明在父widget中,并通过传参构造穿给自己
- 改变变量的函数定义在父widget中 ,并通过传参构造把该函数传递给了孩子,怎么调用呢?该函数赋给了自己的一个函数,调用自己的函数就相当于调用了父widget的函数
二者融合:
例子
import 'package:flutter/material.dart';
//---------------------------- ParentWidget ----------------------------
class ParentWidgetMix extends StatefulWidget {
const ParentWidgetMix({super.key});
@override
State<ParentWidgetMix> createState() => _ParentWidgetMixState();
}
class _ParentWidgetMixState extends State<ParentWidgetMix> {
bool _active = false;
void _handleTapboxChanged(bool newValue) {
setState(() {
_active = newValue;
});
}
@override
Widget build(BuildContext context) {
return SizedBox(
child: TapboxC(
active: _active,
onChanged: _handleTapboxChanged,
),
);
}
}
//----------------------------- TapboxC ------------------------------
class TapboxC extends StatefulWidget {
const TapboxC({
super.key,
this.active = false,
required this.onChanged,
});
final bool active;
final ValueChanged<bool> onChanged;
@override
State<TapboxC> createState() => _TapboxCState();
}
class _TapboxCState extends State<TapboxC> {
bool _highlight = false;
void _handleTapDown(TapDownDetails details) {
setState(() {
_highlight = true;
});
}
void _handleTapUp(TapUpDetails details) {
setState(() {
_highlight = false;
});
}
void _handleTapCancel() {
setState(() {
_highlight = false;
});
}
void _handleTap() {
widget.onChanged(!widget.active);
}
@override
Widget build(BuildContext context) {
// This example adds a green border on tap down.
// On tap up, the square changes to the opposite state.
return GestureDetector(
onTapDown: _handleTapDown, // Handle the tap events in the order that
onTapUp: _handleTapUp, // they occur: down, up, tap, cancel
onTap: _handleTap,
onTapCancel: _handleTapCancel,
child: Container(
width: 200.0,
height: 200.0,
decoration: BoxDecoration(
color: widget.active ? Colors.lightGreen[700] : Colors.grey[600],
border: _highlight
? Border.all(
color: Colors.teal[700]!,
width: 10.0,
)
: null,
),
child: Center(
child: Text(widget.active ? 'Active' : 'Inactive',
textDirection: TextDirection.ltr,
style: const TextStyle(fontSize: 32.0, color: Colors.white)),
),
),
);
}
}
就是既有自己控制的“外观变量(_highlgiht)”,以及父 widget的“外观变量(_active)”,然后分别在不同场景下控制就行了。
【后话:GestureDetector】
- GestureDetector这个组件和有用,用它包裹起来,可以很方便地捕获用户的一些动作,比如tapdown,tapup,tap,tapcance。。。
When you need interactivity, it’s easiest to use one of the prefabricated widgets. Here’s a partial list: