Compose Desktop 实战 宝可梦图鉴

Compose Desktop 实战 宝可梦图鉴

前言

阅读本文需要一定compose基础,如果没有请移步Jetpack Compose入门详解(实时更新)

接口数据来源于pokeapi

项目源代码
如果你觉得不错,请给我一个star,THKS

实现效果

闲话不多说,让我们来看看实现效果
在这里插入图片描述
可以看到我们实现了一个非常简洁的宝可梦图鉴,展示了所有世代的宝可梦,并提供了搜索,与宝可梦图鉴app的UI有了一些变化。


一、架构介绍

如图,展示了主要的一些文件:
在这里插入图片描述
本项目没有适配安卓端,iOS端和web端(如果有乐于开源的小伙伴可以联系我),因此所有核心代码都在desktop中

  • http - 接口
  • util -工具类
  • ui -Compose组件
  • viewmodels - viewmodel

二、一些的功能点的介绍

PreCompose

通过PreCompose 这个三方库,可以像写app一样写desktop,当然这里面有一些与app使用有些差别

import androidx.compose.ui.unit.DpSize       
import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberWindowState
import moe.tlaster.precompose.PreComposeWindow
import ui.FullScreenView
import util.EnvUtil


fun main() = application {
    val windowState = rememberWindowState(size = DpSize(AppConfig.windowMinWidth, AppConfig.windowMinHeight))
    PreComposeWindow(
        state = windowState,
        onCloseRequest = ::exitApplication,
        undecorated = EnvUtil.isWindows(),
        title = ""
    ) {
        //window.minimumSize = Dimension(AppConfig.windowMinWidth.value.toInt(), AppConfig.windowMinHeight.value.toInt())
        window.rootPane.apply {
            rootPane.putClientProperty("apple.awt.fullWindowContent", true)
            rootPane.putClientProperty("apple.awt.transparentTitleBar", true)
            rootPane.putClientProperty("apple.awt.windowTitleVisible", false)
        }
        FullScreenView()
        //CpnWindowsPlaformDecoratedButtons(windowState)
    }
}

PreComposeWindow就是必备的,不然后续使用所有的与PreCompose相关的都会报错
例如初始化viewmodel

import moe.tlaster.precompose.ui.viewModel  

val viewModel  = viewModel { PokemonListViewModel() }

加载网络图片

桌面端加载网络图也没有安卓的原生库使用,这里使用了compose-desktop-imageloader

package ui.common             

import androidx.compose.foundation.Image 
import androidx.compose.runtime.Composable 
import androidx.compose.ui.Modifier 
import androidx.compose.ui.layout.ContentScale 
import androidx.compose.ui.res.painterResource 
import org.succlz123.lib.imageloader.ImageAsyncImageFile 
import org.succlz123.lib.imageloader.ImageAsyncImageUrl 
import org.succlz123.lib.imageloader.ImageRes 
import org.succlz123.lib.imageloader.core.ImageCallback 


@Composable
fun AsyncImage( 
    modifier: Modifier, 
    url: String?, 
    placeHolderUrl: String? = "image/ic_pokmon.jpeg", 
    errorUrl: String? = "image/ic_pokmon.jpeg", 
    contentScale: ContentScale = ContentScale.Crop 
) {
    val imgUrl = url ?: "image/ic_pokmon.jpeg" 
    if (imgUrl.startsWith("http")) { 
        ImageAsyncImageUrl(url = imgUrl, imageCallback = ImageCallback(placeHolderView = { 
            placeHolderUrl?.let { 
                Image( 
                    painter = painterResource(placeHolderUrl), 
                    contentDescription = imgUrl, 
                    modifier = modifier, 
                    contentScale = contentScale 
                )
            }
        }, errorView = { 
            errorUrl?.let { 
                Image( 
                    painter = painterResource(errorUrl), 
                    contentDescription = imgUrl, 
                    modifier = modifier, 
                    contentScale = contentScale 
                )
            }
        }) {
            Image( 
                painter = it, contentDescription = imgUrl, modifier = modifier, contentScale = contentScale 
            )
        })
    } else if (imgUrl.startsWith("/") || imgUrl.contains(":\\")) { 
        ImageAsyncImageFile(filePath = imgUrl, imageCallback = ImageCallback(placeHolderView = { 
            placeHolderUrl?.let { 
                Image( 
                    painter = painterResource(placeHolderUrl), 
                    contentDescription = imgUrl, 
                    modifier = modifier, 
                    contentScale = contentScale 
                )
            }
        }, errorView = { 
            errorUrl?.let { 
                Image( 
                    painter = painterResource(errorUrl), 
                    contentDescription = imgUrl, 
                    modifier = modifier, 
                    contentScale = contentScale 
                )
            }
        }) {
            Image( 
                painter = it, contentDescription = imgUrl, modifier = modifier, contentScale = contentScale 
            )
        })
    } else { 
        ImageRes(resName = imgUrl, imageCallback = ImageCallback(placeHolderView = { 
            placeHolderUrl?.let { 
                Image( 
                    painter = painterResource(placeHolderUrl), 
                    contentDescription = imgUrl, 
                    modifier = modifier, 
                    contentScale = contentScale 
                )
            }
        }, errorView = { 
            errorUrl?.let { 
                Image( 
                    painter = painterResource(errorUrl), 
                    contentDescription = imgUrl, 
                    modifier = modifier, 
                    contentScale = contentScale 
                )
            }
        }) {
            Image( 
                painter = it, contentDescription = imgUrl, modifier = modifier, contentScale = contentScale 
            )
        })
    }
}

