Compose for Desktop (Kolin跨平台编写Mac微信应用)

春光不自留,莫怪东风恶

掘金博客地址-创作不易-希望点赞

在这里插入图片描述

image.png

Compose for Desktop

      Compose是由Kotlin语言快速编辑界面的框架,基于谷歌的现代工具箱,由JetBrains为您带来。
Compose for Desktop简化并加速了桌面应用程序的UI开发,并允许Android和桌面应用程序之间大量的UI代码共享,这是来自官方的一些阐述解释。Compose初忠是声明式UI,当然了跨平台的纷争乱战时代,它也有着跨平台的梦想。在桌面端还未流行和普及之时为何不用划水的时间来尝试一下Compose for
Desktop!

一、环境

      IntelliJ IDEA 2020.3以后的版本根据新建的类型compose desktop、compose app、compose web都可以自动依赖相关的gradle。我下载的最新版本,pojie有点辣手,之前的注册码和.jar方式都可以,如果由大佬知道破解方式可以楼下指点,先试用30天。截图看文字,相信大佬们都能看懂?左边选择Kotlin,右边会出现各种kotlin能干的事:Desktop、Web、Mobile…kotlin牛逼!

image.png

image.png

image.png

一、Desktop

      Name、Location、Project Template->Desktopo即可、Build System 随便、Project JDK->11以上即可,继续finish完成。

你可以点击一下下图的main函数前面的绿色运行箭头…等待奇迹出现
image.png

运行的效果,当然了这是我没事干用贝塞尔曲线绘制的那个男人,时间问题没绘制完。大家如果看过我的自定义相信绘制不是难题!!

image.png

上面我们开发环境已经完毕,接下来是不是有点小激动,我们开始代码编写。

二、Desktop UI分析 - 微信

      微信的桌面端说不上花里胡哨,但是很优雅简约不缺美观。我们这篇文字主要模仿这个UI进行尝试Compose for Desktop

image.png

素材准备

为了达到比较一致的效果,我们通过PS进行素材获取。

1.打开微信截图需要图标。

2.PS截图用魔术棒进行选区删除不需要部分。

image.png

3.通过选区缩放来进行调试边界。

image.png
保存图片即可。逐步操作需要图片。

布局分析

      布局我们经常用,也知道可分为这三块从左到右都有联动。所以我们先进行一级布局UI。
image.png

1.左侧Colum又上到下配合Spacer完美

2.中间的Box内部ListView加搜索框

3.右侧ListView

三、Desktop UI编写 - 微信-Left

      Compose for Desktop简化并加速了桌面应用程序的UI开发,并允许Android和桌面应用程序之间大量的UI代码共享既然官方如此说了和Android端的UI大量共享,我们接下来体验一下。当然了我感受了一波的却大量的组件都基本一致。就自定义方面缺少一些API,阴影的设置,如果你发现了可以告诉一下我,感激不尽。既然和Android一致那么接下来大量的代码,接住了…

image.png

上面分析:1.左侧Colum又上到下配合Spacer完美

实体类封装点击图片路径

/**
 * @param defaultPath 默认图片路径
 * @param selectedPath 选择路径
 * @param path 实际路径
 * @param selected 是否选中
 */
data class WxSelectedBean(val defaultPath:String,var selectedPath:String,var path:String,var selected:Boolean)

负值图片路径

object WxViewModel : RememberObserver {
    val isAppReady = mutableStateOf(false)
    val position = ArrayList<WxSelectedBean>()
    fun initData() {
        var selectedDatas = arrayListOf<WxSelectedBean>()
        selectedDatas.add(
            WxSelectedBean(
                "images/head_lhc.png",
                "images/head_lhc.png",
                "images/head_lhc.png",
                 false
            )
        )
        selectedDatas.add(
            WxSelectedBean(
                "images/message_unselected.png",
                "images/message_selected.png",
                "images/message_selected.png",
                 true
            )
        )
        selectedDatas.add(
            WxSelectedBean(
                "images/person_unselected.png",
                "images/person_selected.png",
                "images/person_unselected.png",
                false
            )
        )
        selectedDatas.add(
            WxSelectedBean(
                 "images/connected_unselecte.png",
                "images/connected_selected.png",
                "images/connected_unselecte.png",
                 false
            )
        )
        selectedDatas.add(
            WxSelectedBean(
                "images/file_default.png",
                "images/file_default.png",
                "images/file_default.png",
                false
            )
        )
        selectedDatas.add(
            WxSelectedBean(
                "images/frends.png",
                "images/frends.png",
                "images/frends.png",
                false
            )
        )

        selectedDatas.add(
            WxSelectedBean(
                "images/phone.png",
                "images/phone.png",
                "images/phone.png",
                false
            )
        )
        selectedDatas.add(
            WxSelectedBean(
                "images/mulu.png",
                "images/mulu.png",
                "images/mulu.png",
                false
            )
        )
        position.addAll(selectedDatas)
    }
    

