Android 滑动标题导航栏_android上滑动合并标题栏-程序员宅基地

技术标签: 开源项目  标题导航  实用功能  Android导航  


我的视频课程:《FFmpeg打造Android万能音频播放器》


        现在Android应用开发中因为功能比较多所以都喜欢用viewpager+fragment的方式加入更多的页面,而每每使用这种模式,标题栏导航也是必不可少的,因此又会重复写很多导航菜单的代码,程序猿都是很懒的,都想写少量的代码就把功能实现了,更何况这都是写重复的代码,不辞辛劳的程序猿就成了CV战士了哈哈。我也是很懒的,不想每次都重复写那些没用的代码,所以就把标题导航栏这块功能封装成了一个自定义的控件,使用起来就三两句代码搞定,是不是听着很爽 反正我是觉得爽了。废话不多说,先上示例图片,所谓有图有真相:

综合类型:


1、第一种类型(只有滑动导航条):


2、第二种类型(滑动导航条有背景色)


3、第三种类型(滑动导航条有边距)


4、第四种类型(选中标题栏文字变大)


5、第五中类型(标题栏直接具有分隔条)


以上这些效果的实现代码只有下面几句(核心语句,去除初始化和布局代码):

navitationLayout.setViewPager(this, titles, viewPager, R.color.color_333333, R.color.color_2581ff, 16, 16, 0, 12, true, R.color.color_333333, 1f, 15f, 15f);
        navitationLayout.setBgLine(this, 1, R.color.colorAccent);
        navitationLayout.setNavLine(this, 3, R.color.colorPrimary, 0);


2、实现思路:

通过我们的需求不难发现,第一要生成标题栏的每个标题(TextView),然而标题又是横向排列的,所以自然就想到了我们的线性布局(LinearLayout),通过代码动态添加标题栏到LinearLayout中;最基本的就实现了,然后再看需求,我们还需要再底部添加导航条,因为导航条在底部,然后还具有背景色,所以我们用相对布局(RelativeLayout)来布局是比较好的,这样基本框架就可以了(父布局是相对布局,里面添加包含标题栏的线性布局,再在底部添加导航条背景布局,再在导航条背景上面添加导航条)。剩下的就是颜色,长款等细节问题的处理了。

3、功能逻辑代码

(1):标题栏

private void setTitles(Context context, String[] titles, final boolean smoothScroll)
    {
        this.textViews = new TextView[titles.length];
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,LayoutParams.MATCH_PARENT);
        params.weight = 1;
        params.gravity = Gravity.CENTER;
        // 循环,根据标题栏动态生成TextView来显示标题,每个标题栏的宽度比例为1:1,其中的内容居中。
        for(int i = 0; i < titles.length; i++)
        {
            final int index = i;
            TextView textView = new TextView(context);
            textView.setText(titles[i]);
            textView.setGravity(Gravity.CENTER);
            textViews[i] = textView;
            textViews[i].setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    viewPager.setCurrentItem(index, smoothScroll);
                    if(onTitleClickListener != null)
                    {
                        onTitleClickListener.onTitleClick(v);
                    }
                }
            });
            titleLayout.addView(textView, params);
        }
    }
用代码根据导航标题数量动态添加标题控件,并为每个标题添加点击事件。

(2):设置导航条背景

/**
     * 设置导航背景色
     * @param context
     * @param height
     * @param color
     */
    public void setBgLine(Context context, int height, int color)
    {
        height = dip2px(context,height);
        LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, height);
        bgLine = new View(context);
        bgLine.setLayoutParams(layoutParams);
        bgLine.setBackgroundColor(context.getResources().getColor(color));

        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, height);
        lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
        addView(bgLine, lp);
    }

也是用代码为导航条添加背景view。

(3):添加导航条

/**
     * 设置导航条颜色
     * @param context
     * @param height
     * @param color
     * @param currentPosition
     */
    public void setNavLine(Activity context, int height, int color, int currentPosition)
    {
        if(textViews != null)
        {
            navWidth = getScreenWidth(context) / textViews.length;
        }
        height = dip2px(context,height);
        System.out.println("width:" + navWidth);

        LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, height);
        navLine = new View(context);
        navLine.setLayoutParams(layoutParams);
        navLine.setBackgroundColor(context.getResources().getColor(color));

        LayoutParams lp = new LayoutParams(navWidth, height);
        lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
        addView(navLine, lp);
        moveBar(navLine, navWidth, widOffset, currentPosition);
    }
