【HarmonyOS开发】ArkUI实现下拉刷新/上拉加载

 列表下拉刷新、上拉加载更多,不管在web时代还是鸿蒙应用都是一个非常常用的功能,基于ArkUI中TS扩展的声明式开发范式实现一个下拉刷新,上拉加载。

上拉加载、下拉刷新

如果数据量过大,可以使用LazyForEach代替ForEach

高阶组件-上拉加载,下拉刷新icon-default.png?t=N7T8https://gitee.com/bingtengaoyu/harmonyos-advanced-componen/tree/master/UpDownRefresh 

1、涉及的知识点

  • 列表容器(List)
  • 触摸事件(onTouch)
  • 位置设置(offset)
  • 显示动画(animateTo)

2、效果图

3、实现思路

根据触摸事件onTouch()处理下拉和上拉,通过记录手指按下的y坐标和move移动的距离判断属于刷拉还是下滑,从而展示不同的内容。

4、关键代码

4.1 生成下拉刷新/上拉加载DOM

  @Builder UpDownRefreshBuilder(text: string, state: string) {Row() {Image($r('app.media.refreshing')).width(32).height(32)Text(text).fontSize(16)}.justifyContent(FlexAlign.Center).position({y: state === 'down' ? 20 : -20}).zIndex(999).width('94%').height('8%')}

