flutter学习-day12-可滚动组件和监听

📚 目录

  1. 简介
  2. 可滚动组件
    1. SingleChildScrollView
    2. ListView
      1. separated分割线
      2. 无限加载列表
      3. 带标题列表
  3. 滚动监听和控制
    1. ScrollController滚动监听
    2. NotificationListener滚动监听
  4. AnimatedList动画列表
  5. 滚动网格布局GridView
    1. 横轴子元素为固定数量
    2. 横轴子元素为固定最大长度
    3. 动态创建
  6. PageView页面切换和缓存
    1. PageState缓存
  7. TabBarView
  8. CustomScrollView和Slivers
    1. 常用的Slivers

本文学习和引用自《Flutter实战·第二版》:作者:杜文

1. 简介

通常可滚动组件的子组件可能会非常多、占用的总高度也会非常大;如果要一次性将子组件全部构建出将会非常昂贵!为此,Flutter中提出一个Sliver(中文为“薄片”的意思)概念,Sliver 可以包含一个或多个子组件。Sliver 的主要作用是配合:加载子组件并确定每一个子组件的布局和绘制信息,如果 Sliver 可以包含多个子组件时,通常会实现按需加载模型。只有当 Sliver 出现在视口中时才会去构建它,这种模型也称为“基于Sliver的列表按需加载模型”。可滚动组件中有很多都支持基于Sliver的按需加载模型,如ListView、GridView,但是也有不支持该模型的,如SingleChildScrollView。

Flutter 中的可滚动组件主要由三个角色组成:

  • Scrollable :用于处理滑动手势,确定滑动偏移,滑动偏移变化时构建 Viewport。
方法描述
axisDirection-滚动方向
physicsClampingScrollPhysics、BouncingScrollPhysics决定可滚动组件如何响应用户操作
controller-控制滚动位置和监听滚动事件
viewportBuilder-当用户滑动时,Scrollable 会调用此回调构建新的 Viewport,同时传递一个 ViewportOffset 类型的 offset 参数,该参数描述 Viewport 应该显示那一部分内容
  • Viewport:显示的视窗,即列表的可视区域。
方法描述
axisDirection-滚动方向
offset-用户的滚动偏移
cacheExtent-预渲染区域
CacheExtentStyle-用于配合解释cacheExtent的含义,也可以为主轴长度的乘数
slivers-需要显示的 Sliver 列表
  • Sliver:视窗里显示的元素,对子组件进行构建和布局。

如果要给可滚动组件添加滚动条,只需将Scrollbar作为可滚动组件的任意一个父级组件即可

2. 可滚动组件

本节讲一下SingleChildScrollView和ListView。

2-1 SingleChildScrollView

SingleChildScrollView类似于Android中的ScrollView,它只能接收一个子组件。通常SingleChildScrollView只应在期望的内容不会超过屏幕太多时使用,因为不支持基于 Sliver 的延迟加载模型,可能性能差。

方法描述
scrollDirection-滚动方向
reverse-
padding-内边距
primary-是否使用 widget 树中默认的PrimaryScrollControlle
physics-决定可滚动组件如何响应用户操作
controller-控制器
child-子组件

竖向排列的字母表例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {String alphabet = 'ABCDEFGHIJKMLNOPKRSTUVWSYZ';Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: Scrollbar(child: SingleChildScrollView(padding: const EdgeInsets.all(16.0),child: Center(child: Column(children: alphabet.split('').map((e) => Text(e,textScaleFactor: 2.0,)).toList(),)),),));}
}

2-2. ListView

ListView是最常用的可滚动组件之一,内部组合了 Scrollable、Viewport 和 Sliver。它可以沿一个方向线性排布所有子组件,并且它也支持列表项懒加载(在需要时才会创建)。它有一个children参数,它接受一个Widget列表。这种方式适合只有少量的子组件数量已知且比较少的情况,反之则应该使用ListView.builder 按需动态构建列表项。

