用kotlin-Compose从0构建一个APP


前言

想写一个用kotlin从0开始的天气APP。具体的一些思路都是参考 晨曦
上面这个想法是5月份就有的,初衷是想做个APP - 在做个APP游戏,后面看了一些其他人写APP游戏的代码,感觉和python差不多,相比于unity老说,做游戏档次就低了。

但是呢,我觉得呢,完成自己的一个小目标,是有那么一丢丢的成就感的。

直接说正题了:
1,先用Auxre 模拟一个 APP大致页面
2,用 kotlin-compose 构建APP,其中一些页面也会插入xml布局的吧
3,加上一些花里胡哨的功能

一、kotlin-Compose是什么?

1,入门 :kotlin-Compose官网
2,进阶:fundroid_方卓

二、关于界面初步构想

因为是入门级,也不追求什么完美了,要求自己能完成就可以了。
不过一些想法还是要有的,毕竟嘛,统治世界的是想象力
1,游戏 人文 舞蹈 那加起来7个按钮能做成三维立体效果,背景图嘛,跟随天气发生变化
2,下面对话框 什么语音输入呀,AI自动回话什么,随机匹配啊什么的
在这里插入图片描述

实现效果
在这里插入图片描述

package com.example.myapplication

import android.content.Context
import android.content.Intent
import android.hardware.*
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.Crossfade
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.*

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Menu
import androidx.compose.material.icons.filled.Settings
import androidx.compose.runtime.*
import androidx.compose.ui.AbsoluteAlignment
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.focusModifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat.startActivity
import com.example.myapplication.ui.theme.MyApplicationTheme
import kotlinx.coroutines.launch


class MainActivity : ComponentActivity(), SensorEventListener{


    private lateinit var sensorManager: SensorManager
    private var mSensor: Sensor? = null
    private val NS2S = 1.0f / 1000000000.0f
    private val timestamp = 0f


    @ExperimentalAnimationApi
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        var xDistance by remember { mutableStateOf(0f) }
        var yDistance by remember { mutableStateOf(0f) }
        setContent {
            MyApplicationTheme {
                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
//                    Banner(x = xDistance, Y = yDistance)
                    HomeScreen()
                }
            }
        }

//        val context = LocalContext.current
        val sensorManager = getSystemService(Context.SENSOR_SERVICE)  as SensorManager
//        mLight = sensorManager.getDefaultSensor((Sensor.TYPE_LIGHT))
        val sensor = sensorManager?.getDefaultSensor(Sensor.TYPE_GYROSCOPE)

    }

    override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
        TODO("Not yet implemented")
    }

    override fun onSensorChanged(event: SensorEvent?) {
        if (timestamp != 0) {
            final float dT = (event.timestamp - timestamp) * NS2S;
            // Axis of the rotation sample, not normalized yet.
            float axisX = event?.values?.get[0]!!
            float axisY = event?.values?.get[1]!!
            float axisZ = event?.values?.get[2]!!

            // Calculate the angular speed of the sample
            float omegaMagnitude = sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);

            // Normalize the rotation vector if it's big enough to get the axis
            if (omegaMagnitude > EPSILON) {
                  axisX /= omegaMagnitude;
                  axisY /= omegaMagnitude;
                  axisZ /= omegaMagnitude;
         }

        // Integrate around this axis with the angular speed by the time step
        // in order to get a delta rotation from this sample over the time step
        // We will convert this axis-angle representation of the delta rotation
        // into a quaternion before turning it into the rotation matrix.
        float thetaOverTwo = omegaMagnitude * dT / 2.0f;
        float sinThetaOverTwo = sin(thetaOverTwo);
        float cosThetaOverTwo = cos(thetaOverTwo);
        deltaRotationVector[0] = sinThetaOverTwo * axisX;
        deltaRotationVector[1] = sinThetaOverTwo * axisY;
        deltaRotationVector[2] = sinThetaOverTwo * axisZ;
        deltaRotationVector[3] = cosThetaOverTwo;
        }
        timestamp = event.timestamp;
        float[] deltaRotationMatrix = new float[9];
        SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector);






    //   上秤,78KG---“哦, 秤坏了”
//       体检,77KG,超重---“md测的真准”
//       夜跑一个月,79kg--哎呀
    //

