活动海报轮播

master
pan 4 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
import androidx.annotation.DrawableRes
import androidx.compose.animation.Crossfade
import androidx.compose.animation.animateColor
import androidx.compose.animation.core.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.*
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.Modifier
import androidx.compose.ui.graphics.Color
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.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import androidx.navigation.compose.navigate
import androidx.navigation.compose.rememberNavController
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
/**
@ -57,6 +64,14 @@ enum class MainMenu(@DrawableRes val selectedIcon:Int,
Center(R.drawable.ic_account_fill,R.drawable.ic_account)
}
/**
* 底部菜单按钮
*
* @param _menu
* @param menu
* @param modifier
* @param onClick
*/
@Composable
fun MenuIconButton(_menu: MainMenu,menu: MainMenu,modifier: Modifier,onClick: () -> Unit){
Row(modifier = modifier
@ -70,8 +85,15 @@ fun MenuIconButton(_menu: MainMenu,menu: MainMenu,modifier: Modifier,onClick: ()
}
}
/**
* 底部菜单
*
* @param menu
* @param nav
* @param modifier
*/
@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) {
//图标宽度平等分
@ -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
@Composable
fun AnimationTextPreview(){
@ -101,7 +219,7 @@ fun MyBottomAppBarPreview(){
val nav= rememberNavController()
CSAMSTheme {
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 androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.core.*
import androidx.compose.foundation.Image
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
import androidx.compose.ui.graphics.Color
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.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.model.CarouselViewModel
import com.gyf.csams.ui.model.MarqueeViewModel
import com.gyf.csams.ui.theme.CSAMSTheme
@ -63,7 +59,11 @@ fun Body() {
ClubActivitiesTitle()
Spacer(modifier = Modifier.height(10.dp))
Column(Modifier.rotate(180F)) {
MyBottomAppBar(MainMenu.Main, navController, Modifier.rotate(180F))
MainBottomAppBar(
MainMenu.Main,
navController,
Modifier.rotate(180F)
)
ClubActivitiesImage()
}
}
@ -72,7 +72,7 @@ fun Body() {
composable(MainMenu.List.name) {
Box(modifier = Modifier.fillMaxSize()) {
Column(Modifier.rotate(180F)) {
MyBottomAppBar(MainMenu.List, navController, Modifier.rotate(180F))
MainBottomAppBar(MainMenu.List, navController, Modifier.rotate(180F))
Row(
modifier = Modifier
.fillMaxSize()
@ -88,7 +88,7 @@ fun Body() {
composable(MainMenu.Center.name) {
Box(modifier = Modifier.fillMaxSize()) {
Column(Modifier.rotate(180F)) {
MyBottomAppBar(MainMenu.Center, navController, Modifier.rotate(180F))
MainBottomAppBar(MainMenu.Center, navController, Modifier.rotate(180F))
Row(
modifier = Modifier
.fillMaxSize()
@ -152,7 +152,7 @@ fun MyBorder(content: @Composable BoxScope.() -> Unit) {
*
*/
@Composable
fun MessageBoard(model: MainViewModel= viewModel()) {
fun MessageBoard(model: MarqueeViewModel = viewModel()) {
MyBorder {
Row(
verticalAlignment = Alignment.CenterVertically
@ -169,9 +169,11 @@ fun MessageBoard(model: MainViewModel= viewModel()) {
modifier = Modifier
.fillMaxWidth()
) {
Marquee(model = model) {
model, value -> TestA(model = model,
offset = value)
Marquee(model = model) { model, value ->
MarqueeText(
model = model,
offset = value
)
}
}
@ -208,7 +210,8 @@ fun ClubActivitiesTitle() {
*
*/
@Composable
fun ClubActivitiesImage() {
fun ClubActivitiesImage(model: CarouselViewModel = viewModel()) {
Carousel(model = model) {
Column(modifier = Modifier.fillMaxSize()) {
Card(
modifier = Modifier
@ -235,25 +238,27 @@ fun ClubActivitiesImage() {
modifier = Modifier
.weight(0.6F)
.fillMaxWidth()
.rotate(180F)
) {
Image(
painter = painterResource(id = R.drawable.hot_activity_background),
contentDescription = null
)
Image(
painter = painterResource(id = R.drawable.ic_launcher_foreground),
painter = painterResource(id = it),
contentDescription = null
)
}
}
}
}
@Preview(showBackground = true)
//@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
val model = MainViewModel()
val model = MarqueeViewModel()
CSAMSTheme {
Box(modifier = Modifier.fillMaxSize()) {
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