致谢

项目中大部分技术栈都参考自NCMusicDesktop,感谢大佬

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

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

相关文章

php通过cURL爬取数据(3):CURLINFO_HTTP_CODE返回0的排查和解决方案

CURLINFO_HTTP_CODE返回0的排查和解决方案 一、curl本地服务器需要DNS解析域名二、如何排查错误原因三、无法解析 DNS的程序升级方案四、宝塔配置DNS的操作方法1.etc/resolv.conf2.通过GUI界面 一、curl本地服务器需要DNS解析域名 在使用 curl 命令发送请求到域名地址&#xf…

测试(二)

1.软件测试的生命周期 需求分析→测试计划→ 测试设计→ 测试开发→ 测试执行→ 测试评估 2.如何描述一个Bug 3.Bug的优先级 1、Blocker(崩溃): 阻碍开发或测试工作的问题;造成系统崩溃、死机、死循环,导致数据库数…

Unity基础 视频组件VideoPlayer,视频的播放与控制

在Unity中,视频播放功能具有广泛的应用,以下是一些视频播放在Unity中的常见用途: 游戏引入和过场动画:使用视频播放可以在游戏开始或过场动画中添加引人注目的视频,为游戏制造氛围和引起玩家的兴趣。这种方式可以通过播…

CSS基础学习--11 padding(填充)

一、定义 CSS padding(填充)是一个简写属性,定义元素边框与元素内容之间的空间,即上下左右的内边距。 当元素的 padding(填充)内边距被清除时,所释放的区域将会受到元素背景颜色的填充。 单独使…

Linux运维监控学习笔记1

1. 监控系统的概念: 监控系统,将所有需要监控的服务器及其各种各种需要的状态数据都实时地收集,并图形化地展示,并可以进行报警,让机器主动及时地与人沟通。 2. 为什么要监控? 答:实时地收集数…

kubernetes(k8s)理论篇

注意:kubeadm与docker是有版本要求的。 如果版本不兼容,初始化 kubeadm是会出现以下问题。 学习k8s掌握知识 基础概念 什么是 Pod 控制器类型 K8S 网络通讯模式 Kubernetes 构建 K8S 集群 资源清单 资源 掌握资源清单的语法 编写 Pod 掌握 Pod 的…

JVM知识点整理

JVM 回收哪个区域?关联面试题:fullgc会回收方法区(元空间)吗? 怎么判断对象可以被回收了关联面试题:哪些对象可以作为 GC Root (两栈两方法) JVM GC什么时候执行?分代回收机制思考&…

docker容器启动的问题 - docker容器和虚拟机的比较 - docker的底层隔离机制

目录 一、docker容器启动的问题? 二、什么是docker仓库? 三、虚拟机和docker容器的区别: docker的优势: docker的缺点: 对比: 四、docker的底层隔离机制 参考文献:LXC linux容器简介——…

图像 检测 - CenterNet: Objects as Points (arXiv 2019)

