Android 最简单的自定义Toolbar之一

370 阅读7分钟

作者: Jooyer, 时间: 2018.09.08

天星

Github地址,欢迎点赞,fork

一般APP 都使用自己写的 Toolbar , 使用系统情况比较少,本次自定义其实是组合控件而已,虽然有很多大佬有类似控件,有些时候不一定完全满足自己的需要.

本次代码简单,我就直接贴源码,如果还有不清楚的,可以留言或者看github

只需要一个类 + 两个 XML 文件即可,即拷即用

接下来我们依次讲解:

  1. CustomToolbar
  2. 两个 XML 文件
  3. 属性及默认值

首先,看看 CustomToolbar

package cn.molue.jooyer.toolbar

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: 自定义 Toolbar ,格式如下:
 *
 * Author: Jooyer
 * Date: 2018-08-08
 * Time: 17:13
 */
class CustomToolbar(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_center_title_menu: TextView
    /**
     * 最右侧文本
     */
    private lateinit var tv_right_name_menu: TextView
    /**
     * 最右侧图标,默认显示
     */
    private lateinit var iv_right_icon_menu: ImageView

    /**
     * 底部分割线
     */
    private lateinit var view_bottom_divider_menu: View


    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.toolbar_custom, 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_center_title_menu = parent.findViewById(R.id.tv_center_title_menu)
        tv_right_name_menu = parent.findViewById(R.id.tv_right_name_menu)
        iv_right_icon_menu = parent.findViewById(R.id.iv_right_icon_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.CustomToolbar)
        val leftImageVisible = arr.getBoolean(R.styleable.CustomToolbar_ct_left_image_visible, true)
        val leftImageDrawable = arr.getDrawable(R.styleable.CustomToolbar_ct_left_image_drawable)
        val leftImageWidth = arr.getDimension(R.styleable.CustomToolbar_ct_left_image_width, dp2px(20F)).toInt()
        val leftImageHeight = arr.getDimension(R.styleable.CustomToolbar_ct_left_image_height, dp2px(20F)).toInt()
        val leftImagePadding = arr.getDimension(R.styleable.CustomToolbar_ct_left_image_padding, dp2px(3F)).toInt()
        val leftImageLeftMargin = arr.getDimension(R.styleable.CustomToolbar_ct_left_image_left_margin, dp2px(0F)).toInt()

        val leftTextVisible = arr.getBoolean(R.styleable.CustomToolbar_ct_left_text_visible, false)
        val leftTextInfo = arr.getText(R.styleable.CustomToolbar_ct_left_text_info)
        val leftTextSize = arr.getInteger(R.styleable.CustomToolbar_ct_left_text_size, 15).toFloat()
        val leftTextLeftMargin = arr.getDimension(R.styleable.CustomToolbar_ct_left_text_left_margin, dp2px(20F)).toInt()
        val leftTextColor = arr.getColor(R.styleable.CustomToolbar_ct_left_text_color,
                ContextCompat.getColor(context, R.color.color_111111))

        val centerTextInfo = arr.getText(R.styleable.CustomToolbar_ct_center_text_info)
        val centerTextSize = arr.getInteger(R.styleable.CustomToolbar_ct_center_text_size, 15).toFloat()
        val centerTextColor = arr.getColor(R.styleable.CustomToolbar_ct_center_text_color,
                ContextCompat.getColor(context, R.color.color_111111))

        val rightImageVisible = arr.getBoolean(R.styleable.CustomToolbar_ct_right_image_visible, true)
        val rightImageDrawable = arr.getDrawable(R.styleable.CustomToolbar_ct_right_image_drawable)
        val rightImageWidth = arr.getDimension(R.styleable.CustomToolbar_ct_right_image_width, dp2px(20F)).toInt()
        val rightImageHeight = arr.getDimension(R.styleable.CustomToolbar_ct_right_image_height, dp2px(20F)).toInt()
        val rightImagePadding = arr.getDimension(R.styleable.CustomToolbar_ct_right_image_padding, dp2px(5F)).toInt()
        val rightImageRightMargin = arr.getDimension(R.styleable.CustomToolbar_ct_right_image_right_margin, dp2px(20F)).toInt()

        val rightTextVisible = arr.getBoolean(R.styleable.CustomToolbar_ct_right_text_visible, false)
        val rightTextInfo = arr.getText(R.styleable.CustomToolbar_ct_right_text_info)
        val rightTextSize = arr.getInteger(R.styleable.CustomToolbar_ct_right_text_size, 15).toFloat()
        val rightTextRightMargin = arr.getDimension(R.styleable.CustomToolbar_ct_right_text_right_margin, dp2px(20F)).toInt()
        val rightTextColor = arr.getColor(R.styleable.CustomToolbar_ct_right_text_color,
                ContextCompat.getColor(context, R.color.color_111111))

        val bottomDividerVisible = arr.getBoolean(R.styleable.CustomToolbar_ct_bottom_divider_visible, false)
        val bottomDividerColor = arr.getColor(R.styleable.CustomToolbar_ct_bottom_divider_color,
                ContextCompat.getColor(context, R.color.color_EEEEEE))
        val backgroundColor = arr.getColor(R.styleable.CustomToolbar_ct_background_color,
                ContextCompat.getColor(context, R.color.color_FE632E))

        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
        leftImageLp.leftMargin = leftImageLeftMargin
        iv_left_icon_menu.setPadding(leftImagePadding, leftImagePadding, leftImagePadding, leftImagePadding)
        iv_left_icon_menu.layoutParams = leftImageLp

        tv_left_name_menu.visibility = if (leftTextVisible) View.VISIBLE else View.GONE
        if (!TextUtils.isEmpty(leftTextInfo)) {
            tv_left_name_menu.text = leftTextInfo
            tv_left_name_menu.setTextSize(TypedValue.COMPLEX_UNIT_DIP, leftTextSize)
            tv_left_name_menu.setTextColor(leftTextColor)
        }

        val leftTextLp: RelativeLayout.LayoutParams = tv_left_name_menu.layoutParams as LayoutParams
        leftTextLp.leftMargin = leftTextLeftMargin
        tv_left_name_menu.layoutParams = leftTextLp

        if (!TextUtils.isEmpty(centerTextInfo)) {
            tv_center_title_menu.text = centerTextInfo
            tv_center_title_menu.setTextSize(TypedValue.COMPLEX_UNIT_DIP, centerTextSize)
            tv_center_title_menu.setTextColor(centerTextColor)
        }

        iv_right_icon_menu.visibility = if (rightImageVisible) View.VISIBLE else View.GONE
        if (null != rightImageDrawable) {
            iv_right_icon_menu.setImageDrawable(rightImageDrawable)
        }
        val rightImageLp: RelativeLayout.LayoutParams = iv_right_icon_menu.layoutParams as LayoutParams
        rightImageLp.width = rightImageWidth
        rightImageLp.height = rightImageHeight
        rightImageLp.rightMargin = rightImageRightMargin
        iv_right_icon_menu.setPadding(rightImagePadding, rightImagePadding, rightImagePadding, rightImagePadding)
        iv_right_icon_menu.layoutParams = rightImageLp


        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.setTextSize(TypedValue.COMPLEX_UNIT_DIP, rightTextSize)
            tv_right_name_menu.setTextColor(rightTextColor)
        }
        val rightTextLp: RelativeLayout.LayoutParams = tv_right_name_menu.layoutParams as LayoutParams
        rightTextLp.rightMargin = rightTextRightMargin
        tv_right_name_menu.layoutParams = rightTextLp

        view_bottom_divider_menu.visibility = if (bottomDividerVisible) View.VISIBLE else View.GONE
        view_bottom_divider_menu.setBackgroundColor(bottomDividerColor)

        setBackgroundColor(backgroundColor)
        arr.recycle()
    }

    public fun setLeftImageListener(listener: View.OnClickListener) {
        iv_left_icon_menu.setOnClickListener(listener)
    }

    public fun setRightImageListener(listener: View.OnClickListener) {
        iv_right_icon_menu.setOnClickListener(listener)
    }

    public fun setRightTextListener(listener: View.OnClickListener) {
        tv_right_name_menu.setOnClickListener(listener)
    }


    public fun setCenterText(text: String) {
        tv_center_title_menu.text = text
    }

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

