flutter:demo (七)

简介: 在移动应用开发中,用户界面的布局设计是提升用户体验的关键要素。Flutter作为一个强大的UI框架,提供了多种布局组件,使开发者能够灵活地构建复杂的用户界面模块。无论是线性布局(如Column和Row)还是非线性布局(如Stack和Wrap),Flutter的布局系统都允许开发者以简洁的方式组织和组合界面元素。

引言

在移动应用开发中,用户界面的布局设计是提升用户体验的关键要素。Flutter作为一个强大的UI框架,提供了多种布局组件,使开发者能够灵活地构建复杂的用户界面模块。无论是线性布局(如Column和Row)还是非线性布局(如Stack和Wrap),Flutter的布局系统都允许开发者以简洁的方式组织和组合界面元素。

小demo

登录页面

动画依赖

shake_animation_widget: ^3.0.4
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:shake_animation_widget/shake_animation_widget.dart';
import 'dart:async';
import 'package:flutter/material.dart';
class test01 extends StatefulWidget {
  const test01({Key? key}) : super(key: key);
  @override
  State<test01> createState() => _test01State();
}
class _test01State extends State<test01> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      //当前显示页面的背景
      backgroundColor: Colors.white,
      body: Container(
        //填充父布局空间
        width: double.infinity,
        height: double.infinity,
        //一个层叠布局
        child: Stack(
          //内容居中
          alignment: Alignment.center,
          children: [
            LoginInputLayout(),
          ],
        ),
      ),
    );
  }
}
class LoginInputLayout extends StatefulWidget {
  @override
  _TestPageState createState() => _TestPageState();
}
class _TestPageState extends State<LoginInputLayout> {
  //用户名输入框的焦点控制
  final FocusNode _userNameFocusNode = new FocusNode();
  final FocusNode _passwordFocusNode = new FocusNode();
  //文本输入框控制器
  final TextEditingController _userNameController = new TextEditingController();
  final TextEditingController _passwordController = new TextEditingController();
  //抖动动画控制器
  //Stream 更新错误方案操作控制器
  StreamController<String> _userNameStream = new StreamController();
  StreamController<String> _userPasswordStream = new StreamController();
  ///代码清单 3-23 输入层build方法
  ///lib/code/code3/example_311_login_page.dart
  @override
  Widget build(BuildContext context) {
    //手势识别点击空白隐藏键盘
    return GestureDetector(
      onTap: () {
        hindKeyBoarder();
      },
      child: Scaffold(
        //键盘弹出不移动布局
        // resizeToAvoidBottomPadding: false,
        //背景透明
        backgroundColor: Colors.transparent,
        //登录页面的主体
        body: Container(
          width: double.infinity,
          height: double.infinity,
          child: buildLoginWidget(),
        ),
      ),
    );
  }
  ///代码清单 3-24
  ///lib/code/code3/example_311_login_page.dart
  Widget buildLoginWidget() {
    return Column(
      mainAxisSize: MainAxisSize.max,
      children: [
        Container(
          margin: const EdgeInsets.only(
            left: 30.0,
            right: 30.0,
          ),
          //内边距
          padding: const EdgeInsets.all(16),
          //圆角边框
          decoration: BoxDecoration(
              //透明的白色
              color: Colors.white.withOpacity(0.8),
              //四个圆角
              borderRadius: const BorderRadius.all(Radius.circular(12))),
          //线性布局
          child: buildColumn(),
        ),
      ],
    );
  }
  ///代码清单 3-25
  ///lib/code/code3/example_311_login_page.dart
  Column buildColumn() {
    return Column(
      //包裹
      mainAxisSize: MainAxisSize.min,
      children: [
        //用户名输入框
        buildUserNameWidget(),
        const SizedBox(
          height: 20,
        ),
        //用户密码输入框
        buildUserPasswordWidget(),
        const SizedBox(
          height: 40,
        ),
        //登录按钮
        Container(
          width: double.infinity,
          height: 40,
          child: ElevatedButton(
            child: Text("登录"),
            onPressed: () {
              checkLoginFunction();
            },
          ),
        )
      ],
    );
  }
  ///代码清单 3-26 抖动用户名输入框构建
  ///lib/code/code3/example_311_login_page.dart
  Widget buildUserNameWidget() {
    return TextField(
  focusNode: _userNameFocusNode,
      onTap: () {
        setState(() {
          if (checkUserName()) {
            _userNameFocusNode.unfocus();
            FocusScope.of(context).requestFocus(_passwordFocusNode);
          } else {
            FocusScope.of(context).requestFocus(_userNameFocusNode);
          }
        });
      },
      decoration: InputDecoration(
        labelText: "用户名",
          border: OutlineInputBorder(
              borderRadius: BorderRadius.all(Radius.circular(10))
          )
      ),
      onSubmitted: (String value) {
        if (checkUserPassword()) {
          loginFunction();
        } else {
          FocusScope.of(context).requestFocus(_passwordFocusNode);
        }
      },
    );
  }
  ///代码清单 3-27 抖动密码输入框构建
  ///lib/code/code3/example_311_login_page.dart
  Widget buildUserPasswordWidget() {
    return TextField(
      focusNode: _passwordFocusNode,
      controller: _passwordController,
      onTap: (){
        setState(() {
        });
      },
      decoration: InputDecoration(
        labelText: "密码",
          border: OutlineInputBorder(
              borderRadius: BorderRadius.all(Radius.circular(10))
          )
      ),
      onSubmitted: (String value) {
        if (checkUserPassword()) {
          loginFunction();
        } else {
          FocusScope.of(context).requestFocus(_passwordFocusNode);
        }
      },
    );
  }
  ///代码清单 3-28 隐藏键盘操作
  ///lib/code/code3/example_311_login_page.dart
  void hindKeyBoarder() {
    //输入框失去焦点
    _userNameFocusNode.unfocus();
    _passwordFocusNode.unfocus();
  }
  bool checkUserName() {
    //获取输入框中的输入文本
    String userName = _userNameController.text;
    print(userName);
    if (userName.length == 0) {
      //Stream 事件流更新提示文案
      _userNameStream.add("请输入用户名");
      //抖动动画开启
      return false;
    } else {
      //清除错误提示
      _userNameStream.add('');
      return true;
    }
  }
  ///代码清单 3-30 校验输入密码操作
  ///lib/code/code3/example_311_login_page.dart
  bool checkUserPassword() {
    String userPassrowe = _passwordController.text;
    if (userPassrowe.length < 6) {
      _userPasswordStream.add("请输入标准密码");
      return false;
    } else {
      _userPasswordStream.add('');
      return true;
    }
  }
  void checkLoginFunction() {
    //隐藏键盘
    hindKeyBoarder();
    //校验用户输入的用户名
    checkUserName();
    //校验用户输入的用户密码
    checkUserPassword();
    //登录功能
    loginFunction();
  }
  void loginFunction() {}
}
shake_animation_widget: ^3.0.4

