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"),
    );
  }
}



相关文章
|
7月前
|
Dart 对象存储 Android开发
带你阅读 Flutter Demo(flutter 保姆级入门教程)
带你阅读 Flutter Demo(flutter 保姆级入门教程)
756 0
|
Dart 开发工具 Android开发
flutter初体验demo踩坑指南
用flutter开发app客户端遇到的各种问题和解决办法
281 1
|
Android开发
android和Flutter的混合工程Demo
Flutter和Android混合工程的启动逻辑与纯Flutter应用程序的启动逻辑略有不同。在混合工程中,您需要在Android项目中添加一些额外的代码来启动Flutter引擎并加载Flutter代码。以下是整个app的启动逻辑的详细解释
android和Flutter的混合工程Demo
|
2月前
|
Android开发 iOS开发 容器
鸿蒙harmonyos next flutter混合开发之开发FFI plugin
鸿蒙harmonyos next flutter混合开发之开发FFI plugin
|
8天前
|
传感器 前端开发 Android开发
在 Flutter 开发中,插件开发与集成至关重要,它能扩展应用功能,满足复杂业务需求
在 Flutter 开发中,插件开发与集成至关重要,它能扩展应用功能,满足复杂业务需求。本文深入探讨了插件开发的基本概念、流程、集成方法、常见类型及开发实例,如相机插件的开发步骤,同时强调了版本兼容性、性能优化等注意事项,并展望了插件开发的未来趋势。
22 2
|
2月前
|
开发者
鸿蒙Flutter实战:07-混合开发
鸿蒙Flutter混合开发支持两种模式:1) 基于har包,便于主项目开发者无需关心Flutter细节,但不支持热重载;2) 基于源码依赖,利于代码维护与热重载,需配置Flutter环境。项目结构包括AppScope、flutter_module等目录,适用于不同开发需求。
80 3
|
26天前
|
传感器 开发框架 物联网
鸿蒙next选择 Flutter 开发跨平台应用的原因
鸿蒙(HarmonyOS)是华为推出的一款旨在实现多设备无缝连接的操作系统。为了实现这一目标,鸿蒙选择了 Flutter 作为主要的跨平台应用开发框架。Flutter 的跨平台能力、高性能、丰富的生态支持和与鸿蒙系统的良好兼容性,使其成为理想的选择。通过 Flutter,开发者可以高效地构建和部署多平台应用,推动鸿蒙生态的快速发展。
170 0
|
28天前
|
Dart 安全 UED
Flutter&鸿蒙next中的表单封装:提升开发效率与用户体验
在移动应用开发中,表单是用户与应用交互的重要界面。本文介绍了如何在Flutter中封装表单,以提升开发效率和用户体验。通过代码复用、集中管理和一致性的优势,封装表单组件可以简化开发流程。文章详细讲解了Flutter表单的基础、封装方法和表单验证技巧,帮助开发者构建健壮且用户友好的应用。
65 0
|
2月前
|
开发框架 移动开发 Android开发
安卓与iOS开发中的跨平台解决方案:Flutter入门
【9月更文挑战第30天】在移动应用开发的广阔舞台上,安卓和iOS两大操作系统各自占据半壁江山。开发者们常常面临着选择:是专注于单一平台深耕细作,还是寻找一种能够横跨两大系统的开发方案?Flutter,作为一种新兴的跨平台UI工具包,正以其现代、响应式的特点赢得开发者的青睐。本文将带你一探究竟,从Flutter的基础概念到实战应用,深入浅出地介绍这一技术的魅力所在。
84 7
|
2月前
|
编解码 Dart API
鸿蒙Flutter实战:06-使用ArkTs开发Flutter鸿蒙插件
本文介绍了如何开发一个 Flutter 鸿蒙插件,实现 Flutter 与鸿蒙的混合开发及双端消息通信。通过定义 `MethodChannel` 实现 Flutter 侧的 token 存取方法,并在鸿蒙侧编写 `EntryAbility` 和 `ForestPlugin`,使用鸿蒙的首选项 API 完成数据的读写操作。文章还提供了注意事项和参考资料,帮助开发者更好地理解和实现这一过程。
74 0