一:摘要
这篇文章主要为大家介绍了使用ViewPager+TabHost实现底部导航效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
下面我们先来看一下要实现的效果吧!
二:具体实现过程
1.新建一个project,把主布局改为TabHost,id为tab_host
2.主布局添加一个相对布局,相对布局里加一个id为view_pager的 ViewPager布局。
加一个id为@android:id/tabs的TabWidget(指明高度)并将其放在最底部。
由于TabWidget要求必须要有一个id为@android:id/tabcontent的FrameLayout,所以得再加一个FrameLayout。
为了看出界限,我们还要添加一条id为tab_divider线,具体可用View实现。
从上往下,对组件进行排布。
ViewPager和FrameLayout的layout_above="@+id/tab_divider",
View的layout_above="@android:id/tabs",
TabWidget的layout_alignParentBottom="true"。
最后,让FrameLayout的visibility="gone"。
3.创建一个TestFragment类继承Fragment并复写onCreate,onCreateView方法。
4.创建fragment_test.xml文件。里面添加一个id为text_view的TextView。
5.在TestFragment的onCreateView方法中,删除原有代码,通过布局反向生成view对象并加以返回。
部分代码:
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//删除原有代码,通过布局反向生成view对象并加以返回。
View view=inflater.inflate(R.layout.fragment_test,null);
TextView textView=view.findViewById(R.id.text_view);
return view;
}
6.因为要给TestFragment传参数(标题),所以得写一个静态方法来实现newInstance。
部分代码:
public static TestFragment newInstance(String title){
TestFragment testFragment=new TestFragment();
//建立一个bundle
Bundle bundle=new Bundle();
bundle.putString(TITLE,title);
testFragment.setArguments(bundle);
return testFragment;
}
//该方法里设置一个bundle用来testFragment.setArguments(bundle);可以把title提取为常量TITLE。
7.在TestFragment的onCreate的方法里,我们要判断是否接受了数据,如果接受了数据,则把数据给提取出来。这时,我们可以把接受到的字符提取为一个叫mTitle的全局变量。
部分代码:
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments()!=null){
mTitle = getArguments().getString(TITLE);
}
}
8.因为有了传参,所以在TestFragment的onCreateView的方法里,我们要把对应布局的TextView找到,设置TextView的文本为传入的参数mTitle。
部分代码:
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//删除原有代码,通过布局反向生成view对象并加以返回。
View view=inflater.inflate(R.layout.fragment_test,null);
TextView textView=view.findViewById(R.id.text_view);
textView.setText(mTitle);
return view;
}
9.在MainActivity把ViewPager引用出来,记为mViewPager。
10.我们要用三个fragment组成的viewpager。因此,先创建final Fragment [] fragments数组。注意分号
部分代码:
final Fragment[] fragments=new Fragment[]{
TestFragment.newInstance("home"),
TestFragment.newInstance("message"),
TestFragment.newInstance("me")
};//注意分号
11.给mViewPager设置适配器。
部分代码:
mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {……};
/*
要重写两个方法,getItem和getCount。
getItem中,return fragments[position];
getCount中,return fragments.length
*/
至此,上面部分已经完成。
我们来看看效果。
12.我们建立一个main_tab_layout.xml文件(相对布局),id为tab_bg。
里面加一个id为main_tab_icon的ImageView,id为main_tab_text的TextView。设置好控件的外边距。
如果以后有需要在右上角做一个小红点的话,可以把这两个放在一个id为main_contain的LinearLayout里,小红点在LinearLayout就行。
13.main_tab_layout.xml里的文本,点击和没点击会显示不同的颜色,所以我们可以用textColor="@color/color_main_tab_text"来实现。
新建color_main_tab_text布局,在其中的选择器selector里,添加item标签
(注意顺序,显示特殊情况下的选择,最后才是默认情况下的选择,否则会失效)
<item android:state_selected="true" android:color="#4dd048"/>
<item android:state_pressed="true" android:color="#4dd048"/>
<item android:color="#cccccc"/>
14.同理,我们可以在drawable里也建立3个选择器。可以直接把color_main_tab_text布局文件复制到drawable后改名改参数即可。
15.复制准备好的图片到drawable文件夹。对布局文件的参数进行修改。(注意顺序)
<item android:state_selected="true" android:drawable="@drawable/tabbar_home_pressed"/>
<item android:state_pressed="true" android:drawable="@drawable/tabbar_home_pressed"/>
<item android:drawable="@drawable/tabbar_home"/>
16.初始化总布局。把TabHost找出来并提取为全局变量mTabHost。调用mTabHost.setup();
17.三个Tab做处理。三个Tab做处理,用数组来准备。
int [] titlesIDs={R.string.home,R.string.message,R.string.me};//利用alt+enter为其设值。
int [] drawableIDs={
R.drawable.color_main_tab_icon_home,
R.drawable.color_main_tab_icon_message,
R.drawable.color_main_tab_icon_me
};
18.利用for循环把数据填充到布局里。
先把视图提取出来,给mIcon设置图片,给title设置文本,给tab设置背景颜色。
调用mTabHost.addTab方法。因为该方法的setContent()要设置视图内容,我们可以通过让该类实现一个TabContentFactory接口来解决。
部分代码:
//数据填到视图里
for (int index = 0; index < titlesIDs.length; index++) {
//先把视图提取出来
View view=getLayoutInflater().inflate(R.layout.main_tab_layout,null,false);
ImageView mIcon=view.findViewById(R.id.main_tab_icon);
TextView mTitle=view.findViewById(R.id.main_tab_text);
View tab=view.findViewById(R.id.tab_bg);
mIcon.setImageResource(drawableIDs[index]);
mTitle.setText(titlesIDs[index]);
//tab背景颜色,可以创建一个value
tab.setBackgroundColor(getResources().getColor(R.color.myColor));
mTabHost.addTab(
mTabHost.newTabSpec(getString(titlesIDs[index]))
.setIndicator(view)//设置分割
//因为实现了TabContentFactory接口,所以我们就可以用this
.setContent(this) );
}
19.MainActivity实现TabContentFactory接口,重写方法createTabContent。
在createTabContent中,直接创建一个view并返回就行。
因为下面的要对应上上面的内容,而我们的内容是用ViewPager做的,虽然我们不要这个内容,但要求我们必须设置,所以直接返回一个view。我们可以把它隐藏掉。
部分代码:
public View createTabContent(String tag) {
/*因为下面的要对应上上面的内容,而我们的内容是用ViewPager做的,
虽然我们不要这个内容,但要求我们必须设置,所以直接返回一个view。我们可以把它隐藏掉。
*/
View view=new View(this);
view.setMinimumWidth(0);
view.setMinimumHeight(0);
return view;
}
至此,界面基本完成。
20.我们看到底下有分割线,
在activity_main的TabWidget里,可以通过调用
android:showDividers="none"去掉分割线
21.最后,添加互动。
给mViewPager添加监听器。
部分代码:
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {……}
//在方法onPageSelected中先判断mTabHost是否为空,
//不为空则调用mTabHost.setCurrentTab(position);方法。具体如下:
public void onPageSelected(int position) {
if(mTabHost!=null){
mTabHost.setCurrentTab(position);
}
}
22.给mTabHost添加监听器。
部分代码:
/*
mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {……}
onTabChanged方法中,先判断mTabHost && mViewPager是否为空。
如果两个都不为空的话,则调用mViewPager.setCurrentItem(mTabHost.getCurrentTab());具体如下:
*/
mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
@Override
public void onTabChanged(String tabId) {
if(mViewPager!=null&&mTabHost!=null){
//写法1
//mViewPager.setCurrentItem(mTabHost.getCurrentTab());
//写法2
int position = mTabHost.getCurrentTab();
mViewPager.setCurrentItem(position);
}
}
});
至此,全部功能已经完成。
下面提供全部代码,欢迎小伙伴们交流学习。
MainActivity:
package com.wxdgut.navigation;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TabHost;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements TabHost.TabContentFactory {
private TabHost mTabHost;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTabHost = findViewById(R.id.tab_host);
mTabHost.setup();
//三个Tab做处理,用数组来准备
int [] titlesIDs= new int[]{R.string.home, R.string.message, R.string.me};
int [] drawableIDs={
R.drawable.main_tab_icon_home,
R.drawable.main_tab_icon_message,
R.drawable.main_tab_icon_me
};
//数据塞到视图里
for (int index = 0; index < titlesIDs.length; index++) {
//先把视图提取出来
View view=
getLayoutInflater().inflate(R.layout.main_tab_layout,null,false);
ImageView mIcon=view.findViewById(R.id.main_tab_icon);
TextView mTitle=view.findViewById(R.id.main_tab_text);
View tab=view.findViewById(R.id.tab_bg);
mIcon.setImageResource(drawableIDs[index]);
mTitle.setText(titlesIDs[index]);
//tab背景颜色,可以创建一个value
tab.setBackgroundColor(getResources().getColor(R.color.myColor));
mTabHost.addTab(
mTabHost.newTabSpec(getString(titlesIDs[index]))
.setIndicator(view)//设置分割
//因为实现了该接口,所以我们就可以用this
.setContent(this)
);
}
final Fragment[] fragments=new Fragment[]{
TestFragment.newInstance("home"),
TestFragment.newInstance("message"),
TestFragment.newInstance("me")
};//注意分号
final ViewPager mViewPager= findViewById(R.id.view_pager);
mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
@NonNull
@Override
public Fragment getItem(int position) {
return fragments[position];
}
@Override
public int getCount() {
return fragments.length;
}
});
//做互动,将tab与viewpager关联
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
if(mTabHost!=null){
mTabHost.setCurrentTab(position);
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
@Override
public void onTabChanged(String tabId) {
if(mViewPager!=null&&mTabHost!=null){
//写法1
//mViewPager.setCurrentItem(mTabHost.getCurrentTab());
//写法2
int position = mTabHost.getCurrentTab();
mViewPager.setCurrentItem(position);
}
}
});
}
@Override
public View createTabContent(String tag) {
/*因为下面的要对应上上面的内容,而我们的内容是用ViewPager做的,
虽然我们不要这个内容,但要求我们必须设置,所以直接返回一个view。我们可以把它隐藏掉。
*/
View view=new View(this);
view.setMinimumWidth(0);
view.setMinimumHeight(0);
return view;
}
}
TestFragment:
package com.wxdgut.navigation;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class TestFragment extends Fragment {
public static final String TITLE = "title";
private String mTitle;
public static TestFragment newInstance(String title){
TestFragment testFragment=new TestFragment();
//建立一个bundle
Bundle bundle=new Bundle();
bundle.putString(TITLE,title);
testFragment.setArguments(bundle);
return testFragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments()!=null){
mTitle = getArguments().getString(TITLE);
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//删除原有代码,通过布局反向生成view对象并加以返回。非activity中就用inflater
View view=inflater.inflate(R.layout.fragment_test,null);
TextView textView=view.findViewById(R.id.text_view);
textView.setText(mTitle);
return view;
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<TabHost 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:id="@+id/tab_host"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/tab_divider">
</androidx.viewpager.widget.ViewPager>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/tab_divider"
android:visibility="gone"/>
<View
android:id="@+id/tab_divider"
android:layout_width="match_parent"
android:layout_height="5dp"
android:background="#dfdfdf"
android:layout_above="@android:id/tabs"/>
<TabWidget
android:id="@android:id/tabs"
android:layout_width="match_parent"
android:layout_height="80dp"
android:showDividers="none"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
</TabHost>
fragment_test.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"
android:gravity="center">
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="wxdgut.com"
android:textSize="25sp" />
</LinearLayout>
main_tab_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/tab_bg">
<LinearLayout
android:id="@+id/main_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:layout_centerInParent="true">
<ImageView
android:id="@+id/main_tab_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@mipmap/ic_launcher"
android:layout_marginTop="4dp"/>
<TextView
android:id="@+id/main_tab_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:textColor="@color/color_main_tab_text"
android:layout_marginTop="5dp"/>
</LinearLayout>
//以后可以做个小红点
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/>
</RelativeLayout>
color_main_tab_text.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
//注意顺序,显示特殊情况下的选择,最后才是默认情况下的选择,否则会失效
<item android:state_selected="true" android:color="#4dd048"/>
<item android:state_pressed="true" android:color="#4dd048"/>
<item android:color="#cccccc"/>
</selector>
main_tab_icon_home.xml:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
//注意顺序,显示特殊情况下的选择,最后才是默认情况下的选择,否则会失效
<item android:drawable="@drawable/tabbar_home_pressed" android:state_selected="true" />
<item android:drawable="@drawable/tabbar_home_pressed" android:state_pressed="true" />
<item android:drawable="@drawable/tabbar_home" />
</selector>
main_tab_icon_me.xml和main_tab_icon_message.xml:同上面的类似。
接下来是图片素材,需要的话就保存一下吧。
1
tabbar_home_pressed2
tabbar_home3
tabbar_msg_pressed4
tabbar_msg5
tabbar_my_pressed6
tabbar_my欢迎小伙伴们批评指正!
网友评论