底部导航栏的实现有很多种方法,我这里采用的是最简单的LinearLayout+TextView布局,没有使用RadioGroup做布局,主要是为了兼容底部出现新消息小圆点的这种情况,本篇文章参考以下链接:
Fragment实例精讲——底部导航栏的实现
提前声明,本篇文章的讲解可能有些长,大家不妨先泡杯维维豆奶再来看戏。
先上一张效果图吧:
提前准备
由于我项目中用到ButterKnife初始化控件,所以app gradle中需要引入ButterKnife的依赖:
//butterKnife
compile 'com.jakewharton:butterknife:8.5.1'
//这条千万不能忘记!!
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
ButterKnife的使用大家可以参考我的另一篇文章
butterknife的使用
首先说是设置底部导航栏中一个上面加有图片的textView和每个小方格中右上角显示小圆点的textView
1.先给出底部显示图片的TextView和显示小圆点的TextView的样式xml
在value文件夹下的stytel.xml中添加两个stytel
2.在drawable下写一个shape_round_textview.xml文件,用于实现小圆点TextView的圆形背景
在drawable下写上点击底部文字颜色切换的tab_menu_text.xml
在drawable下写上点击底部图片切换的tab_menu_chat.xml
其它三个tab_menu_find.xml,tab_menu_user.xml,tab_menu_me.xml图片的切换与此类似,copy一下改改就行
3.写一个BaseFragment用于所有Fragment去继承它,记住,此处用的所有与fragment相关的都是用的v4包下的,别导错包了
package com.test.ui.fragment;
import android.content.Context;
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.EditText;
import com.test.util.StringUtil;
import com.test.util.ToastUtil;
import butterknife.ButterKnife;
import butterknife.Unbinder;
/**
* Created by Admin on 2017/6/7.
*/
public abstract class BaseFragment extends Fragment {
protected View mLayoutView;
protected Context mContext;
private Unbinder mUnbinder;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mContext = context;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mLayoutView = inflater.inflate(getLayoutId(), container, false);
mUnbinder=ButterKnife.bind(this,mLayoutView);//绑定framgent
onCreateFragmentView(inflater, container, savedInstanceState);
return mLayoutView;
}
protected void onCreateFragmentView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
initData();
setListener();
}
@Override
public void onDestroy() {
if(mUnbinder!=null){
mUnbinder.unbind();
}
super.onDestroy();
}
protected abstract int getLayoutId();
protected abstract void initData();
protected abstract void setListener();
/**
* 获取editText的值
*
* @param et
* @return
*/
protected String getTextOfEditText(EditText et){
if (et == null) {
return null;
}
if (et.getText() == null) {
return null;
}
if (StringUtil.isEmpty(et.getText().toString())) {
return "";
}
return et.getText().toString().trim();
}
protected void showToast(String msg) {
if (StringUtil.isNotEmpty(msg)) {
ToastUtil.show(msg);
}
}
protected void showShortToast(String msg){
if (StringUtil.isNotEmpty(msg)) {
ToastUtil.shortShow(msg);
}
}
}
4.给出第一个fragment的代码:
package com.test.ui.fragment;
import android.view.View;
import android.widget.TextView;
import com.test.R;
import butterknife.BindView;
/**
* Created by Admin on 2017/6/7.
*/
public class Fragment1 extends BaseFragment implements View.OnClickListener{
@BindView(R.id.txt_content)
TextView mTvContext;
@Override
protected int getLayoutId() {
return R.layout.one_fragment;
}
@Override
protected void initData() {
}
@Override
protected void setListener() {
mTvContext.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.txt_content:
TextView tab_menu_channel_num = (TextView)((MenuActivity)mContext).findViewById(R.id.tab_menu_channel_num);
tab_menu_channel_num.setText("11");
tab_menu_channel_num.setVisibility(View.VISIBLE);
break;
}
}
}
下面是Fragment1的layout文件one_fragment.xml
Fragment2,Fragment3,Fragment4的代码和Fragment1类似,copy一下改改即可
5.然后是给出activity代码
package com.test.ui.fragment;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.test.R;
import com.test.app.AppActivity;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
/**
* Created by Admin on 2017/6/7.
*/
public class MenuActivity extends AppActivity implements View.OnClickListener,TabOnPageChangeListener.OnSelectedFragmentListener {
public static Intent newIndexIntent(Context context) {
Intent newIntent = new Intent(context, MenuActivity.class);
return newIntent;
}
@BindView(R.id.ly_tab_menu_channel)
LinearLayout ly_tab_menu_channel;
@BindView(R.id.tab_menu_channel)
TextView tab_menu_channel;
@BindView(R.id.tab_menu_channel_num)
TextView tab_menu_channel_num;
@BindView(R.id.ly_tab_menu_message)
LinearLayout ly_tab_menu_message;
@BindView(R.id.tab_menu_message)
TextView tab_menu_message;
@BindView(R.id.tab_menu_message_num)
TextView tab_menu_message_num;
@BindView(R.id.ly_tab_menu_better)
LinearLayout ly_tab_menu_better;
@BindView(R.id.tab_menu_better)
TextView tab_menu_better;
@BindView(R.id.tab_menu_better_num)
TextView tab_menu_better_num;
@BindView(R.id.ly_tab_menu_setting)
LinearLayout ly_tab_menu_setting;
@BindView(R.id.tab_menu_setting)
TextView tab_menu_setting;
@BindView(R.id.tab_menu_setting_partner)
ImageView tab_menu_setting_partner;
@BindView(R.id.vpager)
ViewPager mViewPager;
private ListmFragmentList;
private MainPagerAdapter mainPagerAdapter;
private TabOnPageChangeListener mTabOnPageChangeListener;
@Override
protected int getContentViewId() {
return R.layout.activity_menu;
}
@Override
protected void initData() {
mFragmentList=new ArrayList<>();
mFragmentList.add(0, new Fragment1());
mFragmentList.add(1, new Fragment2());
mFragmentList.add(2, new Fragment3());
mFragmentList.add(3, new Fragment4());
mTabOnPageChangeListener=new TabOnPageChangeListener(mViewPager);
mainPagerAdapter = new MainPagerAdapter(getSupportFragmentManager(), mFragmentList);
mViewPager.setOffscreenPageLimit(4);// 设置预加载Fragment个数
mViewPager.setAdapter(mainPagerAdapter);
mViewPager.setCurrentItem(0);// 设置当前显示标签页为第一页
}
@Override
protected void setListener() {
ly_tab_menu_channel.setOnClickListener(this);
ly_tab_menu_message.setOnClickListener(this);
ly_tab_menu_better.setOnClickListener(this);
ly_tab_menu_setting.setOnClickListener(this);
mViewPager.addOnPageChangeListener(mTabOnPageChangeListener);
mTabOnPageChangeListener.setOnSelectedFragmentListener(this);
//默认显示第一个fragment, 必须在ly_tab_menu_channel.setOnClickListener(this);之后执行
ly_tab_menu_channel.performClick();
}
@Override
public void onClick(View v){
switch (v.getId()) {
case R.id.ly_tab_menu_channel:
clickFragment1();
break;
case R.id.ly_tab_menu_message:
clickFragment2();
break;
case R.id.ly_tab_menu_better:
clickFragment3();
break;
case R.id.ly_tab_menu_setting:
clickFragment4();
break;
}
}
//重置所有文本的选中状态
private void setSelected() {
tab_menu_channel.setSelected(false);
tab_menu_message.setSelected(false);
tab_menu_better.setSelected(false);
tab_menu_setting.setSelected(false);
}
private void clickFragment1(){
setSelected();
tab_menu_channel.setSelected(true);
tab_menu_channel_num.setVisibility(View.INVISIBLE);
mViewPager.setCurrentItem(0);
}
private void clickFragment2(){
setSelected();
tab_menu_message.setSelected(true);
tab_menu_message_num.setVisibility(View.INVISIBLE);
mViewPager.setCurrentItem(1);
}
private void clickFragment3(){
setSelected();
tab_menu_better.setSelected(true);
tab_menu_better_num.setVisibility(View.INVISIBLE);
mViewPager.setCurrentItem(2);
}
private void clickFragment4(){
setSelected();
tab_menu_setting.setSelected(true);
tab_menu_setting_partner.setVisibility(View.INVISIBLE);
mViewPager.setCurrentItem(3);
}
@Override
public void selectedFragment(int index) {
switch (index) {
case 0:
clickFragment1();
break;
case 1:
clickFragment2();
break;
case 2:
clickFragment3();
break;
case 3:
clickFragment4();
break;
}
}
@Override
protected void onDestroy(){
super.onDestroy();
}
}
需要注意的是:
- 我的MenuActivity 继承的是AppActivity,而AppActivity 是我自己写的一个类似BaseActivity的类,大家也可直接 MenuActivity 继承 AppCompatActivity 即可。
- setListener()方法中ly_tab_menu_channel.performClick();是为了默认显示第一个fragment,必须在ly_tab_menu_channel.setOnClickListener(this);之后执行
然后贴出 activity_menu.xml的代码
6.MenuActivity中用到viewPager,肯定少不了适配器 MainPagerAdapter 了
package com.test.ui.fragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.view.View;
import java.util.List;
/***
* 标签主页适配器
*
* @author pei
* @version 1.0
* @create 2016-6-21
*/
public class MainPagerAdapter extends FragmentPagerAdapter {
private List mFragmentList;
public MainPagerAdapter(FragmentManager fm, List mFragmentList) {
super(fm);
this.mFragmentList = mFragmentList;
}
@Override
public Fragment getItem(int position) {
// TODO Auto-generated method stub
return mFragmentList == null ? null : mFragmentList.get(position);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mFragmentList == null ? 0 : mFragmentList.size();
}
@Override
public void destroyItem(View container, int position, Object object) {
// super.destroyItem(container, position, object);
}
}
7.MenuActivity中的viewPager本来是可以直接
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
来监听滑动的,但是我为了去掉滑动到两端的时候出现阴影,所以用
TabOnPageChangeListener重新实现了下ViewPager.OnPageChangeListener()接口,下面贴出 TabOnPageChangeListener代码:
package com.test.ui.fragment;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.support.v4.widget.EdgeEffectCompat;
import java.lang.reflect.Field;
/***
* TabMenuFragmentActivity viewpager滑动监听(禁用滑到边界显示黑边)
*
* @author pei
* @version 1.0
* @create 2016-6-21
*/
public class TabOnPageChangeListener implements OnPageChangeListener {
private ViewPager mViewPager;
private OnSelectedFragmentListener mOnSelectedFragmentListener;
private EdgeEffectCompat leftEdge;//去除viewpager滑到边界的黑边
private EdgeEffectCompat rightEdge;//去除viewpager滑到边界的黑边
public TabOnPageChangeListener(ViewPager viewPager) {
this.mViewPager = viewPager;
init();
}
public void setOnSelectedFragmentListener(OnSelectedFragmentListener onSelectedFragmentListener) {
this.mOnSelectedFragmentListener = onSelectedFragmentListener;
}
private void init() {
try {
Field leftEdgeField = mViewPager.getClass().getDeclaredField("mLeftEdge");
Field rightEdgeField = mViewPager.getClass().getDeclaredField("mRightEdge");
if (leftEdgeField != null && rightEdgeField != null) {
leftEdgeField.setAccessible(true);
rightEdgeField.setAccessible(true);
leftEdge = (EdgeEffectCompat) leftEdgeField.get(mViewPager);
rightEdge = (EdgeEffectCompat) rightEdgeField.get(mViewPager);
}
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// 禁用滑到边界显示黑边
if (leftEdge != null && rightEdge != null) {
leftEdge.finish();
rightEdge.finish();
leftEdge.setSize(0, 0);
rightEdge.setSize(0, 0);
}
}
@Override
public void onPageScrollStateChanged(int state) {
//state的状态有三个,0表示什么都没做,1正在滑动,2滑动完毕
}
@Override
public void onPageSelected(int position) {
if (mOnSelectedFragmentListener != null) {
mOnSelectedFragmentListener.selectedFragment(position);
}
}
public interface OnSelectedFragmentListener {
void selectedFragment(int index);
}
}
8.可能有的同学对我MenuActivity所继承的AppActivity有疑问,那我就贴出来大家随便看看就好
package com.test.app;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import com.test.util.StringUtil;
import com.test.util.ToastUtil;
import butterknife.ButterKnife;
import butterknife.Unbinder;
/**
- Created by Admin on 2017/5/16.
*/
public abstract class AppActivity extends AppCompatActivity{
protected View mLayoutView;//总布局
protected Activity mContext;
private Unbinder mUnbinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//赋值context
mContext=this;
//activity管理
AppActivityManager.getInstance().addActivity(this);
if (getContentViewId() != 0) {
mLayoutView = LayoutInflater.from(mContext).inflate(getContentViewId(), null);
setContentView(mLayoutView);
//控件绑定
mUnbinder= ButterKnife.bind(this);
}
initData();
setListener();
}
/**设置布局**/
protected abstract int getContentViewId();
protected abstract void initData();
protected abstract void setListener();
@Override
protected void onDestroy() {
if(mUnbinder!=null){
mUnbinder.unbind();
}
super.onDestroy();
}
/**获取editText的值**/
protected String getTextOfEditText(EditText et) {
if(et!=null&&et.getText()!=null){
if(StringUtil.isEmpty(et.getText().toString())){
return "";
}else{
return et.getText().toString().trim();
}
}
return null;
}
protected void showShortToast(String msg) {
if (StringUtil.isNotEmpty(msg)) {
ToastUtil.shortShow(msg);
}
}
protected void showLongToast(String msg) {
if (StringUtil.isNotEmpty(msg)) {
ToastUtil.show(msg);
}
}
/** 用于初始化控件的 **/
protected T getView(int rId) {
View view = this.findViewById(rId);
return (T) view;
}
}
9.我在Fragment1 中模拟了一个点击TextView显示消息小圆点,大家在用的时候,自己根据实际情况改改就成
ok,今天fragment+viewPager 实现底部导航栏的功能就基本实现了。谢谢诶。