Android 最簡單的自定義MenuItem之一

天星技術團隊發表於2018-10-08

作者: Jooyer, 時間: 2018.10.08

Android 最簡單的自定義MenuItem之一

Github地址,歡迎點贊,fork

Android 最簡單的自定義MenuItem之一

其實本篇和上一篇 Toolbar 是一起的,因為很多時候我們會自定義一個左邊圖片文字,右邊文字圖片的MenuItem.

本次程式碼也是比較簡單,一個組合控制元件而已,我就直接貼原始碼,如果還有不清楚的,可以留言或者看github

###只需要一個類 + 一個 XML 檔案即可,即拷即用

接下來我們依次講解,和上一次Toolbar套路一致哈:

  1. CustomMenu
  2. 一個 XML 檔案
  3. 屬性及預設值

####首先,看看 CustomMenu

package cn.molue.jooyer.custommenu

import android.content.Context
import android.support.v4.content.ContextCompat
import android.text.TextUtils
import android.util.AttributeSet
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView

/**
 * Desc: 自定義普通選單,格式如下
 *  圖片 -- 文字  --------------- 文字/圖片  圖片
 * Author: Jooyer
 * Date: 2018-08-08
 * Time: 14:44
 */
class CustomMenu(context: Context, attr: AttributeSet, defStyleAttr: Int)
    : RelativeLayout(context, attr, defStyleAttr) {

    /**
     * 最左側圖示
     */
    private lateinit var iv_left_icon_menu: ImageView
    /**
     * 緊挨著左側圖示的文字
     */
    private lateinit var tv_left_name_menu: TextView
    /**
     * 緊挨著右側的文字(與 緊挨著右側的圖片 只顯示一種)
     */
    private lateinit var tv_right_name_menu: TextView
    /**
     * 緊挨著右側的圖片(與 緊挨著右側的文字 只顯示一種)
     */
    private lateinit var iv_near_right_icon_menu: ImageView
    /**
     * 最右側圖示(一般是向右箭頭 →)
     */
    private lateinit var iv_right_arrow_menu: ImageView
    /**
     * 底部分割線
     */
    private lateinit var view_bottom_divider_menu: View

    private var rightTextRightMargin = 0

    constructor(context: Context, attr: AttributeSet) : this(context, attr, 0)

    init {
        initView()
        parseAttrs(context, attr)

    }

    private fun initView() {
        val parent = LayoutInflater.from(context).inflate( R.layout.menu_image_text_text_image, this,true)
        iv_left_icon_menu = parent.findViewById(R.id.iv_left_icon_menu)
        tv_left_name_menu = parent.findViewById(R.id.tv_left_name_menu)
        tv_right_name_menu = parent.findViewById(R.id.tv_right_name_menu)
        iv_near_right_icon_menu = parent.findViewById(R.id.iv_right_icon_menu)
        iv_right_arrow_menu = parent.findViewById(R.id.iv_right_arrow_menu)
        view_bottom_divider_menu = parent.findViewById(R.id.view_bottom_divider_menu)
    }

    private fun parseAttrs(context: Context, attr: AttributeSet) {
        val arr = context.obtainStyledAttributes(attr, R.styleable.CustomMenu)
        val leftImageVisible = arr.getBoolean(R.styleable.CustomMenu_cm_left_image_visible, true)
        val leftImageDrawable = arr.getDrawable(R.styleable.CustomMenu_cm_left_image_drawable)
        val leftImageWidth = arr.getDimension(R.styleable.CustomMenu_cm_left_image_width, dp2px(20F)).toInt()
        val leftImageHeight = arr.getDimension(R.styleable.CustomMenu_cm_left_image_height, dp2px(20F)).toInt()

        val leftTextInfo = arr.getText(R.styleable.CustomMenu_cm_left_text_info)
        val leftTextSize = arr.getInteger(R.styleable.CustomMenu_cm_left_text_size, 14).toFloat()
        val leftTextLeftMargin = arr.getDimension(R.styleable.CustomMenu_cm_left_text_left_margin, dp2px(10F)).toInt()
        val leftTextColor = arr.getColor(R.styleable.CustomMenu_cm_left_text_color,
                ContextCompat.getColor(context, R.color.color_111111))

        val rightTextInfo = arr.getText(R.styleable.CustomMenu_cm_right_text_info)
        val rightTextVisible = arr.getBoolean(R.styleable.CustomMenu_cm_right_text_visible, true)
        val rightTextSize = arr.getInt(R.styleable.CustomMenu_cm_right_text_size, 14).toFloat()
        rightTextRightMargin = arr.getDimension(R.styleable.CustomMenu_cm_right_text_right_margin, dp2px(20F)).toInt()
        val rightTextColor = arr.getColor(R.styleable.CustomMenu_cm_right_text_color,
                ContextCompat.getColor(context, R.color.color_111111))

        val rightNearImageVisible = arr.getBoolean(R.styleable.CustomMenu_cm_right_near_image_visible, false)
        val rightNearImageDrawable = arr.getDrawable(R.styleable.CustomMenu_cm_right_near_image_drawable)
        val rightNearImageWidth = arr.getDimension(R.styleable.CustomMenu_cm_right_near_image_width, dp2px(20F)).toInt()
        val rightNearImageHeight = arr.getDimension(R.styleable.CustomMenu_cm_right_near_image_height, dp2px(20F)).toInt()

        val rightDrawableVisible = arr.getBoolean(R.styleable.CustomMenu_cm_right_image_visible, true)
        val rightImageDrawable = arr.getDrawable(R.styleable.CustomMenu_cm_right_image_drawable)
        val rightImageWidth = arr.getDimension(R.styleable.CustomMenu_cm_right_image_width, dp2px(22F)).toInt()
        val rightImageHeight = arr.getDimension(R.styleable.CustomMenu_cm_right_image_height, dp2px(22F)).toInt()

        val bottomDividerVisible = arr.getBoolean(R.styleable.CustomMenu_cm_bottom_divider_visible, false)
        val bottomDividerColor = arr.getColor(R.styleable.CustomMenu_cm_bottom_divider_color,
                ContextCompat.getColor(context, R.color.color_EEEEEE))
        val bottomDividerLeftMargin = arr.getDimension(R.styleable.CustomMenu_cm_bottom_divider_left_margin, dp2px(20F)).toInt()

        iv_left_icon_menu.visibility = if (leftImageVisible) View.VISIBLE else View.GONE
        if (null != leftImageDrawable) {
            iv_left_icon_menu.setImageDrawable(leftImageDrawable)
        }
        val leftImageLp: RelativeLayout.LayoutParams = iv_left_icon_menu.layoutParams as LayoutParams
        leftImageLp.width = leftImageWidth
        leftImageLp.height = leftImageHeight
        iv_left_icon_menu.layoutParams = leftImageLp


        if (!TextUtils.isEmpty(leftTextInfo)) {
            tv_left_name_menu.text = leftTextInfo
            tv_left_name_menu.setTextColor(leftTextColor)
            tv_left_name_menu.setTextSize(TypedValue.COMPLEX_UNIT_DIP, leftTextSize)

            val leftTextLp: RelativeLayout.LayoutParams = tv_left_name_menu.layoutParams as LayoutParams
            leftTextLp.marginStart = leftTextLeftMargin
            tv_left_name_menu.layoutParams = leftTextLp
        }


        tv_right_name_menu.visibility = if (rightTextVisible) View.VISIBLE else View.GONE
        if (!TextUtils.isEmpty(rightTextInfo)) {
            tv_right_name_menu.text = rightTextInfo
            tv_right_name_menu.setTextColor(rightTextColor)
            tv_right_name_menu.setTextSize(TypedValue.COMPLEX_UNIT_DIP, rightTextSize)

            val rightTextLp: RelativeLayout.LayoutParams = tv_right_name_menu.layoutParams as LayoutParams
            if (rightDrawableVisible) {
                rightTextLp.marginEnd = rightTextRightMargin + dp2px(20F).toInt()
            } else {
                rightTextLp.marginEnd = rightTextRightMargin
            }
            tv_right_name_menu.layoutParams = rightTextLp
        }


        iv_near_right_icon_menu.visibility = if (rightNearImageVisible) View.VISIBLE else View.GONE
        if (null != rightNearImageDrawable) {
            iv_near_right_icon_menu.setImageDrawable(rightNearImageDrawable)
        }

        val rightNearImageLp: RelativeLayout.LayoutParams = iv_near_right_icon_menu.layoutParams as LayoutParams
        rightNearImageLp.width = rightNearImageWidth
        rightNearImageLp.height = rightNearImageHeight
        if (rightDrawableVisible) {
            rightNearImageLp.marginEnd = rightTextRightMargin + dp2px(20F).toInt()
        } else {
            rightNearImageLp.marginEnd = rightTextRightMargin
        }
        iv_near_right_icon_menu.layoutParams = rightNearImageLp


        iv_right_arrow_menu.visibility = if (rightDrawableVisible) View.VISIBLE else View.GONE
        if (null != rightImageDrawable) {
            iv_right_arrow_menu.setImageDrawable(rightImageDrawable)
        }

        val rightImageLp: RelativeLayout.LayoutParams = iv_right_arrow_menu.layoutParams as LayoutParams
        rightImageLp.width = rightImageWidth
        rightImageLp.height = rightImageHeight
        iv_right_arrow_menu.layoutParams = rightImageLp

        view_bottom_divider_menu.visibility = if (bottomDividerVisible) View.VISIBLE else View.GONE
        view_bottom_divider_menu.setBackgroundColor(bottomDividerColor)
        val bottomDividerLp: RelativeLayout.LayoutParams = view_bottom_divider_menu.layoutParams as LayoutParams
        bottomDividerLp.leftMargin = bottomDividerLeftMargin
        view_bottom_divider_menu.layoutParams = bottomDividerLp

        arr.recycle()
    }

    fun setRightTextVisible(isVisible: Boolean) {
        tv_right_name_menu.visibility = if (isVisible) View.VISIBLE else View.GONE
    }

    fun setRightNearImageViewVisible(isVisible: Boolean) {
        iv_near_right_icon_menu.visibility = if (isVisible) View.VISIBLE else View.GONE
    }

    fun getRightNearImageView(): ImageView {
        return iv_near_right_icon_menu
    }

    fun setRightImageViewVisible(isVisible: Boolean) {
        val rightNearImageLp: RelativeLayout.LayoutParams = iv_near_right_icon_menu.layoutParams as LayoutParams
        val rightTextLp: RelativeLayout.LayoutParams = tv_right_name_menu.layoutParams as LayoutParams
        if (isVisible) {
            rightNearImageLp.marginEnd = rightTextRightMargin + dp2px(20F).toInt()
            rightTextLp.marginEnd = rightTextRightMargin + dp2px(20F).toInt()
            iv_right_arrow_menu.visibility = View.VISIBLE
        } else {
            rightNearImageLp.marginEnd = rightTextRightMargin
            rightTextLp.marginEnd = rightTextRightMargin
            iv_right_arrow_menu.visibility = View.GONE
        }

        iv_near_right_icon_menu.layoutParams = rightNearImageLp
        tv_right_name_menu.layoutParams = rightTextLp
    }


    fun setLeftText(text: String?) {
        text?.let {
            tv_left_name_menu.text = text
        }

    }

    fun setLeftText(text: String?, color: Int) {
        text?.let {
            tv_left_name_menu.text = text
            tv_left_name_menu.setTextColor(color)
        }
    }

    fun setRightText(text: String?, color: Int) {
        text?.let {
            tv_right_name_menu.text = it
            tv_right_name_menu.setTextColor(color)
        }
    }

    fun setRightText(text: String?) {
        text?.let {
            tv_right_name_menu.text = it
        }
    }

    private fun dp2px(def: Float): Float {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, def, context.resources.displayMetrics)
    }

}
複製程式碼

