Android全新UI框架之常用ComposeUI组件

在Compose中,每个组件都是一个带有@Composable注解的函数,被称为Composable。Compose已经预置了很多基于MD设计规范的Composable组件。
在布局方面,Compose提供了Column、Row、Box三种布局组件(感觉跟flutter差不多),类似于传统视图开发中的LinearLayout(Vertical)、LinearLayout(Horizontal)、RelateiveLayout,可以满足各类产品的常见布局需求。

Modifier修饰符

在传统开发中,使用xml文件来描述组件的样式,而compose则是使用Modifier修饰符。Modifier允许我们通过链式调用的方式为组件应用一系列的样式设置,如边距、字体、位移等。在Compose中,每个基础的Composable组件都有一个modifier参数,通过传入自定义的Modifier来修改组件的样式。

  • 常见修饰符

    Modifier.size设置被修饰组件的大小 Image( painter = painterResource(id = R.drawable.ic_launcher),contentDescription = null, modifier = Modifier.size(width = 10.dp, height = 10.dp) )
    Modifier.background设置被修饰组件的背景颜色。背景色支持纯色背景,也可以使用brush设置渐变背景Image(painter = painterResource(id = R.drawable.ic_launcher),contentDescription = null,modifier = Modifier.size(width = 100.dp, height = 100.dp).background(brush = Brush.verticalGradient(colors = listOf(Color.Blue,Color.Red)))))
    Modifier.fillMaxXXX()让组件在高度或者宽度上填满父空间fillMaxSize():填满整个父空间, fillMaxHeight():高度填满父空间,fillMaxWidth():宽度填满父空间
    Modifier.border&Modifier.paddingborder用来为被修饰组件添加边框。边框可以指定颜色、粗细、以及通过shape指定形状。padding用来为被修饰组件增加间隙。可以在border前后各插入一个padding,区分对外和对内的间距 Box(modifier = Modifier.padding(5.dp).border(2.dp, Color.Green, shape = RoundedCornerShape(2.dp)).padding(5.dp)) { Spacer(modifier = Modifier.size(width = 100.dp, height = 10.dp).background(Color.Blue)) }
    Modifier.offset用来移动被修饰组件的位置,分别传入水平方向和垂直方向的偏移量即可 Box(modifier = Modifier.size(100.dp).background(Color.Blue).offset(x = 10.dp, y = 10.dp).background(Color.Cyan)) {}
  • 作用域限定Modifier修饰符
    Compose充分发挥kotlin的语法特性,让某些Modifier修饰符只能在特定作用域中使用,有利于类型安全地调用它们。所谓“作用域”,在kotlin中就是一个带有Receiver的代码块。注意Receiver代码块默认可以跨层级访问。在compose的DSL中,一般只需要调用当前作用域的方法,为此可以通过@LayoutScopeMarker注解来规避该问题。常见组件的Receiver作用域类型均已使用@LayoutScopeMarker注解进行了声明,使用了该注解之后,像跨级调用外层作用域的方法必须通过显式指明Receiver具体类型。

    @LayoutScopeMarker
    @Immutable
    interface ColumnScope
    

    常见的作用域限定Modifier修饰符:

    1. matchParentSize
      matchParentSize是只能在BoxScope中使用的作用域限定修饰符。当使用matchParentSize设置尺寸时,可以保证当前组件的尺寸与父组件相同。而父组件默认的是wrapContent。如果使用fillMaxSize取代matchParentSize,那么该组件的尺寸会被设置为父组件所允许的最大尺寸,这样会导致背景铺满整个屏幕,二者区别如下图所示。

          Column(modifier = Modifier.background(Color.DarkGray)) {
              Box() {
                  Box(modifier = Modifier
      //                .fillMaxSize()
                      .matchParentSize()
                      .background(Color.Cyan))
                  Spacer(modifier = Modifier.size(50.dp).padding(10.dp).background(Color.Red))
              }
          }
      

      matchParentSize效果如下所示:
      在这里插入图片描述
      fillMaxSize效果如下所示:在这里插入图片描述

    2. weight
      在RowScope和ColumnScope中,可以使用专属的weight修饰符来设置尺寸。与size不同的是weight允许组件通过百分比设置尺寸,也就是允许组件可以自适应适配各种屏幕尺寸的移动端设备。

          Column(modifier = Modifier
              .background(Color.DarkGray)
              .width(300.dp)
              .height(200.dp)) {
            Spacer(modifier = Modifier
                .fillMaxWidth()
                .weight(1f)
                .background(Color.White))
              Spacer(modifier = Modifier
                  .fillMaxWidth()
                  .weight(1f)
                  .background(Color.Red))
              Spacer(modifier = Modifier.fillMaxWidth().weight(1f).background(Color.Blue))
          }
      
  • Modifier实现原理
    各位读者可以参考下面这篇博客:
    图解Compose Modifier实现原理 ,竟然如此简单!