来看看自定义的属性(xml文件)

里面就是一大堆自定义的属性,具体含义往下看

    <declare-styleable name="CustomToolbar">
        <!-- 左侧文本是否显示 -->
        <attr name="ct_left_text_visible" format="boolean"/>
        <!-- 左侧文本 -->
        <attr name="ct_left_text_info" format="reference|string"/>
        <!-- 左侧文本大小 -->
        <attr name="ct_left_text_size" format="dimension|integer"/>
        <!-- 左侧文本颜色 -->
        <attr name="ct_left_text_color" format="color|reference"/>
        <!-- 左侧文本左侧 MarginLeft -->
        <attr name="ct_left_text_left_margin" format="dimension|integer"/>
        <!-- 左侧图片是否显示 -->
        <attr name="ct_left_image_visible" format="boolean"/>
        <!-- 左侧图片 Drawable -->
        <attr name="ct_left_image_drawable" format="reference"/>
        <!-- 左侧图片宽度 -->
        <attr name="ct_left_image_width" format="dimension|integer"/>
        <!-- 左侧图片高度 -->
        <attr name="ct_left_image_height" format="dimension|integer"/>
        <!-- 左侧图片 Padding(上下左右) -->
        <attr name="ct_left_image_padding" format="dimension|integer"/>
        <!-- 左侧图片左侧 MarginLeft -->
        <attr name="ct_left_image_left_margin" format="dimension|integer"/>
        <!-- 中间文本 -->
        <attr name="ct_center_text_info" format="reference|string"/>
        <!-- 中间文本大小 -->
        <attr name="ct_center_text_size" format="dimension|integer"/>
        <!-- 中间文本颜色 -->
        <attr name="ct_center_text_color" format="color|reference"/>
        <!-- 右侧文本是否可见 -->
        <attr name="ct_right_text_visible" format="boolean"/>
        <!-- 右侧文本 -->
        <attr name="ct_right_text_info" format="reference|string"/>
        <!-- 右侧文本大小 -->
        <attr name="ct_right_text_size" format="dimension|integer"/>
        <!-- 右侧文本颜色 -->
        <attr name="ct_right_text_color" format="color|reference"/>
        <!-- 右侧文本右侧 MarginRight -->
        <attr name="ct_right_text_right_margin" format="dimension|integer"/>
        <!-- 右侧图片是否可见 -->
        <attr name="ct_right_image_visible" format="boolean"/>
        <!-- 右侧图片 Drawable -->
        <attr name="ct_right_image_drawable" format="reference"/>
        <!-- 右侧图片宽度 -->
        <attr name="ct_right_image_width" format="dimension|integer"/>
        <!-- 右侧图片高度 -->
        <attr name="ct_right_image_height" format="dimension|integer"/>
        <!-- 右侧图片 Padding(上下左右) -->
        <attr name="ct_right_image_padding" format="dimension|integer"/>
        <!-- 右侧图片右侧 MarginRight -->
        <attr name="ct_right_image_right_margin" format="dimension|integer"/>
        <!-- 底部分割线是否可见 -->
        <attr name="ct_bottom_divider_visible" format="boolean"/>
        <!-- 底部分割线颜色 -->
        <attr name="ct_bottom_divider_color" format="color|reference"/>
        <!-- Toolbar背景色 -->
        <attr name="ct_background_color" format="color|reference"/>
    </declare-styleable>