按钮加一

import 'package:flutter/material.dart';
class Example01 extends StatefulWidget{
  const Example01({super.key});
  @override
  State<StatefulWidget> createState() {
  return _ExampleState();
  }
}
class _ExampleState extends State<Example01>{
  int _count=0;
  @override
  Widget build(BuildContext context) {
      // Scaffold  用来 搭建主体结构
    return  Scaffold(
      appBar: AppBar(
        title: const Text('hello,world'),),
      body:  Center(
        child: Text('$_count'),
      ),
        floatingActionButton: FloatingActionButton(
         child: const Icon(Icons.add),onPressed: (){
           ++_count;
        },
        ),
    );
  }
}
void main(){
  runApp(MaterialApp(home: Example01(),));
}


列表加一

import 'package:flutter/material.dart';
class Myapp extends StatefulWidget {
  const Myapp({Key? key}) : super(key: key);
  @override
  State<Myapp> createState() => _MyappState();
}
class _MyappState extends State<Myapp> {
  List<String> _list = ['i am the first','i am the second'];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("hello,flutter"),
      ),
      body: ListView(
        children: _list.map((v) {
          return ListTile(
            title: Text(v),
          );
        }).toList(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          //   改变数据  需要 加 setState
          setState(() {
            // _list.add(value);
            _list.add('i am a new list');
          });
        },
        child: Icon(Icons.add),
      ),
    );
  }
}
void main() {
  runApp(MaterialApp(
    home: Myapp(),
  ));
}

搜索页面