根据标题的数量计算导航条的宽度,然后设置导航条颜色和边距。

(4):移动导航条功能

private void moveBar(View bar, int width, float percent, int position) {
        RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) bar.getLayoutParams();
        int marginleft = (position) * width + (int) (width * percent);
        lp.width = width - widOffset * 2;
        lp.setMargins(marginleft + widOffset, 0, widOffset, 0);
        bar.requestLayout();
    }
这个是结合viewpager的滑动事件的功能,根据滑动来定位导航条的位置。

(5)调用方法的设置

/**
     *
     * @param context 上下文
     * @param titles 标题栏
     * @param viewPager
     * @param unselectedcolor 未选中字体颜色
     * @param setectedcolor 选中字体颜色
     * @param txtUnselectedSize 未选中字体大小
     * @param txtSelectedSize 选中字体大小
     * @param currentPosition 当前viewpager的位置
     * @param widOffset 导航条的边距
     * @param smoothScroll 滑动类型
     */
    public void setViewPager(final Context context, String[] titles, ViewPager viewPager, final int unselectedcolor, final int setectedcolor, int txtUnselectedSize, final int txtSelectedSize, final int currentPosition, int widOffset, boolean smoothScroll)
    {
        this.viewPager = viewPager;
        this.txtUnselectedColor = unselectedcolor;
        this.txtSelectedColor = setectedcolor;
        this.txtUnselectedSize = txtUnselectedSize;
        this.txtSelectedSize = txtSelectedSize;
        this.widOffset = dip2px(context, widOffset);

        viewPager.setCurrentItem(currentPosition);
        setTitles(context, titles, smoothScroll);
        setUnselectedTxtColor(context, unselectedcolor, txtUnselectedSize);
        setSelectedTxtColor(context, setectedcolor, txtSelectedSize, currentPosition);
        viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                moveBar(navLine, navWidth, positionOffset, position);
                if(onNaPageChangeListener != null)
                {
                    onNaPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
                }
            }

            @Override
            public void onPageSelected(int position) {
                setSelectedTxtColor(context, setectedcolor, txtSelectedSize, position);
                if(onNaPageChangeListener != null)
                {
                    onNaPageChangeListener.onPageSelected(position);
                }
            }

            @Override
            public void onPageScrollStateChanged(int state) {
                if(onNaPageChangeListener != null)
                {
                    onNaPageChangeListener.onPageScrollStateChanged(state);
                }
            }
        });
    }
这个方法就是设置各种颜色、大小和边距的方法,并且把viewpager的pagechange回调给使用者调用。


核心代码就是这样的了,其他两种类型类似,这里就不多说了,可以看源码哦。

完整项目源码下载地址:

1、CSDN:NavigationBar

2、Github:NavigationBar

欢迎各位使用和start










版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ywl5320/article/details/51866799

智能推荐

独热编码python实现_标签编码、独热编码大不同 - Python 实现-程序员宅基地

文章浏览阅读550次。对于新手在做资料的特征工程时,会看到 Label Encoding 或 One Hot Encoding 两种对于类别行资料的编码方式,那他们之间究竟有什么不同呢?直接讲结论:原始资料是有序离散值的话 => Label Encoding原始资料是无序离散值的话 => One Hot Encoding (Dummies)以下分为两点说明:为什么要将离散转数值?因为大部分的模型都是基于数学..._python 对只对某几个标签独热编码

Android开发:标准身高计算器应用的… 分类: Android开发...-程序员宅基地

文章浏览阅读274次。主程序:package com.leansmall.heightcalculator;import android.app.Activity;import android.app.AlertDialog;import android.content.DialogInterface;import android.os.Bundle;import android.util.L..._安卓开发中开发身高计算器的知识点

【React】1040- 六个问题让你更懂 React Fiber-程序员宅基地

文章浏览阅读569次。大家好,我是零一,很多人都摸不透React,看不懂源码,甚至不想看源码(确实很难看懂啊!),"霸王硬上弓" 肯定是不行呀,不如从React的整体架构或者说从最核心的Fibe..._react无法进行静态节点分析

linux Argument list too long错误解决方法_etcdctl: argument list too long-程序员宅基地