來看看自定義的屬性(xml檔案)

裡面就是一大堆自定義的屬性,具體含義往下看

   <?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="CustomMenu">
        <!-- 最左側圖示是否可見 -->
        <attr name="cm_left_image_visible" format="boolean"/>
        <!-- 最左側圖示的 drawable -->
        <attr name="cm_left_image_drawable" format="reference"/>
        <!-- 最左側圖示寬度 -->
        <attr name="cm_left_image_width" format="dimension|integer"/>
        <!-- 最左側圖表高度 -->
        <attr name="cm_left_image_height" format="dimension|integer"/>

        <!-- 緊靠左側的文字 -->
        <attr name="cm_left_text_info" format="reference|string"/>
        <!-- 緊靠左側的文字大小 -->
        <attr name="cm_left_text_size" format="dimension|integer"/>
        <!-- 緊靠左側的文字顏色 -->
        <attr name="cm_left_text_color" format="color|reference"/>
        <!-- 緊靠左側的文字左側Margin -->
        <attr name="cm_left_text_left_margin" format="dimension|integer"/>

        <!-- 緊靠右側的文字 -->
        <attr name="cm_right_text_info" format="reference|string"/>
        <!-- 緊靠右側的文字是否可見 -->
        <attr name="cm_right_text_visible" format="boolean"/>
        <!-- 緊靠右側的文字大小 -->
        <attr name="cm_right_text_size" format="dimension|integer"/>
        <!-- 緊靠右側的文字顏色 -->
        <attr name="cm_right_text_color" format="color|reference"/>
        <!-- 緊靠右側的文字右側Margin -->
        <attr name="cm_right_text_right_margin" format="dimension|integer"/>

        <!-- 緊靠右側圖示是否可見 -->
        <attr name="cm_right_near_image_visible" format="boolean"/>
        <!-- 緊靠右側圖示的 drawable -->
        <attr name="cm_right_near_image_drawable" format="reference"/>
        <!-- 緊靠右側圖示寬度 -->
        <attr name="cm_right_near_image_width" format="dimension|integer"/>
        <!-- 緊靠右側圖表高度 -->
        <attr name="cm_right_near_image_height" format="dimension|integer"/>

        <!-- 最右側圖示的是否可見 -->
        <attr name="cm_right_image_visible" format="boolean"/>
        <!-- 最右側圖示的 drawable -->
        <attr name="cm_right_image_drawable" format="reference"/>
        <!-- 最右側圖示寬度 -->
        <attr name="cm_right_image_width" format="dimension|integer"/>
        <!-- 最右側圖表高度 -->
        <attr name="cm_right_image_height" format="dimension|integer"/>

        <!-- 底部分割線是否可見 -->
        <attr name="cm_bottom_divider_visible" format="boolean"/>
        <!-- 底部分割線顏色 -->
        <attr name="cm_bottom_divider_color" format="color|reference"/>
        <!-- 底部分割線左側Margin -->
        <attr name="cm_bottom_divider_left_margin" format="dimension|integer"/>


    </declare-styleable>