import 'package:flutter/material.dart';
class Myapp extends StatelessWidget {
  const Myapp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'hello flutter',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text("flutter app"),
        ),
        body: LayoutDemo(),
      ),
    );
  }
}
class LayoutDemo extends StatelessWidget {
  const LayoutDemo({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: EdgeInsets.all(10),
      children: [
        Row(
          children: [
            Text(
              'hot bar',
              style: Theme.of(context).textTheme.headlineSmall,
            ),
          ],
        ),
        Divider(), // 线
        Wrap(
          spacing: 10, //  x axis   水平间距
          runSpacing: 10, // y axis  垂直
          children: [
            Button(
              "phone",
              onPressed: () {},
            ),
            Button(
              "computer",
              onPressed: () {},
            ),
            Button(
              "girl clothes",
              onPressed: () {},
            ),
            Button(
              "boy clothes",
              onPressed: () {},
            ),
            Button(
              "literature",
              onPressed: () {},
            ),
          ],
        ),
        SizedBox(
          height: 20,
        ),
        Row(
          children: [
            Text(
              'history',
              style: Theme.of(context).textTheme.headlineSmall,
            ),
          ],
        ),
        Divider(), // 线
        Column(
          children: [
            ListTile(
              title: Text("computer"),
            ),
            Divider(),
            ListTile(
              title: Text("literature"),
            ),
            Divider(),
            ListTile(
              title: Text("boy clothes"),
            ),
            Divider(),
          ],
        ),
        SizedBox(height: 40,),
        Padding(padding: EdgeInsets.all(40),
        child:  OutlinedButton.icon(
            style: ButtonStyle(
              foregroundColor: MaterialStateProperty.all(Colors.black45),
            ),
            onPressed: (){}, icon:Icon(Icons.delete), label: Text("clear history")),)
      ],
    );
  }
}
//  自定义按钮
class Button extends StatelessWidget {
  final String text;
  final void Function()? onPressed;
  Button(this.text, {Key? key, required this.onPressed}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
        style: ButtonStyle(
            backgroundColor:
                MaterialStateProperty.all(Color.fromRGBO(241, 255, 244, 244)),
            foregroundColor: MaterialStateProperty.all(Colors.black45)),
        onPressed: onPressed,
        child: Text(text));
  }
}
void main() {
  runApp(const Myapp());
}

轮播图

先创建 出口

void main() {
  runApp(MaterialApp(
    debugShowCheckedModeBanner: false,
    title: "轮播图实例",
    theme: ThemeData(primaryColor: Colors.grey),
    home: MyApp(),
  ));
}

用来接收的组件

import 'package:flutter/material.dart';
import 'package:flutter03/banner/bannerPage.dart';
class MyApp extends StatefulWidget{
  const MyApp({Key? key}) : super(key: key);
  @override
  State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
  List<String> list = [];
  @override
  void initState() {
    super.initState();
    list = [
      "images/noodle.jpg",
      "images/laying.jpg",
      "images/umbrella.jpg",
    ];
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("轮播图实例"),
        centerTitle: true,
      ),
      body: ListView(
        children: [
          //   调用 bannerpage 组件
          bannerPage(list: list)
        ],
      ),
    );
  }
}

图片组件

import 'package:flutter/material.dart';
class ImagePage extends StatelessWidget {
  final double width;
  final double height;
  final String src;
  ImagePage({Key? key,this.width=double.infinity,this.height=200,required this.src}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: width,
      height: height,
      child: Image.asset(src,fit: BoxFit.cover,),
    );
  }
}

轮播图组件

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter03/components/imgPage.dart';
class bannerPage extends StatefulWidget {
  final double width;
  final double height;
  final List<String> list;
  const bannerPage(
      {Key? key, this.width = 400, this.height = 300, required this.list})
      : super(key: key);
  @override
  State<bannerPage> createState() => _bannerPageState();
}
class _bannerPageState extends State<bannerPage> {
  List<Widget> ImgList = [];
  int _imgIndex = 0;
  late PageController _pageController;
  late Timer _timer;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _pageController = new PageController(initialPage: 0);
    //  duration  过 多少秒 重复 一次
    _timer = Timer.periodic(Duration(milliseconds: 4000), (timer) {
      // 执行 控制器
      _pageController.animateToPage(_imgIndex + 1 % ImgList.length,
          // 执行的 时间 长度
          duration: Duration(milliseconds: 500), curve: Curves.linear);
    });
    for (var i = 0; i < widget.list.length; i++) {
      // list  是 自己定义的   数组 长度
      ImgList.add(ImagePage(
        src: widget.list[i],
        width: widget.width,
        height: widget.height,
      ));
    }
  }
  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _pageController.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        SizedBox(
          height: 500,
          width: double.infinity,
          child: PageView.builder(
              itemCount: 1000,
              controller: _pageController,
              onPageChanged: (index) {
                setState(() {
                  _imgIndex = index % ImgList.length;
                });
              },
              itemBuilder: (BuildContext context, int index) {
                return ImgList[index % ImgList.length];
              }),
        ),
        Positioned(
            bottom: 0,
            left: MediaQuery.of(context).size.width / 2,
            child: Row(
              children: List.generate(3, (index) {
                return Container(
                  width: 15,
                  height: 15,
                  decoration: BoxDecoration(
                      color: _imgIndex == index ? Colors.blue : Colors.grey,
                      shape: BoxShape.circle),
                );
              }).toList(),
            ))
      ],
    );
  }
}