CenterNet: Objects as Points - 目标作为点(arXiv 2019) 摘要1. 引言2. 相关工作3. 准备工作4. 目标作为点4.1 3D 检测4.2 人体姿态估计 5. 实施细节6. 实验6.1 目标检测6.1.1 附加实验 6.2 3D 检测6.3 姿态估计 7. 结论References附录A:模型…

【C数据结构】动态顺序表_SeqList

目录 【1】数据结构概述 【1.1】什么是数据结构? 【1.2】数据结构分类 【1.3】数据结构术语 【2】数据结构特点 【2】动态顺序表 【2.1】动态顺序表定义数据结构和接口 【2.1】动态顺序表创建初始化 【2.2】动态顺序表初始化 【2.3】动态顺序表内存释放 【…

mac电脑储存内存越来越小如何清理释放空间?

如果你是一位Mac系统的用户,可能会发现你的电脑储存空间越来越小。虽然Mac系统设计得非常优秀,但是系统数据和垃圾文件也会占据大量的储存空间。在这篇文章中,我们将探讨mac系统数据怎么这么大,以及mac清理系统数据怎么清理。 一…

万字详解常用设计模式

本文是博主在工作中对常用设计模式的使用经验总结归纳而来分享给大家。 设计模式一共有23种,本文讲解涉及如下: 责任链模式 模板方法模式 发布订阅模式 策略模式 三大分类 业界一般将设计模式分为三大类: 创建型模式:对类的实…

5、产品经理的工作职责OR主要工作技能和工具

1、产品经理的工作职责 我们通过一个案例来了解产品经理的工作职责。 老板让你给他点餐,你应该怎么做?你需要考虑哪一些方面的问题? 例如:你预算多少,预算是十块钱还是100块还是1000块。有没有忌口,口味…

Kafka详解(一)

第1章 Kafka概述 1.1 定义 1.2 消息队列 目前企业中比较常见的消息队列产品主要有Kafka、ActiveMQ、RabbitMQ、RocketMQ等。Message Queue ② 在大数据场景主要采用Kafka作为消息队列 ② 在JavaEE开发中主要采用ActiveMQ、RabbitMQ、RocketMQ Kafka存储数据,且保证…

「网络编程」第一讲:初识网络_网络基础1

「前言」文章是关于网络编程方面的,今天内容大致是网络基础,讲解下面开始! 「归属专栏」网络编程 「笔者」枫叶先生(fy) 「座右铭」前行路上修真我 「枫叶先生有点文青病」 「每篇一句」 青山不改,绿水长流 ——白居易 目录 一、…

新手快速搭建springboot项目

一、创建项目 1.1、创建项目 1.2、配置编码 1.3、取消无用提示 1.4、取消无用参数提示 二、添加POM父依赖 <!-- 两种方式添加父依赖或者import方式 --> <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-p…

微信小程序触底加载scroll-view

微信小程序触底加载 scroll-view 了解什么是触底加载&#xff1f; 需求&#xff1a;有个固定高度的容器&#xff0c;实现容器里面的内容触底加载 1、内容盒子的高度 2、盒子里内容的总高度 3、滚动条的scrollTop 触底加载的原理就是 当里面的容器触底的时候进行分页&#xff0…

Ansible-playbook-roles安装lnmp

使用roles安装lnmp 1、准备四台主机 192.168.142.10 192.168.142.20 192.168.142.30 192.168.142.40 2、10作为ansible管理端 首先ssh连接剩下三台主机 3、vim/etc/ansible/hosts 添加[nginxservers]配置nginx ip,[phpservers]php ip,[mysqlservers]mysql ip 4、cd /etc/ansibl…

0基础学习VR全景平台篇第42篇:编辑器底部菜单-分组管理

大家好&#xff0c;欢迎观看蛙色VR官方系列——后台使用课程&#xff01; 本期为大家带来蛙色VR平台&#xff0c;底部菜单—分组管理功能操作。 功能位置示意 一、本功能将用在哪里&#xff1f; 分组管理&#xff0c;指观看者可点击不同分组&#xff0c;查看不同类型全景内容…

【ROS】ROS+Gazebo强化学习:训练

1、安装ROS1 【ROS】Ubuntu20.04安装ROS1 2、安装Anaconda 【AI】PyTorch入门&#xff08;一&#xff09;&#xff1a;通过Anaconda安装PyTorch 【PyThon】Anaconda常用命令 3、源码下载 使用论文 Goal-Driven Autonomous Exploration Through Deep Reinforcement Learnin…