Android笔记(七)Android JetPack Compose组件搭建Scaffold脚手架

news2024/11/18 16:44:30

在去年2022年曾发布一篇关于脚手架的文章:“Android JetPack Compose组件中Scaffold的应用” 。但是Android的版本从12变更到13及以上版本,导致一些细节的实现存在不同。在本文中,将从头开始介绍整个脚手架的搭建过程。

一、新建项目模块

在Android Studio(版本是Graffie)中新建模块,选择“Empty Activity",如图1所示。
在这里插入图片描述
图1

二、定义脚手架Scaffold

@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun MainScreen(){
    Scaffold(
        //定义头部
        topBar = {

        },
        //定义底部导航
        bottomBar = {

        },
        //定义信息提示区
        snackbarHost = {

        },
        //定义悬浮按钮
        floatingActionButton = {

        },
        content = {//content定义中心区
        }
    )

或也可以定义成如下形式:

@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun MainScreen(){
    Scaffold(
        //定义头部
        topBar = {

        },
        //定义底部导航
        bottomBar = {

        },
        //定义信息提示区
        snackbarHost = {

        },
        //定义悬浮按钮
        floatingActionButton = {

        }
    ){//content定义中心区

    }
}

与原来:“Android JetPack Compose组件中Scaffold的应用” 最大的不同在于现在Android13版本的Scaffold取消了drawerContent的属性,因此,导致对于侧滑菜单的定义发生变化。

三、创建三个不同界面

首先,定义一个通用的界面:

@Composable
fun DisplayScreen(title:String, preColor: Color=Color.Black, backgroundColor:Color=colorResource(R.color.teal_200)){
    Box(contentAlignment= Alignment.Center,
        modifier = Modifier
            .fillMaxSize()
            .background(backgroundColor)){
        Text(text = title,fontSize = 30.sp,color = preColor)
    }
}

然后,定义的三个不同的界面分别调用上述的DisplayScreen组合函数,代码分别如下,运行效果如图2所示。

@Composable
fun HomeScreen(){
    DisplayScreen(title = "首页")
}
@Composable
fun SettingScreen(){
    DisplayScreen(title = "配置")
}
@Composable
fun HelpScreen(){
    DisplayScreen(title = "帮助和支持")
}

在这里插入图片描述
图2
为了方便后续对这三个界面的切换,定义一个通用的密封类Screen,代码如下

/**
 * 定义要切换界面的密封类Screen
 * @property route String 导航线路名
 * @property title String  标题
 * @property icon ImageVector 图标
 * @property loadScreen [@androidx.compose.runtime.Composable] Function0<Unit> 加载动作处理
 * @constructor
 */
sealed class Screen(val route:String, val title:String, val icon: ImageVector, val loadScreen: @Composable ()->Unit){
    object Home:Screen("home","首页", Icons.Filled.Home,loadScreen={
        HomeScreen()
    })

    object Setting:Screen("setting","配置",Icons.Filled.Settings, loadScreen = {
        SettingScreen()
    })

    object Help:Screen("help","帮助和支持",Icons.Filled.Info, loadScreen = {
        HelpScreen()
    })
}

在此前提下定义一个保存要显示界面的列表:

val screens = listOf(Screen.Home,Screen.Setting,Screen.Help)

四、定义底部导航栏

@Composable
fun BottomView(currentScreen: MutableState<Screen>){
    BottomAppBar {
        screens.forEach {
            NavigationBarItem(
                selected = currentScreen.value.route == it.route,
                onClick = {
                    //定义点击动作
                    currentScreen.value = it
                },
                icon = {
                    Column(horizontalAlignment = Alignment.CenterHorizontally){
                        Icon(imageVector = it.icon,tint = Color.Blue,contentDescription = it.title)
                        Text(text = it.title,fontSize = 20.sp)
                    }
                })
        }
    }
}

然后在Scaffold中进行调用,因为需要保存一个当前屏幕的状态,因此在MainScreen增加一个currentScreen的状态值,修改MainScreen()如下所示。

@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun MainScreen(){
    val currentState:MutableState<Screen> = remember{mutableStateOf(Screen.Home)}
    Scaffold(
        //定义头部
        topBar = {

        },
        //定义底部导航
        bottomBar = {
            BottomView(currentScreen = currentState)
        },
        //定义信息提示区
        snackbarHost = {

        },
        //定义悬浮按钮
        floatingActionButton = {

        }
    ){//content定义中心区
	     currentState.value.loadScreen()
    }
}

这时运行效果如图3所示。
在这里插入图片描述
图3
通过选择底部不同的按钮,可以切换到不同的界面,如图3所示。

五、定义顶部栏

定义顶部栏需要解决两个问题:(1)需要在顶部栏定义顶部的右侧导航菜单;(2)需要定义顶部的导航按钮,使得启动侧滑菜单;

1.定义顶部的后侧菜单

@Composable
fun MenuView(currentScreen: MutableState<Screen>, expandedState:MutableState<Boolean>){
    DropdownMenu(expanded = expandedState.value,
                 onDismissRequest = {
                    expandedState.value = false
                }) {
        screens.forEach {
            DropdownMenuItem(
                leadingIcon = {
                              Icon(imageVector = it.icon,contentDescription = it.title)
                },
                text = {
                         Text(text = it.title,fontSize = 20.sp)
            }, onClick = {
                currentScreen.value = it
            })
        }
    }
}

然后再修改MainScreen,通过一个状态参数expandedState的值判断是否打开菜单,这时修改的MainScreen的代码如下:

@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun MainScreen(){
    //保存当前界面
    val currentState:MutableState<Screen> = remember{mutableStateOf(Screen.Home)}
    //记录菜单是否可以扩展
    val expandedState = remember{mutableStateOf(false)}
    Scaffold(
        //定义头部
        topBar = {
            TopAppBar(
                //左侧的文本
                title = { /*TODO*/ },
                //导航图标
                navigationIcon = {

                },
                //按行处理的交互
                actions = {
                    IconButton(onClick={
                        expandedState.value = !expandedState.value
                    }){
                        Icon(imageVector = Icons.Filled.MoreVert,contentDescription = "More...")
                        if(expandedState.value)
                            MenuView(currentState, expandedState)
                    }
                })
        },
        //定义底部导航
        bottomBar = {
            BottomView(currentScreen = currentState)
        },
        //定义信息提示区
        snackbarHost = {

        },
        //定义悬浮按钮
        floatingActionButton = {

        }
    ){//content定义中心区
        currentState.value.loadScreen()
    }
}

这时,代码的运行效果如图4所示。
在这里插入图片描述
图4
如图4所示,可以发现右上角出现了更多的图标,点击该图标会弹出一个菜单,通过这个菜单可以切换不同的界面。

2.定义顶部栏的导航按钮启动侧滑菜单

定义侧滑菜单的内容,代码如下所示:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DrawerView(currentScreen: MutableState<Screen>, drawerState: DrawerState,scope:CoroutineScope){
    ModalNavigationDrawer(
        drawerState = drawerState,
        drawerContent = {
            Column(
                verticalArrangement = Arrangement.Center,
                modifier = Modifier
                .fillMaxHeight()
                .width(360.dp).background(Color.White)){
                screens.forEach {
                    NavigationDrawerItem(
                        label = {
                            Text(it.title,fontSize = 30.sp)
                        },
                        icon={
                            Icon(imageVector = it.icon,tint=Color.Green,contentDescription = null)
                        },
                        selected = it.route==currentScreen.value.route,
                        onClick = {
                            scope.launch {
                                currentScreen.value = it
                                drawerState.close()
                            }
                        })
                }
            }
        }) {
        currentScreen.value.loadScreen()
    }
}

在此基础上,修改MainScreen,使得点击顶部栏的导航按钮可以弹出侧滑菜单:

@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun MainScreen(){
    val currentState:MutableState<Screen> = remember{mutableStateOf(Screen.Home)}
    val expandedState = remember{mutableStateOf(false)}
    val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
    val scope = rememberCoroutineScope()
    Scaffold(
        //定义头部
        topBar = {
            TopAppBar(
                //左侧的文本
                title = {
                        Text("侧滑菜单")
                        },
                //导航图标
                navigationIcon = {
                    IconButton(onClick={
                        scope.launch {
                            drawerState.open()
                        }
                    }){
                        Icon(imageVector = Icons.Filled.ArrowForward,contentDescription = "弹出侧滑菜单")
                    }
                },
                //按行处理的交互
                actions = {
                    IconButton(onClick={
                        expandedState.value = !expandedState.value
                    }){
                        Icon(imageVector = Icons.Filled.MoreVert,contentDescription = "More...")
                        if(expandedState.value)
                            MenuView(currentState, expandedState)
                    }
                })
        },
        //定义底部导航
        bottomBar = {
            BottomView(currentScreen = currentState)
        },
        //定义信息提示区
        snackbarHost = {

        },
        //定义悬浮按钮
        floatingActionButton = {

        }
    ){ //content定义中心区
        //直接调用侧滑界面
        DrawerView(currentState, drawerState, scope )
    }
}

注意在MainScreen中的Scaffold的中心区修改为调用drawerView组合函数,并增加DrawerState状态值控制侧滑菜单的启动和关闭,通过调用drawerState的open函数和close函数分别实现。因为drawerState的open函数和close函数均为suspend挂起函数,需要在协程中运行,因此还增加了一个scope的参数,用它来加载drawerState的open函数和close函数。
这时,点击顶部栏的导航图标,运行效果如图5所示。
在这里插入图片描述
图5

六、定义悬浮按钮

悬浮按钮定义在Scaffold脚手架的floatingActionButton属性对应的部分,下列将定义一个悬浮按钮,使得点击该按钮可以返回到首页。代码如下:

@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun MainScreen(){
    val currentState:MutableState<Screen> = remember{mutableStateOf(Screen.Home)}
    val expandedState = remember{mutableStateOf(false)}
    val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
    val scope = rememberCoroutineScope()
    Scaffold(
        ......
        //定义悬浮按钮
        floatingActionButton = {
            FloatingActionButton(onClick = {
                currentState.value = Screen.Home
            }) {
                Icon(imageVector = Icons.Filled.Refresh,contentDescription = "返回")
            }
        }
    ){ //content定义中心区
        DrawerView(currentState, drawerState, scope )
    }
}

运行效果如图6所示。
在这里插入图片描述
图6

七、定义信息栏

定义一个信息栏增加一个状态值displayedSnackState,通过它来修改信息栏显示的控制。代码示例如下:

@Composable
fun MainScreen(){
    val currentState:MutableState<Screen> = remember{mutableStateOf(Screen.Home)}
    val expandedState = remember{mutableStateOf(false)}
    val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
    val scope = rememberCoroutineScope()
    val displayedSnackState = remember { mutableStateOf(false)}
    Scaffold(
        //定义头部
        topBar = {
            TopAppBar(
                //左侧的文本
                title = {
                        Text("侧滑菜单")
                        },
                //导航图标
                navigationIcon = {
                    IconButton(onClick={
                        scope.launch {
                            drawerState.open()
                        }
                    }){
                        Icon(imageVector = Icons.Filled.ArrowForward,contentDescription = "弹出侧滑菜单")
                    }
                },
                //按行处理的交互
                actions = {
                    IconButton(onClick={
                        expandedState.value = !expandedState.value
                    }){
                        Icon(imageVector = Icons.Filled.MoreVert,contentDescription = "More...")
                        if(expandedState.value)
                            MenuView(currentState, expandedState)
                    }
                })
        },
        //定义底部导航
        bottomBar = {
            BottomView(currentScreen = currentState)
        },
        //定义信息提示区
        snackbarHost = {
            if(displayedSnackState.value){
                Snackbar(modifier = Modifier
                    .fillMaxWidth()
                    .background(Color.Blue),
                    ) {
                    Text("提示信息:返回首页",fontSize = 24.sp)
                }
            }
        },
        //定义悬浮按钮
        floatingActionButton = {
            FloatingActionButton(onClick = {
                currentState.value = Screen.Home
                displayedSnackState.value = !displayedSnackState.value
            }) {
                Icon(imageVector = Icons.Filled.Refresh,contentDescription = "返回")
            }
        }
    ){ //content定义中心区
        DrawerView(currentState, drawerState, scope )
    }
}

运行结果如图7所示:
在这里插入图片描述
图7

八、状态优化的处理

在上述的处理过程中,可以发现MainScreen中定义了很多的状态值,这些状态值往往需要作为函数的参数进行传递,处理过程复杂,可以对这些状态值做一个优化处理。
首先,定义一个类,保存各种需要的状态。代码如下:

@OptIn(ExperimentalMaterial3Api::class)
class StateHolder(val currentScreen:MutableState<Screen>,
                  val expandedState: MutableState<Boolean>,
                  val drawerState: DrawerState,
                  val displayedSnackState:MutableState<Boolean>,
                  val scope:CoroutineScope)

然后再定义一个组合函数获取所有的状态值,代码如下:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun rememberStates(
    currentScreen: MutableState<Screen> = remember { mutableStateOf(Screen.Home) },
    expandedState: MutableState<Boolean> = remember { mutableStateOf(false) },
    drawerState: DrawerState = rememberDrawerState(initialValue = DrawerValue.Closed),
    displayedSnackState: MutableState<Boolean> = remember{mutableStateOf(false)},
    scope: CoroutineScope = rememberCoroutineScope(),
)=StateHolder(currentScreen,expandedState,drawerState,displayedSnackState,scope)

在此前提的基础上,修改代码,这时以MainScreen为例:

@Composable
fun MainScreen(){
    val states = rememberStates()
    Scaffold(
        //定义头部
        topBar = {
            TopAppBar(
                //左侧的文本
                title = {
                        Text("侧滑菜单")
                        },
                //导航图标
                navigationIcon = {
                    IconButton(onClick={
                        states.scope.launch {
                            states.drawerState.open()
                        }
                    }){
                        Icon(imageVector = Icons.Filled.ArrowForward,contentDescription = "弹出侧滑菜单")
                    }
                },
                //按行处理的交互
                actions = {
                    IconButton(onClick={
                        states.expandedState.value = !states.expandedState.value
                    }){
                        Icon(imageVector = Icons.Filled.MoreVert,contentDescription = "More...")
                        if(states.expandedState.value)
                            MenuView(states)
                    }
                })
        },
        //定义底部导航
        bottomBar = {
            BottomView(states)
        },
        //定义信息提示区
        snackbarHost = {
            if(states.displayedSnackState.value){
                Snackbar(modifier = Modifier
                    .fillMaxWidth()
                    .background(Color.Blue),
                    ) {
                    Text("提示信息:返回首页",fontSize = 24.sp)
                }
            }
        },
        //定义悬浮按钮
        floatingActionButton = {
            FloatingActionButton(onClick = {
                states.currentScreen.value = Screen.Home
                states.displayedSnackState.value = !states.displayedSnackState.value
            }) {
                Icon(imageVector = Icons.Filled.Refresh,contentDescription = "返回")
            }
        }
    ){ //content定义中心区
        DrawerView(states)
    }
}

同时对MainScreen调用的MenuView、BottomView和DrawerView中需要传递状态参数的函数进行修改,修改的代码分别是:

MenuView的定义

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MenuView(states:StateHolder){
    DropdownMenu(expanded = states.expandedState.value,
                 onDismissRequest = {
                     states.expandedState.value = false
                }) {
        screens.forEach {
            DropdownMenuItem(
                leadingIcon = {
                              Icon(imageVector = it.icon,contentDescription = it.title)
                },
                text = {
                         Text(text = it.title,fontSize = 20.sp)
            }, onClick = {
                states.currentScreen.value = it
            })
        }
    }
}

BottomView的定义

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BottomView(states:StateHolder){
    BottomAppBar {
        screens.forEach {
            NavigationBarItem(
                selected = states.currentScreen.value.route == it.route,
                onClick = {
                    //定义点击动作
                    states.currentScreen.value = it
                },
                icon = {
                    Column(horizontalAlignment = Alignment.CenterHorizontally){
                        Icon(imageVector = it.icon,tint = Color.Blue,contentDescription = it.title)
                        Text(text = it.title,fontSize = 20.sp)
                    }
                })
        }
    }
}

DrawerView的定义

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DrawerView(states:StateHolder){
    ModalNavigationDrawer(
        drawerState = states.drawerState,
        drawerContent = {
            Column(
                verticalArrangement = Arrangement.Center,
                modifier = Modifier
                    .fillMaxHeight()
                    .width(360.dp)
                    .background(Color.White)){
                screens.forEach {
                    NavigationDrawerItem(
                        label = {
                            Text(it.title,fontSize = 30.sp)
                        },
                        icon={
                            Icon(imageVector = it.icon,tint=Color.Green,contentDescription = null)
                        },
                        selected = it.route==states.currentScreen.value.route,
                        onClick = {
                            states.scope.launch {
                                states.currentScreen.value = it
                                states.drawerState.close()
                            }
                        })
                }
            }
        }) {
        states.currentScreen.value.loadScreen()
    }
}

通过这样的方式,单一传递状态值在不同的组合函数共享。

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

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

相关文章

uniGUI文件操作

一.文件上传TUniFileUploadButton TUniFileUploadButton主要属性&#xff1a; Filter: 文件类型过滤&#xff0c;有图片image/* audio/* video/*三种过滤 MaxAllowedSize: 设置文件最大上传尺寸&#xff1b; Message&#xff1a;标题以及消息文本&#xff0c;可翻译成中文…

手写call(),apply(),bind()方法

目录 知识储备&#xff1a; 一&#xff1a;手写call方法 1、思路 2、实现 3、Symbol调优 二&#xff1a;手写apply方法 1、思路 2、实现 三&#xff1a;手写bind方法 1、思路 2、实现 四&#xff1a;总结 知识储备&#xff1a; 所有的方法都可以调用我们手写的方法&…

npm ERR! node-sass@6.0.1 postinstall: `node scripts/build.js`

1.遇到的问题 vue npm install提示以下错误 2.首次尝试方法 尝试用下面的方式重新安装弄得-saas&#xff0c;结果不起作用 。 npm config set sass_binary_sitehttps://npm.taobao.org/mirrors/node-sass npm install node-sass 这时考虑降级node版本&#xff0c;node.js从…

上海亚商投顾:沪指再创年内新低 贵州茅台等权重股集体调整

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 三大指数昨日全线调整&#xff0c;沪指逼近3000点大关&#xff0c;深成指、创业板指续创年内新低。芯片板块逆…

推荐系统(RS)

主流推荐算法 协同过滤算法 协同过滤算法的原理 根据用户群体对产品偏好的数据&#xff0c;发现用户之间的相似性或者物品之间的相似性&#xff0c;并基于这些相似性为用户作推荐。 基于用户的协同过滤算法&#xff08;User-based Collaborative Filtering&#xff09; 其本…

Leetcode刷题详解——四数之和

1. 题目链接&#xff1a;四数之和 2. 题目描述&#xff1a; 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若两个四元组元素一一对应&#xff0…

『力扣刷题本』:相交链表

咳咳&#xff0c;实在抱歉&#xff0c;刚开始心气太高了&#xff0c;叫『每日一题』&#xff0c;我是真的坚持不下了。 经过这次打击&#xff0c;我算是摸明白自己在写博客这件事情上几斤几两了&#xff0c;现在预计一周两更&#xff0c;再慢慢把更新频率提上来。 正在努力补…

python写的自动按键和鼠标连点

自己用python写的自动按键和鼠标自动点击。 分享一下源码&#xff0c;比较干净的&#xff0c;缺点就是是python打包有点大50多M from PyQt5 import QtWidgets, uic, QtCore from pynput import keyboard, mouse import pygetwindow as gw from PyQt5.QtGui import QPainter, Q…

YOLOv7改进实战 | 更换轻量化主干网络Backbone(一)之Ghostnet

前言 轻量化网络设计是一种针对移动设备等资源受限环境的深度学习模型设计方法。下面是一些常见的轻量化网络设计方法: 网络剪枝:移除神经网络中冗余的连接和参数,以达到模型压缩和加速的目的。分组卷积:将卷积操作分解为若干个较小的卷积操作,并将它们分别作用于输入的不…

Netty常用类与接口

netty架构图 ServerBootstrap 、 Bootstrap ServerBootstrap &#xff1a;服务器的引导类&#xff0c;可以绑定服务器和端口&#xff0c;配置 Channel、ChannelHandler等。 Bootstrap&#xff1a;客户端的引导类。可以开启客户端&#xff0c;连接服务端的端口&#xff0c;配置…

矩阵系统功能介绍

数据大屏&#xff1a;监测读取后台数据 AI素材库&#xff1a;一键去水印功能 将视频做出自己的 AI智能文案&#xff1a;一键生成各种文案&#xff0c;解决文案编写困难的问题 视频剪辑&#xff1a;一键剪辑多个视频

vue3引入全局js

main.js中引入js&#xff0c;设置全局属性 m a p : a p p . c o n f i g . g l o b a l P r o p e r t i e s . map:app.config.globalProperties. map:app.config.globalProperties.map引入js对象 vue页面中使用。引入vue实例&#xff1a; import {getCurrentInstance} from “…

VS2022更换背景壁纸逐步图示教程

&#x1f984;个人主页:修修修也 ⚙️操作环境:Visual Studio 2022 目录 一.下载壁纸插件 二.更改自定义壁纸 三.调整壁纸布局 一.下载壁纸插件 因为更改自定义壁纸需要一个插件的辅助,所以我们要先下载一个小插件 首先,打开VS2022,点击"扩展"->"管理扩…

无人机电力巡检:国网安徽实际案例解析

在科技快速发展的今天&#xff0c;传统行业正在经历前所未有的转型。电力巡检&#xff0c;这一看似传统且乏味的任务&#xff0c;却因为无人机技术的介入而焕发新生。今天&#xff0c;让我们深入了解一个具体的案例&#xff0c;探索无人机如何革新电力巡检。 案例背景&#xff…

Postman —— postman的介绍和安装

Postman的介绍 Postman 是一款谷歌开发的接口测试工具,使API的调试与测试更加便捷。 它提供功能强大的 Web API & HTTP 请求调试。它能够发送任何类型的HTTP 请求 (GET, HEAD, POST, PUT..)&#xff0c;附带任何数量的参数 headers postman是一款支持http协议的接口调试与…

【试题020】C语言自减运算符例题

1.题目&#xff1a;设int a1&#xff0c;b6;&#xff0c;执行表达式--all(b8)后&#xff0c;a和b的值分别是 &#xff1f; 2.代码分析&#xff1a; #include <stdio.h> int main() {//设int a1&#xff0c;b6;执行表达式--all(b8)后&#xff0c;a和b的值分别是?int a …

【手写数字识别】CNN卷积神经网络入门案例

安装Anaconda 下载地址&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 安装完成后&#xff0c;在CMD窗口 输入conda --help 查看是否安装成功 使用conda创建环境 conda create --name tf python3.7conda activate tf在 tf 环境中安装TensorFlow pip in…

基于SpringCloud实现房产销售平台的设计与实现项目【项目源码+论文说明】

摘要 信息技术的发展推动了管理系统的进步&#xff0c;目前各种行业都积极参与管理系统的建设工作。特别是疫情带来的影响&#xff0c;让传统行业逐渐认识到只有通过在线管理才能继续的发展。房产销售平台是为求租者提供房源必备的平台&#xff0c;如何找到一个好的房源是生活…

PostgreSQL数据库结合内网穿透实现公网远程连接本地

文章目录 前言1. 安装postgreSQL2. 本地连接postgreSQL3. Windows 安装 cpolar4. 配置postgreSQL公网地址5. 公网postgreSQL访问6. 固定连接公网地址7. postgreSQL固定地址连接测试 前言 PostgreSQL是一个功能非常强大的关系型数据库管理系统&#xff08;RDBMS&#xff09;,下…

某马机房预约系统 C++项目(一)

机房预约系统 1、项目介绍 本项目来源于哔哩哔哩 c机房预约系统&#xff0c;本系统采用文件存储。 2、项目流程图 3、创建新项目 首先&#xff0c;我们来新建一个新项目&#xff0c;创建一个.cpp文件 4、创建主菜单 功能描述&#xff1a; 提供设计主菜单&#xff0c;与用…