属性虽然有些多,但是大都都见名知意. 这里还是要看下其布局文件,虽然 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:orientation="vertical">

    <ImageView
        android:id="@+id/iv_left_icon_menu"
        android:layout_width="@dimen/width_45"
        android:layout_height="match_parent"
        android:layout_centerVertical="true"
        android:src="@mipmap/icon_black_back" />

    <TextView
        android:id="@+id/tv_left_name_menu"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_centerVertical="true"
        android:gravity="center_vertical"
        android:textColor="@color/color_111111"
        android:textSize="@dimen/text_size_15"
        tools:text="宝贝头像" />


    <TextView
        android:id="@+id/tv_center_title_menu"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:layout_marginEnd="@dimen/padding_20"
        android:gravity="center_vertical"
        android:textColor="@color/color_111111"
        android:textSize="@dimen/text_size_18"
        android:textStyle="bold"
        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" />


    <View
        android:id="@+id/view_bottom_divider_menu"
        android:layout_width="match_parent"
        android:layout_height="@dimen/divider_2"
        android:layout_alignParentBottom="true"
        android:background="@color/color_EEEEEE" />
</RelativeLayout>

最后来看看在 Activity 布局中的用法

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    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"
    android:orientation="vertical"
    tools:context="cn.molue.jooyer.toolbar.MainActivity"
    >

    <cn.molue.jooyer.toolbar.CustomToolbar
        android:id="@+id/ct_tool_bar1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/padding_6"
        android:layout_marginBottom="@dimen/padding_6"
        app:ct_center_text_info="左边图片,右边文本"
        app:ct_right_text_info="清空"
        app:ct_right_text_right_margin="@dimen/padding_5"
        app:ct_right_text_visible="true"
        />


    <cn.molue.jooyer.toolbar.CustomToolbar
        android:id="@+id/ct_tool_bar2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/padding_6"
        android:layout_marginBottom="@dimen/padding_6"
        app:ct_center_text_info="左边图片,右边图片"
        app:ct_right_image_drawable="@mipmap/icon_black_back"
        app:ct_right_image_right_margin="@dimen/padding_5"
        />

    <cn.molue.jooyer.toolbar.CustomToolbar
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/padding_6"
        android:layout_marginBottom="@dimen/padding_6"
        app:ct_center_text_info="左边文本,右边文本"
        app:ct_left_image_visible="false"
        app:ct_left_text_info="返回"
        app:ct_left_text_left_margin="@dimen/padding_5"
        app:ct_left_text_visible="true"
        app:ct_right_image_right_margin="@dimen/padding_5"
        app:ct_right_text_info="清空"
        app:ct_right_text_right_margin="@dimen/padding_5"
        app:ct_right_text_visible="true"
        />

    <cn.molue.jooyer.toolbar.CustomToolbar
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/padding_6"
        android:layout_marginBottom="@dimen/padding_6"
        app:ct_center_text_info="左边文本,右边图片"
        app:ct_left_image_visible="false"
        app:ct_left_text_info="返回"
        app:ct_left_text_left_margin="@dimen/padding_5"
        app:ct_left_text_visible="true"
        app:ct_right_image_drawable="@mipmap/icon_black_back"
        app:ct_right_image_right_margin="@dimen/padding_5"

        />

    <cn.molue.jooyer.toolbar.CustomToolbar
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/padding_6"
        android:layout_marginBottom="@dimen/padding_6"
        app:ct_background_color="@color/colorAccent"
        app:ct_center_text_info="改变背景色"
        app:ct_left_image_visible="false"
        app:ct_left_text_info="返回"
        app:ct_left_text_left_margin="@dimen/padding_5"
        app:ct_left_text_visible="true"
        app:ct_right_image_drawable="@mipmap/icon_black_back"
        app:ct_right_image_right_margin="@dimen/padding_5"
        />