常用的基础组件

文字组件
  1. Text文本
    在Compose中,Text是遵循MD设计规范的上层文本组件,如果想脱离MD,也可以直接使用更底层的文本组件BasicText。
    @Composable
    fun Text(
        text: String,
        modifier: Modifier = Modifier,
        color: Color = Color.Unspecified,
        fontSize: TextUnit = TextUnit.Unspecified,
        fontStyle: FontStyle? = null,
        fontWeight: FontWeight? = null,
        fontFamily: FontFamily? = null,
        letterSpacing: TextUnit = TextUnit.Unspecified,
        textDecoration: TextDecoration? = null,
        textAlign: TextAlign? = null,
        lineHeight: TextUnit = TextUnit.Unspecified,
        overflow: TextOverflow = TextOverflow.Clip,
        softWrap: Boolean = true,
        maxLines: Int = Int.MAX_VALUE,
        onTextLayout: (TextLayoutResult) -> Unit = {},
        style: TextStyle = LocalTextStyle.current
    )
    
    在很多应用场景中,我们需要在一段文字中对局部内容应用特别格式以示突出,比如一个超链接,此时需要用到AnnotatedString。AnnotatedString是一个数据类,除了文本值,还包含一个SpanStyle和ParagraphStyle的Range列表。SpanStyle用于描述在文本中子串的文字样式,ParagraphStyle则用于描述文本中子串的段落样式,Range确定子串的范围。
    用法如下所示:
    //append用来添加子串的文本
    //withStyle为append的子串指定文字或段落样式
    Text(text = buildAnnotatedString {
        withStyle(style = SpanStyle(fontSize = 24.sp)){
             append("你现在学习的章节是")
         }
         withStyle(style = SpanStyle(fontSize = 24.sp, fontWeight = FontWeight.W900)){
             append("Text")
         }
         append("\n")
         withStyle(style = ParagraphStyle(lineHeight = 25.sp)){
             append("在刚刚讲过的内容中,我们学会了如何应用文字样式,以及如何限制文本的行数和处理溢出的视觉效果。")
             append("\n")
             append("现在,我们正在学习")
             withStyle(style = SpanStyle(fontWeight = FontWeight.W900, textDecoration = TextDecoration.Underline, color = Color(0xff59a869))){
                 append("AnnotatedString")
             }
         }
     })
    
    SpanStyle继承了TextStyle中关于文字样式相关的字段,而ParagraphStyle继承了TextStyle中控制段落的样式,例如textAlign、lineHeight等。SpanStyle和ParagraphStyle中的设置优先于TextStyle中同名属性设置。
  • SelectionContainer选中文字
    Text自身默认是不能被长按选择的,Compose提供了专门的SelectionContainer组件,对包裹的Text进行选中。

    SelectionContainer() {
        Text(text = "我是可以被复制的文字")
    }
    
  • ClickableText
    Compose提供了一种可点击文本组件,可以响应对文字的点击,并返回点击位置。可以让AnnotatedString子串在相应的ClickedText中点击后,做出不同的动作。在AnnotatedString中可以为子串添加一个tag标签,在处理onClick事件时,根据tag实现不同的逻辑。

     ClickableText(text = annotated, onClick ={
                        annotated.getStringAnnotations(
                            tag = "URL",
                            start = it,
                            end = it
                        ).firstOrNull()?.let {
                            Log.e("MainActivity",it.toString())
                        }
                    } )
     
     val annotated = buildAnnotatedString {
            withStyle(style = ParagraphStyle(lineHeight = 25.sp)){
                // 开始一个注解区域
                pushStringAnnotation(tag = "URL", annotation = "https://www.baidu.com")
                // 追加带有注解的文本
                withStyle(
                    style = SpanStyle(
                        fontWeight = FontWeight.W900,
                        textDecoration = TextDecoration.Underline,
                        color = Color(0xff59a869)
                    )
                ){
                    append("AnnotatedString")
                }
                // 结束注解区域
                pop()
                //下面这段文本不会有注解
                withStyle(
                    style = SpanStyle(
                        fontWeight = FontWeight.W900,
                        textDecoration = TextDecoration.Underline,
                        color = Color(0xff59a869)
                    )
                ){
                    append("NotAnnotatedString")
                }
            }
        }
    
  • TextField输入框
    TextField组件是我们最常用的文本输入框,它也遵循MD设计准则。它也有一个低级别的底层组件,BasicTextField,与TextField和OutlinedTextField不同的是,BasicTextField拥有更多的自定义效果。由于TextField和OutlinedTextField是根据MD准则设计的,无法直接修改输入框的高度,如果尝试修改高度,会看到输入区域被截断,影响正常输入。

    fun TextField(
        value: TextFieldValue,
        onValueChange: (TextFieldValue) -> 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,
        supportingText: @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 = TextFieldDefaults.filledShape,
        colors: TextFieldColors = TextFieldDefaults.textFieldColors()
    )
    fun BasicTextField(
        value: String,
        onValueChange: (String) -> Unit,
        modifier: Modifier = Modifier,
        enabled: Boolean = true,
        readOnly: Boolean = false,
        textStyle: TextStyle = TextStyle.Default,
        keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
        keyboardActions: KeyboardActions = KeyboardActions.Default,
        singleLine: Boolean = false,
        maxLines: Int = Int.MAX_VALUE,
        visualTransformation: VisualTransformation = VisualTransformation.None,
        onTextLayout: (TextLayoutResult) -> Unit = {},
        interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
        cursorBrush: Brush = SolidColor(Color.Black),
        decorationBox: @Composable (innerTextField: @Composable () -> Unit) -> Unit =
            @Composable { innerTextField -> innerTextField() }
    ) 
    

    TextField输入框案例如下:

    @Composable
        fun TextFieldSample(){
            var text by remember {
                mutableStateOf("")
            }
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .background(Color(0xfd3d3d3)),
                contentAlignment = Alignment.Center
            ) {
                BasicTextField(
                    modifier = Modifier
                        .padding(10.dp)
                        .background(Color.White, CircleShape)
                        .height(30.dp)
                        .fillMaxSize(),
                    value = text,
                    onValueChange = {text = it},
                    decorationBox = {
                        Row(
                            verticalAlignment = Alignment.CenterVertically,
                            modifier = Modifier.padding(vertical = 2.dp, horizontal = 8.dp)
                        ) {
                            Icon(imageVector = Icons.Filled.Search, contentDescription = null)
                            Box(modifier = Modifier
                                .padding(horizontal = 10.dp)
                                .width(100.dp), contentAlignment = Alignment.CenterStart) {
                                if(text.isEmpty()){
                                    Text(
                                        text = "输入点东西看看吧~",
                                        style = TextStyle(
                                            color = Color(0,0,0,128)
                                        )
                                    )
                                }
                                it()
                            }
                           Box(contentAlignment = Alignment.CenterEnd){
                               if(text.isNotEmpty()){
                                   IconButton(
                                       onClick = { text="" },
                                       modifier = Modifier.size(16.dp)) {
                                       Icon(imageVector = Icons.Filled.Close, contentDescription = null, tint = Color.Red)
                                   }
                               }
                           }
                        }
                    })
            }
    
        }
    
  • 图片组件

    1. Icon图标
      Icon组件用于显示一系列小图标。Icon组件支持三种不同类型的图片设置:
    @Composable
    fun Icon(
        imageVector: ImageVector,//矢量图对象,可以显示SVG格式的图标
        contentDescription: String?,
        modifier: Modifier = Modifier,
        tint: Color = LocalContentColor.current
    )
    @Composable
    fun Icon(
        bitmap: ImageBitmap,//位图对象,可以显示JPG、PNG等格式的图标
        contentDescription: String?,
        modifier: Modifier = Modifier,
        tint: Color = LocalContentColor.current
    )
    @Composable
    fun Icon(
        painter: Painter,//代表一个自定义画笔,可以使用画笔在Canvas上直接绘制图标
        contentDescription: String?,
        modifier: Modifier = Modifier,
        tint: Color = LocalContentColor.current
    )
    
    1. Image图片
      Image组件用来显示一张图片。它和Icon一样也支持三种类型的图片设置。
  • 按钮组件

    1. Button按钮
      Button也是最常用的组件之一,它也是按照MD风格来实现的。Button并非唯一可点击组件,理论上任何Composable组件都可以通过Modifier.clickable修饰符化身为可点击组件。
      案例如下:
        @Composable
        fun ButtonSample(){
            val interactionSource = remember {
                MutableInteractionSource()
            }
            val pressState = interactionSource.collectIsPressedAsState()
            val borderColor = if (pressState.value) Color.Green else Color.White
            Button(
             modifier = Modifier.clickable {
             //该方法在button组件会失效
                Log.e("MainActivity","点击Butttonclickable")
            },
                interactionSource = interactionSource,
                border = BorderStroke(2.dp, color = borderColor),
                onClick = {
                    Log.e("MainActivity","点击Buttton")
                }) {
                Icon(imageVector = Icons.Filled.Done, contentDescription = null, modifier = Modifier.size(ButtonDefaults.IconSize))
                Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing))
                Text(text = "确认")
            }
        }
    
    1. IconButton图标按钮
      IconButton组件实际上只是Button组件的简单封装(一个可点击的图标),它一般用于应用栏中的导航或者其他行为。一般来说,需要在IconButton组件里提供一个图标组件,这个图标的默认尺寸一般为24*24dp。
     IconButton(
        onClick = { text="" },
        modifier = Modifier.size(16.dp)) {
        Icon(imageVector = Icons.Filled.Close, contentDescription = null, tint = Color.Red)
    
    1. FloatingActionButton悬浮按钮
        @Composable
        fun FloatButton(){
            FloatingActionButton(
                onClick = {}) {
                Row() {
                    Text(text = "添加到我的喜欢")
                    Icon(imageVector = Icons.Filled.Done, contentDescription = null, modifier = Modifier.size(ButtonDefaults.IconSize))
                }
            }
            ExtendedFloatingActionButton(
                onClick = { /*TODO*/ }) {
                Row() {
                    Text(text = "添加到我的喜欢")
                    Icon(imageVector = Icons.Filled.Done, contentDescription = null, modifier = Modifier.size(ButtonDefaults.IconSize))
                }
            }
        }
    
  • 选择器

    1. CheckBox复选框
        @Composable
        fun ChecBoxDemo(){
            val checkedState = remember {
                mutableStateOf(true)
            }
            Checkbox(
                checked = checkedState.value,
                onCheckedChange ={checkedState.value = it},
            colors = CheckboxDefaults.colors(checkedColor =  Color(0xff0079d3)))
        }
    
    1. TriStateCheckBox三态选择框
      很多时候,我们的复选框会有很多个,并且希望能够统一选择或者取消,这个时候就可以使用三态选择框
     @Composable
        fun ChecBoxDemo(){
            val (state,onStateChange) = remember { mutableStateOf(true) }
            val (state2,onStateChange2) = remember { mutableStateOf(true) }
    
            val parentState = remember(state,state2) {
                if (state&&state2) ToggleableState.On
                else if (!state&&!state2) ToggleableState.Off
                else ToggleableState.Indeterminate
            }
    
            val onParentClick = {
                val s = parentState != ToggleableState.On
                onStateChange(s)
                onStateChange2(s)
            }
    
            TriStateCheckbox(
                colors = CheckboxDefaults.colors(checkedColor = Color.Red),
                state = parentState,
                onClick = onParentClick,
            )
    
            Column(Modifier.padding(10.dp,0.dp,0.dp,0.dp)) {
                Checkbox(checked = state, onCheckedChange = onStateChange )
                Checkbox(checked = state2, onCheckedChange = onStateChange2 )
    
            }
        }
    
    1. Switch单选开关——控制单个项目的开启或关闭状态
      @Composable
        fun ChecBoxDemo(){
            val checkedState = remember {
                mutableStateOf(true)
            }
            Switch(checked = checkedState.value, onCheckedChange = {checkedState.value = it})
        }
    
    1. Slider滑竿组件——可用来做音量、亮度之类的数值调整或进度条
     var sliderPosition by remember {
                mutableStateOf(0f)
            }
            Slider(value = sliderPosition, onValueChange = {sliderPosition = it})
    
    1. 进度条
      var progress by remember {
                        mutableStateOf(0.1f)
                    }
    
                    val animatedProgress by animateFloatAsState(targetValue = progress, animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec)
    
                    Column {
                        CircularProgressIndicator(progress = animatedProgress)
                        Spacer(modifier = Modifier.requiredHeight(30.dp))
                        OutlinedButton(onClick = {
                            if(progress<1f)progress +=.1f
                        }) {
                            Text(text = "增加进度")
                        }
    
                    }
    
    1. 对话框
        @Composable
        fun DialogDemo(){
            val openDialog = remember {
                mutableStateOf(true)
            }
            val dialogWidth = 200.dp
            val dialogHeight = 50.dp
            if(openDialog.value){
                Dialog(
                    onDismissRequest = { openDialog.value = false },
                properties = DialogProperties(
                    dismissOnBackPress = true,//允许通过点击物理返回键取消对话框
                    dismissOnClickOutside = true//允许点击对话框外部取消对话框
                )
                ) {
                    Box(modifier = Modifier
                        .size(dialogWidth, dialogHeight)
                        .background(Color.Blue))
                }
            }
        }
    

常用的布局组件

  • 线性布局
    线性布局对应于传统视图中的linearLayout,Compose根据orientation的不同又分为Column和Row。

    1. Column
      Column是一个垂直线性布局组件,它能够将子项按照从上到下的顺序垂直排列。verticalArrangement和horizontalAlignment参数分别可以帮助我们安排子项的垂直/水平位置,在默认的情况下,子项会以垂直方向上靠上,水平方向上靠左来布置。
    2. Row
      Row组件能够将内部子项按照从左到右的方向水平排列。用法Column类似。
  • 帧布局

    1. Box
      Box组件是一个能够将里面的子项依次按照顺序堆叠的布局组件,在使用上类似于传统视图中的Framelayout。
    2. Surface
      Surface是一个平面,在MD设计准则中也同样如此,我们可以将很多的组件摆放在这个平面之上,可以设置这个平面的边框、圆角、颜色等。
  • Spacer留白
    在很多时候,需要让两个组件之间留有空白的间隔,这个时候就可以使用该组件。其实当Box组件没有content时,完全可以用Spacer替换。可以给Spacer做如下封装,可以更方便地用在水平或垂直布局中。

        @Composable
        fun WidthSpacer(value:Dp){
            Spacer(modifier = Modifier.width(value))
        }
    
        @Composable
        fun HeightSpacer(value:Dp){
            Spacer(modifier = Modifier.height(value))
        }
    
  • ConstraintLayout约束布局
    各位读者可以参考下面这篇博客:
    Compose ConstraintLayout 详讲

  • Scaffold脚手架
    Scaffold组件实现了MD的布局结构,通过配合其他MD组件可以轻松构建MD风格的页面。

        @SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
        @OptIn(ExperimentalMaterial3Api::class)
        @Composable
        fun Sample(){
            var selectedItem by remember {
                mutableStateOf(0)
            }
            val items = listOf(
                Item("主页",R.drawable.ic_launcher),
                Item("列表",R.drawable.ic_launcher),
                Item("设置",R.drawable.ic_launcher),
            )
    
            Scaffold(
    
                topBar ={
                   TopAppBar(
                       title = { Text(text = "主页")},
                       navigationIcon = {
                           IconButton(onClick = { /*TODO*/ }) {
                               Icon(imageVector = Icons.Filled.Menu, contentDescription = null)
                           }
                   })
                }){
                Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center){
                    Text(text = "主页面")
                }
            }
        }
    

