Android ItemLayout工具类

Posted 左郁

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android ItemLayout工具类相关的知识,希望对你有一定的参考价值。

1. 在开发中,经常会遇到千篇一律的子条目列表,比如个人中心里一堆功能设置

像这样的:

这样的:

每个子条目都是一个布局里嵌套三到四个组件,虽说可以通过 style 样式表去节省一部分重复代码,但是整体看 xml 还是好长一串
总结一下,大概有以下这几种情况:

所以,为了布局 “看起来” 简洁一些, 我这边封装了一个自定义view:ItemLayout,注意哈,这里只是为了让布局看起来简洁,因为内部还是布局嵌套组件。

下面先来看一下效果图:

2. 自定义view:效果展示和调用方式


对应调用代码片段:

   
    <!-- 情况一:左侧图标 + 左侧文字 -->
    <com.sunny.widget.ItemLayout
        android:id="@+id/item1"
        style="@style/style_register_item_layout"
        app:startIcon="@drawable/svg_chat_duty"
        app:startAfterText="用户信息"
        app:lineVisible="true" />

    <!-- 情况二:左侧图标 + 左侧文字 -->
    <com.sunny.widget.ItemLayout
        android:id="@+id/item2"
        style="@style/style_register_item_layout"
        app:startAfterText="收藏文件"
        app:startIcon="@drawable/svg_chat_product"
        app:endIcon="@drawable/svg_btn_more"
        app:lineVisible="true" />

    <!-- 情况三:左侧图标 + 左侧文字 + 右侧文字 + 右侧图标 -->
    <com.sunny.widget.ItemLayout
        android:id="@+id/item3"
        style="@style/style_register_item_layout"
        app:startIcon="@drawable/svg_chat_edit"
        app:startAfterText="个人简介"
        app:endIcon="@drawable/svg_btn_more"
        app:endText="听说android还不错.."
        app:lineVisible="true" />

    <!-- 情况四:左侧文字 + 右侧文字 -->
    <com.sunny.widget.ItemLayout
        android:id="@+id/item4"
        style="@style/style_register_item_layout"
        app:startText="登录账号"
        app:endText="131****6393"
        app:lineVisible="true" />

    <!-- 情况五:左侧文字 + 右侧图标 -->
    <com.sunny.widget.ItemLayout
        android:id="@+id/item5"
        style="@style/style_register_item_layout"
        app:startText="通知设置"
        app:endIcon="@drawable/svg_btn_more"
        app:lineVisible="true" />

    <!-- 情况六:左侧文字 + 右侧文字 + 右侧图标 -->
    <com.sunny.widget.ItemLayout
        android:id="@+id/item6"
        style="@style/style_register_item_layout"
        app:startAfterText="清除缓存"
        app:endIcon="@drawable/svg_btn_more"
        app:endText="20M" />
        

下面来看看具体怎么实现的:

3. 自定义View属性:attr.xml 文件

    <declare-styleable name="ItemLayout">
    	<!-- 左侧图标 -->
        <attr name="startIcon" format="reference|color" />
        <attr name="startIconWidth" format="dimension" />
        <attr name="startIconHeight" format="dimension" />
		
		<!-- 左侧文字 -->
        <attr name="startText" format="string" />
        <attr name="startTextSize" format="dimension" />
        <attr name="startTextColor" format="reference" />

		<!-- 左侧图标 + 文字 -->
        <attr name="startAfterText" format="string" />
        <attr name="startAfterTextSize" format="dimension" />
        <attr name="startAfterTextColor" format="reference" />

		<!-- 右侧图标 -->
        <attr name="endIcon" format="reference" />
        <attr name="endIconWidth" format="dimension" />
        <attr name="endIconHeight" format="dimension" />

		<!-- 右侧文字 -->
        <attr name="endText" format="string" />
        <attr name="endTextSize" format="dimension" />
        <attr name="endTextColor" format="color" />

		<!-- 右侧文字 + 图标 -->
        <attr name="endBeforeText" format="string" />
        <attr name="endBeforeTextSize" format="dimension" />
        <attr name="endBeforeTextColor" format="reference" />

		<!-- 子条目之间的分割线 -->
        <attr name="lineColor" format="color" />
        <attr name="lineHeight" format="dimension" />
        <attr name="lineVisible" format="boolean" />

		<!-- 左右边距 -->
        <attr name="leftMargin" format="dimension" />
        <attr name="rightMargin" format="dimension" />
    </declare-styleable>