中英文切换

先导包

get: ^4.3.8

创建使用

return GetMaterialApp(
      debugShowCheckedModeBanner: false,
      title: "title",
      // 国际化 配置 化 文件
      translations: Messages(),
      //  默认 语言
      locale: Locale('zh', 'CN'),
      // 配置错误  使用的语言
      fallbackLocale: Locale('zh', 'CN'),
      home: MyTest(), //
    );

配置文件

import 'package:get/get.dart';
class Messages extends Translations{
  @override
  Map<String,Map<String,String>> get keys =>{
    'zh_CN':{
      'hello':"你好,世界"
    },
    'en_US':{
      'hello':"hello,world"
    }
  };
}

控制器

import 'dart:ui';
import 'package:get/get.dart';
class MessagesController extends GetxController{
  void changeLanguage(String languageCode,String countryCode){
    var locale=Locale(languageCode,countryCode);
    Get.updateLocale(locale);
  }
}


页面广告倒计时

late Timer _timer;
  double progress=1000;
  double totalProgress=6000;
  double borderWidth=1.0;
  int time=5;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _timer= Timer.periodic(Duration(milliseconds: 1000), (timer) {
      progress+=1000;
      time--;
      print(time);
      if(progress>=totalProgress){
        _timer.cancel();
        goHome();
      }
    });
  }
  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _timer.cancel();
  }
body: Column(
        children: [
          Container(
            child: Text(
              '倒计时: $time',
              style: TextStyle(fontSize: 22),
            ),
          ),
        ],
      )
goHome(){
    return Navigator.push( context as BuildContext,MaterialPageRoute(builder: (context){
      return Test03();
    }));
  }
