[Android]引导页

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

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.guideimport 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 - 1Column(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 ScreengoHome(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 PurchasesButton(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 PolicyButton(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 UseButton(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,  // 设置行间距为20spmodifier = Modifier.fillMaxWidth().verticalScroll(scrollState)//.heightIn(max = 100.dp)  // 设置最大高度以限制视图高度.padding(bottom = 10.dp))}}}if (isLast) {// 跳过按钮Button(onClick = {// Navigate to Home ScreengoHome(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.dataimport android.content.Context
import android.content.SharedPreferences
import android.util.Logobject PrefsManager {private lateinit var sharedPreferences: SharedPreferencesfun 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 ?: defaultValueis Int -> sharedPreferences.getInt(prefKey.key, defaultValue) as? T ?: defaultValueis String -> sharedPreferences.getString(prefKey.key, defaultValue)  as? T ?: defaultValueelse -> {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 themeSurface(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/6978831090693701639

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/3553.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法-KMP算法

时间复杂度&#xff1a; public int strStr(String haystack, String needle) {int[] next new int[needle.length()];//next数组的生成next[0] 0;int prefixLen 0;//共同前后缀长度int i 1, j 1;//i,j复用while (i < needle.length()) {if (needle.charAt(prefixLen)…

数据库工程师的工作职责(合集)

数据库工程师的工作职责1 职责&#xff1a; 1. 日常数据库的基本安装&#xff0c;维护&#xff0c;升级&#xff0c;监控的; 2. 配合研发部门进行数据库设计支持&#xff0c;协助开发、设计和进行SQL语言优化; 3. 配合相关部门数据库相关的任务&#xff0c;比如数据导入导出&am…

「屡教不改」又被罚,谁还在相信山姆?

值得信赖的品质」「全球进口品牌」……「更好的生活尽在山姆」。 作为全球最大的会员制商店&#xff0c;山姆这几年可以说在中国线下零售市场集体遇劫的背景下&#xff0c;逆势崛起&#xff0c;甚至可以说做到了独树一帜。‍‍‍‍‍‍ 背后的原因是什么&#xff1f;会员制这一…

迅雷不限速破解方法

背景&#xff1a;现在迅雷和百度云的下载速度真的太恶心了&#xff0c;所以总有大佬可以采用厉害的方法进行破解&#xff0c;在网上看了一圈&#xff0c;很多都是骗人或者是无效的&#xff0c;找了一个靠谱的方法&#xff0c;亲测速度能达到10M以上&#xff0c;非常给力。 以下…

MySQL数据库运维:运行监控及解决sql执行死锁问题

前言 在现代数据密集型应用程序的开发和部署中&#xff0c;MySQL数据库的运维是至关重要的环节之一。一个良好设计和维护的MySQL数据库系统可以确保数据的准确性、可靠性和高效的访问&#xff0c;从而支持业务的顺利运行。然而&#xff0c;随着业务规模的增长和复杂性增加&…

查看HDF5文件软件(HDFView)

HDFView&#xff1a;下载地址 note&#xff1a;我们需要下载 win10 、App软件&#xff08;win10在win11也能运行&#xff09;&#xff0c;因为App软件是轻量版&#xff0c;不需要安装就可以使用。 eg&#xff1a; 下载完后解压就可以使用。

配置SSL证书需要几步,有免费的吗

我们要明白什么是SSL证书。SSL&#xff08;Secure Sockets Layer&#xff09;是一种安全协议&#xff0c;用于在互联网上进行信息加密传输&#xff0c;保护数据不被第三方窃取或篡改。SSL证书就是用来执行这种加密的一种数字证书&#xff0c;它可以提供身份验证&#xff0c;防止…

这个合租室友真的没有一点公德心,还好他搬走了

这个合租室友真的没有一点公德心&#xff0c;还好他搬走了 这个出租屋有四个房间。 有三个卧室&#xff0c;和一个隔断。 我住三个卧室中的一个。下图中右边那个就是我住的。 2023年下半年&#xff0c;左边那个屋子来了一个新租户小白。 在住的过程中&#xff0c;隔断间的租…

30V-STM32设计项目

30V-STM32设计 一、项目描述 (已验证) 基于STM32c8t6芯片设计的开发板&#xff0c;支持4-30V宽电压输入&#xff0c;串口模式自动下载功能&#xff0c;支持串口和STlink&#xff0c;方式下载程序 二、原理图介绍 电源电路采用了DCDCLDO电路&#xff0c;如果是外接DC头供电的话&…

Spring Boot 3.2.5 集成 mysql

版本 Spring Boot 3.2.5 第一步&#xff0c;添加必要依赖 // mysql jdbc 及 驱动 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency><gr…

嵌入式单片机的高级编程技巧和优化

引言 嵌入式单片机&#xff08;MCU&#xff09;是实现智能设备控制的核心&#xff0c;广泛应用于工业自动化、智能家居、医疗设备等领域。 下面将探讨STM32单片机的高级编程技巧&#xff0c;包括中断管理、低功耗模式和内存优化等方面&#xff0c;并提供具有一定难度的代码示…

深度学习的炼金术:转化数据为黄金的秘密

深度学习的炼金术&#xff1a;转化数据为黄金的秘密 1 引言 在现代深度学习的壮阔疆域中&#xff0c;数据是王冠上耀眼的宝石&#xff0c;而性能优化则是锻造这顶王冠的炼金术。这份融合了数据和算法魔力的艺术&#xff0c;不仅仅依赖于强大的计算资源和复杂的网络结构&#x…

【蓝桥杯省赛真题40】python摘苹果 中小学青少年组蓝桥杯比赛 算法思维python编程省赛真题解析

目录 python摘苹果 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python摘苹果 第十三届蓝桥杯青少年组python编程省赛真题 一、题目要求 &…

【C语言】万字详讲操作符

目录 前言 一、操作符分类 二、算数操作符 三、移位操作符 四、位操作符 五、赋值操作符 六、单目操作符 6.1 逻辑反操作 6.2 负值与正值 6.3 取地址 6.4 sizeof 6.5 取反操作符 6.6 --和操作符 6.7 间接访问操作符&#xff08;解引用操作符&#xff09; 6.8 强…

安装JAVA和java IDEA并汉化过程

1.安装java: 打开java的下载链接&#xff1a; Java Downloads | Oracle 然后选择对应的版本下载即可&#xff0c;我这里是windows 所以下载这个 然后正常一步步安装即可。 2.配置java环境&#xff1a; 在桌面右键此电脑然后点击属性——高级系统设置——环境变量——然后…

H5点击复制功能 兼容安卓、IOS

效果图 HTML代码 <div>链接&#xff1a;<span style"color: #FF8A21" click"CopyUrl" id"copyId"> https://blog.csdn.net/qq_51463650?spm1000.2115.3001.5343</span> </div>复制方法 const CopyUrl () > {let …

12.Blender 界面介绍(上)及物体基础编辑操作

设置语言 首先在菜单栏打开编辑-Preferences-界面-翻译&#xff0c;可以修改语言 这里使用的是Steam上下载的4.1版本 工具栏 左边的工具栏&#xff0c;按T就会出现&#xff0c;再按T就会隐藏 右边的工具栏是按N&#xff0c;按N显示&#xff0c;再按N隐藏 旋转画面 长按鼠…

CSS 标准流 浮动 Flex布局

目录 1. 标准流2. 浮动2.1 清除浮动 3. Flex 布局3.1 Flex 组成3.2 Flex 布局 - 主轴与侧轴对齐方式3.2.1 主轴对齐方式3.2.2 侧轴对齐方式 3.3 Flex 布局 - 修改主轴方向3.4 Flex 布局 - 弹性伸缩比3.5 Flex 布局 - 弹性盒子换行3.6 Flex 布局 - 行对齐方式 1. 标准流 标准流…

使用selenium时出现element click intercepted报错的解决办法

win10&#xff0c;python3.8.10。 selenium版本如下&#xff08;用pip38 show selenium查看&#xff09;&#xff1a; 在定位中&#xff0c;定位了一个按钮&#xff08;特点&#xff1a;button下还有span然后才是文本&#xff09;&#xff0c;代码如下&#xff1a; from sele…

ubuntu22.04 CH340/CH34x 驱动安装

CH34x驱动地址&#xff1a;CH341SER_LINUX.ZIP - 南京沁恒微电子股份有限公司 1、卸载旧驱动&#xff08;如果存在&#xff09; sudo rmmod ch341.ko 2、解压进入 driver 目录 unzip CH341SER_LINUX.ZIP cd CH341SER_LINUX/driver 3、编译 make 可能错误&#xff1a; make[1]…