• 《Jetpack Compose从入门到实战》第九章 Accompanist 与第三方组件库


    在这里插入图片描述

    Accompanist

    SystemUiController

    • 依赖:implementation “com.google.accompanist:accompanist-systemuicontroller:
    @Composable
    fun SystemUiTest() {
        Box(modifier = Modifier.fillMaxSize()) {
    
            val systemUiController = rememberSystemUiController()
            val useDarkIcons = MaterialTheme.colors.isLight
            SideEffect {
                systemUiController.setSystemBarsColor(color = Color.Transparent, darkIcons = useDarkIcons)
            }
    //        TopAppBar(title = { Text(text = "TopAppBar") }, modifier = Modifier.statusBarsPadding(), backgroundColor = Color.Gray)
            //使用com.google.accompanist:accompanist-insets-ui:0.30.1 实现沉浸式状态栏的效果
            TopAppBar(title = { Text(text = "TopAppBar") }, backgroundColor = Color.Gray, contentPadding = WindowInsets.statusBars.asPaddingValues())
    
        }
    }
    @Composable
    fun SystemUiControllerDemo() {
        val systemUiController = rememberSystemUiController()
        val useDarkIcons = MaterialTheme.colors.isLight
    
        val colorPanel = listOf(
            Color.Gray,
            Color.Red,
            Color.Black,
            Color.Cyan,
            Color.Transparent,
            Color.DarkGray,
            Color.LightGray,
            Color.Yellow
        )
    
        SideEffect {
            systemUiController.setSystemBarsColor(Color.Transparent, useDarkIcons)
        }
        Column(Modifier.systemBarsPadding().fillMaxSize().background(Color(0xFF0079D3))) {
            colorPanel.forEach {
                Box(
                    modifier = Modifier
                        .fillMaxWidth()
                        .height(48.dp)
                        .background(it)
                        .clickable {
                            systemUiController.setSystemBarsColor(it, useDarkIcons)
                        }
                )
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 略直接设置状态栏和底部导航栏颜色的方法

    Pager

    • implementation “com.google.accompanist:accompanist-pager:$accompanist_version”
    @OptIn(ExperimentalFoundationApi::class)
    @Composable
    fun PagerTest() {
        Box(modifier = Modifier.fillMaxSize()) {
            val pagerState = rememberPagerState()
            val scope = rememberCoroutineScope()
            HorizontalPager(pageCount = 3, modifier = Modifier.fillMaxSize(), state = pagerState) { page ->
                when (page) {
                    0 -> ColorBox(color = Color.Blue, pageIndex = page)
                    1 -> ColorBox(color = Color.Cyan, pageIndex = page)
                    2 -> ColorBox(color = Color.Magenta, pageIndex = page)
                }
            }
            SideEffect {
                scope.launch {
                    delay(3000)
                    pagerState.scrollToPage(2)
                }
            }
        }
    }
    
    @Composable
    fun ColorBox(color: Color, pageIndex: Int) {
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(color = color), contentAlignment = Alignment.Center
        ) {
            Text(text = "page $pageIndex")
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 略直接跳转到某个页面的方法
    @OptIn(ExperimentalPagerApi::class)
    @Composable
    fun PagerDemo() {
    
        val pagerState = rememberPagerState()
        val scope = rememberCoroutineScope()
        var selectedScreens by remember { mutableStateOf(0) }
    
        val screens = listOf(
            Screens("首页", Icons.Filled.Home) { Home() },
            Screens("我喜欢的", Icons.Filled.Favorite) { Favorite() },
            Screens("设置", Icons.Filled.Settings) { Settings() }
        )
    
        Scaffold(
            bottomBar = {
                BottomNavigationBar(
                    selectedScreens,
                    screens,
                    onClick = {
                        selectedScreens = it
                        scope.launch { pagerState.scrollToPage(selectedScreens) }
                    }
                )
            }
        ) {
            HorizontalPager(
                count = screens.size,
                modifier = Modifier.fillMaxSize(),
                state = pagerState
            ) { page ->
                screens.forEachIndexed { index, screens ->
                    when (page) {
                        index -> screens.content()
                    }
                }
            }
        }
    
        LaunchedEffect(pagerState) {
            snapshotFlow { pagerState.currentPage }.collect { page ->
                selectedScreens = page
            }
        }
    
    }
    
    @Composable
    fun Home() {
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(Color.Gray),
            contentAlignment = Alignment.Center
        ) {
            Text(
                text = "1. 首页🤭",
                style = MaterialTheme.typography.h5
            )
        }
    }
    
    @Composable
    fun Favorite() {
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(Color(0xFFF8F8F8)),
            contentAlignment = Alignment.Center
        ) {
            Text(
                text = "2. 我喜欢的❤",
                style = MaterialTheme.typography.h5
            )
        }
    }
    @Composable
    fun Settings() {
        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center
        ) {
            Text(
                text = "3. 设置⚙",
                style = MaterialTheme.typography.h5
            )
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    @Composable
    fun BottomNavigationBar(
        selectedScreen: Int,
        screens: List<Screens>,
        onClick: (targetIndex: Int) -> Unit
    ) {
        NavigationBar {
            screens.forEachIndexed { index, screen ->
                NavigationBarItem(
                    icon = { Icon(screen.iconVector, contentDescription = null) },
                    label = { Text(screen.label) },
                    selected = selectedScreen == index,
                    onClick = { onClick(index) }
                )
            }
        }
    }
    
    data class Screens(
        val label: String,
        val iconVector: ImageVector,
        val content: @Composable () -> Unit
    )
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    SwipeRefresh

    • implementation “com.google.accompanist:accompanist-swiperefresh:$accompanist_version”
    @Preview
    @OptIn(ExperimentalMaterialApi::class)
    @Composable
    fun SwipeRefreshTest() {
        Box(modifier = Modifier.fillMaxSize()) {
            val viewModel: MyViewModel = viewModel()
            val isRefreshing by viewModel.isRefreshing.collectAsState()
            val background by animateColorAsState(targetValue = viewModel.background, animationSpec = tween(1000), label = "backgroundAnim")
            /* SwipeRefresh(state = rememberSwipeRefreshState(isRefreshing), onRefresh = { viewModel.refresh() }) {
                 Box(
                     modifier = Modifier
                         .fillMaxSize()
                         .verticalScroll(rememberScrollState())
                         .background(background)
                 )
             }*/
            val pullRefreshState = rememberPullRefreshState(refreshing = isRefreshing, onRefresh = { viewModel.refresh() })
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .pullRefresh(pullRefreshState)
                    .verticalScroll(rememberScrollState())
                    .background(background),
            ) {
                PullRefreshIndicator(isRefreshing, pullRefreshState, modifier = Modifier.align(Alignment.TopCenter))
            }
        }
    }
    
    class MyViewModel : ViewModel() {
        private val _isRefreshing = MutableStateFlow(false)
        private val colorPanel = listOf(Color.Gray, Color.Red, Color.Black, Color.Cyan, Color.DarkGray, Color.LightGray, Color.Yellow)
        val isRefreshing: StateFlow<Boolean>
            get() = _isRefreshing
    
        var background by mutableStateOf(Color.Gray)
    
        fun refresh() {
            viewModelScope.launch {
                _isRefreshing.emit(true)
                delay(1000)
                background = colorPanel.random()
                _isRefreshing.emit(false)
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    Flow Layout

    • 会自动换行的row和Column
    • implementation “com.google.accompanist:accompanist-flowlayout:$accompanist_version”
    @OptIn(ExperimentalLayoutApi::class)
    @Composable
    fun FlowLayoutTest() {
        Column(modifier = Modifier.fillMaxSize()) {
            FlowRow(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly, verticalAlignment = Alignment.CenterVertically, maxItemsInEachRow = 3) {
                Text(text = "text1")
                Text(text = "text2")
                Text(text = "text3")
                Text(text = "text4")
                Text(text = "text5")
                Text(text = "text6")
            }
            Divider(modifier = Modifier.fillMaxWidth())
            FlowColumn(modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.SpaceEvenly, horizontalAlignment = Alignment.CenterHorizontally, maxItemsInEachColumn = 3) {
                Text(text = "text1")
                Text(text = "text2")
                Text(text = "text3")
                Text(text = "text4")
                Text(text = "text5")
                Text(text = "text6")
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    @Composable
    fun Tag(
        modifier: Modifier = Modifier,
        shape: Shape = CircleShape,
        elevation: Dp = 0.dp,
        leadingIcon: @Composable (() -> Unit)? = null,
        trailingIcon: @Composable (() -> Unit)? = null,
        text: String,
        textStyle: TextStyle = TextStyle(
            fontWeight = FontWeight.Normal,
            fontSize = 16.sp,
            letterSpacing = 0.15.sp
        ),
        backgroundColor: Color = Color(0xFFE8E8E8),
        border: BorderStroke? = null,
        onClick:() -> Unit
    ){
    
        Surface(
            shape = shape,
            color = backgroundColor,
            modifier = modifier,
            elevation = elevation,
            border = border
        ) {
            Row(
                modifier = Modifier
                    .clickable(
                        onClick = onClick
                    )
                    .padding(start = 15.dp, end = 15.dp, top = 8.dp, bottom = 8.dp),
                verticalAlignment = Alignment.CenterVertically,
            ) {
                when{
                    leadingIcon != null -> {
                        CompositionLocalProvider(
                            LocalContentAlpha provides ContentAlpha.high,
                            content = leadingIcon
                        )
                        Spacer(Modifier.padding(horizontal = 4.dp))
                        Text(
                            text = text,
                            style = textStyle,
                        )
                    }
                    trailingIcon != null -> {
                        Text(
                            text = text,
                            style = textStyle,
                        )
                        Spacer(Modifier.padding(horizontal = 4.dp))
                        CompositionLocalProvider(
                            LocalContentAlpha provides ContentAlpha.high,
                            content = trailingIcon
                        )
                    }
                    else -> {
                        Text(
                            text = text,
                            style = textStyle,
                        )
                    }
                }
            }
        }
    }
    
    @Composable
    fun FlowLayoutDemo() {
        Surface(
            modifier = Modifier
                .systemBarsPadding()
                .fillMaxWidth(),
            elevation = 8.dp
        ) {
            FlowRow(
                modifier = Modifier.padding(8.dp),
                crossAxisSpacing = 12.dp,
                mainAxisSpacing = 10.dp
            ) {
                Tag(
                    leadingIcon = {
                        Icon(painterResource(id = R.drawable.wechat), null, tint = Color.White)
                    },
                    text = "WeChat",
                    elevation = 6.dp,
                    textStyle = TextStyle(Color.White),
                    backgroundColor = Color(0xFF07C160)
                ) { }
                Tag(
                    leadingIcon = {
                        Icon(painterResource(id = R.drawable.twitter), null, tint = Color.White)
                    },
                    text = "Twitter",
                    elevation = 6.dp,
                    textStyle = TextStyle(Color.White),
                    backgroundColor = Color(0xFF1DA1F2)
                ) { }
                Tag(
                    leadingIcon = {
                        Icon(painterResource(id = R.drawable.github), null, tint = Color.White)
                    },
                    text = "Github",
                    elevation = 6.dp,
                    textStyle = TextStyle(Color.White),
                    backgroundColor = Color(0xFF181717)
                ) { }
                Tag(
                    leadingIcon = {
                        Icon(painterResource(id = R.drawable.microsoftedge), null, tint = Color(0xFF0078D7))
                    },
                    text = "Edge",
                    elevation = 6.dp
                ) { }
                Tag(
                    leadingIcon = {
                        Icon(painterResource(id = R.drawable.microsoft), null, tint = Color(0xFF5E5E5E))
                    },
                    text = "Microsoft",
                    elevation = 6.dp
                ) { }
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125

    Insets

    • implementation “com.google.accompanist:accompanis-inss-ui:
    @Composable
    fun InsetsDemo() {
        val systemUiController = rememberSystemUiController()
        val useDarkIcons = MaterialTheme.colors.isLight
    
        SideEffect {
            systemUiController.setSystemBarsColor(Color.Transparent, useDarkIcons)
        }
        Scaffold(
            topBar = {
                TopAppBar(
                    title = {
                        Text("TopAppBar")
                    },
                    backgroundColor = Color.Gray,
                    contentPadding = WindowInsets.statusBars.asPaddingValues()
                )
            },
            modifier = Modifier.fillMaxSize(),
            contentColor = Color.Black
        ) { }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    Lottie

    1. 添加依赖配置 implementation “com.airbnb.android:lottie-compose:$lottieVersion”
    2. 创建Lottie动画
    • 创建两个状态用来描述动画的速度和开始暂停状态
    var isPlaying by remember {
            mutableStateOf(true)
        }
        var speed by remember {
            mutableStateOf(1f)
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 加载Lottie动画资源,这里用本地加载方式
      • Lottie框架提供了加载res/raw,加载URL,加载手机目录下的静态资源,加载asset目录下的静态资源,加载json字符串的功能
        val lottieComposition by rememberLottieComposition(
            spec = RawRes(R.raw.lottie),
        )
    
    • 1
    • 2
    • 3
    • 接下来创建Lottie动画状态
        val lottieAnimationState by animateLottieCompositionAsState (
            composition = lottieComposition,
            iterations = LottieConstants.IterateForever,
            isPlaying = isPlaying,
            speed = speed,
            restartOnPlay = false
        )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 最后设置动画资源句柄和动画状态
     LottieAnimation(
                    lottieComposition,
                    lottieAnimationState,
                    modifier = Modifier.size(400.dp)
                )
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Coil

    • 添加依赖: implementation “io.coil-kt:coil-compose:$coil_version”

    AsyncImage

    @Preview
    @Composable
    fun AsyncImageDemo() {
        AsyncImage(
            model = ImageRequest.Builder(LocalContext.current)
                .data(ImageUrl)
                .crossfade(true)
                .build(),
            //model = (ImageUrl),
            contentDescription = stringResource(R.string.description),
            placeholder = painterResource(id = R.drawable.place_holder),
            error = painterResource(id = R.drawable.error),
            onSuccess = {
                Log.d(TAG, "success")
            },
            onError = { error ->
                Log.d(TAG, "error")
            },
            onLoading = { loading ->
                Log.d(TAG, "loading")
            },
            modifier = Modifier.clip(CircleShape)
        )
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    SubcomposeAsyncImage

    @Preview
    @Composable
    fun SubcomposeAsyncImageDemo() {
        SubcomposeAsyncImage(
            model = "ImageUrl",
            loading = { CircularProgressIndicator() },
            contentDescription = "compose_museum"
        ) 
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    @Preview
    @Composable
    fun SubcomposeAsyncImageDemo() {
        SubcomposeAsyncImage(
            model = "ImageUrl",
            contentDescription = "compose_museum"
        ) {
            if (painter.state is AsyncImagePainter.State.Loading || painter.state is AsyncImagePainter.State.Error) {
                CircularProgressIndicator()
            } else {
                SubcomposeAsyncImageContent()
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    SubcomposeAsyncImage(
                model = ImageRequest
                	.Builder(LocalContext.current)
                	.data(ImageUrl.testUrl1)
                	.size(1920,1080),
                	.build(),
                contentDescription = null,
            ) {
                val state = painter.state
                when(state) {
                    is AsyncImagePainter.State.Loading -> CircularProgressIndicator()
                    is AsyncImagePainter.State.Error -> Text("${state.result.throwable}")
                    is AsyncImagePainter.State.Success -> SubcomposeAsyncImageContent()
                    is AsyncImagePainter.State.Empty -> Text("Empty")
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    AsyncImagePainter

    • 这个组件是底层API,使用时会出现很多不可预期的行为,所以建议用前面两个
    • 如果项目要求不能用AsyncImage则用这个
    • 不能用Success状态来判断,否则图片不能加载成功
    val painter = rememberAsyncImagePainter(
      model = ImageRequest.Builder(LocalContext.current)
        .data("https://pic-go-bed.oss-cn-beijing.aliyuncs.com/img/20220316151929.png")
        .build()
    )
    if (painter.state is AsyncImagePainter.State.Loading) {
      CircularProgressIndicator()
    }
    Image(
      painter = painter,
      contentDescription = stringResource(R.string.description)
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    《Jetpack Compose从入门到实战》第一章 全新的 Android UI 框架

    《Jetpack Compose从入门到实战》 第二章 了解常用UI组件

    《Jetpack Compose从入门到实战》第三章 定制 UI 视图

    《Jetpack Compose从入门到实战》第八章 Compose页面 导航

    《Jetpack Compose从入门到实战》第九章 Accompanist 与第三方组件库

  • 相关阅读:
    文心一言 VS 讯飞星火 VS chatgpt (242)-- 算法导论17.4 1题
    Vue中如何进行分布式日志收集与日志分析(如ELK Stack)
    高分植物线粒体研究:揭示棉花细胞质雄性不育的花粉败育机制
    目标检测前言,RCNN,Fast RCNN,Faster RCNN
    CSS特殊学习网址
    SpringBoot集成道历(实现道历日期查询)
    Java-数据结构-数组
    Unity随笔:C#运行时
    低代码开发平台助力生产管理:采购成本管理的优化
    ansible中的剧本playback详解
  • 原文地址:https://blog.csdn.net/qq_61735602/article/details/133470190