Android实现顶部底部双导航界面功能
最近想弄一个双导航功能,查看了许多资料,总算是实现了功能,这边就算是给自己几个笔记吧!
先来看看效果
那么就开始实现了!
底部导航栏我选择用fragmenttabhost+fragment来实现,这个方法我觉得挺好用的,代码量也不多
首先是开始的activity_main.xml
<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="match_parent" tools:context="${relativepackage}.${activityclass}" > <framelayout android:id="@+id/main_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/main_tab" android:layout_alignparentleft="true" android:layout_alignparenttop="true" > </framelayout> <view android:id="@+id/main_tab" android:layout_width="match_parent" android:layout_height="50dp" android:layout_alignparentbottom="true" android:layout_alignparentleft="true" class="android.support.v4.app.fragmenttabhost" /> </relativelayout>
其中我是直接拉的view所以是形成的fragmenttabhost
也可以直接在xml文件里面写
<android.support.v4.view.fragmenttabhost >
</android.support.v4.view.fragmenttabhost>
这xml文件就一个view加一个tab view用来显示碎片,tab用来放置底部按钮的数量
再来是tab_foot.xml
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#f6f6f6" android:gravity="center" android:orientation="vertical" > <imageview android:id="@+id/foot_iv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/home1" /> <textview android:id="@+id/foot_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margintop="3dp" android:text="首页" android:textcolor="@color/tab_color" /> </linearlayout>
这是每个底部按钮的布局设置的xml文件
显示效果。
再来是mainactivity的代码
package com.gjn.mynavigation; import android.os.bundle; import android.support.v4.app.fragmentactivity; import android.support.v4.app.fragmenttabhost; import android.view.layoutinflater; import android.view.view; import android.view.window; import android.widget.imageview; import android.widget.tabwidget; import android.widget.textview; import android.widget.tabhost.ontabchangelistener; import android.widget.tabhost.tabspec; public class mainactivity extends fragmentactivity implements ontabchangelistener { private fragmenttabhost mtabhost; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); requestwindowfeature(window.feature_no_title); setcontentview(r.layout.activity_main); //初始化fragmenttabhost inithost(); //初始化底部导航栏 inittab(); //默认选中 mtabhost.ontabchanged(tabdb.gettabstxt()[0]); } private void inittab() { string[] tabs = tabdb.gettabstxt(); for (int i = 0; i < tabs.length; i++) { //新建tabspec tabspec tabspec = mtabhost.newtabspec(tabdb.gettabstxt()[i]); //设置view view view = layoutinflater.from(this).inflate(r.layout.tabs_foot, null); ((textview) view.findviewbyid(r.id.foot_tv)).settext(tabdb.gettabstxt()[i]); ((imageview) view.findviewbyid(r.id.foot_iv)).setimageresource(tabdb.gettabsimg()[i]); tabspec.setindicator(view); //加入tabspec mtabhost.addtab(tabspec,tabdb.getframgent()[i],null); } } /*** * 初始化host */ private void inithost() { mtabhost = (fragmenttabhost) findviewbyid(r.id.main_tab); //调用setup方法 设置view mtabhost.setup(this, getsupportfragmentmanager(),r.id.main_view); //去除分割线 mtabhost.gettabwidget().setdividerdrawable(null); //监听事件 mtabhost.setontabchangedlistener(this); } @override public void ontabchanged(string arg0) { //从分割线中获得多少个切换界面 tabwidget tabw = mtabhost.gettabwidget(); for (int i = 0; i < tabw.getchildcount(); i++) { view v = tabw.getchildat(i); textview tv = (textview) v.findviewbyid(r.id.foot_tv); imageview iv = (imageview) v.findviewbyid(r.id.foot_iv); //修改当前的界面按钮颜色图片 if (i == mtabhost.getcurrenttab()) { tv.settextcolor(getresources().getcolor(r.color.tab_light_color)); iv.setimageresource(tabdb.gettabsimglight()[i]); }else{ tv.settextcolor(getresources().getcolor(r.color.tab_color)); iv.setimageresource(tabdb.gettabsimg()[i]); } } } }
其中tabdb类是用来设置导航栏的数据和图片切换时候的资源
以下是tabdb类
package com.gjn.mynavigation; public class tabdb { /*** * 获得底部所有项 */ public static string[] gettabstxt() { string[] tabs = {"首页","交易","地点","我的"}; return tabs; } /*** * 获得所有碎片 */ public static class[] getframgent(){ class[] cls = {onefm.class,twofm.class,threefm.class,fourfm.class}; return cls ; } /*** * 获得所有点击前的图片 */ public static int[] gettabsimg(){ int[] img = {r.drawable.home1,r.drawable.glod1,r.drawable.xc1,r.drawable.user1}; return img ; } /*** * 获得所有点击后的图片 */ public static int[] gettabsimglight(){ int[] img = {r.drawable.home2,r.drawable.glod2,r.drawable.xc2,r.drawable.user2}; return img ; } }
到此,底部导航栏就算是完全实现了。
--------------------------------------------------------------------------------------------------------------------------
现在来实现顶部导航栏,看了许多最后使用了radiogroup+viewpager来实现
首先是为第一个碎片设计一个xml布局
fm_one.xml
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <horizontalscrollview android:id="@+id/one_hv" android:layout_width="match_parent" android:layout_height="wrap_content" android:scrollbars="none" > <radiogroup android:id="@+id/one_rg" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > </radiogroup> </horizontalscrollview> <view android:id="@+id/one_view" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" class="android.support.v4.view.viewpager" /> </linearlayout>
设置顶部导航栏和显示view
之后吧导航栏的每个项的布局
tab_rb.xml
<?xml version="1.0" encoding="utf-8"?> <radiobutton xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/tab_rb_selector" android:button="@null" android:paddingbottom="10dp" android:paddingleft="15dp" android:paddingright="15dp" android:paddingtop="10dp" android:text="今日" > </radiobutton>
其中设置selector文件来控制点击和未点击的状态
tab_rb_selector.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android" > <!-- 点击 --> <item android:state_checked="true"> <layer-list > <item > <shape android:shape="rectangle"> <stroke android:width="5dp" android:color="@color/tab_light_color"/> </shape> </item> <item android:bottom="5dp"> <shape android:shape="rectangle"> <solid android:color="#fff"/> </shape> </item> </layer-list> </item> <!-- 默认 --> <item > <shape > <solid android:color="#fafafa"/> </shape> </item> </selector>
设置了点击和默认的时候的显示状态
最后来实现onefm类
package com.gjn.mynavigation; import java.util.arraylist; import java.util.list; import android.os.bundle; import android.support.annotation.nullable; import android.support.v4.app.fragment; import android.support.v4.view.viewpager; import android.support.v4.view.viewpager.onpagechangelistener; import android.util.displaymetrics; import android.view.layoutinflater; import android.view.view; import android.view.viewgroup; import android.widget.horizontalscrollview; import android.widget.radiobutton; import android.widget.radiogroup; import android.widget.radiogroup.layoutparams; import android.widget.radiogroup.oncheckedchangelistener; public class onefm extends fragment implements onpagechangelistener { private view view; private radiogroup rg_; private viewpager vp_; private horizontalscrollview hv_; private list<fragment> newslist = new arraylist<fragment>(); private onefmadapter adapter; @override public view oncreateview(layoutinflater inflater, @nullable viewgroup container, @nullable bundle savedinstancestate) { if (view == null) { //初始化view view = inflater.inflate(r.layout.fm_one, container,false); rg_ = (radiogroup) view.findviewbyid(r.id.one_rg); vp_ = (viewpager) view.findviewbyid(r.id.one_view); hv_ = (horizontalscrollview) view.findviewbyid(r.id.one_hv); //设置radiogroup点击事件 rg_.setoncheckedchangelistener(new oncheckedchangelistener() { @override public void oncheckedchanged(radiogroup group, int id) { vp_.setcurrentitem(id); } }); //初始化顶部导航栏 inittab(inflater); //初始化viewpager initview(); } /* * 底部导航栏切换后 由于没有销毁顶部设置导致如果没有重新设置view * 导致底部切换后切回顶部页面数据会消失等bug * 以下设置每次重新创建view即可 */ viewgroup parent = (viewgroup) view.getparent(); if (parent != null) { parent.removeview(view); } return view; } /*** * 初始化viewpager */ private void initview() { list<htab> htabs = htabdb.getselected(); for (int i = 0; i < htabs.size(); i++) { onefm1 fm1 = new onefm1(); bundle bundle = new bundle(); bundle.putstring("name", htabs.get(i).getname()); fm1.setarguments(bundle); newslist.add(fm1); } //设置viewpager适配器 adapter = new onefmadapter(getactivity().getsupportfragmentmanager(),newslist); vp_.setadapter(adapter); //两个viewpager切换不重新加载 vp_.setoffscreenpagelimit(2); //设置默认 vp_.setcurrentitem(0); //设置viewpager监听事件 vp_.setonpagechangelistener(this); } /*** * 初始化头部导航栏 * @param inflater */ private void inittab(layoutinflater inflater) { list<htab> htabs = htabdb.getselected(); for (int i = 0; i < htabs.size(); i++) { //设置头部项布局初始化数据 radiobutton rbbutton = (radiobutton) inflater.inflate(r.layout.tab_rb, null); rbbutton.setid(i); rbbutton.settext(htabs.get(i).getname()); layoutparams params = new layoutparams(layoutparams.wrap_content, layoutparams.wrap_content); //加入radiogroup rg_.addview(rbbutton,params); } //默认点击 rg_.check(0); } @override public void onpagescrollstatechanged(int arg0) { } @override public void onpagescrolled(int arg0, float arg1, int arg2) { } @override public void onpageselected(int id) { settab(id); } /*** * 页面跳转切换头部偏移设置 * @param id */ private void settab(int id) { radiobutton rbbutton = (radiobutton) rg_.getchildat(id); //设置标题被点击 rbbutton.setchecked(true); //偏移设置 int left = rbbutton.getleft(); int width = rbbutton.getmeasuredwidth(); displaymetrics metrics = new displaymetrics(); getactivity().getwindowmanager().getdefaultdisplay().getmetrics(metrics); int screenwidth = metrics.widthpixels; //移动距离= 左边的位置 + button宽度的一半 - 屏幕宽度的一半 int len = left + width / 2 - screenwidth / 2; //移动 hv_.smoothscrollto(len, 0); } }
其中有两个数据类和一个碎片类
数据类
htab.java
package com.gjn.mynavigation; /*** * 头部tab属性 * */ public class htab { private string name; public htab(string name) { super(); this.setname(name); } public string getname() { return name; } public void setname(string name) { this.name = name; } }
htabdb.java
package com.gjn.mynavigation; import java.util.arraylist; import java.util.list; public class htabdb { private static final list<htab> selected = new arraylist<htab>(); static{ selected.add(new htab("今日")); selected.add(new htab("头条")); selected.add(new htab("娱乐")); selected.add(new htab("财经")); selected.add(new htab("军事")); selected.add(new htab("科技")); selected.add(new htab("时尚")); selected.add(new htab("体育")); } /*** * 获得头部tab的所有项 */ public static list<htab> getselected() { return selected; } }
碎片类
onefm1.java
package com.gjn.mynavigation; import android.os.bundle; import android.support.annotation.nullable; import android.support.v4.app.fragment; import android.view.layoutinflater; import android.view.view; import android.view.viewgroup; import android.widget.textview; public class onefm1 extends fragment { private string name; @override public void setarguments(bundle args) { name = args.getstring("name"); } @override public view oncreateview(layoutinflater inflater, @nullable viewgroup container, @nullable bundle savedinstancestate) { view view = inflater.inflate(r.layout.fragment, container,false); ((textview) view.findviewbyid(r.id.fm_text)).settext(name); return view; } }
这样就把顶部的导航栏加入到了第一个fragment里面并且实现了切换功能
最后把fragment.xml贴下,就是每个碎片最默认的显示页面罢了
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" > <textview android:id="@+id/fm_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="large text" android:textappearance="?android:attr/textappearancelarge" /> </linearlayout>
总结:
算是一个笔记记录吧!一段时间没更新了,由于刚毕业断了一个时间,走走停停留下一些自己的记录,就怕自己以后要写忘了。
下载地址:点击打开链接
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。