文章浏览阅读4w次,点赞3次,收藏5次。linux Argument list too long错误解决方法今日需要删除/tmp目录下的所有文件,文件数量比较多。ls -lt /tmp | wc -l385412使用 rm * 后,系统提示错误 Argument list too long原因是在linux下,试图传太多参数给一个系统命令(ls *; cp *; rm *; cat *; etc.._etcdctl: argument list too long

sudo apt-get install python3.5-dev安装不了的一些解决方法_apt安装python-dev和tinker后仍然提示安装-程序员宅基地

文章浏览阅读4.1k次。需要编译个工程老是报找不到Python.h,后面查找需要用到python3.5-dev包,但是尝试用sudo apt-get install python3.5-dev老是出现无法下载一些库的问题,对于这种问题,一般有下面几种解决方法:1、采用https://www.cnblogs.com/wileywote0633/p/9096274.html的做法2、直接去一台同系统同版..._apt安装python-dev和tinker后仍然提示安装

继承中使用构造函数_tp已继承怎么使用构造函数-程序员宅基地

文章浏览阅读187次。<?phpclass BaseClass { function __construct() { print "我是构造函数\n"; }}class AClass extends BaseClass { function __construct() { print "我是 AClass 下的构造函数\n"; }}c..._tp已继承怎么使用构造函数

随便推点

Java怎么配置环境变量?_java环境变量设置-程序员宅基地

文章浏览阅读2k次。作为一个开发者在自己的系统上面安装Java开发环境设置环境变量是必须会的一项技能。今天小千就来教大家如何去配置环境变量。配置步骤1.首先先要安装好Java环境,这个步骤比较简单,下一步即可,注意要记住我们的安装路径后面需要用到。之后我们在桌面此电脑图标上面点击右键,选择属性。在打开的页面中我们点击左侧的高级系统设置,之后就能够看到环境变量的按钮了。2.点击进去之后可以看到有两个变量设置,我们选择系统变量下面的新建选项,新建一个变量3.之后我们需要用到刚刚安装Java的路径了,在里面我们输入变量名_java环境变量设置

Navicat for MySQL 命令列 执行SQL语句 历史日志_sqlyog的历史记录在navicat中有吗-程序员宅基地

文章浏览阅读7.3k次。工具 下有命令列界面 或者在数据库上鼠标右键也有。_sqlyog的历史记录在navicat中有吗

时间序列预测——时序卷积网络(TCN)_tcn用于时间序列分类教程-程序员宅基地

文章浏览阅读3w次,点赞60次,收藏513次。  本文展示了使用时序卷积网络(TCN)进行时间序列预测的全过程,包含详细的注释。整个过程主要包括:数据导入、数据清洗、结构转化、建立TCN模型、训练模型(包括动态调整学习率和earlystopping的设置)、预测、结果展示、误差评估等完整的时间序列预测流程。  本文使用的tcn库在本人上传的资源中,链接为tcn.py  本文使用的数据集在本人上传的资源中,链接为mock_kaggle.csvimport pandas as pdimport numpy as npimport mathfro_tcn用于时间序列分类教程

ABP Vnext 4.4:统一Ef Core的DbContext/移除EF Core Migrations项目-程序员宅基地

文章浏览阅读507次。Abp vnext 4.4出现了一个比较重大的变更:在Startup template中移除了EF Core Migrations项目,本文翻译自community.abp.io/arti..._entityframeworkcore.dbmigrations

蓝桥杯专题-真题版含答案-【三角螺旋阵】【干支记年法】【异或加密法】【金字塔】_蓝桥杯 异或三角-程序员宅基地

文章浏览阅读155次,点赞4次,收藏5次。有真题,有答案,认认真真阅读,轻轻松松通过。蓝桥在等你。有什么需要欢迎文章底部卡片私我,获取更多支持,交流让学习不再孤单_蓝桥杯 异或三角

跳跃游戏_左神-跳跃游戏-程序员宅基地

文章浏览阅读171次。程序员代码面试指南——跳跃游戏自己的动态规划做法dp[i]表示从i位置跳到最后一个位置需要的最少跳数;base : dp[n-1] = 0, dp[n-2] = 1;递归:dp[i] = min(dp[i+1], ... , dp[i+arr[i]]);import java.util.*;public class Main{ int cnt = 0; public static void main(String[] args) { Scanne_左神-跳跃游戏