列表

很多产品中都有展示一组数据的需求场景,如果数据数量是可以枚举的,则仅需通过Column组件来枚举列出。然而很多时候,列表中的项目会非常多,我们需要滑动列表来查看所有内容,可以通过给Column的modifier添加verticalScroll方法来让列表实现滑动。

    @Composable
    fun ListDemo(){
        val initialCapacity = 1000 // 设置你想要的初始容量
        val items = ArrayList<String>(initialCapacity)
        for (i in 1..initialCapacity) {
            items.add("我是text$i")
        }
        Column(
            modifier = Modifier
                .verticalScroll(state = ScrollState(5), enabled = true)
        ) {
            items.forEach{
                Text(text = "$it")
            }

        }
    }

给Column的Modifier添加verticalScroll方法可以让列表实现滑动。但是如果列表过长,众多的内容会占用大量的内存。然而更多的内容对于用户其实都是不可见的,没有必要加载到内存。所以compose提供了专门用于处理长列表的组件,LazyColumn和LazyRow,其作用类似于传统视图中的Listview和RecyclerView。

  LazyColumn(
    modifier = Modifier
            .fillMaxSize()
            .background(Color.Cyan),
        contentPadding = PaddingValues(30.dp),//为内容设置外边距
    verticalArrangement = Arrangement.spacedBy(10.dp)//为每个item设置间隔
    ) {
        items(1000){
            Text(text = "$it")
        }

    }

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《Python 语音转换简易速速上手小册》第5章 音频数据处理(2024 最新版)