//
//        var speedY =event?.values?.get(1)!!
//        var speedX =event?.values?.get(0)!!
//        var speedZ =event?.values?.get(2)!!
//        // 将手机在各个轴上的旋转角度相加
//        var angularX = (event.values[0] * dT).toLong()
//        var angularY = (event.values[1] * dT).toLong()
//        var angularZ = (event.values[2] * dT).toLong()
//
//        //设置x轴y轴最大边界值,
//        if (angularY > mMaxAnular) {
//            angularY = mMaxAnular.toFloat()
//        } else if (angularY < -mMaxAnular) {
//            angularY = -mMaxAnular.toFloat()
//        }
//
//        if (angularX > mMaxAnular) {
//            angularX = mMaxAnular.toFloat()
//        } else if (angularX < -mMaxAnular) {
//            angularX = -mMaxAnular.toFloat()
//        }
//
//        val xRadio: Float = (angularY / mMaxAnular).toFloat()
//        val yRadio: Float = (angularX / mMaxAnular).toFloat()
//        xDistance = xRadio * maxOffset
//        yDistance = yRadio * maxOffset

    }



}

//
//fun Image(
//    painter: Painter, // 要绘制的图片(还可以是ImageVector和ImageBitmap)
//    contentDescription: String?, // 用来描述图片,等价于ImageView的contentDescription
//    modifier: Modifier = Modifier, // 修饰符
//    alignment: Alignment = Alignment.Center, // 对齐方式,等价于ImageView的gravity,默认居中显示
//    contentScale: ContentScale = ContentScale.Fit, // 缩放方式,等价于ImageView的scaleType,默认是ContentScale.Fit,等价于ImageView的fitCenter
//    alpha: Float = DefaultAlpha, // 透明度,等价于ImageViwe的alpha,默认为1.0
//    colorFilter: ColorFilter? = null // 颜色过滤器,可以对图片色值进行混合处理
//)


@Composable
fun Chip(modifier: Modifier = Modifier, text: String) {
    Card(
        modifier = modifier,
        border = BorderStroke(color = Color.Black, width = Dp.Hairline),
        shape = RoundedCornerShape(8.dp)
    ) {
        Row(
            modifier = Modifier.padding(start = 8.dp, top = 4.dp, end = 8.dp, bottom = 4.dp),
            verticalAlignment = Alignment.CenterVertically
        ) {
            Box(
                modifier = Modifier
                    .size(16.dp, 16.dp)
                    .background(color = MaterialTheme.colors.secondary)
            )
            Spacer(Modifier.width(4.dp))
            Text(text = text)
        }
    }
}

@ExperimentalAnimationApi
@Composable
fun ArtistCard() {
    var screen by  remember { mutableStateOf("home") }
    if (screen == "home") {
        Column(
            Modifier
                .padding(16.dp)
                .clickable { }
                .offset(y = 3.dp)
//    clickable 使可组合项响应用户输入,并显示涟漪。
//    padding 在元素周围留出空间。
//    fillMaxWidth 使可组合项填充其父项为它提供的最大宽度。
//    size() 指定元素的首选宽度和高度
        ) {
            Box() {
                Card() {
                    var expanded by remember { mutableStateOf(false) }
                    Column(Modifier.clickable { expanded = !expanded }) {
                        Image(
                            painter = painterResource(id = R.drawable.yan2),
                            contentDescription = "顶部背景图"
                        )
                        AnimatedVisibility(visible = expanded) {
                            Text(
                                text = "Jetpack",
                                style = MaterialTheme.typography.h2
                            )

                        }
                    }
                }
                Row(
//            size()确定 长宽
                    Modifier.fillMaxWidth(),
//            Row 中设置子项的位置,请设置 horizontalArrangement
//            和 verticalAlignment 参数
//            verticalAlignment = Alignment.CenterVertically,
                    horizontalArrangement = Arrangement.SpaceAround,
                ) {

                    Chip(
                        Modifier
                            .paddingFromBaseline(85.dp)
                            .offset(x = 12.dp)
                            .clickable { screen = "ganme" },
                        "游戏",
                    )
                    Text(text = "阴阳", Modifier.paddingFromBaseline(30.dp))
                    Text(text = "八卦", Modifier.paddingFromBaseline(95.dp))

                    Chip(
                        Modifier
                            .paddingFromBaseline(15.dp)
                            .clickable { screen = "tianqi" },
                        "天气",
                    )


                    Text(text = "地图", Modifier.paddingFromBaseline(75.dp))
                    Text(text = "舞蹈", Modifier.paddingFromBaseline(40.dp))
                    Text(text = "人文", Modifier.paddingFromBaseline(78.dp))
                }

            }
            Spacer(Modifier.height(20.dp))
            Text("今天又是美好的一天")
            Spacer(Modifier.height(10.dp))
            Row(
                Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.End,
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text(text = "是的呢")
                Image(
                    painter = painterResource(R.drawable.face),
                    contentDescription = null,
                    Modifier.size(48.dp, 48.dp)
                )
            }
            Spacer(Modifier.height(10.dp))
            Text("接下来干什么")
            Spacer(Modifier.height(10.dp))

            Row(
                Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.End,
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text("远赴人间惊鸿宴")
                Image(
                    painter = painterResource(R.drawable.face),
                    contentDescription = null,
                    Modifier.size(48.dp, 48.dp)
                )
            }
            Spacer(Modifier.height(10.dp))

            Row(
                Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.End,
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text("一睹人间盛世颜")
                Image(
                    painter = painterResource(R.drawable.face),
                    contentDescription = null,
                    Modifier.size(48.dp, 48.dp)
                )
            }

            Spacer(Modifier.height(10.dp))

            Chip(text = "说点什么呢...")
        }
    }
    when (screen){
        "tianqi" -> {
            Text(text = "123",Modifier.clickable { screen="home" })
//            Banner()
        }
        "game"  -> game()


    }




}