    override fun onAbandoned() {

    }

    override fun onForgotten() {
    }

    override fun onRemembered() {
    }
}

界面

import androidx.compose.animation.core.TweenSpec
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.desktop.Window
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
import module_view.WxSelectedBean
import module_view.WxViewModel

fun main() = Window {
    WxViewModel.initData()
    var wxData by remember { mutableStateOf(WxViewModel.position) }
    //选中的索引
    var selectedIndex by remember { mutableStateOf(1) }
    //图片选中动画执行与否
    var imageAnimal by remember { mutableStateOf(true) }
    //图片旋转动画
    val imageAngle: Float by animateFloatAsState(
        if (imageAnimal) {
            0f
        } else {
            360f
        }, animationSpec = TweenSpec(durationMillis = 1001)
    )
    MaterialTheme {
        Scaffold {
            Row {
                Column(
                    horizontalAlignment = Alignment.CenterHorizontally,
                    modifier = Modifier.fillMaxHeight().width(66.dp)
                        .background(Color(247, 242, 243))
                ) {
                    ImageRes(
                        getPath(wxData, selectedIndex, 0),
                        modifier = Modifier.padding(top = 30.dp).size(48.dp)
                            .clickable(role = Role.Image) {
                            imageAnimal = !imageAnimal
                        }.rotate(imageAngle)
                    )

                    ImageRes(
                        getPath(wxData, selectedIndex, 1),
                        modifier = Modifier.padding(vertical = 20.dp).size(42.dp).clickable {
                            selectedIndex = 1
                        })
                    ImageRes(getPath(wxData, selectedIndex, 2),
                        modifier = Modifier.size(32.dp).clickable {
                            selectedIndex = 2
                        })
                    ImageRes(
                        getPath(wxData, selectedIndex, 3),
                        modifier = Modifier.padding(vertical = 20.dp).size(30.dp).clickable {
                            selectedIndex = 3
                        }
                    )
                    ImageRes(getPath(wxData, selectedIndex, 4), modifier = Modifier.size(30.dp))
                    ImageRes(
                        getPath(wxData, selectedIndex, 5),
                        modifier = Modifier.padding(vertical = 20.dp).size(30.dp)
                    )
                    Spacer(modifier = Modifier.weight(1f))
                    ImageRes(
                        getPath(wxData, selectedIndex, 6),
                        modifier = Modifier.padding(vertical = 20.dp).size(35.dp)
                    )
                    ImageRes(
                        getPath(wxData, selectedIndex, 7),
                        modifier = Modifier.padding(vertical = 20.dp).size(30.dp)
                    )
                }
            }
        }

    }

}


/**
 * @param wxData 数据集合
 * @param selectedIndex 选中的索引
 * @param currenIndex 当前Image对应的索引
 * return 返回各个按钮选中和未选中图片路径
 */
private fun getPath(
    wxData: ArrayList<WxSelectedBean>,
    selectedIndex: Int,
    currenIndex: Int
): String {
    return if (selectedIndex == currenIndex) {
        wxData[currenIndex].selectedPath
    } else {
        wxData[currenIndex].defaultPath
    }

}

看看效果?

compose_desk_1.gif

四、Desktop UI编写 - 微信-Center

      中间部分如下图分析可见Box里面一个Row一个列表搞定?对于UI代码编写之前,大概的代码框架构思还是比较重要的。<

  • 16
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值