范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

ComposeDesktop初体验之绘制

  从 0 到 1 搞一个 Compose Desktop 版本的玩天气之绘制
  上一篇文章 "从 0 到 1 搞一个 Compose Desktop 版本的玩天气之踩坑" 中大概说了下刚开始使用  Compose Desktop   会遇到的一些问题,帮大家踩了踩坑,那么这一篇则会带大家一起来看下项目中绘制的一些东西,再来看下项目的最终实现效果吧!
  视频 动画的使用
  通过上面的 GIF 图可以看到项目中使用到了一些动画,效果还是非常不错的,其实实现起来非常简单! 可见性动画
  首先来看下可见性动画的使用,之前我写过一个专栏,里面专门说了下  Compose   中的动画的使用及原理,有兴趣的大家可以去看下:Compose 动画开发艺术探索 。
  可见性动画在页面左边用到了,点击添加按钮出现搜索页面的时候就使用的是可见性动画,简单看下代码: @Composable fun LeftInformation() {     var showSearch by rememberSaveable { mutableStateOf(false) }     Box(         Modifier.fillMaxHeight().width(300.dp).padding(end = 10.dp)     ) {         WeatherDetails(onAddClick = {             showSearch = true         })          AnimatedVisibility(             visible = showSearch,             enter = slideInHorizontally(),             exit = slideOutHorizontally()         ) {             SearchCity()         }     } }
  可以看到这块在进入的时候使用了  slideInHorizontally   动画,顾名思义,就是水平滑动展开,退出的时候使用了 slideOutHorizontally   ,就是水平滑动退出。
  实现效果这里就不展示了,就是文章左边的动画效果。 无限重复动画
  无限重复动画在左边展示天气信息的天气图标上用到了,这块的重复动画使用了两种,如果是晴天的话就修改  Modifier.rotate   ,因为晴天是太阳,旋转的话好看一些,如果不是晴天的话旋转不好看,所以改为 Modifier.offset   ,这样平移的话好看一些。来看下实现代码吧:@Composable private fun RotateWeatherIcon(icon: String) {     val infiniteTransition = rememberInfiniteTransition()     val modifier = if (icon == "100") {         val rotate by infiniteTransition.animateFloat(             initialValue = 0f,             targetValue = 360f,             animationSpec = infiniteRepeatable(                 animation = tween(3500, easing = LinearOutSlowInEasing),                 repeatMode = RepeatMode.Reverse             )         )         Modifier.rotate(rotate)     } else {         val offsetX by infiniteTransition.animateValue(             initialValue = (-30).dp, // 初始值             targetValue = 30.dp, // 目标值             typeConverter = TwoWayConverter(                 { AnimationVector1D(it.value) },                 { it.value.dp }), // 类型转换             animationSpec = infiniteRepeatable(  // 动画规格!!!                 animation = tween(3500, easing = LinearOutSlowInEasing),                 repeatMode = RepeatMode.Reverse             )         )         Modifier.offset(x = offsetX)     }     Image(         painter = painterResource(getWeatherIcon(icon)),         "",         modifier = modifier.size(170.dp).padding(10.dp)     ) }
  无限重复动画的使用方式也不难,在之前的章节中说过,感兴趣的可以去上面所说的专栏中查看,大家放心, Jetpack Compose   中动画的使用方式和 Compose Desktop   一致。空气质量
  空气质量就是右边天气详情中的第一个模块,样子如下图所示:
  这块是一个 "自定义 View",为什么要加引号呢?因为这是  Compose   啊,不是安卓的 View   系统。
  下面来看下这个 "自定义 View" 如何实现的吧! @Composable private fun AirQualityProgress(aqiValue: Int) {     Canvas {         drawLine(             brush = Brush.linearGradient(                 0.0f to Color(red = 139, green = 195, blue = 74),                 0.1f to Color(red = 255, green = 239, blue = 59),                 0.2f to Color(red = 255, green = 152, blue = 0),                 0.3f to Color(red = 244, green = 67, blue = 54),                 0.4f to Color(red = 156, green = 39, blue = 176),                 1.0f to Color(red = 143, green = 0, blue = 0),             ),             start = Offset.Zero,             end = Offset(size.width, 0f),             strokeWidth = 20f,             cap = StrokeCap.Round,         )         drawPoints(             points = arrayListOf(                 Offset(size.width / 500 * aqiValue, 0f)             ),             pointMode = PointMode.Points,             color = Color.White,             strokeWidth = 20f,             cap = StrokeCap.Round,         )     } }
  因为我没有开发过桌面的应用,所以不太清楚在桌面程序中实现这样的一个控件需要写多少代码,我只开发过安卓,只能拿安卓原生  View   做对比,在安卓 View   中如果想实现这样的一个控件的话绝对不止这么一点代码…
  来简单解释下这个控件吧:在  Compose   中绘制需要使用可组合项 Canvas   ,然后来绘制下面的那条线,线上的颜色是渐变的,在 Compose   中只需要使用 Brush   就可以实现渐变,也可以控制在不同的进度显示不同颜色,空气质量一般分为六个等级:优、良、轻度污染、中度污染、重度污染和严重污染,所以上面对应有六种颜色。最后算出当前的 AQI 值应该绘制的地方进行绘制即可。7 日天气预报
  24 小时天气预报中没有什么需要说的,一个  LazyRow   就实现了,就直接跳过了。
  接下来来看下 7 日天气预报,这里其实大部分也不难,但注意看右边的温度条,这是模仿苹果天气中的温度条实现的,下面来看下苹果的样子吧:
  再来看下我模仿实现的效果:
  不能说一模一样,只能说大差不离。
  在模仿苹果这个小彩条的时候刚开始就犯了难,这是啥意思啊…这条里面都代表着什么啊,也看不太懂,后来网上找了半天才知道。 小彩条的长度代表温差,彩条越长温差越大。 根据最近 10 天的温度,分别设置最高值和最低值。例如上面的苹果截图,近十天的最高温度为4度,则这组彩条最右端代表 4 度。 近十天最低温为 -12 度,那么这组彩条最左端就代表 -12 度。左右两端的极值不是固定不变的。 小白点代表了此时的温度。
  搞明白这个小彩条的含义就好说了,来自定义下这个控件吧! @Composable private fun TemperatureChart(min: Int, max: Int, currentMin: Int,                               currentMax: Int, currentTemperature: Int = -100) {     val currentMinColor: Color = getTemperatureColor(currentMin)     val currentMaxColor: Color = getTemperatureColor(currentMax)     // 计算周温差     val num = max - min     Canvas {         // 绘制底条         drawLine(             color = Color.Gray,             start = Offset.Zero,             end = Offset(size.width, 0f),             strokeWidth = 10f,             cap = StrokeCap.Round,         )         // 绘制这一天的气温         drawLine(             brush = Brush.linearGradient(                 0.0f to currentMinColor,                 1.0f to currentMaxColor,             ),             start = Offset(size.width / num * (currentMin - min), 0f),             end = Offset(size.width / num * (currentMax - min), 0f),             strokeWidth = 10f,             cap = StrokeCap.Round,         )         // 如果是当天,则绘制当前温度小白点         if (currentTemperature > -100) {             drawPoints(                 points = arrayListOf(                     Offset(size.width / num * (currentTemperature - min), 0f)                 ),                 pointMode = PointMode.Points,                 color = Color.White,                 strokeWidth = 10f,                 cap = StrokeCap.Round,             )         }     } }
  首先看下这个可组合项接收的几个参数: min :未来几天最低温度 max :未来几天最高温度 currentMin :当前绘制天的最低温度 currentMax :当前绘制天的最高温度 currentTemperature :当前天的当前温度
  再简单说下函数内容,先计算下这几天的温差,然后绘制温度底条,再然后绘制温度条,这个温度条是渐变的,需要根据不同温度换不同颜色,最后判断是不是当天,如果是当天的就绘制当前温度的小白点。
  上面调用一个函数  getTemperatureColor   ,这是为了计算不同温度的颜色的方法,来看下这个方法吧:/**  * 获取不同气温的颜色值,需要动态判断  */ private fun getTemperatureColor(temperature: Int): Color {     return if (temperature < -20) {         Color(red = 26, green = 92, blue = 249)     } else if (temperature < 30) {         Color(red = 253, green = 138, blue = 11)     } else {         Color(red = 248, green = 60, blue = 30)     } }
  这块没有写全这些颜色,其实写了挺多,篇幅原因就不写了,大家能理解就好。 太阳月亮
  顾名思义,太阳月亮就是指的日出日落和月出月落,还是再来看下实现好的样式吧:
  根据日出日落和月出月落的时间来展示当前太阳和月亮的状态。由上面图大概可以看出,需要使用到贝塞尔曲线,由于只是一段曲线,所以使用二阶贝塞尔曲线就可以了。
  什么是贝塞尔曲线呢?来看下百度百科的描述吧:
  贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。
  下面来简单看下二阶贝塞尔曲线的简单动画吧:
  二阶贝塞尔曲线的公式如下:
  B  (  t  )=(1−  t  )2  P  0+2  t  (1−  t  )  P  1+  t  2  P  2,  t  ∈[0,1]
  下面来看下在  Compose   中如何绘制二阶贝塞尔曲线吧:Canvas {     val path = Path()     path.moveTo(0f, size.height)     // 二阶贝塞尔曲线     path.quadraticBezierTo(         size.width / 2, -size.height,         size.width, size.height     )      drawPath(         path = path, color = Color(red = 255, green = 193, blue = 7, alpha = 255),         style = Stroke(width = 3f)     ) }
  可以看到在  Compose   使用 Path   的 quadraticBezierTo   函数来绘制二阶贝塞尔曲线,这块需要解释下,二阶贝塞尔曲线一共需要三个点,但 quadraticBezierTo   函数中只接收了两个点,那剩下一个点呢?其实 Path   先 moveTo   到的点就是第一个点,quadraticBezierTo   函数接收的第一个点是控制点,第二个参数是终点。绘制完后贝塞尔曲线后还要绘制曲线两边的圆点:drawPoints(     points = arrayListOf(         Offset(0f, size.height),         Offset(size.width, size.height)     ),     pointMode = PointMode.Points,     color = Color(red = 255, green = 193, blue = 7, alpha = 255),     strokeWidth = 20f,     cap = StrokeCap.Round, )
  绘制完贝塞尔曲线和圆点之后就该绘制太阳和月亮图标了,这块需要使用贝塞尔曲线的公式来计算点的坐标了。绘制点之前需要计算当前时间占太阳或月亮在天上的百分比: fun getAccounted(rise: String, set: String, isSun: Boolean = true): Double {     val calendar = Calendar.getInstance()     val currentMills = calendar.timeInMillis     calendar.set(Calendar.HOUR_OF_DAY, getHour(rise))     calendar.set(Calendar.MINUTE, getMinute(rise))     val riseMills = calendar.timeInMillis     if (!isSun) {         calendar.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH) + 1)     }     calendar.set(Calendar.HOUR_OF_DAY, getHour(set))     calendar.set(Calendar.MINUTE, getMinute(set))     val setMills = calendar.timeInMillis     val result = (currentMills - riseMills) / (setMills - riseMills).toDouble()     return if (currentMills < riseMills) 0.0 else if (result > 1) 1.0 else result }
  这块的代码不多,使用  Calendar   来获取当前毫秒值存下来,然后设置日出日落的小时分钟并记录下来毫秒值,最后进行计算即可。
  现在百分比也有了,只剩下计算贝塞尔曲线上的坐标点了,先来看下计算坐标点的公式吧: P0(起始点) , P1(控制点), P2 (终点) P0(x1,y1),P2(x2,y2), P1(cx,cy) val x = Math.pow(1-t, 2) * x1 + 2 * t * (1-t) * cx + Math.pow(t, 2) * x2 val y = Math.pow(1-t, 2) * y1 + 2 * t * (1-t) * cy + Math.pow(t, 2) * y2
  公式是固定的,只需要往里套点即可: val x = (1.0 - sunResult).pow(2.0) * 0f + 2 * sunResult * (1 - sunResult) * (size.width / 2) + sunResult.pow(2.0) * size.width  val y = (1.0 - sunResult).pow(2.0) * size.height + 2 * sunResult * (1 - sunResult) * (-size.height) + sunResult.pow(2.0) * size.height
  计算出来贝塞尔曲线中的点后就该绘制月亮或太阳的图标了: drawImage(     image = sunImage,     topLeft = Offset(         x - sunImage.width / 2,         x - sunImage.height / 2     ) )
  这块的图片需要  ImageBitmap   格式,直接使用上一篇文章中的 useResource   即可生成。drawImage   中的 topLeft   参数表示左上角的坐标,默认的话时(0,0),但图片有宽高,所以需要减去宽高的一半,这样太阳和月亮的图标才能显示在正中间。跳转浏览器
  在安卓中咱们可以使用  WebView   来展示网页,但是在桌面版的应用中就没有了,需要使用系统自带的浏览器,那使用 Compose Desktop   应该如何打开系统自带的浏览器呢?可以使用 Desktop   中的 browse   方法,下面是我写的一个扩展函数:/**  * 通过字符串打开系统默认浏览器  */ fun String?.openBrowse() {     if (this?.startsWith("http") == false && !this.startsWith("https")) {         throw IllegalArgumentException("this illegal argument exception")     }     try {         val uri = URI.create(this ?: "https://www.baidu.com")         // 获取当前系统桌面         val dp = Desktop.getDesktop()         // 判断系统桌面是否支持要执行的功能         if (dp.isSupported(Desktop.Action.BROWSE)) {             // 获取系统默认浏览器打开链接             dp.browse(uri)         }     } catch (e: Exception) {         println(e.message)     } }
  首先判断当前字符串前缀是否为 "http" 和 "https",如果不是的话就证明这个字符串不是网络链接,就直接抛出异常,剩下代码中的注释写的已经比较全了,就不多说了。
  函数有了再来看下如何调用吧: Row {     Image(painter = painterResource("image/ic_launcher.svg"), "", modifier = Modifier.size(15.dp))      Spacer(modifier = Modifier.width(5.dp))      Text(text = "数据来自和风天气", fontSize = 12.sp, modifier = Modifier.clickable {         fxLink.openBrowse()     }) }
  很简单,直接调用即可。运行效果就不在这里进行展示了,大家可以下载代码运行看看。 对话框
  在安卓中对话框的使用场景实在是太多了,就不一一列举了,随便打开一个应用里面都有一堆对话框,那么在  Compose Desktop   中该如何弹出对话框呢?先来看下 Dialog   的函数定义吧:@Composable fun Dialog(     onCloseRequest: () -> Unit,     state: DialogState = rememberDialogState(),     visible: Boolean = true,     title: String = "Untitled",     icon: Painter? = null,     undecorated: Boolean = false,     transparent: Boolean = false,     resizable: Boolean = true,     enabled: Boolean = true,     focusable: Boolean = true,     onPreviewKeyEvent: ((KeyEvent) -> Boolean) = { false },     onKeyEvent: ((KeyEvent) -> Boolean) = { false },     content: @Composable DialogWindowScope.() -> Unit )
  看到这些参数眼熟么?和上一篇文章中提到的  Window   基本一致,不同的就是这块的 state   为 DialogState   ,接下来看下 DialogState   吧:interface DialogState {     var position: WindowPosition      var size: DpSize }
  可以看到通过定义  DialogState   可以定义对话框的位置和大小,大小可以直接通过 DpSize   设置,位置的话通过 WindowPosition   来设置,但 WindowPosition   可以通过绝对位置和相对位置来设置位置:// 绝对位置,绝对坐标 fun WindowPosition(x: Dp, y: Dp) = WindowPosition.Absolute(x, y)  // 相对位置 fun WindowPosition(alignment: Alignment) = WindowPosition.Aligned(alignment)
  可以看到对话框也可以设置标题和图标,剩下的参数都见过,就不过多介绍了。
  来看看在  Compose Desktop   中如何使用对话框吧:val alertDialog = rememberSaveable { mutableStateOf(false) } Dialog(     onCloseRequest = { alertDialog.value = false }, visible = alertDialog.value,     state = rememberDialogState(size = DpSize(300.dp, 200.dp)),     title = "Weather", icon = buildPainter("image/ic_launcher.svg") ) {     Column(         horizontalAlignment = Alignment.CenterHorizontally,         modifier = Modifier.padding(top = 20.dp)     ) {         Text(             text = title,             fontSize = 16.sp,             maxLines = 1,             fontWeight = FontWeight.Bold,             color = MaterialTheme.colors.onSecondary,             modifier = Modifier.padding(horizontal = 20.dp)         )     } }
  代码中设置了下对话框的大小,对话框使用方式和  Jetpack Compose   基本一致,看下运行效果吧:
  可以看到对话框使用很简单,有需要的可以在  Dialog   中添加一些别的可组合项进行使用。桌面的 PopopWindow
  在安卓中咱们经常使用的  PopopWindow   如何在 Compose Desktop   中使用呢?
  Compose   中可以直接使用 Popup   来构建类似于安卓中 PopupWindow   的弹框,但我试着直接使用了下 Popup   ,不太好控制弹出的地方,所以我就想着有没有能更简单控制弹出位置的方法,仔细找了下,果然有!可以使用 CursorDropdownMenu   ,它可以将 Popup   在鼠标点击的地方弹出。@Composable fun CursorDropdownMenu(     expanded: Boolean,     onDismissRequest: () -> Unit,     focusable: Boolean = true,     modifier: Modifier = Modifier,     content: @Composable ColumnScope.() -> Unit ) { 		......         Popup(             focusable = focusable,             onDismissRequest = onDismissRequest,             popupPositionProvider = rememberCursorPositionProvider(),             onKeyEvent = {                 handlePopupOnKeyEvent(it, onDismissRequest, focusManager!!, inputModeManager!!)             },         )   	...... }
  上面就是  CursorDropdownMenu   进行了一些删减的源码,可以看到里面也调用了 Popup   。
  接下来看下使用方式吧: var showPopupWindow by remember { mutableStateOf(false) }  CursorDropdownMenu(     showPopupWindow,     onDismissRequest = { showPopupWindow = false },     modifier = modifier.width(300.dp).padding(horizontal = 15.dp).padding(bottom = 10.dp) ) {     Row(         modifier = Modifier.fillMaxWidth(),         horizontalArrangement = Arrangement.SpaceBetween,         verticalAlignment = Alignment.CenterVertically,     ) {         Text(             text = data.titleDetails,             fontSize = 15.sp,             fontWeight = FontWeight.Bold,             color = MaterialTheme.colors.onSecondary         )         IconButton(onClick = { showPopupWindow = false }) {             Icon(Icons.Sharp.Close, "Close")         }     } }
  其实使用方法和对话框是类似的,都是通过定义一个是否展开的变量,然后通过这个变量来确定当前弹框是否显示。
  下面来看下运行效果:
  可以看到还是挺好看的,哈哈哈! 系统菜单
  在 Mac 中右上角会显示应用的菜单,如下图所示:
  别的应用有,我们当然也想要!那咱们的  Compose Desktop   应该如何展示呢?
  放心, Jetbrains   都为我们想到了!来看看如何使用吧!Window(onCloseRequest = ::exitApplication, title = "天青色等烟雨") {     MenuBar {         Menu("文件", mnemonic = "F") {             Item("复制(假的)", onClick = { action = "Last action: Copy" }, shortcut = KeyShortcut(Key.C, ctrl = true))             Item("粘贴(假的)", onClick = { action = "Last action: Paste" }, shortcut = KeyShortcut(Key.V, ctrl = true))         }         Menu("帮助", mnemonic = "H") {             Item("天气帮助", onClick = { action = "Last action: Help" })         }     }     App() }
  直接使用  MenuBar   就可以展示类似于上方图片中的菜单了,需要注意的是 MenuBar   需要 FrameWindowScope   ,上一篇文章中所说 Window   的 content   就是 FrameWindowScope   ,所以可以进行使用,要直接拿出来就不行了,如果想拿出来的话需要添加一个扩展函数:private fun FrameWindowScope.DemoMenu() {     MenuBar {         Menu("文件", mnemonic = "F") {             Item("复制(假的)", onClick = { action = "Last action: Copy" }, shortcut = KeyShortcut(Key.C, ctrl = true))             Item("粘贴(假的)", onClick = { action = "Last action: Paste" }, shortcut = KeyShortcut(Key.V, ctrl = true))         }         Menu("帮助", mnemonic = "H") {             Item("天气帮助", onClick = { action = "Last action: Help" })         }     } }
  简单说下吧,先来看下  Menu   吧:@Composable fun Menu(     text: String,     mnemonic: Char? = null,     enabled: Boolean = true,     content: @Composable MenuScope.() -> Unit )
  函数参数并不多,只有  mnemonic   不太好理解,它对应于键盘上某个键的字符,当这个键和 Alt 被按下时菜单将打开。然后需要重点看下 content   ,它的参数类型为 MenuScope   ,那就来看下 MenuScope   中都能添加什么可组合项吧!class MenuScope internal constructor(private val impl: MenuScopeImpl) {      @Composable     fun Menu()      	@Composable     fun Separator() = impl.Separator()      @Composable     fun Item()      @Composable     fun CheckboxItem()      @Composable     fun RadioButtonItem() }
  可以看到,还能再添加  Menu   ,剩下可添加的还有 Item   、Separator   、CheckboxItem   和 RadioButtonItem   ,故名思义,分别是条目、分隔符、复选框和单选框。
  废话不多说,运行看下效果吧!
  大家在使用的时候可以根据需求选择需要使用的可组合项来组合系统菜单。 托盘及通知
  托盘是什么呢?在  Mac   中右上角展示的就是托盘,如下图所示;Windows   中在右下角。
  托盘
  同样的, Jetbrains   也为我们想到了,使用方法也不难,直接来看下吧:Tray(     state = rememberTrayState(),     icon = painterResource("image/launcher.png"),     menu = {         Item(             "天气预报",             onClick = {}         )         Separator()         Item(             "退出",             onClick = {}         )     } )
  在  Compose Desktop   中使用 Tray   来为应用添加系统托盘,这里的 Menu   其实和上面系统菜单中的 Menu   是一回事,所以上面所描述的 Item   、Separator   、CheckboxItem   和 RadioButtonItem   都可以进行使用。
  下面来运行看下实际效果吧:
  这块还有一个小知识点,咱们有时候使用的一些工具其实都没有真正页面,只是在系统托盘中存在, Tray   也可以在没有窗口的情况下创建托盘应用程序:fun main() = application {     Tray(         icon = painterResource("image/launcher.png"),         menu = {             Item(                 "退出",                 onClick = ::exitApplication             )         }     ) }
  这样就可以创建出一个没有窗口的程序了。 通知
  咱们还可以使用系统托盘,也就是  Tray   向用户发送通知。一共有 3 种类型的通知:notify - 简单的通知 warn - 警告通知 Error - 错误通知
  下面来看下使用方法: val trayState = rememberTrayState() val infoNotification = rememberNotification("天气预报", "明天的天气很好,建议出门遛弯", Notification.Type.Info)  Tray(     state = trayState,     icon = painterResource("image/launcher.png"),     menu = {         Item(             "天气预报",             onClick = {                 trayState.sendNotification(infoNotification)             }         )         Separator()         Item(             "退出",             onClick = {                 isOpen.value = false             }         )     } )
  使用起来很简单,先使用  rememberNotification   来构建出一个 Notification   ,然后直接使用 trayState   中的 sendNotification   进行发送通知即可。
  我录制了一个完整的显示系统菜单、托盘以及通知的 GIF ,大家来看下效果吧。
  小结
  本文大概描述了下我在编写这个天气应用时遇到的一些问题及难点,还有自定义绘制的一些避坑点到此就告一段落了。此项目所有代码都放到了  Github   中。
  Github   地址:https://github.com/zhujiang521/PlayWeather/tree/desktop
  如果文中写的有误,欢迎在评论区提出,咱们一起探讨。
  文章如果能帮助到大家,哪怕是一点,我也非常高兴,先这样。

从男人的发型上可以看出一个人的性格我在头条搞创作第二期男人没有统一的发型,都是根据自己的性格与爱好,选择了不同的发型。反过来讲,从男人不同的发型上也可以看出一个人的性格。虽然不能以偏概全,但也能管中窥豹,所见一斑。八强对阵法国!女篮决定太正确!郑薇布阵有奇效,奖牌稳了在和比利时女篮强强对话中胜出后,女篮的姑娘们锁定了小组第二,从而为自己淘汰赛可以得到较为轻松的赛程打下了坚实的基础。14决赛,中国女篮将迎战实力并不出众的法国女篮,此前就有过33分赛艇世锦赛中国队获得一枚银牌新华社北京9月24日电(记者公兵)国际赛艇联合会官网消息,正在捷克拉齐采举行的世界赛艇锦标赛当地时间23日进入首个决赛日,中国队在男子轻量级四人双桨项目上获得银牌。中国队派出孙满陈升温!未来一周,舒服今天省内气温再升14最高温升至25上下朝阳29会有种仿佛还在夏天的感觉中午前后甚至可以穿上夏装出行今晨最低温白天最高温未来五天沈阳几乎都是晴天偶尔有白云飘过遮一遮耀眼的阳光温度的表曝浙江省运会U15决赛爆发大冲突,赛后追打裁判拒绝领奖根据社媒平台账号10号沛沛的透露,浙江省运会U15决赛中爆发超级冲突,而且在赛后小球员追打裁判,并且拒绝领奖。此前,广东省运会的比赛被曝光决赛中出现了假球现象,但包括广东省体育局中皮肤暗黄的原因很多人认为皮肤黄是外部因素导致,诸如化妆品色素沉淀,电脑辐射,紫外线照射等等,其实这些都是次要的,真正影响我们肤色发黄的主要原因有2点第一贫血。贫血我们得干嘛?自然就得补血,也就是盘点英国玛丽长公主的嫁妆和珠宝到底有多豪玛丽长公主也是珠宝大户,毕竟是很多人乔治五世和珠宝商玛丽王后要把宝贝独生女,结婚的时候杜父母送了好多好多珠宝当嫁妆。玛丽长公主嫁给大自己15岁又显老的第六代哈伍德伯爵亨利拉塞尔斯,中国人的头发中国人的头发於恢无论哪个年代,拥有一头秀美的长发,始终都是美女丽人的标配。可能是因为现代的男人主流都是短发,所以总对长发及腰的女子情有独钟。据说中国人自有历史记录开始,流行的都是短提升知艾防艾能力第二届校园情景剧展播活动揭开序幕9月25日,聚力防疫抗艾?共担健康责任第二届校园情景剧开机仪式在北京举行。主办方供图中新网北京9月26日电聚力防疫抗艾共担健康责任第二届校园情景剧开机仪式25日在北京举行,为第二届二十大代表风采周雷勇攀量子科技产业化新高峰代表名片周雷,理学博士,科大国盾量子技术股份有限公司项目总监,负责和参与国家城域量子通信组网技术等多个重大项目,荣获安徽省科学技术一等奖等,获评安徽省优秀共产党员安徽省劳动模范等。每个人都是自己的灵感缪斯上海时装周记者周芳颖编辑楼婍沁COMMEMOIWEARETHEWORLD由国际超模吕燕创办的设计师品牌COMMEMOI踩着动感的鼓点再次打开2023春夏上海时装周的聚光灯。久等线下盛宴的时尚
天神下凡,詹姆斯生日夜爆砍47109,湖人队15分大逆转老鹰北京时间12月31日,NBA常规赛,湖人队对阵老鹰队,最终,湖人队在最多落后15分的情况下上演了大逆转的好戏,130121击败了老鹰队!此役詹姆斯可谓是天神下凡,爆砍了47分10篮湖人险胜老鹰!老詹轰47分,5配角上双,哈姆开窍,里弗斯13中1北京时间12月31号湖人和老鹰的比赛,这场比赛肯定会吸引无数人关注,毕竟这场比赛是詹姆斯的生日夜。而在这种情况下,双方都保持了足够激烈的表现,但詹姆斯凭借自己的发挥,一个人带队13小巧便携,直插即用科唛VimoS迷你无线麦克风体验无线麦克风现在是很多短视频创作者必备的生产力工具之一,手机和相机录制视频在室外或者空旷的房间效果并不理想,无线麦克风可以很好地解决一些场景的音频录制问题,今天给大家介绍一款科唛Vi超级混动DMi,圣诞节与车友相约的新能源车冬测能耗如何MerryChristmas12。25虽然是西方的节日,但冬日里浪漫在这一天总会显得格外与众不同,特别是遇到天降瑞雪,那感觉对于有生活讲究的年轻人来说则更欢心与以往不同,很早就和车现在不缺吃喝穿咋还幸福不起来现在的人不缺吃穿用,指的是一个基本的满足,别人每天也是三餐,但有两餐是八个盘盘,两个汤,穷人就是一碗汤面条,或者是几个小菜加上辣椒段段再加上一份大米也是一餐中饭,你说能幸福吗?别人你是一个喜欢逃避的人吗?在今天文章的开始,我想请大家一起来做一个小小的测试。以下这些行为,有哪些是经常出现在你生活中,已经对你造成过困扰的?请在心里默默打个勾,并计数。1)明知道一项事情很重要,也有时间,余生最好的活法戒欲文花妖馆人的一生有很多的欲望,最为重要的便是三欲。他们分别是出格之欲口腹之欲名利之欲。拉马丁说能力有限,欲海无边,人是贬入凡间的神,他没有忘记天国的一切。人的欲望是难以控制的,不管越没本事的人,越喜欢在这4个方面大方,希望你一个都没有人常说,这世上有三件事情无法隐藏贫穷咳嗽和爱。钱的重要性不言而喻,我们每个人都想过富足优渥的生活。可现实生活往往是,很多人为了微薄的工资去拼命,到头来却越忙越穷。正如著名企业家稻盛如果你还在该多好不平凡的20222022年12月20日之前,我从来没有那么害怕过,这么多年,不切实际也好,自欺欺人也罢,没有想过这一天会来的那么突然,那么急促,以至于成了永别,这一天,我永远的失去吃辣竟有这么多好处!这几条你很可能不知道吃辣真的太爽了!对于喜欢吃辣的人来说,水煮鱼麻辣香锅麻辣烫麻辣火锅变态辣烤鸡翅简直就是痛,并快乐着!实际上食物中含有的辛辣成分,是一部分植物为了保护自己的一种防御手段。所谓的辣味也冬季里的长靴,选择高跟款式的姑娘也不少,增高显瘦还衬托精致到了冬季,出门的人少了很多,随着疫情的恢复,时尚街区,行人也比前段时间多了不少,大多数人还是注意身体健康的,当然出门要让自己精致一些,还要搭配出保暖,长靴搭配,也多了起来,不少姑娘