</resources>
複製程式碼

屬性雖然有些多,但是大都都見名知意. 這裡還是要看下其佈局檔案,雖然 so easy

####再來看看其佈局(xml檔案)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="@dimen/height_50"
    android:background="@android:color/white"
    android:orientation="vertical"
    >

    <ImageView
        android:id="@+id/iv_left_icon_menu"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginStart="@dimen/padding_20"
        />

    <TextView
        android:id="@+id/tv_left_name_menu"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_centerVertical="true"
        android:layout_marginStart="@dimen/padding_8"
        android:layout_toEndOf="@+id/iv_left_icon_menu"
        android:gravity="center_vertical"
        android:textColor="@color/color_111111"
        android:textSize="@dimen/text_size_15"
        tools:text="寶貝頭像"
        />


    <TextView
        android:id="@+id/tv_right_name_menu"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_alignParentEnd="true"
        android:layout_centerVertical="true"
        android:layout_marginEnd="@dimen/padding_20"
        android:gravity="center_vertical"
        android:textColor="@color/color_111111"
        android:textSize="@dimen/text_size_15"
        tools:text="請填寫"
        />

    <ImageView
        android:id="@+id/iv_right_icon_menu"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_alignParentEnd="true"
        android:layout_centerVertical="true"
        android:layout_marginEnd="@dimen/padding_20"
        android:visibility="visible"
        />


    <ImageView
        android:id="@+id/iv_right_arrow_menu"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_centerVertical="true"
        android:layout_marginEnd="@dimen/padding_10"
        android:src="@drawable/ic_right_gray_next"
        />

    <View
        android:id="@+id/view_bottom_divider_menu"
        android:layout_width="match_parent"
        android:layout_height="@dimen/divider_2"
        android:layout_alignParentBottom="true"
        android:layout_marginStart="@dimen/padding_20"
        android:background="@color/color_EEEEEE"
        />
