Flutter开发日常练习-小猫咪杂货店(新增欢迎页,广告页和侧滑页面)

news2024/11/25 7:15:17

养小猫咪的伙伴来我的店铺逛逛吧!抖音商城搜索#早睡早起的猫咪小铺子

Flutter开发日常练习-小猫咪杂货店(新增动画和跳转抖音)_workersJiaDa的博客-CSDN博客URL Launcher是一个Flutter插件,它允许您的应用程序启动网络浏览器、地图应用程序、拨号器应用程序、邮件应用程序等。设定好每个图片的id,通过id作为 'Hero' 组件的标识,id不能重,否则会报错,在这两个页面中必须相同。给列表上的文字加了个缩放的提示动画,感觉很有意思,也有别的效果可以自己试一下。之前的练习加了个详情页面,然后跳转第三方页面抖音用户详情页面。跳转详情页添加了Hero的动画,共享元素过度。https://blog.csdn.net/zxc8890304/article/details/130317615

猫咪杂货铺项目持续更新中

APP设计思路的话改成猫咪百科好了,不会后端,数据源抓包,本地存着了

  1. 登录注册,个人信息添加本地存储修改
  2. 国际化版本
  3. 白天黑夜模式 
  4. 购物车物品删除
  5. 下单到订单支付流程
  6. 工具类整理(字体大小,字体颜色,主题颜色等)
  7. 图片库工具处理
  8. webview页面拦截优化
  9. 整体性能优化
  10. 打包处理

sp_util 是个不错的工具类

flutter_screenutil

在使用的时候需要注册宽度和高度

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return ScreenUtilInit(
      designSize: const Size(375, 681),
      builder: (BuildContext context, Widget? child) =>  ChangeNotifierProvider(
        create: (context) => CarModel(),
        child: MaterialApp(
          debugShowCheckedModeBanner: false,
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const StartPage(),
        ),
      ),
    );
  }
}

webview_flutter

添加webview跳转 

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:webview_flutter/webview_flutter.dart';

class WebPage extends StatefulWidget {
  final String url;
  final String title;
  const WebPage({super.key, required this.url, required this.title});

  @override
  State<WebPage> createState() => _WebPageState(this.url, this.title);
}

class _WebPageState extends State<WebPage> {
  final String url;
  final String title;

  late final WebViewController controller;

  _WebPageState(this.url, this.title);
  @override
  void initState() {
    controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..setBackgroundColor(const Color(0x00000000))
      ..setNavigationDelegate(
        NavigationDelegate(
          onProgress: (int progress) {
            // Update loading bar.
          },
          onPageStarted: (String url) {},
          onPageFinished: (String url) {},
          onWebResourceError: (WebResourceError error) {},
          onNavigationRequest: (NavigationRequest request) {
            if (request.url.startsWith('https://pub.dev/')) {
              return NavigationDecision.prevent;
            }
            return NavigationDecision.navigate;
          },
        ),
      )
      ..loadRequest(Uri.parse(url));

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Column(
        children: [
          Expanded(
            child: WebViewWidget(controller: controller),
          ),
        ],
      ),
    );
  }
}

倒计时的广告,使用Timer来倒计时实现,

second_index是设定时间

设定时间自己修改,也可以服务端来修改

import 'dart:async';

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_cat_1/pages/intro_page.dart';
import 'package:flutter_cat_1/tools/tools.dart';
import 'package:flutter_cat_1/web/web_page.dart';
import 'package:google_fonts/google_fonts.dart';

import '../main.dart';

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

  @override
  State<WelcomePage> createState() => _WelcomePageState();
}

class _WelcomePageState extends State<WelcomePage> {
  int second_index = 3;
  int timeIndex = 0;
  late Timer timer;