文章目录 5.1 音频数据的基本处理5.1.1 基础知识5.1.2 主要案例&#xff1a;音频剪辑工具案例介绍案例 Demo案例分析 5.1.3 扩展案例 1&#xff1a;自动音量调节器案例介绍案例 Demo案例分析 5.1.4 扩展案例 2&#xff1a;语音识别预处理案例介绍案例 Demo案例分析 5.2 使用 Py…

LLM 模型融合实践指南:低成本构建高性能语言模型

编者按&#xff1a;随着大语言模型技术的快速发展&#xff0c;模型融合成为一种低成本但高性能的模型构建新途径。本文作者 Maxime Labonne 利用 mergekit 库探索了四种模型融合方法&#xff1a;SLERP、TIES、DARE和passthrough。通过配置示例和案例分析&#xff0c;作者详细阐…

开启智能互动新纪元——ChatGPT提示词工程的引领力

目录 提示词工程的引领力 高效利用ChatGPT提示词方法 提示词工程的引领力 近年来&#xff0c;随着人工智能技术的迅猛发展&#xff0c;ChatGPT提示词工程正逐渐崭露头角&#xff0c;为智能互动注入了新的活力。这一技术的引入&#xff0c;使得人机交流更加流畅、贴近用户需求&…

S-35390A计时芯片介绍及开发方案