import 'dart:async';
import 'package:flutter/material.dart';
class CountdownPage extends StatefulWidget {
  @override
  _CountdownPageState createState() => _CountdownPageState();
}
class _CountdownPageState extends State<CountdownPage> {
  late Timer _timer;
  int _second = 10;
  @override
  void initState() {
    super.initState();
    startTimer();
  }
  void startTimer() {
    _timer = Timer.periodic(Duration(milliseconds: 1000), (timer) {
      setState(() {
        if (_second < 1) {
          _timer.cancel();
        } else {
          _second--;
        }
      });
    });
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Countdown Page'),
      ),
      body: Center(
        child: Text(
          "$_second",
          style: TextStyle(
            fontSize: 48,
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
    );
  }
  @override
  void dispose() {
    _timer.cancel();
    super.dispose();
  }
}
void main() {
  runApp(MaterialApp(
    home: CountdownPage(),
  ));
}


顶部的导航条


先写一个 出口

import 'dart:math';
import 'package:flutter/material.dart';
import 'MyApp.dart';
void main() {
  runApp(MaterialApp(
    debugShowCheckedModeBanner: false,
    title: "轮播图实例",
    theme: ThemeData(primaryColor: Colors.grey),
    home: MyApp(),
  ));
}

写一个  searchPage

import 'package:flutter/material.dart';
class SearchAppBar extends StatefulWidget {
  //  带  的 属性  hint label
  String hintLabel;
  SearchAppBar({Key? key, required this.hintLabel}) : super(key: key);
  @override
  State<SearchAppBar> createState() => _SearchAppBarState();
}
class _SearchAppBarState extends State<SearchAppBar> {
  // focus
  late FocusNode _focusNode;
  // 组件 的 显示 控制
  bool _offstAge = false;
  //  文本框 的  控制
  final TextEditingController _textEditingController = TextEditingController();
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    //   初始化
    _focusNode = FocusNode();
// 添加  点击 事件
    _textEditingController.addListener(() {
      // 判断  是否 显示
      var isVisible =
          _textEditingController.text.isNotEmpty; //  不是空的  false  不显示
      //  更新 按钮
      _updateDelIconVisible(isVisible);
    });
  }
  //...
  _updateDelIconVisible(bool isVisible) {
    setState(() {
      // 点击 取反
      _offstAge = !isVisible;
    });
  }
  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _focusNode.unfocus();
  }
  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: double.infinity,
      height: 30,
      child: Row(
        children: [
          Expanded(
              flex: 1,
              child: Container(
                height: double.infinity,
                // 框框 总体 向左走
                margin: EdgeInsets.only(left: 12),
                decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(4)),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    Padding(padding: EdgeInsets.only(left: 8)),
                    // Icon(Icons.search_rounded,color: Colors.black,),
                    // Padding(padding: EdgeInsets.only(left: 8)),
                    Expanded(
                        flex: 1,
                        child: TextField(
                          controller: _textEditingController,
                          keyboardType: TextInputType.text,
                          autofocus: false,
                          focusNode: _focusNode,
                          style: TextStyle(
                            fontSize: 14,
                            color: Colors.black,
                          ),
                          decoration: InputDecoration(
                              // 输入框 文字的 位置
                              contentPadding:
                                  EdgeInsets.only(top: 8.0, left: 8.0),
                              hintText: widget.hintLabel,
                              // 前面 的 图标
                              prefixIcon: GestureDetector(
                                child: Icon(Icons.search_rounded),
                              ),
                              // 后面的图标
                              suffixIcon: GestureDetector(
                                onTap: () {
                                  _textEditingController.clear();
                                  _focusNode.unfocus();
                                },
                                child: Icon(Icons.cancel_outlined),
                              ),
                              border: OutlineInputBorder(
                                borderRadius:
                                    BorderRadius.all(Radius.circular(5)),
                              )),
                          maxLines: 1,
                        )),
                    //配置 显示 与不显示
                    // Offstage(
                    //   offstage: _offstAge,
                    //   child: GestureDetector(
                    //       onTap: () => {
                    //         _textEditingController.clear()
                    //       },
                    //       child: Icon(Icons.cancel_outlined,color: Colors.black,)),
                    // ),
                    Padding(padding: EdgeInsets.only(right: 8)),
                  ],
                ),
              )),
          GestureDetector(
            onTap: () {
              _focusNode.unfocus();
            },
            child: Container(
              padding: const EdgeInsets.only(left: 16, right: 16),
              child: Text("取消",
                  style: TextStyle(fontSize: 16, color: Colors.black)),
            ),
          ),
        ],
      ),
    );
  }
}

使用

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          // padding
          titleSpacing: 0,
        toolbarHeight: 44,
        backgroundColor: Colors.white,
        elevation: 0,
        title: SearchAppBar(
          hintLabel:"电影/电视剧/影视"
        ),
      ),
      body: ListView(
        children: [
        ],
      ),
    );
  }


底部选择

_modelBottomSheet() {
    showModalBottomSheet(
        context: this.context,
        builder: (BuildContext context) {
          return Container(
            height: 200,
            width: double.infinity,
            child: Column(
              children: [
                Container(
                  alignment: Alignment.center,
                  height: 44,
                  child: Text("this is title"),
                ),
                Expanded(child: Text("this is content")),
                Container(
                  height: 1,
                  color: Colors.grey[200],
                ),
                Container(
                  height: 64,
                  child: Row(
                    children: [
                      Expanded(
                          child: TextButton(
                        onPressed: () {},
                        child: Text("cancel"),
                      )),
                      Container(width: 1, color: Colors.grey[200]),
                      Expanded(
                          child: TextButton(
                              onPressed: () {}, child: Text("confirm"))),
                    ],
                  ),
                ),
              ],
            ),
          );
        });
  }


路由点击跳转


GestureDetector(
            onTap: (){
              setState(() {
                Navigator.of(context).pushNamed("/personPage");
              });
            },
            child: Column(
              children: [
                Icon(Icons.home),
                Text("主页"),
              ],
            ),
          ),


得到输入框的值


TextEditingController _textEditingController = new TextEditingController();

children: [
            TextField(
              controller: _textEditingController,
            ),
            ElevatedButton(onPressed: (){
              print("${_textEditingController.text}");
            }, child: Text("得到输入框的值"))
          ],


