留言板实现跑马灯效果

master
pan 3 years ago
parent 890af8cfcd
commit 6fef3d8097
  1. 2
      app/build.gradle.kts
  2. 9
      app/src/main/java/com/gyf/csams/ui/Base.kt
  3. 227
      app/src/main/java/com/gyf/csams/ui/MainActivity.kt
  4. 33
      app/src/main/java/com/gyf/csams/ui/model/MainViewModel.kt

@ -129,8 +129,6 @@ dependencies {
kapt("androidx.room:room-compiler:${rootProject.extra["room_version"]}") kapt("androidx.room:room-compiler:${rootProject.extra["room_version"]}")
// optional - Kotlin Extensions and Coroutines support for Room // optional - Kotlin Extensions and Coroutines support for Room
implementation("androidx.room:room-ktx:${rootProject.extra["room_version"]}") implementation("androidx.room:room-ktx:${rootProject.extra["room_version"]}")
//
implementation("androidx.constraintlayout:constraintlayout-compose:1.0.0-alpha03")
// optional - Test helpers // optional - Test helpers
testImplementation("androidx.room:room-testing:${rootProject.extra["room_version"]}") testImplementation("androidx.room:room-testing:${rootProject.extra["room_version"]}")
//测试 //测试

@ -17,6 +17,7 @@ import androidx.navigation.NavController
import androidx.navigation.compose.navigate import androidx.navigation.compose.navigate
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.gyf.csams.R 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 @Composable
fun MyBottomAppBar(menu:MainMenu,nav: NavController,modifier: Modifier=Modifier){ 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) val weight=1/(MainMenu.values().size*1.0f)
@ -98,5 +99,9 @@ fun AnimationTextPreview(){
@Composable @Composable
fun MyBottomAppBarPreview(){ fun MyBottomAppBarPreview(){
val nav= rememberNavController() val nav= rememberNavController()
MyBottomAppBar(menu = MainMenu.Main,nav=nav) CSAMSTheme {
Surface(color = MaterialTheme.colors.background) {
MyBottomAppBar(menu = MainMenu.Main, nav = nav)
}
}
} }

@ -3,13 +3,16 @@ package com.gyf.csams.ui
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.compose.animation.core.*
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.* import androidx.compose.material.*
import androidx.compose.runtime.Composable 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.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate 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.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp 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.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.gyf.csams.R import com.gyf.csams.R
import com.gyf.csams.ui.model.MainViewModel
import com.gyf.csams.ui.theme.CSAMSTheme import com.gyf.csams.ui.theme.CSAMSTheme
/** /**
* 主界面 * 主界面
* *
*/ */
class MainActivity: ComponentActivity() { class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
CSAMSTheme { CSAMSTheme {
Body() Body()
} }
} }
} }
} }
@Composable @Composable
fun Body(){ fun Body() {
// A surface container using the 'background' color from the theme // A surface container using the 'background' color from the theme
Surface(color = MaterialTheme.colors.background) { Surface(color = MaterialTheme.colors.background) {
val navController = rememberNavController() val navController = rememberNavController()
val scaffoldState = rememberScaffoldState() val scaffoldState = rememberScaffoldState()
Scaffold(scaffoldState=scaffoldState) { Scaffold(scaffoldState = scaffoldState) {
NavHost(navController, startDestination = MainMenu.Main.name) { NavHost(navController, startDestination = MainMenu.Main.name) {
composable(MainMenu.Main.name){ composable(MainMenu.Main.name) {
Box(modifier = Modifier.fillMaxSize()) { Box(modifier = Modifier.fillMaxSize()) {
Column { Column {
Notification() Notification()
@ -58,35 +63,39 @@ fun Body(){
ClubActivitiesTitle() ClubActivitiesTitle()
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
Column(Modifier.rotate(180F)) { Column(Modifier.rotate(180F)) {
MyBottomAppBar(MainMenu.Main, navController,Modifier.rotate(180F)) MyBottomAppBar(MainMenu.Main, navController, Modifier.rotate(180F))
ClubActivitiesImage() ClubActivitiesImage()
} }
} }
} }
} }
composable(MainMenu.List.name){ composable(MainMenu.List.name) {
Box(modifier = Modifier.fillMaxSize()) { Box(modifier = Modifier.fillMaxSize()) {
Column(Modifier.rotate(180F)){ Column(Modifier.rotate(180F)) {
MyBottomAppBar(MainMenu.List, navController,Modifier.rotate(180F)) MyBottomAppBar(MainMenu.List, navController, Modifier.rotate(180F))
Row(modifier = Modifier Row(
.fillMaxSize() modifier = Modifier
.rotate(180F), .fillMaxSize()
.rotate(180F),
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically) { verticalAlignment = Alignment.CenterVertically
) {
AnimationText(text = "社团列表") AnimationText(text = "社团列表")
} }
} }
} }
} }
composable(MainMenu.Center.name){ composable(MainMenu.Center.name) {
Box(modifier = Modifier.fillMaxSize()) { Box(modifier = Modifier.fillMaxSize()) {
Column(Modifier.rotate(180F)){ Column(Modifier.rotate(180F)) {
MyBottomAppBar(MainMenu.Center, navController,Modifier.rotate(180F)) MyBottomAppBar(MainMenu.Center, navController, Modifier.rotate(180F))
Row(modifier = Modifier Row(
.fillMaxSize() modifier = Modifier
.rotate(180F), .fillMaxSize()
.rotate(180F),
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically) { verticalAlignment = Alignment.CenterVertically
) {
AnimationText(text = "个人中心") AnimationText(text = "个人中心")
} }
} }
@ -103,14 +112,18 @@ fun Body(){
* *
*/ */
@Composable @Composable
fun Notification(){ fun Notification() {
Row(horizontalArrangement = Arrangement.End, Row(
horizontalArrangement = Arrangement.End,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(10.dp)) { .padding(10.dp)
Icon(painter = painterResource(id = R.drawable.ic_notification), ) {
Icon(
painter = painterResource(id = R.drawable.ic_notification),
contentDescription = null, contentDescription = null,
modifier = Modifier.size(50.dp)) modifier = Modifier.size(50.dp)
)
} }
} }
@ -119,12 +132,16 @@ fun Notification(){
* *
*/ */
@Composable @Composable
fun MyBorder(content: @Composable BoxScope.() -> Unit){ fun MyBorder(content: @Composable BoxScope.() -> Unit) {
Box(modifier = Modifier.padding(horizontal = 15.dp)) { Box(modifier = Modifier.padding(horizontal = 15.dp)) {
Box( Box(
modifier = Modifier 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() content()
} }
} }
@ -135,25 +152,27 @@ fun MyBorder(content: @Composable BoxScope.() -> Unit){
* *
*/ */
@Composable @Composable
fun MessageBoard() { fun MessageBoard(model: MainViewModel= viewModel()) {
MyBorder { MyBorder {
Row(modifier = Modifier.rotate(180F), Row(
verticalAlignment = Alignment.CenterVertically) { verticalAlignment = Alignment.CenterVertically
) {
Icon( Icon(
painter = painterResource(id = R.drawable.ic_comments), painter = painterResource(id = R.drawable.ic_comments),
contentDescription = null, contentDescription = null,
modifier = Modifier modifier = Modifier
.size(50.dp) .size(50.dp)
.rotate(180F)
) )
Row( Row(
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.rotate(180F)
) { ) {
Text(text = "跑马灯留言") Marquee(model = model) {
model, value -> TestA(model = model,
offset = value)
}
} }
} }
@ -165,7 +184,7 @@ fun MessageBoard() {
* *
*/ */
@Composable @Composable
fun ClubActivitiesTitle(){ fun ClubActivitiesTitle() {
MyBorder { MyBorder {
Row( Row(
modifier = Modifier modifier = Modifier
@ -174,10 +193,12 @@ fun ClubActivitiesTitle(){
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Text(text = "超级课程表X滴滴出行-了不起的社团", Text(
text = "超级课程表X滴滴出行-了不起的社团",
style = MaterialTheme.typography.h6, style = MaterialTheme.typography.h6,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
maxLines = 1) maxLines = 1
)
} }
} }
} }
@ -187,60 +208,122 @@ fun ClubActivitiesTitle(){
* *
*/ */
@Composable @Composable
fun ClubActivitiesImage(){ fun ClubActivitiesImage() {
Column(modifier=Modifier.fillMaxSize()) { Column(modifier = Modifier.fillMaxSize()) {
Card(modifier = Modifier Card(
.weight(0.4f) modifier = Modifier
.fillMaxWidth()) { .weight(0.4F)
Image(painter = painterResource(id = R.drawable.hot_activity_desc_background), .fillMaxWidth()
contentDescription = null) ) {
Box(modifier = Modifier Image(
painter = painterResource(id = R.drawable.hot_activity_desc_background),
contentDescription = null
)
Box(
modifier = Modifier
.padding(horizontal = 85.dp, vertical = 30.dp) .padding(horizontal = 85.dp, vertical = 30.dp)
.rotate(180F)){ .rotate(180F)
Text(text = "文字对任何界面都属于核心内容,而利用 Jetpack Compose 可以更轻松地显示或写入文字。Compose 可以充分利用其构建块的组合,这意味着您无需覆盖各种属性和方法,也无需扩展大型类,即可拥有特定的可组合项设计以及按您期望的方式运行的逻辑。" ) {
.repeat(10),overflow = TextOverflow.Ellipsis) Text(
} text = "文字对任何界面都属于核心内容,而利用 Jetpack Compose 可以更轻松地显示或写入文字。Compose 可以充分利用其构建块的组合,这意味着您无需覆盖各种属性和方法,也无需扩展大型类,即可拥有特定的可组合项设计以及按您期望的方式运行的逻辑。"
.repeat(10), overflow = TextOverflow.Ellipsis
)
} }
Card(modifier = Modifier
.weight(0.6f) }
.fillMaxWidth()) { Card(
Image(painter = painterResource(id = R.drawable.hot_activity_background), modifier = Modifier
contentDescription = null) .weight(0.6F)
Image(painter = painterResource(id = R.drawable.ic_launcher_foreground), .fillMaxWidth()
contentDescription = null) ) {
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 @Composable
fun DefaultPreview() { fun DefaultPreview() {
val model = MainViewModel()
CSAMSTheme { CSAMSTheme {
Box(modifier = Modifier.fillMaxSize()) { Box(modifier = Modifier.fillMaxSize()) {
Column { Column {
ClubActivitiesImage() // Marquee(model = model) {
// model, value -> TestA(model = model,
// offset = value)
// }
MessageBoard(model = model)
} }
} }
} }
} }
@Preview
@Composable @Composable
fun ConstraintLayoutContent() { fun TestA(model: MainViewModel= viewModel(),offset:State<Float>){
Box(modifier = Modifier.background(Color.Cyan)) { val poetryIndex: Int by model.poetryIndex.observeAsState(0)
ConstraintLayout {
// Create references for the composables to constrain
val (button, text,text2,box) = createRefs()
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<Float>) -> 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)
}
} }
} }
} }

@ -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<Int> = _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())
}
}
}
}
Loading…
Cancel
Save