计时芯片 S-35390A芯片是计时芯片&#xff0c;一般用来计算时间。低功耗&#xff0c;宽电压&#xff0c;受温度影响小&#xff0c;适用于很多电路。它有一个问题&#xff0c;不阻止用户设置不存在的时间&#xff0c;设置进去之后计时或者闹钟定时会出错。 规格书阅读 首先我…

推荐几款项目经理常用的项目管理软件

随着科技的发展和项目需求&#xff0c;项目管理工具成为了确保工作顺利进行的关键。市场上有许多优秀的免费项目管理工具&#xff0c;它们功能强大、易于使用&#xff0c;并可以帮助团队更有效地规划、组织、执行和监控项目。以下是几款深受项目经理欢迎&#xff0c;好用且免费…

【转载】企业资产收集与脆弱性检查工具

简介 云图极速版是针对拥有攻击面管理需求的用户打造的 SaaS 应用&#xff0c;致力于协助用户管理互联网资产攻击面的 SaaS 化订阅服务产品。可实现对备案域名、子域名、IP、端口、服务、网站、漏洞、安全风险等场景进行周期性监控&#xff0c;支持多维度分析攻击面。利用可视化…

uni-app 开发调试自动打开手机屏幕大小界面(Aidex移动端开发项目)

上效果&#xff1a; 下载Aidex的移动端项目并打开&#xff1a; 若依-ruoyi-AiDex-Uniapp: 若依-Ruoyi APP 移动解决方案&#xff0c;基于uniappuView封装的一套基础模版&#xff0c;开箱即用&#xff0c;免费开源&#xff0c;一份代码多终端适配&#xff0c;支持H5、支付宝小程…

