活动海报轮播

master
pan 3 years ago
parent 6fef3d8097
commit cf2c48cc9e
  1. 128
      app/src/main/java/com/gyf/csams/ui/Base.kt
  2. 100
      app/src/main/java/com/gyf/csams/ui/MainActivity.kt
  3. 33
      app/src/main/java/com/gyf/csams/ui/model/MainViewModel.kt
  4. 72
      app/src/main/java/com/gyf/csams/ui/model/MarqueeViewModel.kt

@ -1,22 +1,29 @@
package com.gyf.csams.ui package com.gyf.csams.ui
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.compose.animation.Crossfade
import androidx.compose.animation.animateColor import androidx.compose.animation.animateColor
import androidx.compose.animation.core.* import androidx.compose.animation.core.*
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.fillMaxWidth
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.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
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.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController 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.model.CarouselViewModel
import com.gyf.csams.ui.model.MarqueeViewModel
import com.gyf.csams.ui.theme.CSAMSTheme import com.gyf.csams.ui.theme.CSAMSTheme
/** /**
@ -57,6 +64,14 @@ enum class MainMenu(@DrawableRes val selectedIcon:Int,
Center(R.drawable.ic_account_fill,R.drawable.ic_account) Center(R.drawable.ic_account_fill,R.drawable.ic_account)
} }
/**
* 底部菜单按钮
*
* @param _menu
* @param menu
* @param modifier
* @param onClick
*/
@Composable @Composable
fun MenuIconButton(_menu: MainMenu,menu: MainMenu,modifier: Modifier,onClick: () -> Unit){ fun MenuIconButton(_menu: MainMenu,menu: MainMenu,modifier: Modifier,onClick: () -> Unit){
Row(modifier = modifier Row(modifier = modifier
@ -70,8 +85,15 @@ fun MenuIconButton(_menu: MainMenu,menu: MainMenu,modifier: Modifier,onClick: ()
} }
} }
/**
* 底部菜单
*
* @param menu
* @param nav
* @param modifier
*/
@Composable @Composable
fun MyBottomAppBar(menu:MainMenu,nav: NavController,modifier: Modifier=Modifier){ fun MainBottomAppBar(menu:MainMenu, nav: NavController, modifier: Modifier=Modifier){
BottomAppBar(backgroundColor = Color.White,modifier=modifier) { BottomAppBar(backgroundColor = Color.White,modifier=modifier) {
//图标宽度平等分 //图标宽度平等分
@ -89,6 +111,102 @@ fun MyBottomAppBar(menu:MainMenu,nav: NavController,modifier: Modifier=Modifier)
} }
/**
* 跑马灯
*
* @param model
* @param content
*/
@Composable
fun Marquee(model: MarqueeViewModel = viewModel(), content: @Composable BoxScope.(model: MarqueeViewModel,
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)
}
}
}
}
@Composable
fun MarqueeText(model: MarqueeViewModel = viewModel(), offset: State<Float>) {
val poetryIndex: Int by model.marqueeIndex.observeAsState(0)
// Text(text = "$poetryIndex")
// Text(text = "offset.value=${offset.value}")
Text(
text = model.marqueeTexts[poetryIndex % model.marqueeTexts.size],
modifier = Modifier.offset(x = offset.value.dp),
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
/**
* 图片轮播
*
*/
@Composable
fun Carousel(
model: CarouselViewModel = viewModel(),
durationMillis: Int = 2000,
content: @Composable (id: Int) -> Unit
) {
val index: Int by model.index.observeAsState(0)
Crossfade(targetState = index, animationSpec = tween(durationMillis = durationMillis)) {
content(id = model.imageList[it])
}
}
@Preview
@Composable
fun CarouselPreview() {
val model = CarouselViewModel()
// ClubActivitiesImage(model = model)
Carousel(model = model) {
Card(
modifier = Modifier
.height(300.dp)
.fillMaxWidth()
// .rotate(180F)
) {
Image(
painter = painterResource(id = R.drawable.hot_activity_background),
contentDescription = null
)
Image(
painter = painterResource(id = it),
contentDescription = null
)
}
}
}
@Preview @Preview
@Composable @Composable
fun AnimationTextPreview(){ fun AnimationTextPreview(){
@ -101,7 +219,7 @@ fun MyBottomAppBarPreview(){
val nav= rememberNavController() val nav= rememberNavController()
CSAMSTheme { CSAMSTheme {
Surface(color = MaterialTheme.colors.background) { Surface(color = MaterialTheme.colors.background) {
MyBottomAppBar(menu = MainMenu.Main, nav = nav) MainBottomAppBar(menu = MainMenu.Main, nav = nav)
} }
} }
} }

@ -3,30 +3,26 @@ 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.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
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource 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.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel 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.model.CarouselViewModel
import com.gyf.csams.ui.model.MarqueeViewModel
import com.gyf.csams.ui.theme.CSAMSTheme import com.gyf.csams.ui.theme.CSAMSTheme
@ -63,7 +59,11 @@ 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)) MainBottomAppBar(
MainMenu.Main,
navController,
Modifier.rotate(180F)
)
ClubActivitiesImage() ClubActivitiesImage()
} }
} }
@ -72,7 +72,7 @@ fun Body() {
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)) MainBottomAppBar(MainMenu.List, navController, Modifier.rotate(180F))
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@ -88,7 +88,7 @@ fun Body() {
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)) MainBottomAppBar(MainMenu.Center, navController, Modifier.rotate(180F))
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@ -152,7 +152,7 @@ fun MyBorder(content: @Composable BoxScope.() -> Unit) {
* *
*/ */
@Composable @Composable
fun MessageBoard(model: MainViewModel= viewModel()) { fun MessageBoard(model: MarqueeViewModel = viewModel()) {
MyBorder { MyBorder {
Row( Row(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
@ -169,9 +169,11 @@ fun MessageBoard(model: MainViewModel= viewModel()) {
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
) { ) {
Marquee(model = model) { Marquee(model = model) { model, value ->
model, value -> TestA(model = model, MarqueeText(
offset = value) model = model,
offset = value
)
} }
} }
@ -208,7 +210,8 @@ fun ClubActivitiesTitle() {
* *
*/ */
@Composable @Composable
fun ClubActivitiesImage() { fun ClubActivitiesImage(model: CarouselViewModel = viewModel()) {
Carousel(model = model) {
Column(modifier = Modifier.fillMaxSize()) { Column(modifier = Modifier.fillMaxSize()) {
Card( Card(
modifier = Modifier modifier = Modifier
@ -235,25 +238,27 @@ fun ClubActivitiesImage() {
modifier = Modifier modifier = Modifier
.weight(0.6F) .weight(0.6F)
.fillMaxWidth() .fillMaxWidth()
.rotate(180F)
) { ) {
Image( Image(
painter = painterResource(id = R.drawable.hot_activity_background), painter = painterResource(id = R.drawable.hot_activity_background),
contentDescription = null contentDescription = null
) )
Image( Image(
painter = painterResource(id = R.drawable.ic_launcher_foreground), painter = painterResource(id = it),
contentDescription = null contentDescription = null
) )
}
} }
} }
} }
@Preview(showBackground = true) //@Preview(showBackground = true)
@Composable @Composable
fun DefaultPreview() { fun DefaultPreview() {
val model = MainViewModel() val model = MarqueeViewModel()
CSAMSTheme { CSAMSTheme {
Box(modifier = Modifier.fillMaxSize()) { Box(modifier = Modifier.fillMaxSize()) {
Column { Column {
@ -268,62 +273,3 @@ fun DefaultPreview() {
} }
@Composable
fun TestA(model: MainViewModel= viewModel(),offset:State<Float>){
val poetryIndex: Int by model.poetryIndex.observeAsState(0)
// 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
)
}
/**
* 轮播
*
*/
@Composable
fun Carousel(){
}
/**
* 跑马灯
*
* @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)
}
}
}
}

@ -1,33 +0,0 @@
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())
}
}
}
}

@ -0,0 +1,72 @@
package com.gyf.csams.ui.model
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.gyf.csams.R
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
/**
* 跑马灯
*
*/
class MarqueeViewModel:ViewModel() {
val marqueeTexts= listOf("床前明月光","疑是地上霜","举头望明月","低头思故乡")
private val _marqueeIndex=MutableLiveData(0)
var marqueeIndex:LiveData<Int> = _marqueeIndex
var marqueeJob:Job? = null
fun addAsync(delayMillis:Int){
if(marqueeJob == null || marqueeJob?.isCompleted==true) {
marqueeJob = viewModelScope.launch {
_marqueeIndex.postValue(
if (_marqueeIndex.value == marqueeTexts.size-1) 0 else _marqueeIndex.value?.plus(
1
)
)
delay(timeMillis = delayMillis.toLong())
}
}
}
}
class CarouselViewModel:ViewModel(){
val imageList= listOf(R.drawable.ic_launcher_foreground,R.drawable.ic_account_fill,R.drawable.ic_all_fill,R.drawable.ic_home_fill)
private val _index=MutableLiveData(0)
val index:LiveData<Int> = _index
var job:Job? = null
init {
start()
}
fun start(){
job = viewModelScope.launch {
do{
_index.postValue(if (_index.value==imageList.size-1) 0 else _index.value?.plus(1))
println("值更新为 :$_index")
delay(5000)
}while (job?.isActive==true)
}
}
fun stop(){
println("停止更新")
job?.cancel()
}
}
class MainViewModel:ViewModel(){
}
Loading…
Cancel
Save