  @override
  void initState() {
    super.initState();
    timer = Timer.periodic(
      Duration(milliseconds: 50),
      (sd) {
        setState(() {
          timeIndex += 1;
          if (timeIndex % 20 == 0) {
            second_index -= 1;
          }
        });
        if (timeIndex >= 100) {
          _openMain();
        }
      },
    );
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        alignment: Alignment.center,
        children: <Widget>[
          Container(
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
            child: Image.asset(
              "assets/IMG_8050.png",
              fit: BoxFit.cover,
            ),
          ),
          Container(
            alignment: Alignment.bottomRight,
            child: Container(
              width: 50,
              height: 50,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(25),
              ),
              alignment: Alignment.center,
              margin: const EdgeInsets.all(25),
              child: GestureDetector(
                onTap: () {
                  _openMain();
                },
                child: Stack(
                  children: <Widget>[
                    Container(
                      alignment: Alignment.center,
                      child: CircularProgressIndicator(
                        value: timeIndex / 100,
                        strokeWidth: 2,
                      ),
                    ),
                    Container(
                      alignment: Alignment.center,
                      child: Text(
                        "跳过",
                        style: TextStyle(fontSize: 12,color: Colors.white,fontWeight: FontWeight.bold,),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
          Container(
            alignment: Alignment.center,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                RichText(
                  text: TextSpan(
                    text: "Flutter开发日常练习",
                    style: GoogleFonts.notoSerif(
                      color: Colors.black,
                      fontSize: 17,
                    ),
                    children: [
                      TextSpan(
                          text: "-小猫咪杂货店",
                          style: GoogleFonts.notoSerif(
                            color: Colors.black,
                            fontSize: 17,
                            // decoration: TextDecoration.underline,
                            // decorationColor: Colors.blue[800],
                          )),
                    ],
                  ),
                  textDirection: TextDirection.ltr,
                ),
                SizedBox(
                  height: 10,
                ),
                RichText(
                  text: TextSpan(
                    text: 'CSDN关注',
                    style: GoogleFonts.notoSerif(
                      fontSize: 17,
                      color: Colors.black,
                    ),
                    children: [
                      TextSpan(
                          text: 'workersJiaDa',
                          style: GoogleFonts.notoSerif(
                            fontSize: 17,
                            color: Colors.blue[800],
                            decoration: TextDecoration.underline,
                            decorationColor: Colors.blue[800],
                            fontWeight: FontWeight.bold,
                          ),
                          recognizer: TapGestureRecognizer()
                            ..onTap = () {
                              timer.cancel();
                              Navigator.of(context)
                                  .push(
                                    MaterialPageRoute(
                                      builder: (context) => WebPage(
                                          url:
                                              "https://blog.csdn.net/zxc8890304",
                                          title: "workersJiaDa的博客"),
                                    ),
                                  )
                                  .then((value) => reGetTimer());
                            }),
                    ],
                  ),
                ),
                SizedBox(
                  height: 10,
                ),
                RichText(
                  text: TextSpan(
                    text: '抖音商城搜索',
                    style: GoogleFonts.notoSerif(
                      color: Colors.black,
                      fontSize: 17,
                    ),
                    children: [
                      TextSpan(
                        text: "早睡早起的猫咪小铺子",
                        style: GoogleFonts.notoSerif(
                          fontSize: 17,
                          color: Colors.blue[800],
                          decoration: TextDecoration.underline,
                          decorationColor: Colors.blue[800],
                          fontWeight: FontWeight.bold,
                        ),
                        recognizer: TapGestureRecognizer()
                          ..onTap = () {
                            // timer.cancel();
                            launchURL('snssdk1128://user/profile/88486395468');
                          },
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  void _openMain() {
    timer.cancel();
    Navigator.pushAndRemoveUntil(
        context,
        MaterialPageRoute(
          builder: (context) => const IntroPage(),
        ),
        (route) => false);
  }

  void reGetTimer() {
    timer = Timer.periodic(
      Duration(milliseconds: 50),
      (sd) {
        setState(() {
          timeIndex += 1;
          if (timeIndex % 20 == 0) {
            second_index -= 1;
          }
        });
        if (timeIndex >= 100) {
          _openMain();
        }
      },
    );
  }
}

 欢迎页的话是

flutter_swiper_plus 

 非常简陋,简单的实现效果,要重新优化修改

添加了isFirst的判断,第一次打开APP才会显示,

之前做过国际化的项目,海外的需求是

只要是进入欢迎页不点跳过或者进入APP,每次进入APP都会再进入欢迎页面

这样做的话判断的条件需要重新修改一下

import 'dart:isolate';

import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
import 'package:flutter_cat_1/welcome/welcome_page.dart';
import 'package:flutter_swiper_plus/flutter_swiper_plus.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:sp_util/sp_util.dart';

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

  @override
  State<StartPage> createState() => _StartPageState();
}

class _StartPageState extends State<StartPage> {
  bool _isLogin = false;
  bool _isFirst = false;
  bool _islastPage = false;
  int pageInt = 1;
  final List _welcomeList = ["welcome_1.png", "welcome_2.png", "welcome_3.png"];

  @override
  void initState() {
    super.initState();
    _isFirst = SpUtil.getBool("first")!;

    if (_isFirst) {
      String? tokenStr = SpUtil.getString('token');
      _isLogin = (tokenStr == null || tokenStr.isEmpty) ? false : true;
      new Future.delayed(Duration(seconds: 0), () {
        Navigator.of(context).pushAndRemoveUntil(
            MaterialPageRoute(
              builder: (context) => WelcomePage(),
            ),
            (route) => false);
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return 
    Container(
      color: Colors.white,
      height: ScreenUtil().screenHeight,
      child: Stack(
        children: [
          Swiper(
            itemBuilder: (context, index) {
              return Image.asset(
                "assets/${_welcomeList[index]}",
                fit: BoxFit.cover,
              );
            },
            itemCount: _welcomeList.length,
            loop: false,
            onIndexChanged: (index) {
              pageInt = index + 1;
              if (index == _welcomeList.length - 1) {
                setState(() {
                  _islastPage = true;
                });
              } else {
                setState(() {
                  _islastPage = false;
                });
              }
            },
          ),
          Container(
            width: 100,
            height: 40,
            alignment: Alignment.center,
            margin: EdgeInsets.only(
              left: ScreenUtil().screenWidth / 2 - 50,
              bottom: 40,
              top: ScreenUtil().screenHeight - 80,
              right: ScreenUtil().screenWidth / 2 - 50,
            ),
            child: Text(
              "$pageInt / 3",
              style: const TextStyle(
                  color: Colors.white,
                  fontSize: 30,
                  fontWeight: FontWeight.bold,
                  decoration: TextDecoration.none),
            ),
          ),
          Container(
            width: 100,
            height: 40,

            margin: EdgeInsets.only(
              left: ScreenUtil().screenWidth / 2 + 100,
              bottom: 40,
              top: ScreenUtil().screenHeight - 80,
              // right: ScreenUtil().screenWidth / 2 - 10,
            ),
            // decoration: BoxDecoration(
            //   border: Border.all(color: Colors.blue[900], width: 2),
            //   borderRadius: BorderRadius.circular(8),
            // ),
            child: Center(
              child: TextButton(
                onPressed:() => _jumpWelcome(),
                  // Navigator.push(context, MaterialPageRoute(
                  //   builder: (context) {
                       
                  //   },
                  // ));
              
                child: _islastPage
                    ? Text(
                        "立即进入",
                        style: GoogleFonts.notoSerif(
                            fontSize: 17,
                            color: Colors.blue[700],
                            fontWeight: FontWeight.bold),
                      )
                    : Text(
                        "跳过",
                        style: GoogleFonts.notoSerif(
                            fontSize: 17,
                            color: Colors.blue[700],
                            fontWeight: FontWeight.bold),
                      ),
              ),
            ),
          )
        ],
      ),
    );
  }

  _jumpWelcome() {
    SpUtil.putBool('first',true);
    String? tokenStr = SpUtil.getString("token");
    _isLogin = (tokenStr == null || tokenStr.isEmpty) ? false : true;
        Navigator.of(context).pushAndRemoveUntil(
            MaterialPageRoute(
              builder: (context) => WelcomePage(),
            ),
            (route) => false);
  }
}

 侧滑栏也是,比较简陋

import 'package:flutter/material.dart';
import 'package:flutter_cat_1/welcome/start_page.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

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

  @override
  Widget build(BuildContext context) {
    return Drawer(
      elevation: 300,
      child: Stack(
        children: <Widget>[
          Column(
            children: <Widget>[
              UserAccountsDrawerHeader(
                accountName: Text("铲屎官铲屎官铲屎官"),
                accountEmail: Text("饲养员饲养员饲养员"),
                currentAccountPicture: CircleAvatar(
                  backgroundImage: AssetImage("assets/IMG_9406.png"),
                ),
                arrowColor: Colors.red,
                onDetailsPressed: () {},
                decoration: BoxDecoration(
                  boxShadow: [
                    BoxShadow(
                      color: Colors.black.withOpacity(0.5),
                      offset: Offset(10, 10),
                      blurRadius: 45,
                      spreadRadius: 0.0,
                    ),
                  ],
                  image: DecorationImage(
                      image: AssetImage(
                        "assets/IMG_0259.png",
                      ),
                      fit: BoxFit.cover),
                ),
              ),
              Expanded(
                child: ListView(
                  padding: EdgeInsets.symmetric(vertical: 10),
                  children: <Widget>[
                    ListTile(
                      title: Text('个人中心'),
                    ),
                    Divider(),
                    ListTile(
                      title: Text('我的小猫咪'),
                    ),
                    Divider(),
                    ListTile(
                      title: Text("我的订单"),
                    ),
                    Divider(),
                    ListTile(
                      title: Text("关于我们"),
                    ),
                    Divider(),
                  ],
                ),
              ),
            ],
          ),
          Positioned(
            bottom: 20,
            right: 20,
            child: InkWell(
              child: Row(
                mainAxisAlignment: MainAxisAlignment.end,
                crossAxisAlignment: CrossAxisAlignment.end,
                children: <Widget>[
                  GestureDetector(
                    onTap: () => Navigator.of(context).pushAndRemoveUntil(
                        MaterialPageRoute(
                      builder: (context) {
                        return StartPage();
                      },
                    ), (route) => false),
                    child: MenuItemButton(
                        child: Column(
                      children: const <Widget>[
                        Icon(
                          Icons.power_settings_new_outlined,
                          color: Colors.red,
                        ),
                        Text(
                          "退出登录",
                          style: TextStyle(
                            color: Colors.red,
                            fontSize: 12,
                          ),
                        ),
                      ],
                    )),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

DEMO地址 

GitHub - HelloJiada/flutter_cat_1Contribute to HelloJiada/flutter_cat_1 development by creating an account on GitHub.https://github.com/HelloJiada/flutter_cat_1.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/461280.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Object Manager中的Hierarchy Columns

【前言】&#xff1a;最近偶然发现Object Manager中多了一项Hierarchy Columns&#xff0c;正好在做Case Mgmt这块的业务&#xff0c;需要做Case Hierarchy&#xff0c;或许熟悉这个新概念对后续方案的落地有一定启发。 #1. Account Hierarchy - 这个是标准功能&#xff0c;Acc…

【Winform学习笔记(二)】TextBox文本框实现按回车键触发Button事件

TextBox文本框实现按回车键触发Button事件 前言正文1、实现方法2、具体代码3、实现效果 前言 在本文中主要介绍 如何基于 Winform 框架实现 TextBox 文本框实现按回车键触发 Button 事件&#xff0c;该功能可实现在文本框中输入密码后不需要按登录或确定按钮&#xff0c;直接回…

如果建立一个由AI组成的社会……

你有没有想过&#xff0c;如果我们建立一个完全由AI组成的公民社会团体&#xff0c;让它们模仿人类的文明发展&#xff0c;那么这个AI社会最终将会进化到何种文明程度&#xff1f;需要明确的是AI社会只有AI&#xff0c;没有人类&#xff0c;完全是AI之间互相沟通交流&#xff0…

制作剧本杀小游戏系统

制作剧本杀小游戏软件的功能可以包括以下几点&#xff1a; 角色设定和分配&#xff1a;提供多种角色供玩家选择&#xff0c;根据玩家数量随机分配角色。 剧情框架&#xff1a;提供预设的剧情框架&#xff0c;或者允许用户自定义剧情。 背景设定&#xff1a;提供游戏…

图像处理:高斯滤波算法

目录 前言 概念介绍 基本原理 卷积核的大小 卷积核的形状和权重比 卷积核的归一化 结论 Opencv实现高斯滤波 Python手写实现高斯滤波 参考文章 前言 在此之前&#xff0c;我曾在此篇中推导过图像处理&#xff1a;推导五种滤波算法&#xff08;均值、中值、高斯、双边…

linux 命令之 tar -czvf和 tar -xzvf

文章目录 一、概述&#xff1a;二、基础知识 一、概述&#xff1a; tar 用于linux 系统中压缩和解压 二、基础知识 tar常用命令参数说明 tar命令的czvf/xzvf参数分别代表的意义如下&#xff1a; -c 或–create 建立新的备份文件。 -x或–extract或–get 从备份文件中还原文件…

为什么用Selenium做自动化测试

手工测试的问题 手工操作点点点借助的是人脑的反应和聪明&#xff0c;为什么不用手点了呢&#xff1f;手会酸&#xff0c;脑子会累&#xff0c;会占据太多的时间。想一想为什么会学习自动化测试。我们都希望通过工具来解放我们的双手&#xff0c;大脑&#xff0c;眼睛。 为什…

蚂蚁安全科技 Nydus 镜像加速实践

蚂蚁安全科技 Nydus 镜像加速实践 原创 曦栖 金融级分布式架构 文&#xff5c;蚂蚁集团 ZOLOZ 团队 使用全球领先安全科技&#xff0c;为用户和机构提供安全、便捷的安全风控解决方案。 本文 6386 字 阅读 12 分钟 背景简介 ZOLOZ[1]是蚂蚁集团旗下的全球安全风控平台&…

84.qt qml-Sprite精灵、SpriteSequence、ImageParticle使用Sprite精灵动画(三)

在上章我们学习了83.qt qml-初步学习2D粒子影响器(二)_诺谦的博客-CSDN博客 然后还有两个影响器没有学习: 粒子精灵影响器SpriteGoal 粒子组影响器GroupGoal 本章我们便来学习粒子精灵和粒子精灵影响器 ImageParticle通过sprites来设置精灵列表,如下图所示: 所以我们需要…

JVM学习(八):运行时数据区——虚拟机栈(字节码程度深入剖析)

目录 一、概述 1.1 基于栈结构的虚拟机 1.2 栈和堆 二、虚拟机栈&#xff08;Java Virtual Machine Stack&#xff09;详述 2.1 虚拟机栈介绍 2.2 虚拟机栈作用 2.3 虚拟机栈特点 三、栈中常见的异常 3.1 StackOverflowError异常 3.2 OutOfMemoryError异常 四、…

OpenGL学习笔记(一)

文章目录 1. 顶点2. 着色器(Shader) 1. 顶点 OpenGL本质是一个状态机&#xff0c;点作为表示图形最基本的元素&#xff0c;如何告诉OpenGL点的基本信息就是我们要做的事情 1.1VertexArray VertexArray是所有顶点的集合&#xff0c;我们可以将VertexBuffer分成很多组&#xff…

Volatile系列(一):Volatile测试案例一可见性

系列文章 Volatile测试案例一可见性 目录​​​​​​​ 前言 测试1 逻辑 代码 结果 测试2 逻辑 代码 结果 结论 原理探讨&#xff08;可见性&#xff09; 前言 多线程是 JAVA 并发编程的主要应用&#xff0c;并发环境能大幅提高应用性能&#xff0c;提高 CPU 使用…

基于springboot+mysql+html实现智能停车场管理系统

基于springbootmysqlhtml实现智能停车场管理系统 一、系统介绍1、系统主要功能&#xff1a;2.涉及技术框架&#xff1a;3.本项目所用环境&#xff1a; 二、功能展示三、其它系统四、获取源码 一、系统介绍 1、系统主要功能&#xff1a; 系统管理&#xff1a;角色管理、接口管…

华为OD机试真题(Java),货币单位换算(100%通过+复盘思路)

一、题目描述 记账本上记录了若干条多国货币金额&#xff0c;需要转换成人民币分 (fen)&#xff0c;汇总后输出每行记录一条金额&#xff0c;金额带有货币单位&#xff0c;格式为数字单位&#xff0c;可能是单独元&#xff0c;或者单独分&#xff0c;或者元与分的组合要求将这…

解决方案:Zotero实现参考文献中英文混排,将英文文献中的“等”转成“et al.”

Zotero 是一款非常实用且易于使用的参考文献管理工具&#xff0c;可帮助用户收集、整理和引用各种类型的文献&#xff0c;包括图书、期刊文章、网页等。在学术写作中起着重要作用。 但是其在中文世界中&#xff0c;运行起来偶尔会出现问题&#xff0c;这里记录一个问题及其解决…

Nacos安装配置2.0以上版本

一、Nacos使用 1、官网 Nacos Spring 快速开始 Nacos Spring Boot 快速开始 Nacos Spring Cloud 快速开始 Nacos Docker 快速开始 Dubbo 融合 Nacos 成为注册中心 Kubernetes Nacos NacosSync 介绍 2、配置文件 nacos-配置中心官方文档说明 nacos-注册中心官方文档说明 在nacos…

浅谈拉格朗日插值法

浅谈拉格朗日插值法 好像FFT要用到&#xff0c;所以就学习一手 文章目录 浅谈拉格朗日插值法什么是插值拉格朗日插值法 什么是插值 在离散数据的基础上补插连续的函数&#xff0c;使得这条连续函数经过所有离散数据点&#xff0c;这个过程就叫插值。其意义在于&#xff1a; …

缓存和数据库一致性问题

情况一 先更新缓存再更新数据库 先更新缓存 再更新数据库 如果数据库更新失败 那我们缓存也没有意义 而且这个缓存也是需要计算的消耗资源的 所以不可取到 情况二 先更新数据库 后更新缓存 两个线程 线程A更新数据库 但是由于某些原因被阻塞了 也就是A更新后的数值没有被更新到…

Ajax 创建对象

文章目录 AJAX 创建对象创建 XMLHttpRequest 对象XMLHttpRequest 对象创建 XMLHttpRequest 对象 AJAX 创建对象 创建 XMLHttpRequest 对象 XMLHttpRequest 是 AJAX 的基础。 XMLHttpRequest 对象 所有现代浏览器均支持 XMLHttpRequest 对象&#xff08;IE5 和 IE6 使用 Acti…

【pyTorch学习笔记③】PyTorch基础·上篇

文章目录 一、PyTorch介绍二、PyTorch的安装1、CPU版本2、GPU版本 三、Numpy与Tensor1.Tensor的创建2.Tensor的变形 相关推荐 一、PyTorch介绍 PyTorch是Facebook发布的一款深度学习框架&#xff0c;继承了Torch灵活、动态的编程环境和用户友好的界面&#xff0c;支持以快速和灵…