diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 436d7b4..0ceb916 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -129,8 +129,6 @@ dependencies { kapt("androidx.room:room-compiler:${rootProject.extra["room_version"]}") // optional - Kotlin Extensions and Coroutines support for Room implementation("androidx.room:room-ktx:${rootProject.extra["room_version"]}") - // - implementation("androidx.constraintlayout:constraintlayout-compose:1.0.0-alpha03") // optional - Test helpers testImplementation("androidx.room:room-testing:${rootProject.extra["room_version"]}") //测试 diff --git a/app/src/main/java/com/gyf/csams/ui/Base.kt b/app/src/main/java/com/gyf/csams/ui/Base.kt index 869cc18..b0f1121 100644 --- a/app/src/main/java/com/gyf/csams/ui/Base.kt +++ b/app/src/main/java/com/gyf/csams/ui/Base.kt @@ -17,6 +17,7 @@ import androidx.navigation.NavController import androidx.navigation.compose.navigate import androidx.navigation.compose.rememberNavController import com.gyf.csams.R +import com.gyf.csams.ui.theme.CSAMSTheme /** * 淡入淡出并且颜色变化文本 @@ -71,7 +72,7 @@ fun MenuIconButton(_menu: MainMenu,menu: MainMenu,modifier: Modifier,onClick: () @Composable fun MyBottomAppBar(menu:MainMenu,nav: NavController,modifier: Modifier=Modifier){ - BottomAppBar(backgroundColor = Color.Transparent,modifier=modifier) { + BottomAppBar(backgroundColor = Color.White,modifier=modifier) { //图标宽度平等分 val weight=1/(MainMenu.values().size*1.0f) @@ -98,5 +99,9 @@ fun AnimationTextPreview(){ @Composable fun MyBottomAppBarPreview(){ val nav= rememberNavController() - MyBottomAppBar(menu = MainMenu.Main,nav=nav) + CSAMSTheme { + Surface(color = MaterialTheme.colors.background) { + MyBottomAppBar(menu = MainMenu.Main, nav = nav) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/gyf/csams/ui/MainActivity.kt b/app/src/main/java/com/gyf/csams/ui/MainActivity.kt index 72b8608..74f749f 100644 --- a/app/src/main/java/com/gyf/csams/ui/MainActivity.kt +++ b/app/src/main/java/com/gyf/csams/ui/MainActivity.kt @@ -3,13 +3,16 @@ package com.gyf.csams.ui import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.compose.animation.core.* import androidx.compose.foundation.Image -import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.rotate @@ -18,38 +21,40 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.constraintlayout.compose.ConstraintLayout +import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import com.gyf.csams.R +import com.gyf.csams.ui.model.MainViewModel import com.gyf.csams.ui.theme.CSAMSTheme + /** * 主界面 * */ -class MainActivity: ComponentActivity() { +class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { CSAMSTheme { - Body() + Body() } } } } @Composable -fun Body(){ +fun Body() { // A surface container using the 'background' color from the theme Surface(color = MaterialTheme.colors.background) { val navController = rememberNavController() val scaffoldState = rememberScaffoldState() - Scaffold(scaffoldState=scaffoldState) { + Scaffold(scaffoldState = scaffoldState) { NavHost(navController, startDestination = MainMenu.Main.name) { - composable(MainMenu.Main.name){ + composable(MainMenu.Main.name) { Box(modifier = Modifier.fillMaxSize()) { Column { Notification() @@ -58,35 +63,39 @@ fun Body(){ ClubActivitiesTitle() Spacer(modifier = Modifier.height(10.dp)) Column(Modifier.rotate(180F)) { - MyBottomAppBar(MainMenu.Main, navController,Modifier.rotate(180F)) + MyBottomAppBar(MainMenu.Main, navController, Modifier.rotate(180F)) ClubActivitiesImage() } } } } - composable(MainMenu.List.name){ + composable(MainMenu.List.name) { Box(modifier = Modifier.fillMaxSize()) { - Column(Modifier.rotate(180F)){ - MyBottomAppBar(MainMenu.List, navController,Modifier.rotate(180F)) - Row(modifier = Modifier - .fillMaxSize() - .rotate(180F), + Column(Modifier.rotate(180F)) { + MyBottomAppBar(MainMenu.List, navController, Modifier.rotate(180F)) + Row( + modifier = Modifier + .fillMaxSize() + .rotate(180F), horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically) { + verticalAlignment = Alignment.CenterVertically + ) { AnimationText(text = "社团列表") } } } } - composable(MainMenu.Center.name){ + composable(MainMenu.Center.name) { Box(modifier = Modifier.fillMaxSize()) { - Column(Modifier.rotate(180F)){ - MyBottomAppBar(MainMenu.Center, navController,Modifier.rotate(180F)) - Row(modifier = Modifier - .fillMaxSize() - .rotate(180F), + Column(Modifier.rotate(180F)) { + MyBottomAppBar(MainMenu.Center, navController, Modifier.rotate(180F)) + Row( + modifier = Modifier + .fillMaxSize() + .rotate(180F), horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically) { + verticalAlignment = Alignment.CenterVertically + ) { AnimationText(text = "个人中心") } } @@ -103,14 +112,18 @@ fun Body(){ * */ @Composable -fun Notification(){ - Row(horizontalArrangement = Arrangement.End, +fun Notification() { + Row( + horizontalArrangement = Arrangement.End, modifier = Modifier .fillMaxWidth() - .padding(10.dp)) { - Icon(painter = painterResource(id = R.drawable.ic_notification), + .padding(10.dp) + ) { + Icon( + painter = painterResource(id = R.drawable.ic_notification), contentDescription = null, - modifier = Modifier.size(50.dp)) + modifier = Modifier.size(50.dp) + ) } } @@ -119,12 +132,16 @@ fun Notification(){ * */ @Composable -fun MyBorder(content: @Composable BoxScope.() -> Unit){ +fun MyBorder(content: @Composable BoxScope.() -> Unit) { Box(modifier = Modifier.padding(horizontal = 15.dp)) { Box( modifier = Modifier - .border(width = 1.dp, color = Color.Black, shape = RoundedCornerShape(size = 20.dp)), - ){ + .border( + width = 1.dp, + color = Color.Black, + shape = RoundedCornerShape(size = 20.dp) + ), + ) { content() } } @@ -135,25 +152,27 @@ fun MyBorder(content: @Composable BoxScope.() -> Unit){ * */ @Composable -fun MessageBoard() { +fun MessageBoard(model: MainViewModel= viewModel()) { MyBorder { - Row(modifier = Modifier.rotate(180F), - verticalAlignment = Alignment.CenterVertically) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { Icon( painter = painterResource(id = R.drawable.ic_comments), contentDescription = null, modifier = Modifier .size(50.dp) - .rotate(180F) ) Row( horizontalArrangement = Arrangement.Center, modifier = Modifier .fillMaxWidth() - .rotate(180F) ) { - Text(text = "跑马灯留言") + Marquee(model = model) { + model, value -> TestA(model = model, + offset = value) + } } } @@ -165,7 +184,7 @@ fun MessageBoard() { * */ @Composable -fun ClubActivitiesTitle(){ +fun ClubActivitiesTitle() { MyBorder { Row( modifier = Modifier @@ -174,10 +193,12 @@ fun ClubActivitiesTitle(){ horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { - Text(text = "超级课程表X滴滴出行-了不起的社团", + Text( + text = "超级课程表X滴滴出行-了不起的社团", style = MaterialTheme.typography.h6, overflow = TextOverflow.Ellipsis, - maxLines = 1) + maxLines = 1 + ) } } } @@ -187,60 +208,122 @@ fun ClubActivitiesTitle(){ * */ @Composable -fun ClubActivitiesImage(){ - Column(modifier=Modifier.fillMaxSize()) { - Card(modifier = Modifier - .weight(0.4f) - .fillMaxWidth()) { - Image(painter = painterResource(id = R.drawable.hot_activity_desc_background), - contentDescription = null) - Box(modifier = Modifier +fun ClubActivitiesImage() { + Column(modifier = Modifier.fillMaxSize()) { + Card( + modifier = Modifier + .weight(0.4F) + .fillMaxWidth() + ) { + Image( + painter = painterResource(id = R.drawable.hot_activity_desc_background), + contentDescription = null + ) + Box( + modifier = Modifier .padding(horizontal = 85.dp, vertical = 30.dp) - .rotate(180F)){ - Text(text = "文字对任何界面都属于核心内容,而利用 Jetpack Compose 可以更轻松地显示或写入文字。Compose 可以充分利用其构建块的组合,这意味着您无需覆盖各种属性和方法,也无需扩展大型类,即可拥有特定的可组合项设计以及按您期望的方式运行的逻辑。" - .repeat(10),overflow = TextOverflow.Ellipsis) - } - + .rotate(180F) + ) { + Text( + text = "文字对任何界面都属于核心内容,而利用 Jetpack Compose 可以更轻松地显示或写入文字。Compose 可以充分利用其构建块的组合,这意味着您无需覆盖各种属性和方法,也无需扩展大型类,即可拥有特定的可组合项设计以及按您期望的方式运行的逻辑。" + .repeat(10), overflow = TextOverflow.Ellipsis + ) } - Card(modifier = Modifier - .weight(0.6f) - .fillMaxWidth()) { - Image(painter = painterResource(id = R.drawable.hot_activity_background), - contentDescription = null) - Image(painter = painterResource(id = R.drawable.ic_launcher_foreground), - contentDescription = null) + + } + Card( + modifier = Modifier + .weight(0.6F) + .fillMaxWidth() + ) { + Image( + painter = painterResource(id = R.drawable.hot_activity_background), + contentDescription = null + ) + Image( + painter = painterResource(id = R.drawable.ic_launcher_foreground), + contentDescription = null + ) } } } -//@Preview(showBackground = true) + +@Preview(showBackground = true) @Composable fun DefaultPreview() { + val model = MainViewModel() CSAMSTheme { Box(modifier = Modifier.fillMaxSize()) { Column { - ClubActivitiesImage() +// Marquee(model = model) { +// model, value -> TestA(model = model, +// offset = value) +// } + MessageBoard(model = model) } } } } -@Preview + + + @Composable -fun ConstraintLayoutContent() { - Box(modifier = Modifier.background(Color.Cyan)) { - ConstraintLayout { - // Create references for the composables to constrain - val (button, text,text2,box) = createRefs() +fun TestA(model: MainViewModel= viewModel(),offset:State){ + val poetryIndex: Int by model.poetryIndex.observeAsState(0) - Box(Modifier.fillMaxSize()) +// Text(text = "$poetryIndex") +// Text(text = "offset.value=${offset.value}") + Text( + text = model.poetry[poetryIndex % model.poetry.size], + modifier = Modifier.offset(x = offset.value.dp), + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) - Box(Modifier.size(50.dp).background(Color.Red).constrainAs(box){ - bottom.linkTo(parent.bottom) +} + +/** + * 轮播 + * + */ +@Composable +fun Carousel(){ - end.linkTo(parent.end) - }) +} + +/** + * 跑马灯 + * + * @param model + * @param content + */ +@Composable +fun Marquee(model: MainViewModel= viewModel(),content: @Composable BoxScope.(model:MainViewModel, + value:State) -> Unit) { + + val delayMillis=2000 + Column { + BoxWithConstraints { + val transition = rememberInfiniteTransition() + val maxWidth = maxWidth + 30.dp + val offset = transition.animateFloat( + initialValue = 0F, + targetValue = maxWidth.value, + animationSpec = infiniteRepeatable( + animation = tween(durationMillis = 3000,delayMillis = delayMillis), + repeatMode = RepeatMode.Restart + ) + ) + Box(modifier = Modifier.fillMaxWidth()) { + content(model=model,value=offset) + } + + if (offset.value.toInt() == maxWidth.value.toInt()) { + model.addAsync(delayMillis = delayMillis) + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/gyf/csams/ui/model/MainViewModel.kt b/app/src/main/java/com/gyf/csams/ui/model/MainViewModel.kt new file mode 100644 index 0000000..6f7cf2a --- /dev/null +++ b/app/src/main/java/com/gyf/csams/ui/model/MainViewModel.kt @@ -0,0 +1,33 @@ +package com.gyf.csams.ui.model + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch + + +class MainViewModel:ViewModel() { + val poetry= listOf("床前明月光","疑是地上霜","举头望明月","低头思故乡") + + private val _poetryIndex=MutableLiveData(0) + var poetryIndex:LiveData = _poetryIndex + var job:Job? = null + + + fun addAsync(delayMillis:Int){ + if(job == null || job?.isCompleted==true) { + job = viewModelScope.launch { + _poetryIndex.postValue( + if (_poetryIndex.value == poetry.size-1) 0 else _poetryIndex.value?.plus( + 1 + ) + ) + delay(timeMillis = delayMillis.toLong()) + } + } + + } +} \ No newline at end of file