撸一个自定义view,先上想要做成的效果图,可以看到我们默认选则的就是第二个按钮,中间图片不可替换,居中。有选中和非选中时展示不同的图片的效果。并且给外部实现点击时的回调,让外部知道当前点击的是哪个的回调。

不想了解,只想要代码请直接下拉至底部,查看完整代码。

如果想了解Java、Kotlin代码实现点击右侧链接进入 Java、Kotlin代码实现...

首先,我们使用依赖布局文件的方式来完成,上布局代码

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="67dp"android:background="@mipmap/layout_bottom_bar_background_with_shadow"><RadioGroupandroid:id="@+id/radio_group"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_marginTop="7dp"android:layout_marginBottom="7dp"android:background="@color/white"android:orientation="horizontal"><RadioButtonandroid:id="@+id/radio_home_page_selected_one"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:button="@null"android:drawablePadding="4dp"android:gravity="center"android:text="kotlin1"android:textSize="12sp" /><RadioButtonandroid:id="@+id/radio_home_page_selected_two"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:button="@null"android:drawablePadding="4dp"android:gravity="center"android:text="kotlin2"android:textSize="12sp" /><android.support.v4.widget.Spaceandroid:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1" /><RadioButtonandroid:id="@+id/radio_home_page_selected_three"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:button="@null"android:drawablePadding="4dp"android:gravity="center"android:text="kotlin3"android:textSize="12sp" /><RadioButtonandroid:id="@+id/radio_home_page_selected_four"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:button="@null"android:drawablePadding="4dp"android:gravity="center"android:text="kotlin4"android:textSize="12sp" /></RadioGroup><ImageViewandroid:id="@+id/radio_home_page_selected_center"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_centerHorizontal="true"android:layout_gravity="center"android:layout_marginBottom="10dp"android:scaleType="fitCenter"android:src="@mipmap/ic_launcher" /></RelativeLayout>

上图中的layout_bottom_bar_background_with_shadow.png是底部资源文件哦,这个需要你自己找一张透明的png图片呢,如果不想这么麻烦可以看我的 Java、Kotlin代码实现...    。可以看到我们用到的是RadioGroup嵌套RadioButton的方式,中间用一个space预留位置,再在外层使用imageView使其展示在中间,这样,我们的布局就已经完成了。先介绍一下布局内部使用的属性,一般具有基础的Android开发水平人员可以直接忽略一下内容,需则看

RadioGroup  单选按钮组
android:layout_alignParentBottom="true"  使布局置于父布局底部
android:layout_marginTop="7dp"           布局距离父布局顶部距离
android:layout_marginBottom="7dp"        布局距离父布局底部距离
android:background="@color/white"        当前布局背景颜色
android:orientation="horizontal"         当前布局的排列方式RadioButton  单选按钮
android:button="@null"             设置默认的样式为空
android:gravity="center"           设置当前布局内部子控件居中
android:drawablePadding="4dp"      设置当前控件内部图片内边距为4dp
android:layout_weight="1"          设置当前控件权重为1,需配合width=0或者hight=0使用
android:text="kotlin1"             设置控件文字内容
android:textSize="12sp"            设置控件文字大小Space        该控件在本文当做占位控件使用ImageView 图片控件
android:layout_centerHorizontal="true"   设置控件相当于父布局水平居中
android:src="@mipmap/ic_launcher"        设置图片控件图片资源

接下来,我们新建一个类继承RelativeLayout 实现他的构造方法,我们在这选择两个

package com.goldze.mvvmhabit.app;import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;/*** 费浩东* 2019/1/4* Created by fhd*/
public class MainBottomBarTest extends RelativeLayout{public MainBottomBarTest(Context context) {super(context);}public MainBottomBarTest(Context context, AttributeSet attrs) {super(context, attrs);}
}

然后在构造方法中,依赖布局以及初始化控件

//第一个按钮
private RadioButton mRadioOne;
//第二个按钮
private RadioButton mRadioTwo;
//中间的按钮
private ImageView mCenter;
//第四个按钮
private RadioButton mRadioThree;
//第五个按钮
private RadioButton mRadioFour;private void init(Context context) {//当前控件依赖布局LayoutInflater.from(context).inflate(R.layout.home_bottom_bar, this);//获取布局中的控件,实例化到当前对象中mRadioOne = findViewById(R.id.radio_home_page_selected_one);mRadioTwo = findViewById(R.id.radio_home_page_selected_two);mCenter = findViewById(R.id.radio_home_page_selected_center);mRadioThree = findViewById(R.id.radio_home_page_selected_three);mRadioFour = findViewById(R.id.radio_home_page_selected_four);
}