方法描述
itemExtent-子组件长度,如果指定了该值,就不用动态计算listview高度,性能更好
prototypeItem-指定一个列表项,可滚动组件会在 layout 时计算一次它延主轴方向的长度,和itemExtent互斥
shrinkWrapfalse是否根据子组件的总长度来设置ListView的长度
addRepaintBoundaries-是否将列表项(子组件)包裹在RepaintBoundary组件中,看list复杂情况设置
  • 数量固定的情况:
ListView(shrinkWrap: true, padding: const EdgeInsets.all(16.0),children: <Widget>[const Text('a'),const Text('b'),const Text('c'),const Text('d'),],
);
  • 数量不固定的情况:
ListView.builder(itemCount: 100,// 强制高度为50.0itemExtent: 50.0,itemBuilder: (BuildContext context, int index) {return ListTile(title: Text("$index"));}
);

2-2-1. separated分割线

ListView.separated可以在生成的列表项之间添加一个分割组件,它比ListView.builder多了一个separatorBuilder参数,该参数是一个分割组件生成器。

  • 奇数行添加一条红色下划线,偶数行添加一条绿色下划线:
import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {Widget divider1 = const Divider(color: Colors.red);Widget divider2 = const Divider(color: Colors.green);Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: ListView.separated(itemCount: 100,// 列表项构造器itemBuilder: (BuildContext context, int index) {return ListTile(title: Text("$index"));},// 分割器构造器separatorBuilder: (BuildContext context, int index) {return index % 2 == 0 ? divider1 : divider2;},));}
}

2-2-2. 无限加载列表

在实际开发中,我们经常需要实现一个无限加载列表,即当列表滚动到底部时,再向服务器请求数据,并添加到列表,例子如下:

import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {static const loadingTag = "##loading##"; //表尾标记var words = <String>[loadingTag];void initState() {super.initState();_retrieveData();}// 加载数据void _retrieveData() {Future.delayed(const Duration(seconds: 2)).then((e) {setState(() {//重新构建列表words.insertAll(words.length - 1,//每次生成20个单词generateWordPairs().take(20).map((e) => e.asPascalCase).toList(),);});});}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: ListView.separated(itemCount: words.length,itemBuilder: (context, index) {// 如果到了表尾if (words[index] == loadingTag) {// 不足100条,继续获取数据if (words.length - 1 < 100) {// 获取数据_retrieveData();// 加载时显示loadingreturn Container(padding: const EdgeInsets.all(16.0),alignment: Alignment.center,child: const SizedBox(width: 24.0,height: 24.0,child: CircularProgressIndicator(strokeWidth: 2.0),),);} else {// 已经加载了100条数据,不再获取数据return Container(alignment: Alignment.center,padding: const EdgeInsets.all(16.0),child: const Text("没有更多了",style: TextStyle(color: Colors.grey),),);}}// 显示单词列表项return ListTile(title: Text(words[index]));},separatorBuilder: (context, index) => const Divider(height: .0),));}
}

2-2-3. 带标题列表

Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: Column(children: [// 标题const ListTile(title: Text('标题')),// 用Expanded 占满剩余空间Expanded(child: ListView.builder(itemBuilder: (BuildContext context, int index) {return ListTile(title: Text('行:$index'),);}),)],));}

3. 滚动监听和控制

可以用ScrollController来控制可滚动组件的滚动位置。而,可滚动组件在滚动时会发送ScrollNotification类型的通知,ScrollBar正是通过监听滚动通知来实现的。

3-1. ScrollController滚动监听

ScrollController间接继承自Listenable,我们可以根据ScrollController来监听滚动事件。如下例子:

  • 滚动到1000的时候,出现回到顶部的按钮,点击即可回到顶部
import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {/// 监听控制器ScrollController myController = ScrollController();/// 是否显示回到顶部按钮bool toTop = false;void initState() {super.initState();/// 开启监听myController.addListener(() {if (myController.offset < 1000 && toTop) {setState(() {toTop = false;});} else if (myController.offset >= 1000 && toTop == false) {setState(() {toTop = true;});}});}void dispose() {/// 注销监听myController.dispose();super.dispose();}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: Scrollbar(child: ListView.builder(/// 固定列数itemCount: 100,/// 固定列高itemExtent: 50.0,controller: myController,/// 渲染行itemBuilder: (BuildContext context, int index) {return ListTile(title: Text('行:$index'));},)),/// 返回顶部按钮floatingActionButton: !toTop? null: FloatingActionButton(child: const Icon(Icons.arrow_upward),onPressed: () {/// 动画返回myController.animateTo(0.0,duration: const Duration(microseconds: 200),curve: Curves.ease);},),);}
}

3-2. NotificationListener滚动监听

和ScrollController不同,NotificationListener可以在可滚动组件到widget树根之间任意位置监听,而ScrollController只能和具体的可滚动组件关联后才可以。并且,收到滚动事件时,NotificationListener通知中会携带当前滚动位置和ViewPort的一些信息,而ScrollController只能获取当前滚动位置。如下例子:

  • 中间有个文字会显示滚动的进度是多少
import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {/// 进度文案String myProgress = '0%';Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: NotificationListener(onNotification: (ScrollNotification  notification) {double progress = notification.metrics.pixels / notification.metrics.maxScrollExtent;setState(() {myProgress = '${(progress * 100).toInt()}%';});return false;},child: Stack(alignment: Alignment.center,children: [ListView.builder(itemCount: 100,itemExtent: 50.0,itemBuilder: (context, index) => ListTile(title: Text('第$index行'),),),CircleAvatar(radius: 30.0,backgroundColor: Colors.black12,child: Text(myProgress))],),));}
}

4. AnimatedList动画列表

AnimatedList 和 ListView 的功能大体相似,不同的是, AnimatedList 可以在列表中插入或删除节点时执行一个动画,在需要添加或删除列表项的场景中会提高用户体验。如下例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {/// 数据列表var dataList = <String>[];/// 初始个数int counter = 6;/// Keyfinal myKey = GlobalKey<AnimatedListState>();void initState() {super.initState();/// 初始化数据for (var i = 0; i < counter; i++) {dataList.add('标题:${i + 1}');}}Widget buildItem(context, index) {String str = dataList[index];return ListTile(key: ValueKey(str),title: Text(str),trailing: IconButton(icon: const Icon(Icons.delete),onPressed: () {/// 删除的逻辑和动画setState(() {myKey.currentState!.removeItem(index, (context, animation) {var item = buildItem(context, index);dataList.removeAt(index);return FadeTransition(opacity: CurvedAnimation(parent: animation, curve: const Interval(0.5, 1.0)),child: SizeTransition(sizeFactor: animation,axisAlignment: 0.0,child: item,),);}, duration: const Duration(milliseconds: 200));});},),);}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: Stack(alignment: Alignment.center,children: [AnimatedList(key: myKey,initialItemCount: dataList.length,itemBuilder: (context, index, animation) {return FadeTransition(opacity: animation, child: buildItem(context, index));},),Positioned(left: 0,right: 0,bottom: 30.0,child: FloatingActionButton(/// 添加项onPressed: () {dataList.add('标题:${++counter}');myKey.currentState!.insertItem(dataList.length - 1);},child: const Icon(Icons.add),),)],));}
}

5. 滚动网格布局GridView

GridView是ListView的升级版,可以构建二维网格列表,可以指定子组件的布局方式,如网格布局、列表布局等。他的参数和ListView是一致的,唯一区别是多了个gridDelegate参数,控制GridView子组件的排列。它提供了SliverGridDelegateWithFixedCrossAxisCount和SliverGridDelegateWithMaxCrossAxisExtent两个子类。

5-1. 横轴子元素为固定数量

使用SliverGridDelegateWithFixedCrossAxisCount,可以实现一个横轴为固定数量子元素的layout布局。子元素的大小(最大显示空间)是通过crossAxisCount和childAspectRatio两个参数共同决定的。

/// 写法一
GridView(gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(/// 横轴子元素的数量crossAxisCount: 3,/// 主轴方向的间距mainAxisSpacing: 10.0,/// 横轴方向子元素的间距crossAxisSpacing: 20.0,/// 子元素在横轴长度和主轴长度的比例childAspectRatio: 1.0),/// 元素列表children: const [Icon(Icons.ac_unit),Icon(Icons.airport_shuttle),Icon(Icons.all_inclusive),Icon(Icons.beach_access),Icon(Icons.cake),Icon(Icons.free_breakfast)]
)
/// 写法二
GridView.count( crossAxisCount: 3,childAspectRatio: 1.0,children: const [Icon(Icons.ac_unit),Icon(Icons.airport_shuttle),Icon(Icons.all_inclusive),Icon(Icons.beach_access),Icon(Icons.cake),Icon(Icons.free_breakfast),],
)

5-2. 横轴子元素为固定最大长度

使用SliverGridDelegateWithMaxCrossAxisExtent,可以实现一个横轴子元素为固定最大长度的layout布局,子元素的大小(最大显示空间)是通过maxCrossAxisExtent参数决定的。

/// 写法一
GridView(gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(/// 子元素在横轴上的最大长度maxCrossAxisExtent: 100.0,/// 子元素在横轴长度和主轴长度的比例childAspectRatio: 1.0,/// 主轴方向的间距mainAxisSpacing: 10.0,/// 横轴方向子元素的间距crossAxisSpacing: 20.0,),children: const [Icon(Icons.ac_unit),Icon(Icons.airport_shuttle),Icon(Icons.all_inclusive),Icon(Icons.beach_access),Icon(Icons.cake),Icon(Icons.free_breakfast)]
)/// 写法二
GridView.extent(maxCrossAxisExtent: 120.0,childAspectRatio: 1.0,children: const [Icon(Icons.ac_unit),Icon(Icons.airport_shuttle),Icon(Icons.all_inclusive),Icon(Icons.beach_access),Icon(Icons.cake),Icon(Icons.free_breakfast),],
)

5-3. 动态创建

当子widget比较多时,我们可以通过GridView.builder来动态创建子widget。如下例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {/// Icon列表List<IconData> myIcons = [];void initState() {super.initState();/// 初始化数据handleSyncAddIcon();}/// 模拟异步获取数据void handleSyncAddIcon() {Future.delayed(const Duration(milliseconds: 2000)).then((e) {setState(() {myIcons.addAll([Icons.ac_unit,Icons.airport_shuttle,Icons.all_inclusive,Icons.beach_access,Icons.cake,Icons.free_breakfast,]);});});}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: GridView.builder(gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(/// 每行三列crossAxisCount: 3,/// 显示区域宽高相等childAspectRatio: 1.0,),itemCount: myIcons.length,itemBuilder: (context, index) {/// 如果显示到最后一个 并且Icon总数小于200时 继续获取数据if (index == myIcons.length - 1 && myIcons.length < 200) {handleSyncAddIcon();}return Icon(myIcons[index]);},));}
}

6. PageView页面切换和缓存

如果要实现页面切换和 Tab 布局,Tab 换页效果、图片轮动以及抖音上下滑页切换视频功能等等,我们可以使用 PageView 组件。如下全屏切换的例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class PageItem extends StatefulWidget {const PageItem({Key? key,required this.text}) : super(key: key);final String text;PageItemState createState() => PageItemState();
}class PageItemState extends State<PageItem> {Widget build(BuildContext context) {debugPrint('触发${widget.text}');return Center(child: Text("第${widget.text}页", textScaleFactor: 5));}
}class HomePageState extends State<HomePage> {var children = <Widget>[];void initState() {super.initState();for (int i = 0; i < 6; ++i) {children.add(PageItem(text: '$i'));}}Widget build(BuildContext context) {debugPrint('触发');return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: PageView(/// 每次滑动是否强制切换整个页面pageSnapping: true,padEnds: true,/// 滑动方向scrollDirection: Axis.vertical,/// 子元素children: children,));}
}

6-1. PageState缓存

只需要让 PageState 混入这个 AutomaticKeepAliveClientMixin ,简单改造就可以实现缓存。

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class PageItem extends StatefulWidget {const PageItem({Key? key,required this.text}) : super(key: key);final String text;PageItemState createState() => PageItemState();
}class PageItemState extends State<PageItem> with AutomaticKeepAliveClientMixin {Widget build(BuildContext context) {super.build(context);debugPrint('触发${widget.text}');return Center(child: Text("第${widget.text}页", textScaleFactor: 5));}/// 是否需要缓存bool get wantKeepAlive => true;
}class HomePageState extends State<HomePage> {var children = <Widget>[];void initState() {super.initState();for (int i = 0; i < 6; ++i) {children.add(PageItem(text: '$i'));}}Widget build(BuildContext context) {debugPrint('触发');return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: PageView(/// 每次滑动是否强制切换整个页面pageSnapping: true,padEnds: true,/// 滑动方向scrollDirection: Axis.vertical,/// 子元素children: children,));}
}

7. TabBarView

abBarView 封装了 PageView,而abController 用于监听和控制 TabBarView 的页面切换,通常和 TabBar 联动。如果没有指定,则会在组件树中向上查找并使用最近的一个 DefaultTabController。如下例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class PageItem extends StatefulWidget {const PageItem({Key? key, required this.text}) : super(key: key);final String text;PageItemState createState() => PageItemState();
}class PageItemState extends State<PageItem> with AutomaticKeepAliveClientMixin {Widget build(BuildContext context) {super.build(context);debugPrint('触发${widget.text}');return Center(child: Text("${widget.text}", textScaleFactor: 5));}/// 是否需要缓存bool get wantKeepAlive => true;
}class HomePageState extends State<HomePage> {var children = <Widget>[];List tabs = ["新闻", "历史", "图片"];void initState() {super.initState();for (int i = 0; i < tabs.length; ++i) {children.add(PageItem(text: '${tabs[i]}'));}}Widget build(BuildContext context) {return DefaultTabController(length: children.length,child: Scaffold(appBar: AppBar(title: const Text("App Name"),bottom: TabBar(tabs: tabs.map((e) => Tab(text: e)).toList(),),),body: TabBarView(/// tab子页面children: children,),),);}
}

8. CustomScrollView和Slivers

CustomScrollView的 slivers 参数接受一个 Sliver 数组,这样就可以在一个页面中,同时包含多个可滚动组件,且使它们的滑动效果能统一起来。如下例子:

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => HomePageState();
}class HomePageState extends State<HomePage> {var listView = SliverFixedExtentList(itemExtent: 56,delegate: SliverChildBuilderDelegate((_, index) => ListTile(title: Text('$index')),childCount: 10,));Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Home Page'),backgroundColor: Theme.of(context).colorScheme.inversePrimary,),body: Center(child: CustomScrollView(slivers: [listView,listView,],),));}
}

8-1. 常用的Slivers

  • 可滚动组件对应的Sliver
名称功能对应组件
SliverList列表ListView
SliverFixedExtentList高度固定的列表ListView,指定itemExtent后
SliverAnimatedList添加/删除列表项可以执行动画AnimatedList
SliverGrid网格GridView
SliverPrototypeExtentList根据原型生成高度固定的列表ListView,指定prototypeItem后
SliverFillViewport包含多个子组件,每个都可以填满屏幕PageView
  • 子组件必须是Sliver
名称对应RenderBox容器
SliverPaddingPadding
SliverVisibility、SliverOpacityVisibility、Opacity
SliverFadeTransitionFadeTransition
SliverLayoutBuilderLayoutBuilder
  • 其他常用的Sliver
名称功能
SliverAppBar对应 AppBar,主要是为了在 CustomScrollView 中使用
SliverToBoxAdapter一个适配器,可以将 RenderBox 适配为 Sliver
SliverPersistentHeader滑动到顶部时可以固定住

本次分享就到这儿啦,我是鹏多多,如果您看了觉得有帮助,欢迎评论,关注,点赞,转发,我们下次见~

往期文章

  • 手把手教你搭建规范的团队vue项目,包含commitlint,eslint,prettier,husky,commitizen等等
  • Web Woeker和Shared Worker的使用以及案例
  • Vue2全家桶+Element搭建的PC端在线音乐网站
  • vue3+element-plus配置cdn
  • 助你上手Vue3全家桶之Vue3教程
  • 助你上手Vue3全家桶之VueX4教程
  • 助你上手Vue3全家桶之Vue-Router4教程
  • 超详细!Vue的九种通信方式
  • 超详细!Vuex手把手教程
  • 使用nvm管理node.js版本以及更换npm淘宝镜像源
  • vue中利用.env文件存储全局环境变量,以及配置vue启动和打包命令
  • 超详细!Vue-Router手把手教程

个人主页

  • CSDN
  • GitHub
  • 简书
  • 博客园
  • 掘金

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

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

相关文章

[wp]第四届江西省赣网杯网络安全大赛-web 部分wp

第四届江西省赣网杯网络安全大赛&#xff08;gwb&#xff09;线上预选赛 因为学业繁忙 只玩了1小时&#xff0c;后续看看补一下这些 2023gwb-web1 九宫格拼图 2023gwb-web2 $filexxx;extract($_GET);if(isset($fun)){$contenttrim(file_get_contents($file));if($fun!&…

MLX:苹果 专为统一内存架构(UMA) 设计的机器学习框架

“晨兴理荒秽&#xff0c;带月荷锄归” 夜深闻讯&#xff0c;有点兴奋&#xff5e; 苹果为 UMA 设计的深度学习框架真的来了 统一内存架构 得益于 CPU 与 GPU 内存的共享&#xff0c;同时与 MacOS 和 M 芯片 交相辉映&#xff0c;在效率上&#xff0c;实现对其他框架的降维打…

uniapp之屏幕右侧出现滚动条去掉、隐藏、删除【好用!】

目录 问题解决大佬地址最后 问题 解决 在最外层view上加上class“content”;输入以下样式。注意&#xff1a;两个都必须存在在生效。 .content {/* 跟屏幕高度一样高,不管view中有没有内容,都撑开屏幕高的高度 */height: 100vh; overflow: auto; } .content::-webkit-scrollb…

【JavaWeb】往浏览器打印一个hello world

上集:建一个web项目 第一步&#xff1a;建好Servlet类的文件 右键src&#xff0c;建一个class 就行 第二步&#xff1a;编代码 可以直接复制粘贴 用来测试的类 import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; //↓是注解&#xff0…

Java 基础学习(十一)File类与I/O操作

1 File类 1.1 File类概述 1.1.1 什么是File类 File是java.io包下作为文件和目录的类。File类定义了一些与平台无关的方法来操作文件&#xff0c;通过调用File类中的方法可以得到文件和目录的描述信息&#xff0c;包括名称、所在路径、读写性和长度等&#xff0c;还可以对文件…

Graphics Profiler 使用教程

GraphicsProfiler 使用教程 1.工具简介&#xff1a;2.Navigation介绍2.1.打开安装好的Graphics Profiler。2.2.将手机连接到计算机&#xff0c;软件会在手机中安装一个GraphicsProfiler应用(该应用是无界面的&#xff09;。2.3.Show files list2.4.Record new trace2.4.1.Appli…

听GPT 讲Rust源代码--src/tools(13)

File: rust/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs 在Rust源代码中&#xff0c;路径为rust/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs的文件是为了处理Rust代码中的不一致实现问题而存在的。…

Linux 动态库和静态库

文章目录 前言动态库创建和使用静态库创建和使用动态库和静态库差异生成过程的差异运行效果的差异 补充说明库的名称的注意事项库的搜索路径的方法什么是位置无关代码动态链接与静态链接/usr/lib 和 /usr/local/lib 前言 动静态库的创建和使用部分更多的是意在说明动态库和静态…

关于枚举的简单理解

1. 枚举的简单认识 1.1 枚举的引入 枚举是在JDK1.5以后引入的。主要用途是&#xff1a;将一组常量组织起来&#xff0c;在这之前表示一组常量通常使用定义常量的方式如下面的代码所示&#xff1a; public static final int RED 1; public static final int GREEN 2; public…

【MySQL】(DDL)总结

总结&#xff1a; 1.DDL数据库操作 show database; //查看当前创建的数据库 create database 数据库名; //创建数据库 use 数据库; //切换数据库 select database(); //查看当前所处的数据库(当前进入的那个数据库) drop database 数据库名; //删除数据库名 2.DDL表操作 …

鸿蒙开发之网络请求

//需要导入http头文件 import http from ohos.net.http//请求地址url: string http://apis.juhe.cn/simpleWeather/queryText(this.message).maxFontSize(50).minFontSize(10).fontWeight(FontWeight.Bold).onClick(() > {console.log(请求开始)let req http.createHttp()…

【音视频 | H.264】H.264视频编码及NALU详解

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

2023“楚怡杯”湖南省赛“信息安全管理与评估“--数字取证调查(高职组)

2023“楚怡杯”湖南省“信息安全管理与评估”(高职组)任务书 2023“楚怡杯”湖南省“信息安全管理与评估”(高职组)任务书第一阶段竞赛项目试题第二阶段竞赛项目试题第二部分 数字取证调查:需要环境私聊博主:2023“楚怡杯”湖南省“信息安全管理与评估”(高职组)任务书…

C语言——谁考了第k名(头歌编程刷题)

目录 一、题目描述&#xff1a; 二、输入格式&#xff1a; 三、输出格式&#xff1a; 四、输出样例&#xff1a; 五、输出样例&#xff1a; 六、代码呈现&#xff1a; 一、题目描述&#xff1a; 在一次考试中&#xff0c;每个学生的成绩都不相同&#xff0c;现知道了每个…

TCP与UDP:网络世界中的“顺丰快递”与“广播电台”

随着互联网的普及&#xff0c;我们每天都在与网络打交道。而在这背后&#xff0c;数据的传输离不开TCP和UDP这两种传输协议。它们就像网络世界中的“顺丰快递”和“广播电台”&#xff0c;各自有着不同的工作方式和特点。让我们一起来了解一下它们吧&#xff01; 一、TCP&…

如何下载 GitHub 私有仓库

概述 GitHub 是一个用于托管代码的开源平台。它提供私有仓库功能&#xff0c;允许用户将代码保密。如果您需要下载 GitHub 私有仓库&#xff0c;可以使用以下两种方式。 方式一&#xff1a;使用 SSH 密钥 SSH 密钥是一种安全的身份验证方法&#xff0c;可用于访问 GitHub 私…

了解 Flutter 3.16 功能更新

作者 / Kevin Chisholm 我们在季度 Flutter 稳定版发布会上带来了 Flutter 3.16&#xff0c;此版本包含诸多更新: Material 3 成为新的默认主题、为 Android 带来 Impeller 的预览版、允许添加适用于 DevTools 的扩展程序等等&#xff0c;以及同步推出 Flutter 休闲游戏工具包重…

浅谈基于不信任的防御性编程

背景 在实际开发过程中&#xff0c;我们经常遇到这样的场景&#xff1a; 后端报错了&#xff0c;手忙脚乱一顿排查&#xff0c;发现是前端传的参数为空&#xff0c;或者格式不对&#xff1b;后端又报错了&#xff0c;传参没问题&#xff0c;根据日志流发现&#xff0c;是某“给…

CAN 五: CAN编程实践

1、CAN基本驱动步骤 (1)CAN参数初始化 工作模式、波特率等函数&#xff1a;HAL_CAN_Init (2)使能CAN时钟和初始化相关引脚 GPIO模式设为复用功能模式函数&#xff1a;HAL_CAN_MspInit(CAN的初始化回调函数) (3)设置过滤器 过滤器的配置函数&#xff1a;HAL_CAN_ConfigFil…

Photoshop插件3D Map Generator Geo的使用记录1(版本说明、安装卸载使用和高程数据生成3D地形图的准备工作)

3D Map Generator是一款强大的地图创建和定制化工具&#xff0c;具有以下特点和功能&#xff1a; 快速创建3D地图&#xff1a;用户可以通过该工具快速创建出高质量的3D地图&#xff0c;而无需具备专业的GIS或PS技能。支持多种图层类型&#xff1a;3D Map Generator支持多种图层…