</LinearLayout>

这个就不解释了,最后看看 Activity中的操作

class MainActivity : AppCompatActivity() {

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

        ct_tool_bar1.setLeftImageListener(View.OnClickListener {
            Toast.makeText(this@MainActivity,"点击了左侧图片",Toast.LENGTH_SHORT).show()
        })

        ct_tool_bar1.setRightTextListener(View.OnClickListener {
            Toast.makeText(this@MainActivity,"点击了右侧文字",Toast.LENGTH_SHORT).show()
        })

        ct_tool_bar2.setRightImageListener(View.OnClickListener {
            Toast.makeText(this@MainActivity,"点击了右侧图片",Toast.LENGTH_SHORT).show()
        })
    }
}

最后讲解下属性和默认值

 		<!-- 左侧文本是否显示 -->
        <attr name="ct_left_text_visible" format="boolean"/>  // 默认是false
        <!-- 左侧文本 -->
        <attr name="ct_left_text_info" format="reference|string"/>
        <!-- 左侧文本大小 -->
        <attr name="ct_left_text_size" format="dimension|integer"/> // 默认是15dp
        <!-- 左侧文本颜色 -->
        <attr name="ct_left_text_color" format="color|reference"/> // 默认颜色是 #111111
        <!-- 左侧文本左侧 MarginLeft -->
        <attr name="ct_left_text_left_margin" format="dimension|integer"/> // 默认是20dp
        <!-- 左侧图片是否显示 -->
        <attr name="ct_left_image_visible" format="boolean"/> // 默认是 true
        <!-- 左侧图片 Drawable -->
        <attr name="ct_left_image_drawable" format="reference"/> // 给了个黑色箭头
        <!-- 左侧图片宽度 -->
        <attr name="ct_left_image_width" format="dimension|integer"/> // 默认20dp
        <!-- 左侧图片高度 -->
        <attr name="ct_left_image_height" format="dimension|integer"/> // 默认20dp
        <!-- 左侧图片 Padding(上下左右) -->
        <attr name="ct_left_image_padding" format="dimension|integer"/> // 默认3dp
        <!-- 左侧图片左侧 MarginLeft -->
        <attr name="ct_left_image_left_margin" format="dimension|integer"/> // 默认为 0 
        <!-- 中间文本 -->
        <attr name="ct_center_text_info" format="reference|string"/>
        <!-- 中间文本大小 -->
        <attr name="ct_center_text_size" format="dimension|integer"/> // 默认15dp
        <!-- 中间文本颜色 -->
        <attr name="ct_center_text_color" format="color|reference"/> // 默认#111111
        <!-- 右侧文本是否可见 -->
        <attr name="ct_right_text_visible" format="boolean"/> // 默认false
        <!-- 右侧文本 -->
        <attr name="ct_right_text_info" format="reference|string"/>
        <!-- 右侧文本大小 -->
        <attr name="ct_right_text_size" format="dimension|integer"/> // 默认15dp
        <!-- 右侧文本颜色 -->
        <attr name="ct_right_text_color" format="color|reference"/> // 默认#111111
        <!-- 右侧文本右侧 MarginRight -->
        <attr name="ct_right_text_right_margin" format="dimension|integer"/>  // 默认20dp
        <!-- 右侧图片是否可见 -->
        <attr name="ct_right_image_visible" format="boolean"/> // 默认是true 
        <!-- 右侧图片 Drawable -->
        <attr name="ct_right_image_drawable" format="reference"/>
        <!-- 右侧图片宽度 -->
        <attr name="ct_right_image_width" format="dimension|integer"/> // 默认20dp
        <!-- 右侧图片高度 -->
        <attr name="ct_right_image_height" format="dimension|integer"/> // 默认20dp
        <!-- 右侧图片 Padding(上下左右) -->
        <attr name="ct_right_image_padding" format="dimension|integer"/> // 默认5dp
        <!-- 右侧图片右侧 MarginRight -->
        <attr name="ct_right_image_right_margin" format="dimension|integer"/> // 默认20dp
        <!-- 底部分割线是否可见 -->
        <attr name="ct_bottom_divider_visible" format="boolean"/> // 默认false
        <!-- 底部分割线颜色 -->
        <attr name="ct_bottom_divider_color" format="color|reference"/> // 默认#EEEEEE
        <!-- Toolbar背景色 -->
        <attr name="ct_background_color" format="color|reference"/> // 默认#FE632E

注意,如果不是使用默认属性,比如左侧不是图片,而是文字,记得隐藏图片,同时显示文字

当然,这些属性也可以在 CustomToolbar 中定义方法,在代码里动态设置,这个就没有写,主要是懒,大家需要什么加入什么就好了!

喜欢记得点赞,收藏,转发哈!