</RelativeLayout>
複製程式碼

最後來看看在 Activity 佈局中的用法

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="cn.molue.jooyer.custommenu.MainActivity">



    <!-- 左邊文字,右邊圖片 -->
    <cn.molue.jooyer.custommenu.CustomMenu
        android:id="@+id/cm_1_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cm_left_image_visible="false"
        app:cm_left_text_left_margin="@dimen/padding_20"
        app:cm_left_text_info="左邊文字"
        app:cm_bottom_divider_visible="true"
        app:cm_right_text_color="@color/color_999999"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        />

    <!-- 左邊文字,右邊文字+圖片 -->
    <cn.molue.jooyer.custommenu.CustomMenu
        android:id="@+id/cm_2_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cm_left_image_visible="false"
        app:cm_left_text_left_margin="@dimen/padding_20"
        app:cm_left_text_info="左邊文字"
        app:cm_right_text_right_margin="@dimen/padding_10"
        app:cm_right_text_info="右邊文字"
        app:cm_bottom_divider_visible="true"
        app:cm_right_text_color="@color/color_999999"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/cm_1_main"
        app:layout_constraintRight_toRightOf="parent"
        />


    <!-- 左邊圖片,右邊圖片 -->
    <cn.molue.jooyer.custommenu.CustomMenu
        android:id="@+id/cm_3_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cm_left_image_visible="true"
        app:cm_left_image_drawable="@drawable/ic_launcher_background"
        app:cm_bottom_divider_visible="true"
        app:cm_right_text_color="@color/color_999999"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/cm_2_main"
        app:layout_constraintRight_toRightOf="parent"
        />

    <!-- 左邊圖片,右邊文字 -->
    <cn.molue.jooyer.custommenu.CustomMenu
        android:id="@+id/cm_4_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cm_left_image_visible="true"
        app:cm_left_image_drawable="@drawable/ic_launcher_background"
        app:cm_right_text_right_margin="@dimen/padding_10"
        app:cm_right_text_info="右邊文字"
        app:cm_bottom_divider_visible="true"
        app:cm_right_image_visible="false"
        app:cm_right_text_color="@color/color_999999"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/cm_3_main"
        app:layout_constraintRight_toRightOf="parent"
        />

    <!-- 左邊圖片+文字,右邊文字 -->
    <cn.molue.jooyer.custommenu.CustomMenu
        android:id="@+id/cm_5_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cm_left_image_visible="true"
        app:cm_left_image_drawable="@drawable/ic_launcher_background"
        app:cm_right_text_right_margin="@dimen/padding_10"
        app:cm_right_text_info="右邊文字"
        app:cm_left_text_info="左邊文字"
        app:cm_bottom_divider_visible="true"
        app:cm_right_image_visible="false"
        app:cm_right_text_color="@color/color_999999"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/cm_4_main"
        app:layout_constraintRight_toRightOf="parent"
        />

    <!-- 左邊圖片+文字,右邊文字+圖片 -->
    <cn.molue.jooyer.custommenu.CustomMenu
        android:id="@+id/cm_6_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cm_left_image_visible="true"
        app:cm_left_image_drawable="@drawable/ic_launcher_background"
        app:cm_right_text_right_margin="@dimen/padding_10"
        app:cm_right_text_info="右邊文字"
        app:cm_left_text_info="左邊文字"
        app:cm_bottom_divider_visible="true"
        app:cm_right_image_visible="true"
        app:cm_right_text_color="@color/color_999999"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/cm_5_main"
        app:layout_constraintRight_toRightOf="parent"
        />

    <!-- 左邊圖片+文字,右邊圖片+圖片 -->
    <cn.molue.jooyer.custommenu.CustomMenu
        android:id="@+id/cm_7_main"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:cm_left_image_visible="true"
        app:cm_left_image_drawable="@drawable/ic_launcher_background"
        app:cm_right_text_visible="false"
        app:cm_right_near_image_visible="true"
        app:cm_right_near_image_drawable="@drawable/ic_launcher_background"
        app:cm_left_text_info="左邊文字"
        app:cm_bottom_divider_visible="false"
        app:cm_right_image_visible="true"
        app:cm_right_near_image_width="@dimen/width_20"
        app:cm_right_near_image_height="@dimen/height_20"
        app:cm_right_text_color="@color/color_999999"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/cm_6_main"
        app:layout_constraintRight_toRightOf="parent"
        />

</android.support.constraint.ConstraintLayout>


複製程式碼

這個就不解釋了,最後看看 Activity中的操作

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 有多個方法,不夠可以自己再定義
//        cm_7_main.setLeftText("")
//        cm_7_main.setRightText("")

    }
}
複製程式碼

是不是相當簡單呢,其實至於左邊圖片,右邊文字還是圖片什麼的,可以自己根據需要組合, app:cm_bottom_divider_visible="false" 主要是一個分割線,根據需要可以定製哈!

###喜歡記得點贊,收藏,轉發哈!

相關文章