写一个widget的 步骤

先创建 数据

import 'package:flutter/material.dart';
class FunctionButtonItem {
  final String imgUri;
  final String title;
  final Function? onTapHandle;
  FunctionButtonItem(this.imgUri, this.title, this.onTapHandle);
}
void defaultTapHandler(context) {}
final List<FunctionButtonItem> list = [
  FunctionButtonItem("assets/images/start.jpg", "看星星", null),
  FunctionButtonItem("assets/images/eat.jpeg", "吃东西", null),
  FunctionButtonItem("assets/images/face.jpg", "去上学", null),
  FunctionButtonItem("assets/images/battle.jpg", "决斗", null),
  FunctionButtonItem("assets/images/noodle.jpg", "面条", null),
  FunctionButtonItem("assets/images/sleep.webp", "躺着", null),
  FunctionButtonItem("assets/images/houseManage.jpg", "管理", (context) {
    bool isLogin = true;
    if (isLogin) {
      Navigator.pushNamed(context, "/login");
      return;
    } else {}
    Navigator.pushNamed(context, "/login");
  }),
  FunctionButtonItem("assets/images/sleep2.jpg", "睡觉", null),
];

使用数据

import 'package:flutter/material.dart';
import 'ButtonItem.dart';
class FunctionButtonWidget extends StatelessWidget {
  final FunctionButtonItem data;
  const FunctionButtonWidget(this.data, {Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: (){
        if(null != data.onTapHandle){
          data.onTapHandle!(context);
        }
      },
      child: Container(
        decoration: BoxDecoration(
          // color: Colors.black12
        ),
        margin: EdgeInsets.only(top: 20,left: 2.6),
        child: Column(
          children: [
            Image.asset(
              data.imgUri,
              width: MediaQuery.of(context).size.width * 0.32,
              height: 40,
            ),
            Padding(padding: EdgeInsets.only(top: 3)),
            Text(data.title),
          ],
        ),
      ),
    );
  }
}

封装成 widget

import 'package:flutter/material.dart';
import 'package:flutter03/components/buttonItem/function_button_widget.dart';
import 'ButtonItem.dart';
class FunctionButton extends StatelessWidget {
  const FunctionButton({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
  return Container(
    child: Wrap(
      spacing: 2.0,
      runSpacing: 1.0,
      children: list.map((item) => FunctionButtonWidget(item)).toList(),
    ),
  );
  }
}
FunctionButton(),


大demo


思路且代码

初始化 图片列表

@override
void initState() {
  super.initState();
  list = [
    "imgs/1.png",
    "imgs/laying.jpg",
    "imgs/noodle.jpg",
  ];
}

banner 组件

轮播图的 长宽高 参数

final double width;
  final double height;
  final List<String> list;
  const BannerPage(
      {super.key, this.height = 400, this.width = 400, required this.list});

组件 里面 的参数

int _currentIndex = 0;
  List<Widget> pageList = [];
  late PageController _pageController;
  late Timer timer;

初始化

@override
  void initState() {
    super.initState();
    //  pagecontroller
    _pageController = PageController(initialPage: 0);
   //   设置 循环时间 的 api 定时器
   timer  =  Timer.periodic(Duration(seconds: 2), (t) {
     _pageController.animateToPage(
         //  当前 页面 +1  余 数组的长度
         _currentIndex+1 % pageList.length,
         // duration
         duration: Duration(milliseconds: 300),
         //   动画 显示的样子
         curve: Curves.linear);
    });
   //data
    for (var i = 0; i < widget.list.length; i++) {
      //  添加 图片 
      pageList.add(ImagePage(
        src: widget.list[i],
        width: widget.width,
        height: widget.height,
      ));
    }
  }

图片组件

class ImagePage extends StatelessWidget {
  final double width;
  final double height;
  final String src;
  const ImagePage(
      {super.key,
      this.width = double.infinity,
      this.height = 200,
      required this.src});
  @override
  Widget build(BuildContext context) {
    //    定义 组件     设置 属性 在 组件  里面
    return SizedBox(
      width: width,
      height: height,
      child: Image.asset(src, fit: BoxFit.cover),
      // child: Text("hello,world"),
    );
  }
}

主要 代码

SizedBox(
            height: 400,
            width: 400,
            // 页面 编辑
            child: PageView.builder(
              // 需要加 控制器
              controller: _pageController,
              //  图片 改变时 
              onPageChanged: (index) {
                setState(() {
                  //  index  为  参数  得到的值 为  当前 图片 的下标
                  // 0 , 1,2,3,4
                  _currentIndex = index % pageList.length;
                });
              },
              //  页面 大小
              itemCount: 1000,
              itemBuilder: (context, index) {
                //0 % 3  = 0   1 %3 = 1   2 % 3 = 2   3  % 3 =  1
                return pageList[index % pageList.length];
              },
            ),
        ),

配置园点

Positioned(
          //  right  加  left   都 为 0  就会  占满 整行
          //  之后 便可 居中
          left: 180,
          bottom: 2,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: List.generate(3, (index) {
              return Container(
                margin: EdgeInsets.all(5),
                width: 10,
                height: 10,
                decoration: BoxDecoration(
                    //   小点 的 判断
                    color: _currentIndex == index ? Colors.blue : Colors.grey,
                    // borderRadius: BorderRadius.circular(5)
                    shape: BoxShape.circle),
              );
            }).toList(),
          ),
        )

