留言板实现跑马灯效果

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"]}")
// 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"]}")
//测试

@ -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)
}
}
}

@ -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<Float>){
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<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