com.dd.CircularProgressButton (代码家的一个button)

本文介绍了一款名为CircularProgressButton的控件,该控件可在不同状态下展示不同的UI效果,如进度条、成功和失败状态等。文章还提供了如何在布局文件中配置该控件的方法,并展示了通过设置不同进度值实现四种状态转换的具体示例。

最近学了好多第三方的类库,用起来特别炫酷,故此来分享给像我一样的新手

CircularProgressButton是大神 林惠文排名最高的一个,大概在28名左右,这个控件有点特殊,用起来效果挺炫的,

它有四个状态,默认时是单纯的一个button,但在运行时,它会变成一个progress在不停的转,

成功时,它会跳跳转为一个绿色背景中间一个打钩的状态,失败时呈现一个红色背景打叉的状态。


布局文件

  • <com.dd.CircularProgressButton
  •             android:layout_width="300dp"
  •             android:layout_height="40dp"
  •             app:cpb_iconComplete="@drawable/ic_cpb_action_accept"//成功时的状态图标
  •             app:cpb_textError="@drawable/ic_cpb_action_cancel"//失败时的状态图标
  •             app:cpb_textIdle="登录" />//默认文字,注意:text在这里没用了
  • 四个状态的使用
  • btnlogin.setIndeterminateProgressMode(true);
     btnlogin.setProgress(50);//运行状态
    btnlogin.setProgress(100);//成功状态
  • btnlogin.setProgress(-1);//失败状态
  • btnlogin.setProgress(0);//默认状态
  • 当处于失败状态是,如果按钮一直处于失败状态,给用户的体验就会不好,
  • 因此我们要给它一个时间,例如:登录失败时,过两秒它就又变成默认状态
  • 所以我给他起了一个线程
  • handler.postDelayed(new Runnable() {

                @Override
                public void run() {
                    btnlogin.setProgress(0);
                }
            }, 2000);//在失败时。隔两秒钟自动回到默认状态
package com.example.myapplication2.ui.theme import android.content.pm.PackageManager import android.net.Uri import android.os.Build import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.PickVisualMediaRequest import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material3.Button import androidx.compose.material3.Icon import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import com.example.myapplication2.bin.TimeViewmodel import org.threeten.bp.format.DateTimeFormatter import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import coil3.compose.rememberAsyncImagePainter import androidx.activity.result.contract.ActivityResultContracts import kotlin.contracts.contract @Composable fun Create(navController: NavController, vc: TimeViewmodel = hiltViewModel() ){ val time by vc.time.collectAsState() val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") val text: String = time.format(formatter) var bookText by remember {mutableStateOf("")}//文本状态 val scroll = rememberScrollState() // 子状态提升到父状态 var hasPermission by remember { mutableStateOf(false) } var selectedImageUri by remember { mutableStateOf<Uri?>(null) } val onPermissionChanged = remember { { newValue: Boolean -> hasPermission = newValue } } val onSelectedImageUri = remember { {uri: Uri? -> selectedImageUri = uri} } Column( modifier = Modifier .fillMaxSize(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { OutlinedTextField( value = bookText, onValueChange = { bookText = it }, modifier = Modifier .size(300.dp, 200.dp) .verticalScroll(scroll), singleLine = false, maxLines = Int.MAX_VALUE, placeholder = { Text("输入内容") }, label = { Text("编辑框") } ) picture( hasPermission = hasPermission, selectedImageUri = selectedImageUri, onPermissionChanged = onPermissionChanged, onSelectedImageUri = onSelectedImageUri ) Button( onClick = {navController.navigate("four")} ) { Icon( imageVector = Icons.Default.ArrowBack, contentDescription = "back" ) } } } @Composable fun picture( hasPermission: Boolean, selectedImageUri: Uri?, onPermissionChanged: (Boolean) -> Unit, onSelectedImageUri: (Uri?) -> Unit ) { val context = LocalContext.current // 确定所需权限 val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { arrayOf( android.Manifest.permission.READ_MEDIA_IMAGES, android.Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED ) } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { arrayOf(android.Manifest.permission.READ_MEDIA_IMAGES) } else { arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE) } // 检查权限(优化键值为Unit,确保只执行一次) LaunchedEffect(Unit) { val hasPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { permissions.all { ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED } } else { ContextCompat.checkSelfPermission(context, permissions[0]) == PackageManager.PERMISSION_GRANTED } onPermissionChanged(hasPermission) } // 多权限请求启动器 val requestPermissionLauncher = rememberLauncherForActivityResult( ActivityResultContracts.RequestMultiplePermissions() ) { results: Map<String, Boolean>-> val allGranted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { results.all { it.value } } else { results.values.firstOrNull() == true } onPermissionChanged(allGranted) } // 图片选择器启动器 val pickImageLauncher = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU){ rememberLauncherForActivityResult<PickVisualMediaRequest?, Uri?>( contract = ActivityResultContracts.PickVisualMedia(), onResult = { uri: Uri? -> onSelectedImageUri(uri) }) }else{ rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri:Uri? -> onSelectedImageUri(uri) } } // 选择图片逻辑(优化参数传递) val selectImage = { if (hasPermission) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { pickImageLauncher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)) } else { pickImageLauncher.launch("image/*") } } else { requestPermissionLauncher.launch(permissions) } } Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(16.dp) ) { if (selectedImageUri != null) { Image( painter = rememberAsyncImagePainter(selectedImageUri), contentDescription = "Selected image", modifier = Modifier .size(300.dp) .padding(bottom = 16.dp), contentScale = ContentScale.Crop ) } else { Text("点击下方按钮选择图片") } Button(onClick = selectImage) { Text("选择图片") } } }
10-19
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值