全部代码

编写viewTest 页面

import 'package:flutter/material.dart';
import '../pages/widget/banner.dart';
class ViewTest extends StatefulWidget {
  const ViewTest({Key? key}) : super(key: key);
  @override
  State<ViewTest> createState() => _ViewTestState();
}
class _ViewTestState extends State<ViewTest> {
  List<String> list = [];
  @override
  void initState() {
    super.initState();
    list = [
      "imgs/1.png",
      "imgs/laying.jpg",
      "imgs/noodle.jpg",
    ];
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('hello,flutter'),
      ),
      body: ListView(
        children: [BannerPage(list: list)],
      ),
    );
  }
}

在 main 里面 配置

路 由

@override
  Widget build(BuildContext context) {
    return  MaterialApp(
      debugShowCheckedModeBanner: false,
      // home: Tabs(),
      initialRoute: '/',
    routes: {
        "/":(context)=>const Tabs(),
      "/news":(context)=>const NewsPage(),
      "/viewtest":(context)=> ViewTest(),
      "/form":(context)=>const DialogPage(),
      "/login":(context)=>const LoginPage(),
      "/register":(context)=>const RegisterPage()
    },
    );
  }

编写banner页面的代码

import 'dart:async';
import 'package:flutter/material.dart';
class BannerPage extends StatefulWidget {
  final double width;
  final double height;
  final List<String> list;
  const BannerPage(
      {super.key, this.height = 400, this.width = 400, required this.list});
  @override
  State<BannerPage> createState() => _BannerPageState();
}
class _BannerPageState extends State<BannerPage> {
  int _currentIndex = 0;
  List<Widget> pageList = [];
  late PageController _pageController;
  late Timer timer;
  @override
  void initState() {
    super.initState();
    //  pagecontroller
    _pageController = PageController(initialPage: 0);
   timer  =  Timer.periodic(Duration(seconds: 2), (t) {
     _pageController.animateToPage(_currentIndex+1 % pageList.length, duration: Duration(milliseconds: 300), curve: Curves.linear);
    });
    //data
    for (var i = 0; i < widget.list.length; i++) {
      pageList.add(ImagePage(
        src: widget.list[i],
        width: widget.width,
        height: widget.height,
      ));
    }
  }
  //  销毁
  @override
  void dispose(){
    super.dispose();
    //  取消  计时器
    timer.cancel();
    _pageController.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        SizedBox(
            height: 400,
            width: 400,
            child: PageView.builder(
              controller: _pageController,
              onPageChanged: (index) {
                setState(() {
                  _currentIndex = index % pageList.length;
                });
              },
              itemCount: 1000,
              itemBuilder: (context, index) {
                //0 % 3  = 0   1 %3 = 1   2 % 3 = 2   3  % 3 =  1
                return pageList[index % pageList.length];
              },
            ),
        ),
        Positioned(
          //  right  加  left   都 为 0  就会  占满 整行
          //  之后 便可 居中
          left: 180,
          bottom: 2,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: List.generate(3, (index) {
              return Container(
                margin: EdgeInsets.all(5),
                width: 10,
                height: 10,
                decoration: BoxDecoration(
                    //   小点 的 判断
                    color: _currentIndex == index ? Colors.blue : Colors.grey,
                    // borderRadius: BorderRadius.circular(5)
                    shape: BoxShape.circle),
              );
            }).toList(),
          ),
        )
      ],
    );
  }
}
class ImagePage extends StatelessWidget {
  final double width;
  final double height;
  final String src;
  const ImagePage(
      {super.key,
      this.width = double.infinity,
      this.height = 200,
      required this.src});
  @override
  Widget build(BuildContext context) {
    //    定义 组件     设置 属性 在 组件  里面
    return SizedBox(
      width: width,
      height: height,
      child: Image.asset(src, fit: BoxFit.cover),
      // child: Text("hello,world"),
    );
  }
}



