Android compose wanandroid app之导航规整以及登录页个人中心页实现

本文主要是介绍Android compose wanandroid app之导航规整以及登录页个人中心页实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

导航规整并实现登录页个人中心页

  • 前言
      • 导航规整
      • 个人中心的实现
        • MineViewmodel获取数据
        • MinePage
        • 请求头添加cookie
      • 登录页面的实现
        • OutlinedTextField 属性解析
        • 封装输入框
        • 输入框的使用
        • 登录按钮实现
        • 创建按钮状态枚举
        • 定义transition
        • 设置按钮颜色、大小以及shape
        • 使用Button并配置样式
        • 按钮全部代码
        • LoginViewModel
      • 源码地址

前言

在前面开发时只是注重了页面绘制,已经compose各种组件的使用,没有规整导航,所以页面跳转的操作很难实现;今天先规整一下页面导航,在页面跳转操作完成之后在绘制登录页以及个人中心页。

导航规整

在前面绘制页面的时候说到,compose打开页面的时候会在当前页面直击打开,所以就需要把要打开的页面都放在主页中进行打开,那么就要区分页面是首页,还是其他页面。

首先定义一个页面枚举,main代表首页,其他则是其他页面:

/*** 页面类* */
enum class RouteKey(val route:String){Main("main"),Login("login"),WebView("webview")
}

使用navhost进行导航,主页所有页面都用navigation进行包裹:

@ExperimentalMaterialApi
@ExperimentalCoilApi
@ExperimentalPagerApi
@Composable
fun RouteNavigation(navHostController: NavHostController,onFinish: () -> Unit
){val context = LocalContext.currentNavHost(navController = navHostController, startDestination = RouteKey.Main.route){//主页面navigation(route = RouteKey.Main.route,startDestination = Nav.BottomNavScreen.HomeScreen.route){composable(Nav.BottomNavScreen.HomeScreen.route){HomePage(navHostController = navHostController)}....//其他要展示在主页面的paer}//要打开的新页面//登录页composable(RouteKey.Login.route) {LoginPage(navHostController = navHostController)}}
}

首页导航页面把四个页面都封装起来:

object Nav {sealed class BottomNavScreen(val route: String, @StringRes val resourceId: Int, @DrawableRes val id: Int) {object HomeScreen: BottomNavScreen("home", R.string.nav_home, R.drawable.home_unselected)object ProjectScreen: BottomNavScreen("project",R.string.nav_project,R.drawable.project_unselected)object ClassicScreen: BottomNavScreen("classic",R.string.nav_classic,R.drawable.classic_unselected)object MineScreen: BottomNavScreen("mine", R.string.nav_mine, R.drawable.mine_unselected)}//主页点击两次返回桌面var onMainBackPressed = falseval bottomNavRoute = mutableStateOf<BottomNavScreen>(BottomNavScreen.HomeScreen)
}

将不同页面的展示封装到一个page,所有页面都在这个page打开,并加载到MainActivity里面去,但是要区分是主页,还是其他页面。

先判断是否是主页:

fun isMainScreen(route:String):Boolean = when(route){Nav.BottomNavScreen.HomeScreen.route,Nav.BottomNavScreen.ProjectScreen.route,Nav.BottomNavScreen.ClassicScreen.route,Nav.BottomNavScreen.MineScreen.route -> trueelse -> false
}

然后根据得到的结果加载页面:

@ExperimentalPagerApi
@ExperimentalMaterialApi
@Composable
fun MainPage(navHostController: NavHostController = rememberNavController(),onFinish:() -> Unit
){//返回back堆栈的顶部条目val navBackStackEntry by navHostController.currentBackStackEntryAsState()//返回当前routeval currentRoute = navBackStackEntry?.destination?.route ?: Nav.BottomNavScreen.HomeScreen.route//加载主页内容if (isMainScreen(currentRoute)){Scaffold(contentColor = MaterialTheme.colors.background,//标题栏topBar = {Column {Spacer(modifier = Modifier.background(MaterialTheme.colors.primary).statusBarsHeight().fillMaxWidth())}},//底部导航栏bottomBar = {Column {BottomNavBar(Nav.bottomNavRoute.value, navHostController)Spacer(modifier = Modifier.background(MaterialTheme.colors.primary).navigationBarsHeight().fillMaxWidth())}},//内容content = { paddingValues: PaddingValues ->//内容嵌套在Scaffold中RouteNavigation(navHostController, paddingValues, onFinish)OnBackClick(navHostController)})}else{//加载独立页面RouteNavigation(navHostController, onFinish = onFinish)}
}

到这里就完成了导航的规整,页面打开也没有问题,接下来就是个人中心页面以及登录页面的绘制和实现了。

个人中心的实现

目前个人中心比较简单,就展示了一个头像,昵称,用户id以及用户积分,更多的东西等到实现收藏等操作之后在添加,简单看一下效果图。
在这里插入图片描述
布局元素比较简单,这里就不贴布局文件了。

MineViewmodel获取数据

登录成功之后保存cookie,通过cookie调用用户信息接口,获取用户信息。

class MineViewModel : ViewModel() {//默认头像val defaultHead = "https://jusha-info.oss-cn-shenzhen.aliyuncs.com/obt/mall/upload/image/store/2021/08/06/1628250153533.png"private val _userInfo = MutableLiveData<UserConfigModule>()val userInfo = _userInfofun getUserInfo(){Log.e("intoTAG","get user info")NetWork.service.getUserInfo().enqueue(object :  Callback<BaseResult<UserConfigModule>>{override fun onResponse(call: Call<BaseResult<UserConfigModule>>,response: Response<BaseResult<UserConfigModule>>) {Log.e("intoTAG","response")response.body()?.let {_userInfo.value = it.data}}override fun onFailure(call: Call<BaseResult<UserConfigModule>>, t: Throwable) {Log.e("intoTAG","onFailure${t.message}")}})}
}
MinePage

获取信息并展示。

@Composable
fun MinePage(navHostController: NavHostController){val mineViewModel:MineViewModel = viewModel()val userInfo by mineViewModel.userInfo.observeAsState()mineViewModel.getUserInfo()Column(Modifier.fillMaxSize().verticalScroll(rememberScrollState())) {com.yangchoi.composeuidemo.ui.bar.TopAppBar(title = "我的")Box(Modifier.background(Color.White).fillMaxSize()) {Column(Modifier.fillMaxSize()) {if (userInfo !== null){//头像昵称ConstraintLayout {val (headImg,userName,userId)  = createRefs()Image(painter = rememberImagePainter(mineViewModel.defaultHead),contentDescription = "用户头像",modifier = Modifier.size(80.dp).padding(16.dp, 20.dp, 0.dp, 0.dp).clip(shape = RoundedCornerShape(50)).constrainAs(headImg) {})Text(text = "${userInfo!!.userInfo.nickname}",fontSize = 14.sp,color = Color.Black,modifier = Modifier.padding(10.dp, 20.dp, 0.dp, 0.dp).constrainAs(userName) {start.linkTo(headImg.end)top.linkTo(headImg.top)})Text(text = "${userInfo!!.userInfo.id}",fontSize = 12.sp,color = Color.Gray,modifier = Modifier.padding(10.dp, 20.dp, 0.dp, 0.dp).constrainAs(userId) {start.linkTo(headImg.end)bottom.linkTo(headImg.bottom)})}ConstraintLayout(modifier = Modifier.fillMaxWidth().padding(vertical = 40.dp).height(50.dp)) {val (icons,title,integral,btmLine) = createRefs()Row(Modifier.constrainAs(icons) {}.fillMaxHeight().padding(16.dp, 0.dp, 0.dp, 0.dp),verticalAlignment = Alignment.CenterVertically) {Image(painter = painterResource(id =R.drawable.icon_integral),contentDescription = "积分", modifier = Modifier.height(20.dp).width(20.dp))}Row(modifier = Modifier.constrainAs(title) {start.linkTo(icons.end)}.fillMaxHeight().padding(horizontal = 10.dp),verticalAlignment = Alignment.CenterVertically) {Text(text = "积分",fontSize = 12.sp,color = Color.Black,textAlign = TextAlign.Center)}Row(modifier = Modifier.fillMaxHeight().constrainAs(integral) {end.linkTo(parent.end)}.padding(horizontal = 16.dp),verticalAlignment = Alignment.CenterVertically) {Text(text = "${userInfo!!.coinInfo.coinCount}",fontSize = 12.sp,color = Color.Gray,textAlign = TextAlign.Center,)}Divider(modifier = Modifier.padding(0.dp, 0.dp, 16.dp, 0.dp,).constrainAs(btmLine) {bottom.linkTo(parent.bottom)},color = Color(229,224,227),thickness = 1.dp,startIndent = 16.dp)}}else{Row(modifier = Modifier.padding(horizontal = 16.dp, vertical = 200.dp).fillMaxWidth().height(50.dp).border(1.dp,color = Color(114, 160, 240),shape = RoundedCornerShape(20.dp)),verticalAlignment = Alignment.CenterVertically) {Text(text = "登  录",fontSize = 16.sp,modifier = Modifier.fillMaxWidth().clickable {navHostController.navigate("${RouteKey.Login.route}")},color = Color(114, 160, 240),textAlign = TextAlign.Center)}}}}}
}
请求头添加cookie

登录成功之后会返回一个cookie在请求头里面,只需要将cookie拦截并保存下来,就可以通过cookie去获取用户信息。

//创建OKhttp
private val client: OkHttpClient.Builder = OkHttpClient.Builder().addInterceptor(LogInterceptor()).addInterceptor {val request = it.request()val response = it.proceed(request)val requestUrl = request.url.toString()val domain = request.url.host//cookie可能有多个,都保存下来if ((requestUrl.contains(SAVE_USER_LOGIN_KEY) || requestUrl.contains(SAVE_USER_REGISTER_KEY))) {val cookies = response.headers(SET_COOKIE_KEY)val cookie = encodeCookie(cookies)saveCookie(requestUrl, domain, cookie)}response}//请求时设置cookie.addInterceptor {val request = it.request()val builder = request.newBuilder()val domain = request.url.host//获取domain内的cookieif (domain.isNotEmpty()) {val sqDomain: String = DataStoreUtil.readStringData(domain, "")val cookie: String = if (sqDomain.isNotEmpty()) sqDomain else ""if (cookie.isNotEmpty()) {builder.addHeader(COOKIE_NAME, cookie)}}it.proceed(builder.build())}.connectTimeout(10, TimeUnit.SECONDS).readTimeout(20, TimeUnit.SECONDS).retryOnConnectionFailure(false)

在网络请求的位置添加以上两个拦截器就行了。

登录页面的实现

首先来看效果图。
在这里插入图片描述
简单的绘制了一个登录页面,UI就不要纠结了,丑是真的丑~

可以看到在输入框左边有一个图标,然后是提示内容,以及密码框右边的显示和隐藏密码的图标;选中的时候颜色发生改变,并且在左上角显示提示用户输入的内容。

OutlinedTextField 属性解析

在实现以上效果前,先要了解OutlinedTextField的属性,才能加以运用 ;先看一下属性列表。

@Composable
fun OutlinedTextField(value: String,onValueChange: (String) -> Unit,modifier: Modifier = Modifier,enabled: Boolean = true,readOnly: Boolean = false,textStyle: TextStyle = LocalTextStyle.current,label: @Composable (() -> Unit)? = null,placeholder: @Composable (() -> Unit)? = null,leadingIcon: @Composable (() -> Unit)? = null,trailingIcon: @Composable (() -> Unit)? = null,isError: Boolean = false,visualTransformation: VisualTransformation = VisualTransformation.None,keyboardOptions: KeyboardOptions = KeyboardOptions.Default,keyboardActions: KeyboardActions = KeyboardActions.Default,singleLine: Boolean = false,maxLines: Int = Int.MAX_VALUE,interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },shape: Shape = MaterialTheme.shapes.small,colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors()
) 
  • value: String 输入框显示的文本
  • onValueChange: (String) -> Unit 值发生改变之后触发的回调
  • modifier: Modifier = Modifier 修饰
  • enabled: Boolean = true 可用
  • readOnly: Boolean = false 是否只读
  • textStyle: TextStyle = LocalTextStyle.current
  • label: @Composable (() -> Unit)? = null 输入框获取焦点时左上角提示的内容
  • placeholder: @Composable (() -> Unit)? = null 输入框提示的内容
  • leadingIcon: @Composable (() -> Unit)? = null 输入框左侧的图标
  • trailingIcon: @Composable (() -> Unit)? = null 输入框右侧的图标
  • isError: Boolean = false 是否处于错误状态
  • visualTransformation: VisualTransformation = VisualTransformation.None, 转换输入值的视觉表示
  • keyboardOptions: KeyboardOptions = KeyboardOptions.Default 输入框输入类型
  • singleLine: Boolean = false, 是否单行显示
  • maxLines: Int = Int.MAX_VALUE 最大行数
  • colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors() 颜色集合,设置获取焦点,失去焦点以及光标等颜色

大致就是这些属性了,知道使用之后就可以封装输入框了。

封装输入框

定义状态枚举PwdShowState,通过状态设置密码是否可见。

通过value:String设置输入框显示的值。

通过placeholder:String设置输入框提示的值。

通过color:TextFieldColors设置对应状态下的颜色,获得焦点、失去焦点、以及光标时候的颜色。

通过leadingIcon:ImageVector设置左侧图标。

通过trailingIcon:ImageVector设置右侧图标,通过trailingtintIcon:Color设置图标颜色。

通过keyboardOptions: KeyboardOptions设置输入框输入类型。

通过visualTransformation: VisualTransformation = VisualTransformation.None改变设置密码是否可见。

通过onValueChange:(String) -> Unit获取输入框发生改变时值的回调。

//输入框
enum class PwdShowState{Show,Hide
}
@Composable
fun MyTextField(value:String,label:String,placeholder:String,color:TextFieldColors,leadingIcon:ImageVector,trailingIcon:ImageVector,trailingtintIcon:Color,modifier: Modifier,modifierTrailing: Modifier,keyboardOptions: KeyboardOptions,visualTransformation: VisualTransformation = VisualTransformation.None,onValueChange:(String) -> Unit){val showState = remember {mutableStateOf(PwdShowState.Hide)}val icon =  if (showState.value === PwdShowState.Hide){painterResource(id = R.drawable.pwd_look)}else{painterResource(id = R.drawable.pwd_hide)}OutlinedTextField(value = value,colors = color,label = {Text(text = label)},placeholder = {Text(text = placeholder)},modifier = modifier,keyboardOptions = keyboardOptions,leadingIcon = {Icon(leadingIcon,"左边图标",modifierTrailing,trailingtintIcon)},trailingIcon = {if (label.equals("密码")){IconButton(onClick = {if (showState.value === PwdShowState.Hide){showState.value = PwdShowState.Show}else{showState.value = PwdShowState.Hide}}) {if (showState.value === PwdShowState.Hide){Icon(icon, contentDescription = "点击密码可见",modifier = Modifier.size(30.dp))}else{Icon(icon, contentDescription = "点击密码隐藏",modifier = Modifier.size(30.dp))}}}},visualTransformation = if (label.equals("密码")){if (showState.value === PwdShowState.Hide){ PasswordVisualTransformation()} else visualTransformation}else{visualTransformation},singleLine = true,onValueChange = onValueChange)
}
输入框的使用

根据不同的使用场景,设置不同的参数。

账号:

val userName = remember {mutableStateOf("")
}
val colors = TextFieldDefaults.outlinedTextFieldColors(focusedBorderColor = Color(68,84,246),unfocusedBorderColor = Color.Gray,cursorColor = Color(68,84,246)
)
MyTextField(value = userName.value,label = "账号",placeholder = "请输入账号",color = colors,leadingIcon = Icons.Default.Phone,trailingIcon = Icons.Default.Phone,trailingtintIcon = Color(68,84,246),modifier = Modifier.padding(12.dp, 0.dp, 12.dp, 0.dp).fillMaxWidth(),modifierTrailing = Modifier,keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),onValueChange = {userName.value = it}
)

密码:

val password = remember {mutableStateOf("")
}
val colors = TextFieldDefaults.outlinedTextFieldColors(focusedBorderColor = Color(68,84,246),unfocusedBorderColor = Color.Gray,cursorColor = Color(68,84,246)
)
MyTextField(value = password.value,label = "密码",placeholder = "请输入密码",color = colors,leadingIcon = Icons.Default.Lock,trailingIcon = Icons.Default.Lock,trailingtintIcon = Color(68,84,246),modifier = Modifier.padding(12.dp, 0.dp, 12.dp, 0.dp).fillMaxWidth(),modifierTrailing = Modifier,keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),onValueChange = {password.value = it}
)

输入框实现完成~

登录按钮实现

在点击登录按钮的时候,登录接口请求过程中加载一个简单的动画,在登录成功或者失败之后结束动画。

创建按钮状态枚举

Normal正常情况下的状态

Pressed 按下时的状态

remember 记录状态的值

//按钮添加动画
enum class ButtonState{Normal,Pressed
}
//记录状态值
val buttonState = remember {mutableStateOf(ButtonState.Normal)
}
定义transition

定义一个transition,以及后面通过该元素设置颜色、大小等参数。

val transition = updateTransition(targetState = buttonState, label = "ButtonTransition")
设置按钮颜色、大小以及shape
    val buttonBackgroundColor: Color by transition.animateColor(transitionSpec = { tween(duration)}) { buttonState ->when(buttonState.value){ButtonState.Normal -> Color(68,84,246)ButtonState.Pressed -> Color(68,84,246)}}val buttonWidth: Dp by transition.animateDp(transitionSpec = {tween(duration)}) {buttonState ->when(buttonState.value){ButtonState.Normal -> 300.dpButtonState.Pressed -> 60.dp}}val buttonShape: Dp by transition.animateDp(transitionSpec = {tween(duration)}) {buttonState ->when(buttonState.value){ButtonState.Normal -> 4.dpButtonState.Pressed -> 100.dp}}
使用Button并配置样式

属性列表:

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun Button(onClick: () -> Unit,modifier: Modifier = Modifier,enabled: Boolean = true,interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },elevation: ButtonElevation? = ButtonDefaults.elevation(),shape: Shape = MaterialTheme.shapes.small,border: BorderStroke? = null,colors: ButtonColors = ButtonDefaults.buttonColors(),contentPadding: PaddingValues = ButtonDefaults.ContentPadding,content: @Composable RowScope.() -> Unit
)
  • onClick: () -> Unit 点击事件回调
  • enabled: Boolean = true 是否可用,是否可以点击,这里可以加上判断,当用户名和密码都不为空的时候可以使用enabled = !userName.isNullOrBlank() && !password.isNullOrBlank()
  • colors: ButtonColors = ButtonDefaults.buttonColors() 设置背景颜色以及点击时候的背景颜色等
  • content: @Composable RowScope.() -> Unit compose函数,实现逻辑
Button(modifier = Modifier.width(buttonWidth).height(50.dp),shape = RoundedCornerShape(buttonShape),onClick = {//todo},colors = ButtonDefaults.buttonColors(backgroundColor = buttonBackgroundColor,disabledBackgroundColor = Color(68,84,246).copy(0.5f)),enabled = !userName.isNullOrBlank() && !password.isNullOrBlank()) {if (buttonState.value == ButtonState.Normal){Text(text = "登录")}else{CircularProgressIndicator(color = Color.White,strokeWidth = 2.dp,modifier = Modifier.size(24.dp))}}

点击逻辑,将按钮状态设置成Pressed

buttonState.value = ButtonState.Pressed

并请求登录接口

loginViewModel.toLogin(userName,password,{//回调  状态重置buttonState.value = ButtonState.NormalnavHostController.navigateUp()
})

通过CircularProgressIndicator实现动画

if (buttonState.value == ButtonState.Normal){Text(text = "登录")
}else{CircularProgressIndicator(color = Color.White,strokeWidth = 2.dp,modifier = Modifier.size(24.dp))
}
按钮全部代码

按钮封装的代码:

//按钮添加动画
enum class ButtonState{Normal,Pressed
}@Composable
fun MyButton(userName:String,password:String,loginViewModel:LoginViewModel,navHostController: NavHostController){val buttonState = remember {mutableStateOf(ButtonState.Normal)}val transition = updateTransition(targetState = buttonState, label = "ButtonTransition")val duration = 600val buttonBackgroundColor: Color by transition.animateColor(transitionSpec = { tween(duration)}) { buttonState ->when(buttonState.value){ButtonState.Normal -> Color(68,84,246)ButtonState.Pressed -> Color(68,84,246)}}val buttonWidth: Dp by transition.animateDp(transitionSpec = {tween(duration)}) {buttonState ->when(buttonState.value){ButtonState.Normal -> 300.dpButtonState.Pressed -> 60.dp}}val buttonShape: Dp by transition.animateDp(transitionSpec = {tween(duration)}) {buttonState ->when(buttonState.value){ButtonState.Normal -> 4.dpButtonState.Pressed -> 100.dp}}Button(modifier = Modifier.width(buttonWidth).height(50.dp),shape = RoundedCornerShape(buttonShape),onClick = {buttonState.value = ButtonState.PressedloginViewModel.toLogin(userName,password,{buttonState.value = ButtonState.NormalnavHostController.navigateUp()})},colors = ButtonDefaults.buttonColors(backgroundColor = buttonBackgroundColor,disabledBackgroundColor = Color(68,84,246).copy(0.5f)),enabled = !userName.isNullOrBlank() && !password.isNullOrBlank()) {if (buttonState.value == ButtonState.Normal){Text(text = "登录")}else{CircularProgressIndicator(color = Color.White,strokeWidth = 2.dp,modifier = Modifier.size(24.dp))}}
}

调用:

MyButton(userName.value,password.value,loginViewModel,navHostController)

到这里呢整个登录页面所有的元素都构建好了,剩下的就是viewmodel实现登录请求以及结果回调了。

LoginViewModel
class LoginViewModel : ViewModel() {private val _loginInfo = MutableLiveData<Any>()val loginInfo = _loginInfofun toLogin(username:String,password:String,callback:()->Unit){NetWork.service.login(username,password).enqueue(object : Callback<BaseResult<Any>>{override fun onResponse(call: Call<BaseResult<Any>>,response: Response<BaseResult<Any>>) {response.body()?.let {_loginInfo.value = it}callback.invoke()}override fun onFailure(call: Call<BaseResult<Any>>, t: Throwable) {callback.invoke()}})}}

登录页面的绘制以及实现就完成了,因为不能放置视频,登录按钮点击时的动画也没有弄成GIF,这里就不放效果图了,代码很简单,效果跑起来就能看到。

源码地址

gitee源码地址:戳我~

这篇关于Android compose wanandroid app之导航规整以及登录页个人中心页实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/858907

相关文章

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

跨国公司撤出在华研发中心的启示:中国IT产业的挑战与机遇

近日,IBM中国宣布撤出在华的两大研发中心,这一决定在IT行业引发了广泛的讨论和关注。跨国公司在华研发中心的撤出,不仅对众多IT从业者的职业发展带来了直接的冲击,也引发了人们对全球化背景下中国IT产业竞争力和未来发展方向的深思。面对这一突如其来的变化,我们应如何看待跨国公司的决策?中国IT人才又该如何应对?中国IT产业将何去何从?本文将围绕这些问题展开探讨。 跨国公司撤出的背景与

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

【测试】输入正确用户名和密码,点击登录没有响应的可能性原因

目录 一、前端问题 1. 界面交互问题 2. 输入数据校验问题 二、网络问题 1. 网络连接中断 2. 代理设置问题 三、后端问题 1. 服务器故障 2. 数据库问题 3. 权限问题: 四、其他问题 1. 缓存问题 2. 第三方服务问题 3. 配置问题 一、前端问题 1. 界面交互问题 登录按钮的点击事件未正确绑定,导致点击后无法触发登录操作。 页面可能存在