4.2 onTouch处理事件

  private currentOffsetY: number = 0;private timer: number = 0;@State refreshStatus: boolean = false;@State upRefreshStatus: boolean = false;aboutToDisappear() {this.timer = null}putDownRefresh(event?: TouchEvent): void {if (event === undefined) {return;}switch (event.type) {case TouchType.Down:this.currentOffsetY = event.touches[0].y;break;case TouchType.Move:if(this.scroller.currentOffset().yOffset < 50) {this.refreshStatus = event.touches[0].y - this.currentOffsetY > 50;}this.upRefreshStatus = event.touches[0].y - this.currentOffsetY < -50;break;case TouchType.Cancel:break;case TouchType.Up:// Only simulation effect, no data requestthis.timer = setTimeout(() => {if (this.upRefreshStatus) {this.scroller.scrollTo({           // 调用scrollTo滚动到具体位置xOffset: 0,                    // 竖直方向滚动,该值不起作用yOffset: 680,    // 滚动到底部animation: {                     // 滚动动画duration: 1500,curve: Curve.EaseOut}})}this.refreshStatus = false;this.upRefreshStatus = false;}, 1500);break;}}

5、完整代码

兵腾傲宇/harmonyos-healthy-live - Gitee.com

import router from '@ohos.router'
import curves from '@ohos.curves'
import { BreakpointSystem, BreakPointType } from '../common/BreakpointSystem'
import { FoodInfo, Category } from '../model/DataModels'
import { getFoods, getFoodCategories, getSortedFoodData } from '../model/DataUtil'
import { Records } from './components/DietRecord'
import { PersonalCenter } from './PersonalCenter'interface FoodId {foodId: FoodInfo;
}@Component
struct FoodListItem {private foodItem?: FoodInfobuild() {Navigator({ target: 'pages/FoodDetail' }) {Row() {Image(this.foodItem!.image!).objectFit(ImageFit.Contain).autoResize(false).height(40).width(40).backgroundColor('#FFf1f3f5').margin({ right: 16 }).borderRadius(6).sharedTransition(this.foodItem!.letter, {duration: 400,curve: curves.cubicBezier(0.2, 0.2, 0.1, 1.0),delay: 100})Text(this.foodItem?.name).fontSize(14)Blank()Text($r('app.string.calorie_with_kcal_unit', this.foodItem?.calories.toString())).fontSize(14)}.height(64).width('100%')}.params({ foodId: this.foodItem } as FoodId).margin({ right: 24, left: 32 })}
}@Component
struct ListModeFoods {private foodItems: Array<FoodInfo | string> = getSortedFoodData()private currentOffsetY: number = 0;private timer: number = 0;@State refreshStatus: boolean = false;@State upRefreshStatus: boolean = false;aboutToDisappear() {this.timer = null}putDownRefresh(event?: TouchEvent): void {if (event === undefined) {return;}switch (event.type) {case TouchType.Down:this.currentOffsetY = event.touches[0].y;break;case TouchType.Move:if(this.scroller.currentOffset().yOffset < 50) {this.refreshStatus = event.touches[0].y - this.currentOffsetY > 50;}this.upRefreshStatus = event.touches[0].y - this.currentOffsetY < -50;break;case TouchType.Cancel:break;case TouchType.Up:// Only simulation effect, no data requestthis.timer = setTimeout(() => {if (this.upRefreshStatus) {this.scroller.scrollTo({           // 调用scrollTo滚动到具体位置xOffset: 0,                    // 竖直方向滚动,该值不起作用yOffset: 680,    // 滚动到底部animation: {                     // 滚动动画duration: 1500,curve: Curve.EaseOut}})}this.refreshStatus = false;this.upRefreshStatus = false;}, 1500);break;}}@Builder DownRefreshBuilder(text: string, state: string) {Row() {Image($r('app.media.refreshing')).width(32).height(32)Text(text).fontSize(16)}.justifyContent(FlexAlign.Center).position({y: state === 'down' ? 20 : -20}).zIndex(999).width('94%').height('8%')}private scroller: Scroller = new Scroller(); // 创建一个滚动控制器build() {Column() {Text($r("app.string.title_food_list")).width('100%').height(56).padding({ left: 20 }).backgroundColor('#FF1f3f5').fontSize(20)Scroll(this.scroller) {if(this.refreshStatus) {this.DownRefreshBuilder('正在刷新', 'down')}List() {ForEach(this.foodItems, (item: FoodInfo) => {ListItem() {if (item.letter !== undefined) {FoodListItem({ foodItem: item })} else {if (typeof (item) === 'string') {Text(item).fontSize(14).height(48).margin({ left: 24 }).width('100%')}}}})if(this.upRefreshStatus) {ListItem(){this.DownRefreshBuilder('正在加载', 'up')}}}.layoutWeight(1)}.scrollBar(BarState.Off).edgeEffect(EdgeEffect.Spring).width('100%').height('90%').onTouch((event?: TouchEvent) => {this.putDownRefresh(event);})}}
}@Component
struct FoodGridItem {private foodItem?: FoodInfobuild() {Column() {Image(this.foodItem!.image!).objectFit(ImageFit.Contain).backgroundColor('#f1f3f5').width('100%').height(152).sharedTransition(this.foodItem!.letter, {duration: 400,curve: curves.cubicBezier(0.2, 0.2, 0.1, 1.0),delay: 100})Row() {Text(this.foodItem?.name).fontSize(14)Blank()Text($r('app.string.calorie_with_kcal_unit', this.foodItem?.calories.toString())).fontSize(14).fontColor(0x99000000)}.padding({ left: 12, right: 12 }).width('100%').height(32).backgroundColor('#E5E5E5')}.height(184).clip(new Rect({ width: '100%', height: '100%', radius: 12 })).onClick(() => {router.pushUrl({ url: 'pages/FoodDetail', params: { foodId: this.foodItem } })})}
}@Component
struct FoodGrid {@StorageProp('currentBreakpoint') currentBreakpoint: string = 'sm'private foodItems?: FoodInfo[]build() {Grid() {ForEach(this.foodItems!, (item: FoodInfo) => {GridItem() {FoodGridItem({ foodItem: item })}})}.columnsTemplate(new BreakPointType({sm: '1fr 1fr',md: '1fr 1fr 1fr',lg: '1fr 1fr 1fr 1fr'}).getValue(this.currentBreakpoint) as string).columnsGap(8).rowsGap(8).padding({ left: 16, right: 16 })}
}@Component
struct CategoryModeFoods {@State currentTabIndex: number = 0private foodItems: FoodInfo[] = getFoods()private foodCategories: Category[] = getFoodCategories()/* ** 头部分类导航栏** */@BuildertabBarItemBuilder(value: Resource, index: number) {Text(value).fontColor(this.currentTabIndex === index ? Color.Blue : 'rgba(0,0,0,0.6)').fontSize(this.currentTabIndex === index ? 20 : 18).fontWeight(this.currentTabIndex === index ? FontWeight.Bold : FontWeight.Normal).margin({ top: 2 }).height(56)}build() {Tabs() {TabContent() {FoodGrid({ foodItems: this.foodItems })}.tabBar(this.tabBarItemBuilder($r('app.string.category_all'), 0))ForEach(this.foodCategories, (foodCategory: Category, index?: number) => {TabContent() {FoodGrid({ foodItems: this.foodItems.filter(item => (item.categoryId === foodCategory.id)) })}.tabBar(this.tabBarItemBuilder(foodCategory.name!,index! + 1))})}.animationDuration(0).barWidth('80%').onChange((index) => {this.currentTabIndex = index})}
}@Component
struct FoodsDisplay {@State isCategoryMode: boolean = true@State isMoreIconOnClick: boolean = false@State isMoreIconOnHover: boolean = false@State isMoreIconOnFocus: boolean = falsegetMoreIconBgColor() {if (this.isMoreIconOnClick) {return $r('sys.color.ohos_id_color_click_effect')} else if (this.isMoreIconOnHover) {return $r('sys.color.ohos_id_color_hover')} else {return this.isCategoryMode ? Color.White : '#F1F3F5' || Color.Transparent}}build() {Stack({ alignContent: Alignment.TopEnd }) {if (this.isCategoryMode) {CategoryModeFoods()} else {ListModeFoods()}Row() {Image($r("app.media.ic_switch")).height(24).width(24).margin({ left: 24, right: 24 }).focusable(true)}.height(56).backgroundColor(this.getMoreIconBgColor()).stateStyles({focused: {.border({radius: $r('sys.float.ohos_id_corner_radius_clicked'),color: $r('sys.color.ohos_id_color_focused_outline'),style: BorderStyle.Solid})},normal: {.border({radius: $r('sys.float.ohos_id_corner_radius_clicked'),width: 0})}}).onFocus(() => this.isMoreIconOnFocus = true).onBlur(() => this.isMoreIconOnFocus = false).onHover((isOn) => this.isMoreIconOnHover = isOn).onClick(() => {this.isCategoryMode = !this.isCategoryMode})}}
}@Entry
@Component
struct Home {@State currentTabIndex: number = 0@StorageProp('currentBreakpoint') currentBreakpoint: string = 'sm'private breakpointSystem: BreakpointSystem = new BreakpointSystem()/* ** 主页和记录的tabs* */@BuilderbottomBarItemBuilder(name: Resource, icon: Resource, index: number) {Flex({direction: new BreakPointType({sm: FlexDirection.Column,md: FlexDirection.Row,lg: FlexDirection.Column}).getValue(this.currentBreakpoint),justifyContent: FlexAlign.Center,alignItems: ItemAlign.Center}) {Image(icon).height(24).width(24).fillColor(this.getTabBarColor(index))Text(name).margin(new BreakPointType<Padding>({sm: { top: 4 },md: { left: 8 },lg: { top: 4 }}).getValue(this.currentBreakpoint) as Padding).fontSize(11).fontColor(this.getTabBarColor(index))}}aboutToAppear() {this.breakpointSystem.register()}aboutToDisappear() {this.breakpointSystem.unregister()}build() {Tabs({barPosition: new BreakPointType({sm: BarPosition.End,md: BarPosition.End,lg: BarPosition.Start}).getValue(this.currentBreakpoint)}) {TabContent() {FoodsDisplay()}.tabBar(this.bottomBarItemBuilder($r("app.string.tab_bar_home"), $r("app.media.ic_bottom_home"), 0))TabContent() {Records()}.tabBar(this.bottomBarItemBuilder($r("app.string.tab_bar_record"), $r("app.media.ic_bottom_record"), 1))TabContent() {PersonalCenter()}.tabBar(this.bottomBarItemBuilder($r("app.string.tab_bar_me"), $r("app.media.ic_public_me"), 2))}.vertical(new BreakPointType({ sm: false, md: false, lg: true }).getValue(this.currentBreakpoint) as boolean).barWidth(new BreakPointType({ sm: '100%', md: '100%', lg: '56vp' }).getValue(this.currentBreakpoint) as string).barHeight(new BreakPointType({ sm: '56vp', md: '56vp', lg: '60%' }).getValue(this.currentBreakpoint) as string).animationDuration(300).onChange((index) => {this.currentTabIndex = index})}private getTabBarColor(index: number) {return this.currentTabIndex == index ? $r('app.color.tab_bar_select_color') : $r('app.color.tab_bar_normal_color')}
}

6、另外一个思路实现上拉加载,下拉刷新

根据List中的回调方法onScrollIndex()监听当前列表首尾索引,根据触摸事件onTouch()处理下拉和上拉。

const TopHeight = 200;@Entry
@Component
struct Index {@State list: Array<number> = []// 列表y坐标偏移量@State offsetY: number = 0// 按下的y坐标private downY = 0// 上一次移动的y坐标private lastMoveY = 0// 当前列表首部的索引private startIndex = 0// 当前列表尾部的索引private endIndex = 0// 下拉刷新的布局高度private pullRefreshHeight = 70// 下拉刷新文字:下拉刷新、松开刷新、正在刷新、刷新成功@State pullRefreshText: string= '下拉刷新'// 下拉刷新图标:与文字对应@State pullRefreshImage: Resource = $r("app.media.ic_pull_refresh_down")// 是否可以刷新:未达到刷新条件,收缩回去private isCanRefresh = false// 是否正在刷新:刷新中不进入触摸逻辑private isRefreshing: boolean = false// 是否已经进入了下拉刷新操作private isPullRefreshOperation = false// 上拉加载的布局默认高度private loadMoreHeight = 70// 上拉加载的布局是否显示@State isVisibleLoadMore: boolean = false// 是否可以加载更多private isCanLoadMore = false// 是否加载中:加载中不进入触摸逻辑private isLoading: boolean = false// 自定义下拉刷新布局@Builder CustomPullRefreshLayout(){Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {Image(this.pullRefreshImage).width(18).height(18)Text(this.pullRefreshText).margin({ left: 7, bottom: 1 }).fontSize(17)}.width('100%').height(this.pullRefreshHeight)// 布局跟着列表偏移量移动.offset({ x: 0, y: `${vp2px(-this.pullRefreshHeight) + this.offsetY}px` })}// 自定义加载更多布局@Builder CustomLoadMoreLayout(){Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {Image($r("app.media.ic_loading")).width(18).height(18)Text('加载更多中...').margin({ left: 7, bottom: 1 }).fontSize(17)}.width('100%').height(this.loadMoreHeight).backgroundColor('#f4f4f4').visibility(this.isVisibleLoadMore ? Visibility.Visible : Visibility.None)}// 刷新测试数据private refreshData(){this.list = []for (var i = 0; i < 15; i++) {this.list.push(i)}}// 加载更多测试数据private loadMoreData(){let initValue = this.list[this.list.length-1] + 1for (var i = initValue; i < initValue + 10; i++) {this.list.push(i)}}build() {Column() {// 下拉刷新布局this.CustomPullRefreshLayout()// 列表布局List() {ForEach(this.list, item => {ListItem() {Column() {Text(`Item ${item}`).padding(15).fontSize(18)}}}, item => item.toString())// 加载更多布局ListItem(){this.CustomLoadMoreLayout()}}.backgroundColor(Color.White) // 背景.divider({ color: '#e2e2e2', strokeWidth: 1 }) // 分割线.edgeEffect(EdgeEffect.None) // 去掉回弹效果.offset({ x: 0, y: `${this.offsetY - TopHeight}px` }) // touch事件计算的偏移量单位是px,记得加上单位.onScrollIndex((start, end) => { // 监听当前列表首位索引console.info(`${start}=start============end=${end}`)this.startIndex = startthis.endIndex = end})}.width('100%').height('100%').backgroundColor('#f4f4f4').onTouch((event) => this.listTouchEvent(event))// 父容器设置touch事件,当列表无数据也可以下拉刷新.onAppear(() => {this.refreshData()})}// 触摸事件listTouchEvent(event: TouchEvent){switch (event.type) {case TouchType.Down: // 手指按下// 记录按下的y坐标this.downY = event.touches[0].ythis.lastMoveY = event.touches[0].ybreakcase TouchType.Move: // 手指移动// 下拉刷新中 或 加载更多中,不进入处理逻辑if(this.isRefreshing || this.isLoading){console.info('========Move刷新中,返回=========')return}// 判断手势let isDownPull = event.touches[0].y - this.lastMoveY > 0// 下拉手势 或 已经进入了下拉刷新操作if ((isDownPull || this.isPullRefreshOperation) && !this.isCanLoadMore) {this.touchMovePullRefresh(event)} else {this.touchMoveLoadMore(event)}this.lastMoveY = event.touches[0].ybreakcase TouchType.Up: // 手指抬起case TouchType.Cancel: // 触摸意外中断:来电界面// 刷新中 或 加载更多中,不进入处理逻辑if(this.isRefreshing || this.isLoading){console.info('========Up刷新中,返回=========')return}if (this.isPullRefreshOperation) {this.touchUpPullRefresh()} else {this.touchUpLoadMore()}break}}//============================================下拉刷新==================================================// 手指移动,处理下拉刷新touchMovePullRefresh(event:TouchEvent){// 当首部索引位于0if (this.startIndex == 0) {this.isPullRefreshOperation = true// 下拉刷新布局高度var height = vp2px(this.pullRefreshHeight)// 滑动的偏移量this.offsetY = event.touches[0].y - this.downY// 偏移量大于下拉刷新布局高度,达到刷新条件if (this.offsetY >= height) {// 状态1:松开刷新this.pullRefreshState(1)// 偏移量的值缓慢增加this.offsetY = height + this.offsetY * 0.15} else {// 状态0:下拉刷新this.pullRefreshState(0)}if (this.offsetY < 0) {this.offsetY = 0this.isPullRefreshOperation = false}}}// 手指抬起,处理下拉刷新touchUpPullRefresh(){// 是否可以刷新if (this.isCanRefresh) {console.info('======执行下拉刷新========')// 偏移量为下拉刷新布局高度this.offsetY = vp2px(this.pullRefreshHeight)// 状态2:正在刷新this.pullRefreshState(2)// 模拟耗时操作setTimeout(() => {this.refreshData()this.closeRefresh()}, 2000)} else {console.info('======关闭下拉刷新!未达到条件========')// 关闭刷新this.closeRefresh()}}// 下拉刷新状态// 0下拉刷新、1松开刷新、2正在刷新、3刷新成功pullRefreshState(state:number){switch (state) {case 0:// 初始状态this.pullRefreshText = '下拉刷新'this.pullRefreshImage = $r("app.media.ic_pull_refresh_down")this.isCanRefresh = falsethis.isRefreshing = falsebreak;case 1:this.pullRefreshText = '松开刷新'this.pullRefreshImage = $r("app.media.ic_pull_refresh_up")this.isCanRefresh = truethis.isRefreshing = falsebreak;case 2:this.offsetY = vp2px(this.pullRefreshHeight)this.pullRefreshText = '正在刷新'this.pullRefreshImage = $r("app.media.ic_loading")this.isCanRefresh = truethis.isRefreshing = truebreak;case 3:this.pullRefreshText = '刷新成功'this.pullRefreshImage = $r("app.media.ic_refresh_succeed")this.isCanRefresh = truethis.isRefreshing = truebreak;}}// 关闭刷新closeRefresh() {// 如果允许刷新,延迟进入,为了显示刷新中setTimeout(() => {var delay = 50if (this.isCanRefresh) {// 状态3:刷新成功this.pullRefreshState(3)// 为了显示刷新成功,延迟执行收缩动画delay = 500}animateTo({duration: 150, // 动画时长delay: delay, // 延迟时长onFinish: () => {// 状态0:下拉刷新this.pullRefreshState(0)this.isPullRefreshOperation = false}}, () => {this.offsetY = 0})}, this.isCanRefresh ? 500 : 0)}//============================================加载更多==================================================// 手指移动,处理加载更多touchMoveLoadMore(event:TouchEvent) {// 因为加载更多是在列表后面新增一个item,当一屏能够展示全部列表,endIndex 为 length+1if (this.endIndex == this.list.length - 1 || this.endIndex == this.list.length) {// 滑动的偏移量this.offsetY = event.touches[0].y - this.downYif (Math.abs(this.offsetY) > vp2px(this.loadMoreHeight)/2) {// 可以刷新了this.isCanLoadMore = true// 显示加载更多布局this.isVisibleLoadMore = true// 偏移量缓慢增加this.offsetY = - vp2px(this.loadMoreHeight) + this.offsetY * 0.1}}}// 手指抬起,处理加载更多touchUpLoadMore() {animateTo({duration: 200, // 动画时长}, () => {// 偏移量设置为0this.offsetY = 0})if (this.isCanLoadMore) {console.info('======执行加载更多========')// 加载中...this.isLoading = true// 模拟耗时操作setTimeout(() => {this.closeLoadMore()this.loadMoreData()}, 2000)} else {console.info('======关闭加载更多!未达到条件========')this.closeLoadMore()}}// 关闭加载更多closeLoadMore() {this.isCanLoadMore = falsethis.isLoading = falsethis.isVisibleLoadMore = false}}

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

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

相关文章

Seata1.4.2分布式事务搭建部署【Spring cloud Alibaba】

包下载 https://github.com/apache/incubator-seata/releases下载并上传到服务器 //解压 tar -zxvf seata-server-1.4.2.tar.gz创建Seata的数据库及表&#xff0c;地址&#xff1a;https://github.com/seata/seata/tree/develop/script/server 根据数据类型复制相应的sql&…

【 USRP安装教程】MATLAB 2023B

步骤 matlabdocusrp驱动包 doc 安装包内容列表 双击“R2023b_Doc_Windows.iso” 打开cmd 查看盘符 切换盘符 因为是F盘&#xff0c;所以cmd输入&#xff1a;“F:” F:进入可安装界面 cd F:\bin\win64安装离线文档库 .\mpm install-doc --matlabroot"C:\MATLAB\R202…

Java 第14章 集合 本章作业

文章目录 试分析HashSet和TreeSet分别如何实现去重的HashSet重复加入问题比较ArrayList和Vector 试分析HashSet和TreeSet分别如何实现去重的 (1) HashSet的去重机制&#xff1a;hashCode() equals()&#xff0c;底层先通过存入对象,进行运算得到一个hash值&#xff0c;通过ha…

scrapy_redis原理分析并实现断点续爬以及分布式爬虫

scrapy_redis原理分析并实现断点续爬以及分布式爬虫 学习目标 了解 scrapy实现去重的原理了解 scrapy中请求入队的条件掌握 scrapy_redis基于url地址的增量式单机爬虫掌握 scrapy_redis分布式爬虫 1. 下载github的demo代码 clone github scrapy-redis源码文件 git clone http…

比 style gan 更好的 style gan2

上一篇博客介绍了style gan 原理&#xff0c;但是 style gan 的结果会有水珠伪影&#xff0c;作者实验后发现是 Adain 导致的&#xff0c;AdaIN对每一个feature map的通道进行归一化&#xff0c;这样可能破坏掉feature之间的信息。当然实验证明发现&#xff0c;去除AdaIN的归一…

华为数通方向HCIP-DataCom H12-831题库(多选题:201-220)

第201题 在多集群RR组网中,每个集群中部署了一台RR设备及其客户机,各集群的RR与为非客户机关系,并建立IBGP全连接。以下关于BGP路由反射器发布路由规则的描述,正确的有哪些? A、若某RR从EBGP对等体学到的路由,此RR会传递给其他集群的RR B、若某RR从非客户机IBGP对等体学…

QT打包exe文件,在其它电脑里双击exe就可以直接运行

想要不依赖QT环境&#xff0c;在其它电脑里直接双击exe文件就可以运行当前程序。具体打包过程如下&#xff1a; 使用QT编译出release版本的exe release版本运行无误后&#xff0c;需要找到当前构建生成的exe所在文件夹 可以看到具体目录在这里 我在该目录下的bin文件夹里找到…

【科技前沿】数字孪生技术改革智慧供热,换热站3D可视化引领未来

换热站作为供热系统不可或缺的一部分&#xff0c;其能源消耗对城市环保至关重要。在双碳目标下&#xff0c;供热企业可通过搭建智慧供热系统&#xff0c;实现供热方式的低碳、高效、智能化&#xff0c;从而减少碳排放和能源浪费。通过应用物联网、大数据等高新技术&#xff0c;…

【小黑嵌入式系统第十一课】μC/OS-III程序设计基础(一)——任务设计、任务管理(创建基本状态内部任务)、任务调度、系统函数

上一课&#xff1a; 【小黑嵌入式系统第十课】μC/OS-III概况——实时操作系统的特点、基本概念&#xff08;内核&任务&中断&#xff09;、与硬件的关系&实现 文章目录 一、任务设计1.1 任务概述1.2 任务的类型1.2.1 单次执行类任务&#xff08;运行至完成型&#…

Linux调试器gdb的用法

Linux调试器gdb的用法 1. debug/release版本之间的比较2. gdb调试器的基本指令3. 使用展示 1. debug/release版本之间的比较 在之前学习C语言的的时候出过一期vs的调试技巧。 而对于现在的Linux下的调试器gdb其实也是换汤不换药的&#xff0c;基本上的调试思路是不会改变的&am…

FreeSWITCH 1.10 源码阅读(7)-uuid_bridge 命令原理解析

文章目录 1. uuid_bridge 命令执行2. 源码分析3. uuid_bridge 问题处理 1. uuid_bridge 命令执行 uuid_bridge 命令用于将两条腿桥接在一起&#xff0c;以实现双方的通话。下图是该命令在 FreeSWITCH 中的处理流程&#xff0c;大致的流程可以分成以下几个步骤&#xff1a; uui…

手写单链表(指针)(next域)附图

目录 创建文件&#xff1a; 具体实现&#xff1a; 首先是头插。 注意&#xff1a;一定要注意&#xff1a;再定义tmp时&#xff0c;要给它赋一个初始值&#xff08;推荐使用 new list_next) 接着是尾插&#xff1a; 随后是中间插&#xff1a; 然后是最简单的改值&#xf…

JS - 设计模式持续学习中

通过例子持续学习JS设计模式中&#xff0c;接下来请跟随我的步伐走进我的学习笔记世界~ 什么是设计模式&#xff1f;我们为什么需要学习设计模式&#xff1f; 设计模式是可以更好解决问题的一种方案。 这意味着什么&#xff1f;如果你开发的项目的功能是固定的&#xff0c;永…

Java中的继承

继承 什么是继承继承的特点继承后对象的创建 继承的好处与应用场景继承相关注意事项权限修饰符单继承、Object类方法重写什么是方法重写 子类中访问其他成员的特点子类构造器的特点 什么是继承 Java中提供了一个关键字extends&#xff0c;用这个关键字&#xff0c;可以让一个类…

【自用】Ubuntu20.4从Vivado到ddr200t运行HelloWorld

【自用】Ubuntu20.4新系统从输入法到ddr200t运行HelloWorld 一、编辑bashrc二、Vivado2022.2安装三、编译蜂鸟E203自测样例1. 环境准备2. 下载e203_hbirdv2工程文件3. 尝试编译自测案例1. 安装RISC-V GNU工具链2. 编译测试样例 4. 用vivado为FPGA生成mcs文件1.准备RTL2.生成bit…

对大学生创新创业某赛事目前存在的烂尾楼现象的一些研究的分享(1)

经过对”某某网”大学生创新创业大赛国赛第五届-第八届部分金奖项目的研究&#xff0c;进行较为充分的信息溯源、穿透调查&#xff0c;我发现不少项目存在赛事材料画大饼&#xff0c;严重不切合实际&#xff0c;参赛人员并非真正创新创业&#xff0c;赛后迅速销声匿迹、烂尾切割…

图论 | 网络流的基本概念

文章目录 流网路残留网络增广路径割最大流最小割定理最大流Edmonds-Karp 算法算法步骤程序代码时间复杂度 流网路 流网络&#xff1a; G ( V , E ) G (V, E) G(V,E) 有向图&#xff0c;不考虑反向边s&#xff1a;源点t&#xff1a;汇点 c ( u , v ) c(u, v) c(u,v)&#xff…

你以为出现NoClassDefFoundError错误会是什么原因?

你以为出现NoClassDefFoundError错误会是什么原因&#xff1f; 1、概述2、事情经过3、总结 1、概述 大家好&#xff0c;我是欧阳方超&#xff0c;可以关注我的公众号“欧阳方超”&#xff0c;后续内容将在公众号首发。 同样的错误&#xff0c;非一样的解决方式。NoClassDefFou…

【智慧校园】基于国标GB28181协议EasyCVR视频技术的高校宿舍智能监管方案

现如今&#xff0c;各大学校不乏众多住校生&#xff0c;但由于很多学生年龄较小 &#xff0c;又缺乏独自生活的经历&#xff0c;如何给在校住宿生做到安全与生活双重保障&#xff1f;旭帆科技校园智能视频监控通过人工智能技术对住宿区域进行智能监管&#xff0c;确保学生住宿安…

【HCIP学习记录】OSPF Hello报文及状态机

字段长度含义Version1字节版本&#xff0c;OSPF的版本号。对于OSPFv2来说&#xff0c;其值为2。Type1字节类型&#xff0c;OSPF报文的类型&#xff0c;有下面几种类型&#xff1a; 1&#xff1a;Hello报文&#xff1b;● 2&#xff1a;DD报文&#xff1b;● 3&#xff1a;LSR报…