当前位置: 首页 > article >正文

Android级联选择器,下拉菜单

近期android开发,遇到的需求,分享二个android可能用到的小组件

 下拉选择器:它的实现,主要是需要监听它依附的组件当前距离屏幕顶端的位置。

                     在显示下拉菜单中,如果需要点击上面有响应。可通过activity拿到decorview(activity.window.decorView),然后把下拉的view添加到decorView,然后设置该菜单距离顶端的上边距。如果需要先点击屏幕让菜单先消失,可搞一个全屏的下拉菜单,距顶端高度搞一个透明的view来填充(设置一个点击事件,处理decorView.remove该下拉组件)

object DropDownItemsUtils {
    const val DROP_DOWN_ID = -1000
    fun showDropDownView(activity: Activity,marginTopPx:Float,list:List<String>,selectIndex:Int = -1,onItemClick: ((pos: Int?) -> Unit)?=null){
        val decorView = activity.window.decorView as ViewGroup
        decorView.findViewById<View>(DROP_DOWN_ID)?.let {
            decorView.removeView(it)
        }
        val composeView = ComposeView(activity).apply {
            setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
            setContent{
                DropDownItems(modifier = Modifier.fillMaxWidth().wrapContentHeight(), list = list, selectIndex = selectIndex) {
                    decorView.removeView(this@apply)
                    onItemClick?.invoke(it)
                }
            }
            id = DROP_DOWN_ID
        }
        val lp = FrameLayout.LayoutParams(-1,-1)
        lp.topMargin = marginTopPx.toInt()
        decorView.addView(composeView,lp)
    }

    fun dismissDropDownView(activity: Activity){
        val decorView = activity.window.decorView as ViewGroup
        decorView.findViewById<View>(DROP_DOWN_ID)?.let {
            decorView.removeView(it)
        }
    }
}

级联选择器:它的承载容器是一个底部弹窗的 DialogFragment,显示的内容目前我用compose实现,已选的级联它横向显示采用的LazyRow,列表项使用LazyColumn实现。具体实现如下。

data class LevelsItem(
    val text:String,
    var list:List<LevelsItem>? = null,
    var parentId:String? = null,
    var level:Int? = null,
    val tag:Any? = null //LevelsItem,是从服务端给的数据模型转的,实际可以再转化的时候,将该tag    
                        //设置为服务端给的模型.如下我转换的代码
)
/**
    fun convertMotorcadeRespToLevelsItem(list: List<MotorcadeResp>): List<LevelsItem> {
        return list.map { motorcadeResp ->
            LevelsItem(
                text = motorcadeResp.name ?: "", // Map name to text
                parentId = motorcadeResp.parentId,
                level = motorcadeResp.departmentLevel,
                list = motorcadeResp.childDepartment?.let { convertMotorcadeRespToLevelsItem(it) }, // Recursively map childDepartment
                tag = motorcadeResp // Set the original MotorcadeResp as tag
            )
        }
    }
*/
/**
 * 级联选择,可以自行选择。自行点击确定,完成选择成功
 */
class LevelsSelector1Dialog : BottomDialogFragment() {
    private val SELECTSTR: String = "-10000000"

    var title: String? = null

    var list: List<LevelsItem> = ArrayList()

    var onConfirm: ((LevelsItem?) -> Unit)? = null