给每个radioButton设置图片,在init方法中调用setResourcePictures方法

    //默认的资源文件int[] defRes = {R.drawable.layout_bottom_bar_select,R.drawable.layout_bottom_bar_select,R.drawable.layout_bottom_bar_select,R.drawable.layout_bottom_bar_select};    //设置资源图片public void setResourcePictures(int[] drawableTop) {if (drawableTop.length != 4) {Log.e("setResourcePictures", "MainBottomBar中所提供的图片资源必须为4个: ");return;}mRadioOne.setCompoundDrawablesRelativeWithIntrinsicBounds(null, this.getResources().getDrawable(drawableTop[0]), null, null);mRadioTwo.setCompoundDrawablesRelativeWithIntrinsicBounds(null, this.getResources().getDrawable(drawableTop[1]), null, null);mRadioThree.setCompoundDrawablesRelativeWithIntrinsicBounds(null, this.getResources().getDrawable(drawableTop[2]), null, null);mRadioFour.setCompoundDrawablesRelativeWithIntrinsicBounds(null, this.getResources().getDrawable(drawableTop[3]), null, null);}

以下为Resources中的布局代码,请勿一味的复制粘贴,其中两行item内分别代表选中和非选中状态情况显示的图片

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:drawable="@mipmap/main_navigation_bar_my" android:state_checked="false"/><item android:drawable="@mipmap/main_navigation_bar_my_checked" android:state_checked="true"/>
</selector>

我们来看看现在的效果,在你的主页加入你写好的自定义View

<com.goldze.mvvmhabit.app.MainBottomBarTestandroid:layout_marginTop="80dp"android:id="@+id/bottomBarTest"android:layout_width="match_parent"android:layout_height="wrap_content"/>

可以看到我们的效果,已经大致出来了,如果不是,请检测以上的操作以及代码是否正确

从上图中效果看来,视觉效果完成的差不多了,接下来我们需要实现已经选中和非选中事件显示,以及第一次进入默认选中的按钮

选中和非选中事件我们的RadioGroup已经帮我做了,显示我们用了<selector>标签实现了。

现在我们缺少一个默认选中按钮,我们知道RadioButton的setChecked方法可以设置RadioButton的选中与否,所以使用以下代码,考虑到外部使用时有可能会遇到随时需要转换页面显示,我们设置一个公开的设置方法对外提供,方便我们自己。

为了记录我们当前的页面,定义了一个mDefaultPage变量,让我们代码内知道当前显示的页面,在init方法中调用setDefaultPage方法

    //不设置默认按钮,即为第一个按钮为默认按钮 记录当前选中按钮private Integer mDefaultPage = 0;//内部使用,默认使用的页面private void setDefaultPage() {setDefaultPage(mDefaultPage);}//设置默认打开的按钮public void setDefaultPage(Integer page) {mDefaultPage = page ;switch (page) {case 0:mRadioOne.setChecked(true);break;case 1:mRadioTwo.setChecked(true);break;case 2:break;case 3:mRadioThree.setChecked(true);break;case 4:mRadioFour.setChecked(true);break;}}

接下来,运行看效果,很明显我们进入时默认选中了第一个。

接下来,我们需要给外部实现点击回调,并且设置重复点击时的过滤。首先定义一个interface接口,我们给他起名为onRadioClickListener。

    //按钮点击回调public interface onRadioClickListener {void onClick(int postion);}

实现各个按钮的点击方法,并实现implements View.OnClickListener

    //设置点击方法private void initListener() {mRadioOne.setOnClickListener(this);mRadioTwo.setOnClickListener(this);mCenter.setOnClickListener(this);mRadioThree.setOnClickListener(this);mRadioFour.setOnClickListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.radio_home_page_selected_one:clickInterception(0);break;case R.id.radio_home_page_selected_two:clickInterception(1);break;case R.id.radio_home_page_selected_center:mRadioOne.setChecked(false);mRadioTwo.setChecked(false);mRadioThree.setChecked(false);mRadioFour.setChecked(false);clickInterception(2);break;case R.id.radio_home_page_selected_three:clickInterception(3);break;case R.id.radio_home_page_selected_four:clickInterception(4);break;}}//点击拦截,过滤重复点击private void clickInterception(int page) {if (mRepeated && page == mDefaultPage){return;}//记录新的页码.mDefaultPage = page;mListener.onClick(page);}

外部实现我们定义的onRadioClickListener即可监听到回调,至此完成了我们的半自定义view

下面附上完整的代码,如果对您有所帮助请动动手指点点赞,关注关注哦,谢谢~