@ExperimentalAnimationApi
@Composable
fun HomeScreen() {

    val scaffoldState = rememberScaffoldState()
    val scope = rememberCoroutineScope()
    Scaffold(
        scaffoldState = scaffoldState,
        drawerContent = {
            Box(
                modifier = Modifier.fillMaxSize(),
                contentAlignment = Alignment.Center
            ) {
                Text(text = "抽屉组件中内容")
            }
        },

        //标题栏区域
        topBar = {
            TopAppBar(
                title = { Text(text = "某天某月某日") },
                navigationIcon = {
                    IconButton(
                        onClick = {
                            scope.launch { scaffoldState.drawerState.open() }
                        }
                    ) {
                        Icon(
                            imageVector = Icons.Filled.Menu,
                            contentDescription = null
                        )
                    }
                },
                actions = { IconButton(onClick = { /* doSomething() */ }) {
                        Icon(Icons.Filled.Settings, contentDescription = null)
                    }
                }

            )
        },

        //悬浮按钮
        floatingActionButton = {
            Row(
                Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceAround,
                ) {
                ExtendedFloatingActionButton(
                    text = { Text("悬浮按钮") },
                    onClick = { }
                )
                ExtendedFloatingActionButton(
                    text = { Text("主页") },
                    onClick = { }
                )
                ExtendedFloatingActionButton(
                    text = { Text("我的") },
                    onClick = { }
                )
            }

        },
        floatingActionButtonPosition = FabPosition.Center,
        //屏幕内容区域
        content= {
                ArtistCard()
//            var screen by  remember { mutableStateOf("home") }
//            Text(text = "123",Modifier.clickable { screen="tianqi" })
//            Crossfade(targetState = screen) {
//                when(screen){
//                    "home" ->  ArtistCard()
//                    "tianqi"-> Text(text = "123")
//                }
//            }

        },
    )
}


@ExperimentalAnimationApi
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {

        HomeScreen()

}

总结

kotlin-Compose也学习1周,总体来说,给我的感觉是这样,给变量一个监听器–变量改变–包含变量函数重新加载–界面发生变化,这个优点是可以让布局多重嵌套又不影响性能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,出现了两个关于Kotlin的错误信息。第一个引用中显示了一个无法解析依赖的错误,指出无法下载kotlin-reflect.jar文件。第二个引用中显示了一个关于kotlin-gradle-1.8.10.jar (org.jetbrains.kotlin:kotlin-reflect)",这个错误通常是由于Gradle无法找到所需的kotlin-reflect库而引起的。解决这个问题的方法是确保你的项目的Gradle配置正确,并且指定了正确的Kotlin版本。 你可以尝试以下几个步骤来解决这个问题: 1. 确保你的项目的build.gradle文件中包含了正确的Kotlin版本和kotlin-gradle-plugin版本。你可以在build.gradle文件中找到类似于以下代码的部分: ```groovy ext { kotlin_version = '1.8.10' } dependencies { // ... implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" // ... } buildscript { // ... dependencies { // ... classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // ... } } ``` 请确保kotlin_version变量的值与你想要使用的Kotlin版本一致,并且在dependencies和buildscript的classpath中正确引用了kotlin-gradle-plugin。 2. 如果你已经确认了build.gradle文件中的配置正确无误,那么可能是因为Gradle无法从远程仓库下载kotlin-reflect.jar文件。你可以尝试清除Gradle的缓存并重新构建项目。在命令行中执行以下命令: ```shell ./gradlew clean ``` 然后重新构建项目: ```shell ./gradlew build ``` 这将清除Gradle的缓存并重新下载所需的依赖。 3. 如果上述步骤***切换到其他网络环境来解决这个问题。 希望以上步骤能够帮助你解决问题。如果你还有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值