Jetpack Compose 拖动效果
Compose 版本:1.0.0-beta08
效果
代码示例
- 列表页面
@Composable
fun VideoList() {
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.Gray)
.verticalScroll(rememberScrollState())
) {
for (i in 0..20) {
Card(modifier = Modifier.padding(10.dp)) {
Row(
modifier = Modifier
.background(Color.White)
.fillMaxWidth()
.height(70.dp)
) {
Box(
modifier = Modifier
.background(Color.DarkGray)
.fillMaxWidth(0.2f)
.fillMaxHeight()
)
Text(
text = "item $i",
color = Color.Black,
modifier = Modifier
.weight(0.8f)
.fillMaxHeight()
)
}
}
}
}
}
- 详情页面
@ExperimentalAnimationApi
@RequiresApi(Build.VERSION_CODES.R)
@Composable
fun PlayerPage() {
//拖动距离
val offsetY = remember {
mutableStateOf(0f)
}
//获取设备信息
val outMetrics = DisplayMetrics()
val display = LocalContext.current.display
display?.getRealMetrics(outMetrics)
val scale: Float = LocalContext.current.resources.displayMetrics.density
val deviceWidth = (outMetrics.widthPixels / scale + 0.5f).toInt().dp
val deviceHeight = (outMetrics.heightPixels / scale + 0.5f).toInt().dp
//关键帧
val keyframe0 = deviceHeight / 3
val keyframe1 = deviceHeight - playerHeight
//页面状态
val playerState = remember {
mutableStateOf(PlayerState.EXPAND)
}
//宽度变化
val widthAnim = animateDpAsState(
targetValue = when {
offsetY.value < keyframe1.value -> {
deviceWidth
}
else -> {
miniPlayerWidth
}
}
)
//高度变化
val heigtAnim = animateDpAsState(
targetValue = when {
offsetY.value < keyframe1.value -> {
playerState.value = PlayerState.HALF
(deviceHeight.value - offsetY.value).dp
}
else -> {
playerState.value = PlayerState.MINI
miniPlayerHeight
}
}
)
Column(
modifier = Modifier
.padding(if (playerState.value == PlayerState.MINI) 10.dp else 0.dp)
.height(heigtAnim.value)
.draggable(
state = rememberDraggableState {
offsetY.value += it
},
orientation = Orientation.Vertical,
onDragStopped = {
//停止时,根据拖动距离,改变状态
if (playerState.value == PlayerState.HALF) {
if (offsetY.value > keyframe0.value / 2) {
offsetY.value = keyframe0.value
} else {
offsetY.value = 0f
}
}
}
)
) {
Row(
horizontalArrangement = Arrangement.End,
modifier = Modifier
.background(Color.White)
.border(width = 1.dp, color = Color.Black)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Box(
modifier = Modifier
.background(Color.Black)
.height(playerHeight)
.width(widthAnim.value)
) {
Text(text = "Player", modifier = Modifier.align(Alignment.Center))
}
Text(text = "video 123", modifier = Modifier.weight(1f))
Icon(
imageVector = Icons.Default.PlayArrow,
contentDescription = null,
modifier = Modifier.weight(1f)
)
}
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
) {
Text(
text = "summary 123", modifier = Modifier
.padding(10.dp)
)
}
}
}
- 使用
val miniPlayerHeight = 50.dp
val miniPlayerWidth = 100.dp
val playerHeight = 350.dp
enum class PlayerState {
EXPAND, MINI, HALF
}
class MainActivity : ComponentActivity() {
@ExperimentalAnimationApi
@RequiresApi(Build.VERSION_CODES.R)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
PermissionTheme {
Surface(color = MaterialTheme.colors.background) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.BottomCenter
) {
VideoList()
PlayerPage()
}
}
}
}
}
}