package 你的App包名+项目名称+位置;import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RelativeLayout;import com.goldze.mvvmhabit.R;
import com.jakewharton.rxbinding2.view.RxView;import java.util.concurrent.TimeUnit;import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;import static me.goldze.mvvmhabit.binding.viewadapter.view.ViewAdapter.CLICK_INTERVAL;/*** 费浩东* 2019/1/4* Created by fhd*/
public class MainBottomBar extends RelativeLayout implements View.OnClickListener {//默认的资源文件int[] defRes = {R.drawable.layout_bottom_bar_select,R.drawable.layout_bottom_bar_select,R.drawable.layout_bottom_bar_select,R.drawable.layout_bottom_bar_select};//第一个按钮private RadioButton mRadioOne;//第二个按钮private RadioButton mRadioTwo;//中间的按钮private ImageView mCenter;//第四个按钮private RadioButton mRadioThree;//第五个按钮private RadioButton mRadioFour;//不设置默认按钮,即为第一个按钮为默认按钮 记录当前选中按钮private Integer mDefaultPage = 0;//避免重复点击 默认打开private Boolean mRepeated = true ;//点击回调private onRadioClickListener mListener;public MainBottomBar(Context context) {super(context);}public MainBottomBar(Context context, AttributeSet attrs) {super(context, attrs);init(context);}public MainBottomBar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}private void init(Context context) {LayoutInflater.from(context).inflate(R.layout.home_bottom_bar, this);mRadioOne = findViewById(R.id.radio_home_page_selected_one);mRadioTwo = findViewById(R.id.radio_home_page_selected_two);mCenter = findViewById(R.id.radio_home_page_selected_center);mRadioThree = findViewById(R.id.radio_home_page_selected_three);mRadioFour = findViewById(R.id.radio_home_page_selected_four);//设置点击方法initListener();//设置资源图片setResourcePictures(defRes);//默认页面setDefaultPage();}private void initListener() {mRadioOne.setOnClickListener(this);mRadioTwo.setOnClickListener(this);mCenter.setOnClickListener(this);mRadioThree.setOnClickListener(this);mRadioFour.setOnClickListener(this);}//设置点击回调public void setOnRadioClickListener(onRadioClickListener onRadioClickListener) {mListener = onRadioClickListener;}//设置资源图片public void setResourcePictures(int[] drawableTop) {if (drawableTop.length != 4) {Log.e("setResourcePictures", "MainBottomBar中所提供的图片资源必须为4个: ");return;}mRadioOne.setCompoundDrawablesRelativeWithIntrinsicBounds(null, this.getResources().getDrawable(drawableTop[0]), null, null);mRadioTwo.setCompoundDrawablesRelativeWithIntrinsicBounds(null, this.getResources().getDrawable(drawableTop[1]), null, null);mRadioThree.setCompoundDrawablesRelativeWithIntrinsicBounds(null, this.getResources().getDrawable(drawableTop[2]), null, null);mRadioFour.setCompoundDrawablesRelativeWithIntrinsicBounds(null, this.getResources().getDrawable(drawableTop[3]), null, null);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.radio_home_page_selected_one:clickInterception(0);break;case R.id.radio_home_page_selected_two:clickInterception(1);break;case R.id.radio_home_page_selected_center:mRadioOne.setChecked(false);mRadioTwo.setChecked(false);mRadioThree.setChecked(false);mRadioFour.setChecked(false);clickInterception(2);break;case R.id.radio_home_page_selected_three:clickInterception(3);break;case R.id.radio_home_page_selected_four:clickInterception(4);break;}}//点击拦截,过滤重复点击private void clickInterception(int page) {if (mRepeated && page == mDefaultPage){return;}//记录新的页码.mDefaultPage = page;mListener.onClick(page);}//按钮点击回调public interface onRadioClickListener {void onClick(int postion);}//内部使用,默认使用的页面private void setDefaultPage() {setDefaultPage(mDefaultPage);}//设置是否过滤重复点击public void setRepeated(Boolean repeated) {this.mRepeated = repeated;}//设置默认打开的按钮public void setDefaultPage(Integer page) {mDefaultPage = page ;switch (page) {case 0:mRadioOne.setChecked(true);break;case 1:mRadioTwo.setChecked(true);break;case 2:break;case 3:mRadioThree.setChecked(true);break;case 4:mRadioFour.setChecked(true);break;}}}

撸一个自定义底部导航View 布局+代码实现导航栏相关推荐

  1. 通用的网页底部导航div布局代码

    通用的网页底部导航div布局代码 黑色的云服务器公司网页底部快速导航div布局通用模板代码.产品服务,地区划分,快速入口,帮助支持,关于我们等. 演示地址 下载地址

