[Android]引导页

[Android]引导页使用 Kotlin JetpackCompo 创建一个左右滑动的引导页 效果如图 android 引导页

大家好,欢迎来到IT知识分享网。

使用Kotlin + Jetpack Compose创建一个左右滑动的引导页, 效果如图.

[Android]引导页[Android]引导页

1.添加依赖项

androidx.compose.ui最新版本查询:https://maven.google.com/web/index.html

com.google.accompanist:accompanist-pager最新版本查询:https://central.sonatype.com/

确保在 build.gradle (Module: app) 文件中添加:

dependencies { implementation("androidx.compose.ui:ui:1.7.0-alpha06") implementation("com.google.accompanist:accompanist-pager:0.35.0-alpha") }

2.定义引导页

  • HorizontalPager 是一个实现水平滑动页面的组件,常用于实现引导页。它是通过Pager库提供的,支持滑动动画和状态保持。
  • rememberPagerState 是用于记忆并管理HorizontalPager的状态,例如当前页面和总页面数。
  • rememberCoroutineScope 用于创建一个协程作用域,允许在Compose函数外异步执行任务(例如页面滚动)。
package com.randomdt.www.main.guide import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.randomdt.www.R import com.randomdt.www.support.data.PrefKey import com.randomdt.www.support.data.PrefsManager import com.randomdt.www.ui.theme.customScheme import kotlinx.coroutines.launch @OptIn(ExperimentalFoundationApi::class) @Composable fun GuideScreen(onGuideComplete: (Boolean) -> Unit) { val pages = listOf( GuidePage("Enhance your video recording with smooth script scrolling.", R.drawable.icon_guide1), GuidePage("Personalize settings to meet your recording needs.", R.drawable.icon_guide2), GuidePage("Intelligent scrolling for effortless recording control.", R.drawable.icon_guide3), GuidePage("Subscribe to the premium version and unlock additional features.", R.drawable.icon_guide4) ) val pagerState = rememberPagerState(pageCount = { pages.count() }) val scope = rememberCoroutineScope() Box(modifier = Modifier .fillMaxSize() .background(color = MaterialTheme.colorScheme.background)){ HorizontalPager( state = pagerState, modifier = Modifier.matchParentSize() // Use matchParentSize instead ) { page -> GuidePageContent(page = pages[page], modifier = Modifier.fillMaxSize()) } val isLast = pagerState.currentPage == pages.size - 1 Column( modifier = Modifier .fillMaxSize() .padding(horizontal = 16.dp), verticalArrangement = Arrangement.Bottom ) { if (isLast) { Text( "3 Days Trial, \$4.99/week, cancel anytime", fontSize = 14.sp, fontWeight = FontWeight.Normal, color = MaterialTheme.customScheme.text_aux99, textAlign = TextAlign.Center, modifier = Modifier .fillMaxWidth() // 使宽度充满屏幕 .padding(horizontal = 16.dp) // 水平填充 .padding(bottom = 16.dp) // 与按钮之间的空隙 ) } // 渐变色定义 val gradient = Brush.horizontalGradient( colors = listOf( MaterialTheme.customScheme.gradient_start_color, // 渐变起始颜色 MaterialTheme.customScheme.gradient_end_color // 渐变结束颜色 ) ) // Next/Subscribe按钮 Button( onClick = { if (pagerState.currentPage < pages.size - 1) { scope.launch { pagerState.animateScrollToPage(pagerState.currentPage + 1) } } else { // Navigate to Home Screen goHome(onGuideComplete) } }, colors = ButtonDefaults.buttonColors(containerColor = Color.Transparent), // 设置背景透明 contentPadding = PaddingValues(0.dp), // 移除内部填充 border = BorderStroke(1.dp, Color.White), // 设置按钮的边框和背景 shape = RoundedCornerShape(25.dp), // 按钮圆角设置. Button 的 shape 只影响按钮本身的边界形状,而不会应用到渐变色背景上。 modifier = Modifier .fillMaxWidth() // 使宽度充满屏幕 .height(50.dp) .background( gradient, shape = RoundedCornerShape(25.dp) ), // 方式一: 添加渐变色背景, 已经为渐变背景导角 ) { Text( if (pagerState.currentPage == pages.size - 1) "Subscribe" else "Next", fontSize = 17.sp, fontWeight = FontWeight.Bold ) /* // 方式二: 设置Button渐变色 Box( modifier = Modifier .fillMaxSize() .background(gradient, shape = RoundedCornerShape(25.dp)) ) { Text( if (pagerState.currentPage == pages.size - 1) "Subscribe" else "Next", modifier = Modifier.align(Alignment.Center) ) }*/ } Box( modifier = Modifier .fillMaxWidth() .height(100.dp) .alpha(if (isLast) 1f else 0f) ) { // Restore Purchases Button( onClick = { }, colors = ButtonDefaults.buttonColors(containerColor = Color.Transparent), // 设置背景透明 contentPadding = PaddingValues(0.dp), // 移除内部填充 modifier = Modifier.height(40.dp) ) { Text( "Restore Purchases", fontSize = 13.sp, fontWeight = FontWeight.Normal, style = TextStyle(textDecoration = TextDecoration.Underline) // 下划线 ) } // Privacy Policy Button( onClick = { }, colors = ButtonDefaults.buttonColors(containerColor = Color.Transparent), // 设置背景透明 contentPadding = PaddingValues(0.dp), // 移除内部填充 modifier = Modifier .align(Alignment.TopEnd) .padding(end = 95.dp) .height(40.dp) ) { Text( "Privacy Policy", fontSize = 13.sp, fontWeight = FontWeight.Normal, style = TextStyle(textDecoration = TextDecoration.Underline) // 下划线 ) } // Terms of Use Button( onClick = { }, colors = ButtonDefaults.buttonColors(containerColor = Color.Transparent), // 设置背景透明 contentPadding = PaddingValues(0.dp), // 移除内部填充 modifier = Modifier .align(Alignment.TopEnd) .height(40.dp) ) { Text( "Terms of Use", fontSize = 13.sp, fontWeight = FontWeight.Normal, style = TextStyle(textDecoration = TextDecoration.Underline) // 下划线 ) } // val scrollState = rememberScrollState() Box(modifier = Modifier.fillMaxWidth().padding(top = 40.dp)) { // 可滚动的详细文本视图 Text( text = "This subscription automatically renews unless you cancel at least 24 hours before the end of the current subscription period. Your account will be charged for renewal within 24-hours prior to the end of the current subscription period. You can manage your subscription and auto-renewal in your Google Play account settings.", fontSize = 13.sp, color = MaterialTheme.customScheme.text_aux99, fontWeight = FontWeight.Normal, lineHeight = 20.sp, // 设置行间距为20sp modifier = Modifier .fillMaxWidth() .verticalScroll(scrollState) //.heightIn(max = 100.dp) // 设置最大高度以限制视图高度 .padding(bottom = 10.dp) ) } } } if (isLast) { // 跳过按钮 Button( onClick = { // Navigate to Home Screen goHome(onGuideComplete) }, colors = ButtonDefaults.buttonColors(containerColor = Color.Transparent), // 设置背景透明 contentPadding = PaddingValues(0.dp), // 移除内部填充 modifier = Modifier .align(Alignment.TopStart) .size(60.dp) .padding(start = 8.dp, top = 8.dp) ) { Image( painter = painterResource(R.drawable.icon_alert_close), contentDescription = "", ) } } } } private fun goHome(onGuideComplete: (Boolean) -> Unit) { PrefsManager.set(PrefKey.IS_DID_GUIDE, true) onGuideComplete(true) } @Composable fun GuidePageContent(page: GuidePage, modifier: Modifier = Modifier) { Column(modifier = modifier) { Image( painter = painterResource(id = page.imageRes), contentDescription = null, modifier = Modifier .fillMaxWidth() // 填充最大宽度 .aspectRatio(1167 / 1320f) // 设置宽高比例,例如 16:9 的比例为 1.77 ) Text( text = page.description, modifier = Modifier .padding(horizontal = 16.dp) // 设置水平间距 .align(Alignment.CenterHorizontally), // 居中 style = TextStyle( fontSize = 20.sp, textAlign = TextAlign.Center, // 让换行的文案也居中对齐 ) ) // 高度根据内容自适应 } } // imageRes 是一个整数 (int),通常在 Android 开发中,这种整数类型用来代表资源文件(如图片)的 ID。 data class GuidePage(val description: String, val imageRes: Int)

3.定义PrefsManager

package com.randomdt.www.support.data import android.content.Context import android.content.SharedPreferences import android.util.Log object PrefsManager { private lateinit var sharedPreferences: SharedPreferences fun init(context: Context) { sharedPreferences = context.getSharedPreferences("AppPreferences", Context.MODE_PRIVATE) } fun <T> get(prefKey: PrefKey): T { val defaultValue: T = PrefDefaults.getDefaultValue(prefKey) return when (defaultValue) { is Boolean -> sharedPreferences.getBoolean(prefKey.key, defaultValue) as? T ?: defaultValue is Int -> sharedPreferences.getInt(prefKey.key, defaultValue) as? T ?: defaultValue is String -> sharedPreferences.getString(prefKey.key, defaultValue) as? T ?: defaultValue else -> { Log.w("SharedPreferences", "Unsupported type for SharedPreferences.get") defaultValue } } } fun <T> set(prefKey: PrefKey, value: T) { with(sharedPreferences.edit()) { when (value) { is Boolean -> putBoolean(prefKey.key, value) is Int -> putInt(prefKey.key, value) is String -> putString(prefKey.key, value) else -> Log.w("SharedPreferences", "Unsupported type for SharedPreferences.set") } apply() } } } /// 让 PrefKey 枚举仅包含用户定义的键(key) enum class PrefKey(val key: String) { IS_DID_GUIDE("isDidGuide"), USER_AGE("userAge"), USER_NAME("userName"); } /// 管理默认值和类型 object PrefDefaults { private val defaultValues = mapOf<PrefKey, Any>( PrefKey.IS_DID_GUIDE to false, PrefKey.USER_AGE to 18, PrefKey.USER_NAME to "John Doe" ) @Suppress("UNCHECKED_CAST") fun <T> getDefaultValue(prefKey: PrefKey): T = defaultValues[prefKey] as T } /* // 初始化(通常在应用启动时进行) PrefsManager.init(context) // 存储数据 PrefsManager.set(PrefKey.IS_LOGGED_IN, true) PrefsManager.set(PrefKey.USER_AGE, 30) PrefsManager.set(PrefKey.USER_NAME, "Alice") // 读取数据 val isLoggedIn: Boolean = PrefsManager.get(PrefKey.IS_LOGGED_IN) val userAge: Int = PrefsManager.get(PrefKey.USER_AGE) val userName: String = PrefsManager.get(PrefKey.USER_NAME) */

4.引导页进入/离开

class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) PrefsManager.init(this) setContent { RandomdtTheme { // A surface container using the 'background' color from the theme Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { MainContent() } } } } } @Composable fun MainContent() { val isDidGuideState = remember { mutableStateOf(PrefsManager.get<Boolean>(PrefKey.IS_DID_GUIDE)) } if (isDidGuideState.value) { Greeting("Android") } else { GuideScreen { isDidGuideCompleted -> isDidGuideState.value = isDidGuideCompleted } } }

TO

HorizontalPager用法:https://juejin.cn/post/

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/130762.html

(0)
上一篇 2025-08-12 22:00
下一篇 2025-08-12 22:10

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信