基于机器学习的青藏高原高寒沼泽湿地蒸散发插补研究_王秀英_2022

基于机器学习的青藏高原高寒沼泽湿地蒸散发插补研究_王秀英_2022 摘要关键词 1 材料和方法1.1 研究区概况与数据来源1.2 研究方法 2 结果和分析2.1 蒸散发通量观测数据缺省状况2.2 蒸散发与气象因子的相关性分析2.3 不同气象因子输入组合下各模型算法精度对比2.4 随机森林回归模…

【统计分析数学模型】聚类分析

【统计分析数学模型】聚类分析 一、聚类分析1. 基本原理2. 距离的度量&#xff08;1&#xff09;变量的测量尺度&#xff08;2&#xff09;距离&#xff08;3&#xff09;R语言计算距离 三、聚类方法1. 系统聚类法2. K均值法 三、示例1. Q型聚类&#xff08;1&#xff09;问题描…

springboot集成JWT实现token权限认证

vuespringboot登录与注册功能的实现 注&#xff1a;对于JWT的学习&#xff0c;首先要完成注册和登录的功能&#xff0c;本篇博客是基于上述博客的进阶学习&#xff0c;代码页也是在原有的基础上进行扩展 ①在pom.xml添加依赖 <!-- JWT --> <dependency><grou…