  2. html5 两栏等宽布局代码,分三栏栏宽相等 如何将合并的一段分为等宽三栏,栏宽为4.5厘米...

    将正文的最后一段分成等宽的三栏,栏间加分隔线.将正文的最后一段分成等宽的三栏,栏间加分隔线. 方法步骤如下: 打开需要操作的WORD文档,选中正文最后一段,点击页面布局中的"更多分栏&quo ...

  3. (html+css)一个完整的网页主页布局:logo+导航+banner+新闻列表...

    index.html(主页-结构) <!DOCTYPE html> <!-- 声明文档类型--> <html lang="en"> <!- ...

  4. tabBar 自定义,小程序自定义底部导航栏

    创建一个自定义组件 my_tab,组件代码在后面,先看调用自定义组件的代码,比如我需要在index 页面调用,就在index.json中引用组件,index.json 代码(引用的路径为你创建的自定义 ...

  5. Android 自定义底部上拉控件的实现

    前言 又到了新的一月,今天提供一个Android自定义底部上拉布局的实现,起因是自己在项目中需要实现这样一个控件,干脆自己写一个练练手. 写完了觉得能想到的需求都基本有了(可能会有其它需求,不过基本上 ...

  6. 一个完美的导航条html,一个DIV CSS代码布局的简单导航条

    简单的DIV CSS代码布局实现导航条 一个蓝色主题的导航条布局案例,本CSS小实例,采用DIV CSS实现.同时不用图片做背景,直接使用背景色实现,鼠标经过悬停对应栏目名称是对应背景蓝色变深. 导航 ...

  7. 小程序自定义导航栏搜索和自定义底部tab(动态切换)

    自定义导航栏搜索: 首先看效果图大概是这样,样式可以自己细化: 那么这个时候就需要粘贴复制了, 首先在想要这个效果的相应页面的json里开启自定义导航,当然如果想全局每个页面都有那就在app.json ...

  8. Android 自定义底部导航栏消息显示

    转载请标明出处: http://blog.csdn.net/tyzlmjj/article/details/47186249 本文出自:[M家杰的博客] 概述 底部导航栏的做法多种多样,这次主要用到了 ...

  9. uniapp里自定义底部导航

    1.来先看效果图: 2.在uniapp里tabbar不能完全满足客户需求,所以这就需要开发者自定义封装一个底部导航组件. 3.先在components里创建一个tabbar.vue 具体代码: < ...

最新文章

  1. 独家 | 6种让Python程序变慢的坏习惯
  2. spark-submit的参数名称解析
  3. elasticsearch date_histogram
  4. 在选择数据库的路上,我们遇到过哪些坑?(1)
  5. DL之随机性:理解和探究采用深度学习算法预测时导致多次运行结果不一致的问题
  6. python变量持久化_Python 数据持久化:JSON
  7. 概率整形 Peobabilistic Shaping PS 第一节
  8. 最新LAMP源码搭建网站平台PHP5.5.1 + Apache2.4.6 + mysql5.6.12
  9. 未知账户(S-1-5-21)无法删除的问题
  10. Oracle 联合主键
  11. STM32CUBEMX(5)--自定义红外NEC解码,定时器TIM捕获方式
  12. uniapp 电商小程序 置顶特效/分享特效/红包特效 简单实现效果
  13. 奥克兰大学计算机it专业介绍,新西兰奥克兰大学IT硕士专业解析
  14. 20164305 徐广皓《网络对抗》Exp9 Web安全基础实践
  15. UserAgent个人整理
  16. 实验室-天平室设计标准与装修建设
  17. Win10下破解 Idea2021.2 修改idea.vmoptions 导致IDEA 无法启动
  18. 红外感应电子测温枪方案开发
  19. 京东sign签名算法分析h5st log易语言源码
  20. CG100-13景程-9S12HZ256VAL

热门文章

  1. 华中师大计算机专业陈鹏,华师男子不满工作分配流浪16年 与弟弟见面后拒回家...
  2. 华师计算机学院2014级,华师,新生早知道
  3. java集合List解析
  4. C语言模拟实现strlen
  5. php 获取百度权重,PHP获取网站在爱站查询的百度权重
  6. 安装系统html,不用装系统 在线体验网页版WINDOWS 7等.doc
  7. Google 搜索的运作方式
  8. OPPO K7X手机刷root 获取magisk 强解锁BL coloros11教程
  9. 官宣!美国通讯芯片巨头博通610亿美元收购云计算巨头威睿 | 美通社头条
  10. 提醒大家有关越狱组it学院vip会员有猫腻,要小心。。。