相关文章
|
Dart Linux API
Flutter 上使用 C/C++ 代码(上)
Flutter 上使用 C/C++ 代码(上)
2942 0
Flutter 上使用 C/C++ 代码(上)
|
1天前
|
Dart 开发者 Windows
flutter:dart的学习
本文介绍了Dart语言的下载方法及基本使用,包括在Windows系统上和VSCode中的安装步骤,并展示了如何运行Dart代码。此外,还详细说明了Dart的基础语法、构造函数、泛型以及库的使用方法。文中通过示例代码解释了闭包、运算符等概念,并介绍了Dart的新特性如非空断言操作符和延迟初始化变量。最后,提供了添加第三方库依赖的方法。
19 12
|
iOS开发 容器
Flutter系列文章-Flutter UI进阶
在本篇文章中,我们将深入学习 Flutter UI 的进阶技巧,涵盖了布局原理、动画实现、自定义绘图和效果、以及 Material 和 Cupertino 组件库的使用。通过实例演示,你将更加了解如何创建复杂、令人印象深刻的用户界面。
19275 25
Flutter系列文章-Flutter UI进阶
|
Dart IDE Unix
Flutter:创建和发布一个 Dart Package
在 Dart 生态系统中使用 packages(包) 实现代码的共享,比如一些 library 和工具。本文旨在介绍如何创建和发布一个 package。
445 0
Flutter:创建和发布一个 Dart Package
|
开发框架 Dart IDE
Flutter系列文章-Flutter环境搭建和Dart基础
Flutter是Google推出的一个开源的、高性能的移动应用开发框架,可以用一套代码库开发Android和iOS应用。Dart则是Flutter所使用的编程语言。让我们来看看如何搭建Flutter开发环境,并了解Dart语言的基础知识。
180 0
|
设计模式
flutter系列之:在flutter中自定义themes
一般情况下我们在flutter中搭建的app基本上都是用的是MaterialApp这种设计模式,MaterialApp中为我们接下来使用的按钮,菜单等提供了统一的样式,那么这种样式能不能进行修改或者自定义呢? 答案是肯定的,一起来看看吧。
|
Dart Java API
4、Flutter开发-导入并升级flutter-go示例
因Flutter升级,FlutterGo暂停维护,这里导入的项目只能切回到旧版本,这里为了适应新版本的Flutter和Dart,我们新建项目,升级flutter-go,并记录学习。 1、按照之前章节,新建一个flutter_go的Flutter项目,修改build.gradle文件
405 56
|
自然语言处理 Dart JavaScript
Flutter之搞定Dart(一)
Google为Flutter选择了Dart就已经是既定的事实,无论你多么想用你熟悉的语言,比如JavaScript、Java、Swift、C++等来开发Flutter,至少目前都是不可以的。 在讲解Dart的过程中,我会假定你已经有一定的编程语言基础,比如JavaScript、Java、Python、C++等。
386 0
Flutter之搞定Dart(一)
|
Dart
Flutter之搞定Dart(二上)
这里,我只列出来相对其他语言比较特殊的运算符,因为某些运算符太简单了,不浪费时间,比如+、-、+=、==。 你可能会疑惑,Dart为什么要搞出这么多特殊的运算符呢? 你要坚信一点:所有这些特殊的运算符都是为了让我们在开发中可以更加方便的操作,而不是让我们的编码变得更加复杂。
163 0
Flutter之搞定Dart(二上)
|
存储 Dart
Flutter之搞定Dart(二下)
这里,我只列出来相对其他语言比较特殊的运算符,因为某些运算符太简单了,不浪费时间,比如+、-、+=、==。 你可能会疑惑,Dart为什么要搞出这么多特殊的运算符呢? 你要坚信一点:所有这些特殊的运算符都是为了让我们在开发中可以更加方便的操作,而不是让我们的编码变得更加复杂。
322 0
Flutter之搞定Dart(二下)