底部导航栏的组合布局

本篇文章主要记录昨天学习的组合布局实现底部导航栏的效果
显示效果:


image.png

主要知识点结构:

  • 如何添加子控件到指定的布局容器
  • 如何实现布局界面之间的交互

那么如何添加子控件到指定的布局容器呢?

/**
     * 知识点:
     *     当继承于系统自带的layout时 已经规定好了规则
     *     只关心如何添加自己的子控件进去
     *     在哪里添加子控件?
     *     创建的时候添加
     * */

如何实现布局界面之间的交互

/**
这里可以通过子控件的点击事件回调来实现
* */

下面我们开始具体实现如上效果,大致流程如下

  • 首先导入我们需要的项目资源到drawablemipmap包下
  • 然后实现单个控件的显示和点按功能
  • 最后组合多个控件实现自己想要的效果

导入项目资源就不提了,我们首先先实现单个控件的显示和点按功能
BarItem.Kotlin

class BarItem: LinearLayout {

    //正常状态的icon资源
    var normalIcon:Int = 0
    //选中状态的icon资源
    var selectIcon:Int = 0
    //显示标题
    var text:String = ""
        set(value) {
            field = value
            titleTextView?.text = value
        }
    //字体颜色
    var textColor:Int = 0
    //是否选中
    var mIsSelected:Boolean = false
        set(value) {
            field = value
            updateUI()
        }

    //更新UI
    private fun updateUI() {
        if (mIsSelected){
            iconImageView?.setBackgroundResource(selectIcon)
            titleTextView?.setTextColor(textColor)
        }else{
            iconImageView?.setBackgroundResource(normalIcon)
            titleTextView?.setTextColor(Color.BLACK)
        }
    }

    private var iconImageView:ImageView? = null
    private var titleTextView:TextView? = null

    constructor(context: Context):super(context){
        initView()
    }

    constructor(context: Context,attrs:AttributeSet?):super(context, attrs){
        initView()
        initAttr(context, attrs)
    }

    //提取自定义属性
    private fun initAttr(context: Context,attrs:AttributeSet?){
        val array = context.obtainStyledAttributes(attrs,R.styleable.BarItem)
        normalIcon = array.getResourceId(R.styleable.BarItem_normalIcon,R.mipmap.home)
        selectIcon = array.getResourceId(R.styleable.BarItem_selectIcon,R.mipmap.home_selected)
        text = array.getString(R.styleable.BarItem_text).toString()
        textColor = array.getInteger(R.styleable.BarItem_textColor, Color.RED)
        mIsSelected = array.getBoolean(R.styleable.BarItem_selected,false)
        array.recycle()
    }

    //布局子控件
    private fun initView(){
        //横向布局
        orientation = VERTICAL
        //居中对齐
        gravity = Gravity.CENTER
        iconImageView = ImageView(context).also {
            val lp = LayoutParams(dp2px(32),dp2px(32))
            addView(it,lp)
        }
        titleTextView = TextView(context).also {
            val lp = LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT)
            addView(it,lp)
        }
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        if (!mIsSelected){
            mIsSelected = true
        }
        return true
    }


    //dp值 转 px值
    private fun dp2px(dp:Int) = (context.resources.displayMetrics.density * dp).toInt()
}

在这里,我们在布局创建的时候添加子控件,也就是initView()方法在构造方法里使用,然后声明了对应的属性,mIsSelected属性用于判断是否选中,当出现点击事件时,它的值设置为true,这里我们设置了updateUI方法,用于更改对应显示的样式,这里没有设置属性私有化的目的是便于外部设置对应的属性值,我们使用xml布局显示下效果
activity_main.xml布局

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".MainActivity">

    <me.jrl.demo1.BarItem
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:normalIcon="@mipmap/home"
        app:selectIcon="@mipmap/home_selected"
        app:text="主页"
        app:textColor="@android:color/holo_red_light"
        app:selected="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

显示效果


image.png

下面我们组合实现底部导航栏
BarItem里声明的回调方法

//回调
    var callBack:((p:Int)->Unit)? = null

在点击事件中回调我们想要的position值

override fun onTouchEvent(event: MotionEvent?): Boolean {
        if (event?.action == MotionEvent.ACTION_DOWN){
            if (!mIsSelected) {
                mIsSelected = true
                callBack?.let {
                    it(position)
                }
            }
        }
        return true
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,186评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,858评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,620评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,888评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,009评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,149评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,204评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,956评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,385评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,698评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,863评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,544评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,185评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,899评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,141评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,684评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,750评论 2 351