4. 自定义view:ItemLayout

/**
 * Desc 自定义子条目View
 * Author ZY
 * Date 2020/02/04
 */
class ItemLayout : RelativeLayout 

    val startImageView: ImageView by lazy 
        ImageView(context).apply 
            id = R.id.iv_start
        
    

    val startTextView: TextView by lazy 
        TextView(context).apply 
            id = R.id.tv_start
        
    

    val startAfterTextView: TextView by lazy 
        TextView(context)
    


    var endImage = 0
    val endImageView: ImageView by lazy 
        ImageView(context).apply 
            id = R.id.iv_end
        
    

    val endTextView: TextView by lazy 
        TextView(context).apply 
            id = R.id.tv_end
        
    

    val endBeforeTextView: TextView by lazy 
        TextView(context)
    

    constructor(context: Context) : this(context, null)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) 

        val defaultMargin = resources.getDimension(R.dimen.dp_10)
        val defaultTextSize = resources.getDimension(R.dimen.sp_14)
        val defaultTextColor = ContextCompat.getColor(context, R.color.font_black)
        val defaultLineColor = ContextCompat.getColor(context, R.color.color_line)
        val defaultLineHeight = resources.getDimension(R.dimen.dp_1)


        val typeArray = context.theme.obtainStyledAttributes(attrs, R.styleable.ItemLayout, defStyleAttr, 0)


        /**
         * 最外层View
         */
        val leftMargin = typeArray.getDimension(R.styleable.ItemLayout_leftMargin, defaultMargin)
        val rightMargin = typeArray.getDimension(R.styleable.ItemLayout_rightMargin, defaultMargin)

        val parentLayout = RelativeLayout(context)
        val layout = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
        layout.leftMargin = leftMargin.toInt()
        layout.rightMargin = rightMargin.toInt()
        addView(parentLayout, layout)


        /**
         * 最左侧图标
         */
        val startImage = typeArray.getResourceId(R.styleable.ItemLayout_startIcon, 0)
        if (startImage != 0) 
            val lp = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
            lp.addRule(CENTER_VERTICAL)
            startImageView.setImageResource(startImage)
            parentLayout.addView(startImageView, lp)
        


        /**
         * 最左侧文字
         */
        val startText = typeArray.getString(R.styleable.ItemLayout_startText) ?: ""
        val startTextSize = typeArray.getDimension(R.styleable.ItemLayout_startTextSize, defaultTextSize)
        val startTextColor = typeArray.getColor(R.styleable.ItemLayout_startTextColor, defaultTextColor)

        if (startText.isNotEmpty()) 
            val lp = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)
            startTextView.text = startText
            startTextView.setTextColor(startTextColor)
            startTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, startTextSize)
            startTextView.gravity = Gravity.CENTER_VERTICAL
            parentLayout.addView(startTextView, lp)
        

        /**
         * 最左侧文字/图标 —— 文字
         */
        val startAfterText = typeArray.getString(R.styleable.ItemLayout_startAfterText) ?: ""
        val startAfterTextSize = typeArray.getDimension(R.styleable.ItemLayout_startAfterTextSize, defaultTextSize)
        val startAfterTextColor = typeArray.getColor(R.styleable.ItemLayout_startAfterTextColor, defaultTextColor)

        if (startAfterText.isNotEmpty()) 
            val lp = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)
            startAfterTextView.text = startAfterText
            startAfterTextView.setTextColor(startAfterTextColor)
            startAfterTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, startAfterTextSize)
            startAfterTextView.gravity = Gravity.CENTER_VERTICAL

            val mLeft = when 
                startImage != 0 -> startImageView.id
                startText.isNotEmpty() -> startTextView.id
                else -> 0
            
            if (mLeft != 0) 
                lp.leftMargin = defaultMargin.toInt()
                lp.addRule(RIGHT_OF, mLeft)
            
            parentLayout.addView(startAfterTextView, lp)
        

        /**
         * 最右侧图标
         */
        endImage = typeArray.getResourceId(R.styleable.ItemLayout_endIcon, 0)
        if (endImage != 0) 
            val lp = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)
            endImageView.setPadding(defaultMargin.toInt(), 0, 0, 0)
            lp.addRule(ALIGN_PARENT_RIGHT)
            lp.addRule(CENTER_VERTICAL)
            endImageView.setImageResource(endImage)
            parentLayout.addView(endImageView, lp)
        

        /**
         * 最右侧文字
         */
        val endText = typeArray.getString(R.styleable.ItemLayout_endText) ?: ""
        val endTextSize = typeArray.getDimension(R.styleable.ItemLayout_endTextSize, defaultTextSize)
        val endTextColor = typeArray.getColor(R.styleable.ItemLayout_endTextColor, defaultTextColor)

        if (endText.isNotEmpty()) 
            val lp = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)
            if (endImage != 0) 
                lp.addRule(LEFT_OF, endImageView.id)
             else 
                lp.addRule(ALIGN_PARENT_RIGHT)
            

            endTextView.text = endText
            endTextView.setTextColor(endTextColor)
            endTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, endTextSize)
            endTextView.gravity = Gravity.CENTER_VERTICAL
            parentLayout.addView(endTextView, lp)
        

        /**
         * 文字 —— 最右侧文字/图标
         */
        val endBeforeText = typeArray.getString(R.styleable.ItemLayout_endBeforeText) ?: ""
        val endBeforeTextSize = typeArray.getDimension(R.styleable.ItemLayout_endBeforeTextSize, defaultTextSize)
        val endBeforeTextColor = typeArray.getColor(R.styleable.ItemLayout_endBeforeTextColor, defaultTextColor)

        if (endBeforeText.isNotEmpty()) 
            val lp = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)
            endBeforeTextView.text = endBeforeText
            endBeforeTextView.setTextColor(endBeforeTextColor)
            endBeforeTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, endBeforeTextSize)
            endBeforeTextView.gravity = Gravity.CENTER_VERTICAL

            val mRight = if (endText.isNotEmpty()) 
                endTextView.id
             else 
                endImageView.id
            

            if (mRight != 0) 
                lp.addRule(LEFT_OF, mRight)
             else 
                lp.addRule(ALIGN_PARENT_RIGHT)
            

            lp.marginEnd = defaultMargin.toInt()

            parentLayout.addView(endBeforeTextView, lp)
        
        
        /**
         * 分割线
         */
        val lineColor = typeArray.getColor(R.styleable.ItemLayout_lineColor, defaultLineColor)
        val lineHeight = typeArray.getDimension(R.styleable.ItemLayout_lineHeight, defaultLineHeight)
        val lineVisible = typeArray.getBoolean(R.styleable.ItemLayout_lineVisible, false)

        if (lineVisible) 
            val view = View(context)
            view.setBackgroundColor(lineColor)
            val lp = LayoutParams(LayoutParams.MATCH_PARENT, lineHeight.toInt())
            lp.addRule(ALIGN_PARENT_BOTTOM)
            addView(view, lp)
        

        typeArray.recycle()
    

5. 自定义view的属性,随意搭配,总有一种是你需要的,哈哈,还是那句话,布局代码看起来是不是简洁了好多~

以上是关于Android ItemLayout工具类的主要内容,如果未能解决你的问题,请参考以下文章

Android中具有自定义子布局的Expandablelistview

Bootstrap 类 dropdown-menu dropdown-menu-right 不适用于自定义子菜单

在Unity中使用JsonUtility将带有自定义子对象的类打印到JSON输出中

XamarinAndroid组件教程设置自定义子元素动画

JUC简介

JUC 简介