    //用来横向显示tab项列表的item
    private var currentSelectItem: SnapshotStateList<LevelsItem> = mutableStateListOf()
    //记录当前选择的值,最后用来点击确定,来回调给调用方使用的
    private var currentSelectItemVal: SnapshotStateList<LevelsItem> = mutableStateListOf()


    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        return ComposeView(requireContext()).apply {
            setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
            setContent {
                WelcomeAssistantTheme {
                    LevelsSelectorScreen()
                }
            }
        }
    }


    @Preview(widthDp = 375, heightDp = 812)
    @Composable
    private fun LevelsSelectorScreen() {
        currentSelectItem.clear()
        //横向tab,添加一个默认项 “请选择"
        currentSelectItem.add(LevelsItem(SELECTSTR, list))
        val height =
            (0.64f * requireContext().resources.displayMetrics.heightPixels) / LocalDensity.current.density

        Box(
            modifier = Modifier
                .fillMaxWidth()
                .height(height.dp)
                .background(
                    color = Color.White,
                    shape = RoundedCornerShape(
                        topStart = 24.dp,
                        topEnd = 24.dp,
                        bottomStart = 0.dp,
                        bottomEnd = 0.dp
                    )
                )
                .padding(16.dp)
        ) {
            Image(
                painterResource(R.mipmap.ic_levels_selector_close),
                modifier = Modifier
                    .clickable {
                        dismiss()
                    }
                    .size(24.dp)
                    .align(Alignment.TopEnd),
                contentDescription = null
            )
            Text(
                modifier = Modifier
                    .padding(top = 24.dp, bottom = 16.dp)
                    .align(Alignment.TopCenter),
                text = title ?: "",
                style = buildMSDBTextStyle(fontSize = 20.sp, color = ff0A1733)
            )
            val listItems = remember {
                mutableStateOf(list)
            }
            val currentSelectTabIndex = remember {
                mutableIntStateOf(0)
            }
            LazyRow(
                modifier = Modifier
                    .padding(top = 68.dp)
                    .fillMaxWidth()
                    .height(30.dp),
            ) {
                itemsIndexed(currentSelectItem) {index, selectItem ->
                    Column {
                        if (SELECTSTR == selectItem.text) {
                            Text(
                                modifier = Modifier.padding(end = 24.dp).singleClickable {
                                    if(currentSelectTabIndex.intValue == index){
                                        return@singleClickable
                                    }
                                    currentSelectTabIndex.intValue = index
                                    listItems.value =
                                        currentSelectItem[index - 1].list ?: ArrayList()
                                },
                                text = stringResource(R.string.levels_select),
                                style = buildMSDNTextStyle(color = FF9DA2AD, fontSize = 16.sp)
                            )
                        } else {
                            Text(
                                modifier = Modifier
                                    .padding(end = 24.dp)
                                    .widthIn(max = 110.dp)
                                    .singleClickable {
                                        if(currentSelectTabIndex.intValue == index){
                                            return@singleClickable
                                        }
                                        if (index >= 1) {
                                            listItems.value =
                                                currentSelectItem[index - 1].list ?: ArrayList()
                                        } else {
                                            listItems.value =
                                                currentSelectItem[currentSelectItem.size - 1].list
                                                    ?: ArrayList()
                                        }
                                        currentSelectTabIndex.intValue = index
                                    },
                                text = selectItem.text,
                                style = buildMSDBTextStyle(
                                    color = ff0A1733,
                                    fontSize = 16.sp,
                                ),
                                overflow = TextOverflow.Ellipsis,
                                maxLines = 1
                            )
                        }
                        if(currentSelectTabIndex.intValue == index) {
                            Box(
                                modifier = Modifier
                                    .align(Alignment.CenterHorizontally)
                                    .padding(end = 24.dp)
                                    .height(3.dp)
                                    .width(24.dp)
                                    .background(color = FF306DF4, shape = RoundedCornerShape(3.dp))
                            )
                        }
                    }
                }
            }

            LazyColumn(
                modifier = Modifier
                    .padding(top = 108.dp, bottom = 70.dp)
                    .fillMaxSize()
            ) {
                var currentLevelSelectItem: LevelsItem? = null
                itemsIndexed(listItems.value) {i, levelsItem ->
                    var isAlreadySelectItem = currentSelectItemVal.contains(levelsItem)
                    if (isAlreadySelectItem) {
                        currentLevelSelectItem = levelsItem
                    }
                    Row(modifier = Modifier
                        .fillMaxWidth()
                        .padding(vertical = 12.dp)
                        .singleClickable {
                            //子item会有很多,可以判断当前item的父id是否相同
                            val index = currentSelectItem.indexOfFirst {
                                it.parentId == levelsItem.parentId
                            }
                            //可选项是否还有子列表
                            if (levelsItem.list.isNullOrEmpty()) {
                                //级联最后的那个列表
                                if (currentLevelSelectItem != null) {
                                    currentSelectItemVal.removeRange(currentSelectItemVal.indexOf(currentLevelSelectItem),currentSelectItemVal.size)
                                }
                                isAlreadySelectItem = true
                                if(index > 0){
                                    currentSelectItem.removeAt(index)
                                }
                                currentSelectItemVal.add(levelsItem)
                            } else {
                                //可以点出下一个级联
                                if (index < 0) {
                                    currentSelectItem.add(
                                        currentSelectItem.size - 1,
                                        levelsItem
                                    )
                                } else {
                                    currentSelectItem.removeAt(index)
                                    currentSelectItem.add(index,levelsItem)
                                }
                                currentSelectTabIndex.intValue += 1
                                listItems.value = levelsItem.list ?: ArrayList()

                                if (!isAlreadySelectItem) {
                                    if (currentLevelSelectItem != null) {
                                        currentSelectItemVal.removeRange(
                                            currentSelectItemVal.indexOf(
                                                currentLevelSelectItem
                                            ), currentSelectItemVal.size
                                        )
                                    }
                                    currentSelectItemVal.add(levelsItem)
                                }
                            }
                        }) {

                        Row(modifier = Modifier.fillMaxWidth()) {
                            Text(
                                modifier = Modifier.weight(1f),
                                text = levelsItem.text,
                                style = buildMSDNTextStyle(
                                    color = if (isAlreadySelectItem) FF306DF4 else ff0A1733,
                                    fontSize = 16.sp
                                )
                            )
                            if (isAlreadySelectItem) {
                                Image(
                                    modifier = Modifier.size(24.dp),
                                    painter = painterResource(R.mipmap.ic_dialog_levels_check),
                                    contentDescription = null
                                )
                            }
                        }
                    }

                }
            }

            Spacer(
                modifier = Modifier
                    .align(alignment = Alignment.BottomCenter)
                    .padding(bottom = 69.5.dp)
                    .height(0.5.dp)
                    .fillMaxSize()
                    .background(color = FFF2F3F4)
            )
            Box(
                modifier = Modifier
                    .align(alignment = Alignment.BottomCenter)
                    .padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
                    .fillMaxWidth()
                    .height(40.dp)
                    .background(color = FF306DF4, RoundedCornerShape(24.dp))
                    .singleClickable {
                        if (currentSelectItemVal.size > 0) {
                            onConfirm?.invoke(currentSelectItemVal[currentSelectItemVal.size - 1])
                        } else {
                            onConfirm?.invoke(null)
                        }
                        dismiss()
                    },
                contentAlignment = Alignment.Center
            ) {
                Text(
                    text = stringResource(R.string.dialog_confirm_position_txt),
                    style = TextStyle(color = Color.White, fontSize = 14.sp)
                )
            }
        }

    }

}


http://www.kler.cn/a/556548.html

相关文章:

  • Spring Boot 概要(官网文档解读)
  • window安装MySQL5.7
  • Linux中DataX使用第四期
  • 【学习】验证数独的正确性
  • vue项目启动时报错:error:0308010C:digital envelope routines::unsupported
  • Map遍历----
  • 论文笔记-WWWCompanion2024-LLM as Data Augmenters for Cold-Start Item Recommendation
  • 记录:Docker 安装记录
  • git输错用户名或者密码
  • 快速入门——第三方组件element-ui
  • beremiz笔记chatgpt,部署在Ubuntu:20.04版本
  • DeepSeek 助力 Vue 开发:打造丝滑的 键盘快捷键(Keyboard Shortcuts)
  • jenkins【Choice Parameter】来配置发布到不同环境的目录
  • pe不支持重置微软在线账户密码解决方案
  • qt的下载安装详细介绍
  • Ubuntu 下 nginx-1.24.0 源码分析 - ngx_palloc_large 函数
  • Flutter 跳转后不允许返回
  • 八大经典排序算法
  • 物联网+人工智能的无限可能
  • TiDB 助力广发银行新零售信贷业务管理平台上线