QPaint绘制自定义仪表盘组件01

网上抄别人的&#xff0c;只是放这里自己看一下&#xff0c;看完就删掉 ui Dashboard.pro QT core guigreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11# You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomm…

5 原型模式 Prototype

1.模式定义: 指原型实例指定创建对象的种类&#xff0c;并且通过拷贝这些原型创建新的对象 2.应用场景&#xff1a; 当代码不应该依赖于需要复制的对象的具体类时&#xff0c;请使用Prototype模式。 Spring源码中的应用 org.springframework.beans.factory.support.AbstractB…

基于java springboot+mybatis OA办公自动化系统设计和实现

基于java springbootmybatis OA办公自动化系统设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末…

盘点那些世界名校计算机专业采用的教材

清华、北大、MIT、CMU、斯坦福的学霸们在新学期里要学什么&#xff1f;今天我们来盘点一下那些世界名校计算机专业采用的教材。 书单目录 1.《深入理解计算机系统》&#xff08;原书第3版&#xff09;2. 《算法导论》&#xff08;原书第3版&#xff09;3. 《计算机程序的构造和…

打架监测识别摄像机

打架监测识别摄像机是一种用于监控和识别打架行为的智能监控设备。这种摄像机利用先进的人工智能和计算机视觉技术&#xff0c;能够准确识别出监控画面中发生的打架事件&#xff0c;从而及时采取必要的应对措施。 打架监测识别摄像机的工作原理是通过对监控画面的实时分析和识别…

C语言每日一题(60)对链表进行插入排序

题目链接 力扣网 147 对链表进行插入排序 题目描述 给定单个链表的头 head &#xff0c;使用 插入排序 对链表进行排序&#xff0c;并返回 排序后链表的头 。 插入排序 算法的步骤: 插入排序是迭代的&#xff0c;每次只移动一个元素&#xff0c;直到所有元素可以形成一个有…

Jlink+OpenOCD+STM32 Vscode 下载和调试环境搭建

对于 Mingw 的安装比较困难&#xff0c;国内的网无法正常在线下载组件&#xff0c; 需要手动下载 x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z 版本的软件包&#xff0c;添加环境变量&#xff0c;并将 mingw32-make.exe 名字改成 make.exe。 对于 OpenOCD&#xff0c;需要…

【Vue渗透】Vue站点渗透思路

原文地址 极核GetShell 前言 本文经验适用于前端用Webpack打包的Vue站点&#xff0c;阅读完本文&#xff0c;可以识别出Webpack打包的Vue站点&#xff0c;同时可以发现该Vue站点的路由。 成果而言&#xff1a;可能可以发现未授权访问。 识别Vue 识别出Webpack打包的Vue站…

【JAVA】《接口,抽象方法,抽象类 》之二 、抽象方法详解

抽象方法 详解 一、接口二、抽象方法2.1、抽象方法概念2.2、抽象方法的特点&#xff1a;2.3、抽象方法的作用&#xff1a;2.4、抽象方法的应用&#xff1a;2.5、抽象方法的实践&#xff1a;2.6、使用抽象方法的注意事项 三、抽象类四、开发实践 一、接口 1.1、接口的概念 1.2、…

Windows上基于名称快速定位文件和文件夹的免费工具Everything

在Windows上搜索文件时&#xff0c;使用windows上内置搜索会很慢&#xff0c;这里推荐使用Everything工具进行搜索。 "Everything"是Windows上一款搜索引擎&#xff0c;它能够基于文件名快速定位文件和文件夹位置。不像Windows内置搜索&#xff0c;"Everything&…