Fragment+ViewPage一步步实现底部导航栏。

这里写图片描述

首先说下这个demo的结构吧!
1 . 用到了Fragment+ViewPager
2 . 底部用了单选按钮实现的。

再来看下代码的具体实现:

1.新建一个project的,名字自己随意。

2.编写activity_main.xml

<LinearLayout 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"
    android:orientation="vertical"
  >
<android.support.v4.view.ViewPager  
        android:id="@+id/myviewpager"  
        android:layout_width="fill_parent"  
        android:layout_height="0dp"  
        android:layout_weight="8">  
    </android.support.v4.view.ViewPager>
    <!-- 指示标签 -->  
     <LinearLayout   
        android:id="@+id/cursorarea"  
        android:layout_width="fill_parent"  
        android:background="#CDCDCD"  
        android:orientation="horizontal"  
        android:layout_height="2dp">  
        <ImageView  
            android:id="@+id/cursor_btn"  
            android:layout_width="fill_parent"  
            android:layout_height="fill_parent">  
        </ImageView>  
    </LinearLayout>  

    <RelativeLayout   
        android:id="@+id/bottomlinear"  
        android:layout_width="match_parent"  
        android:layout_height="0dp"  
        android:layout_weight="1"   
        android:background="#DCDCDC">  -->
           <RadioGroup
        android:id="@+id/rg_menu"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal"
        android:padding="5dp"   
        >


        <RadioButton
            android:id="@+id/btn_first"  
            android:layout_width="0dp"  
            android:layout_height="wrap_content"
            android:layout_weight="1"  
            android:padding="-5dp"  
            android:textSize="14sp"
             android:button="@null" 
            android:gravity="center"
            android:text="最新"  
            android:checked="true"
            android:drawableTop="@drawable/firstbutton"/>

        <RadioButton
            android:id="@+id/btn_second"  
            android:layout_width="0dp"  
            android:layout_height="wrap_content"
            android:layout_weight="1"  
            android:textSize="14sp" 
             android:button="@null" 
            android:gravity="center" 
             android:text="前端"
             android:drawableTop="@drawable/secondbutton" />

        <RadioButton
            android:id="@+id/btn_third"  
            android:layout_width="0dp"  
            android:layout_height="wrap_content"
            android:layout_weight="1"  
            android:textSize="14sp"
            android:button="@null" 
            android:gravity="center"  
            android:text="移动"
            android:drawableTop="@drawable/thridbutton" />

        <RadioButton
            android:id="@+id/btn_four"  
            android:layout_width="0dp"  
            android:layout_height="wrap_content"  
            android:layout_weight="1"  
            android:textSize="14sp"
             android:button="@null" 
            android:gravity="center"  
            android:text="语言"
            android:drawableTop="@drawable/fourbutton"/>
    </RadioGroup>         
    </RelativeLayout>>
</LinearLayout>

这里我们需要先编写一个按钮选择器
文件目录
这里写图片描述

里面的代码很简单,就是按钮选中状态和未选中状态显示的图片。

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

当然,你要事先准备八张图片,每个按钮两张。

在activity_main.xim布局中最上面一个ViewPager,ViewPage下面写一个ImageView来做指示标签,就是前面展示图片上面看到的在按钮图片上的那个红色的线。指示当前那个按钮被选中。

3.新建四个Fragment
FirstFragment.java

package com.example.fragment;

import com.example.fragment_viewpager.R;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class FirstFragment extends Fragment{  

    @Override  
    public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {  
        // TODO Auto-generated method stub  
        View v = inflater.inflate(R.layout.layout_first, container,false);  
        return v;  
    }  

}  

layout_first.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" >  

    <TextView   
        android:layout_width="fill_parent"  
        android:layout_height="fill_parent"  
        android:gravity="center"  
        android:layout_gravity="center"  
        android:text="这是第一个Fragment"/>  

</LinearLayout>  

其它三个类似,把名字和里面TextView显示的值,修改下即可。

4.我们需要把Fragment加载到ViewPager里面去,需要用的适配器来加载。这里我们用的适配器是FragmentPagerAdapter。

新建一个类MyFragmentPagerAdapter,使它继承FragmentPagerAdapter。并实现它需要实现的方法。

MyFragmentPagerAdapter.java

package com.example.adapter;

import java.util.ArrayList;
import java.util.List;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

public class MyFragmentPagerAdapter extends FragmentPagerAdapter{
    //存储所有的fragment  
    private List<Fragment> list; 
    public MyFragmentPagerAdapter(FragmentManager fm,ArrayList<Fragment> list) {
        super(fm);
        this.list=list;
        // TODO Auto-generated constructor stub
    }

    @Override
    public Fragment getItem(int arg0) {
        // TODO Auto-generated method stub
        return list.get(arg0);
    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return list.size();
    }

}

5.接着开始编写MainActivity.java当中的代码。

package com.example.fragment_viewpager;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.Log;

import java.lang.reflect.Field;
import java.util.ArrayList;

import com.example.adapter.MyFragmentPagerAdapter;
import com.example.fragment.FirstFragment;
import com.example.fragment.FourFragment;
import com.example.fragment.SecondFragment;
import com.example.fragment.ThridFragment;

import android.app.Activity;
import android.graphics.Color;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.Toast;
import android.widget.CompoundButton.OnCheckedChangeListener;

public class MainActivity extends FragmentActivity implements  OnPageChangeListener{  

    private ViewPager myviewpager;  
    //fragment的集合,对应每个子页面  
    private ArrayList<Fragment> fragments;  
    //选项卡中的按钮  
    private RadioButton btn_first;  
    private RadioButton btn_second;  
    private RadioButton btn_third;  
    private RadioButton btn_four;  

    //作为指示标签的按钮  
    private ImageView cursor;  
    //标志指示标签的横坐标  
    float cursorX = 0;  
    //所有按钮的宽度的集合  
    private int[] widthArgs;  
    //所有按钮的集合  
    private Button[] btnArgs;  

    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main2);  

        initView();  

    }  

    public void initView(){  
        myviewpager = (ViewPager)this.findViewById(R.id.myviewpager);  

        //ViewPager的setCurrentItem是跳转到ViewPager的指定页面,
        //但在使用这个方法的时候有个问题,跳转的时候有滑动效果,
        //当需要从当前页面跳转到其它页面时,跳转页面跨度过大、
        //或者ViewPager每个页面的视觉效果相差较大时,通过这种方式实现ViewPager跳转显得很不美观

        //解决办法:
        //我们可以去掉在使用ViewPager的setCurrentItem方法时的滑屏速度
        try {  
            Field mScroller = null;  
            mScroller = ViewPager.class.getDeclaredField("mScroller");  
            mScroller.setAccessible(true);   
            FixedSpeedScroller scroller = new FixedSpeedScroller( myviewpager.getContext());  
            mScroller.set( myviewpager, scroller);  
        }catch(NoSuchFieldException e){  

        }catch (IllegalArgumentException e){  

        }catch (IllegalAccessException e){  

        }  

        btn_first = (RadioButton)this.findViewById(R.id.btn_first);  
        btn_second = (RadioButton)this.findViewById(R.id.btn_second);  
        btn_third = (RadioButton)this.findViewById(R.id.btn_third);  
        btn_four = (RadioButton)this.findViewById(R.id.btn_four);  



        btnArgs = new Button[]{btn_first,btn_second,btn_third,btn_four};  

        cursor = (ImageView)this.findViewById(R.id.cursor_btn);  

        cursor.setBackgroundColor(Color.RED);  


        myviewpager.setOnPageChangeListener(this);  
       /* btn_first.setOnClickListener(this);  
        btn_second.setOnClickListener(this);  
        btn_third.setOnClickListener(this);  
        btn_four.setOnClickListener(this);  */

        btn_first.setOnCheckedChangeListener(new InnerOnCheckedChangeListener());
        btn_second.setOnCheckedChangeListener(new InnerOnCheckedChangeListener());
        btn_third.setOnCheckedChangeListener(new InnerOnCheckedChangeListener());
        btn_four.setOnCheckedChangeListener(new InnerOnCheckedChangeListener());


        fragments = new ArrayList<Fragment>();  
        fragments.add(new FirstFragment());  
        fragments.add(new SecondFragment());  
        fragments.add(new ThridFragment());  
        fragments.add(new FourFragment());       
        MyFragmentPagerAdapter adapter = new MyFragmentPagerAdapter(getSupportFragmentManager(),fragments);  
        myviewpager.setAdapter(adapter);  

        //重置所有按钮颜色
        resetButtonColor();  
        //把第一个按钮的颜色设置为红色
        btn_first.setTextColor(Color.RED);
        //为什么不直接cursor.setWidth()和cursor.setX()
        //因为Android系统绘制原理是只有全部遍历测量之后才会布局,
        //只有在整个布局绘制完毕后,视图才能得到自身的高和宽。
        //所以在正常情况下,在OnCreate()方法中直接获取控件的宽度和高度取得值是0。
        //而我们此处设置指示器的大小和位置都需要用到第一个按钮的大小作为参考值,
        //所以可以通过post将一个runnable投递到消息队列的尾部,然后等待UI线程Looper调用此runnable的时候,view也已经初始化好了。这个时候就能成功获取控件的宽高
        btn_first.post(new Runnable(){  
            @Override  
            public void run() {  
                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)cursor.getLayoutParams();    
                //减去边距*2,以对齐标题栏文字  
                lp.width = btn_first.getWidth()-btn_first.getPaddingLeft()*2;    
                cursor.setLayoutParams(lp);    
                cursor.setX(btn_first.getPaddingLeft());  
            }  
        });  


    }  


  //把事件的内部类定义出来
    private class InnerOnCheckedChangeListener implements OnCheckedChangeListener{
        //单选按钮选中事件方法
        //buttonView表示谁的状态被改变
        //isChecked上面的参数代表的状态是否选中
        public void onCheckedChanged(CompoundButton buttonView,boolean isChecked){
            switch (buttonView.getId()) {
            case R.id.btn_first:
                //单选按钮通过参数isChecked去得到当前到底是选中还是未选中
                if(isChecked){
                  myviewpager.setCurrentItem(0);  
                  cursorAnim(0);  

                }

                break;
            case R.id.btn_second:
                //单选按钮通过参数isChecked去得到当前到底是选中还是未选中
                if(isChecked){
                  myviewpager.setCurrentItem(1);  
                  cursorAnim(1);  
                }

                break;
            case R.id.btn_third:
                //单选按钮通过参数isChecked去得到当前到底是选中还是未选中
                if(isChecked){
                     myviewpager.setCurrentItem(2);  
                    cursorAnim(2);  
                }

                break;
            case R.id.btn_four:
                //单选按钮通过参数isChecked去得到当前到底是选中还是未选中
                if(isChecked){
                    myviewpager.setCurrentItem(3);  
                    cursorAnim(3);  
                }

                break;

            default:
                break;
            }

        }



    }

    //重置所有按钮的颜色  
    public void resetButtonColor(){  
        btn_first.setBackgroundColor(Color.parseColor("#DCDCDC"));  
        btn_second.setBackgroundColor(Color.parseColor("#DCDCDC"));  
        btn_third.setBackgroundColor(Color.parseColor("#DCDCDC"));  
        btn_four.setBackgroundColor(Color.parseColor("#DCDCDC"));  

        btn_first.setTextColor(Color.BLACK);  
        btn_second.setTextColor(Color.BLACK);  
        btn_third.setTextColor(Color.BLACK);  
        btn_four.setTextColor(Color.BLACK);  

    }  


    @Override  
    public void onPageScrollStateChanged(int arg0) {  
        // TODO Auto-generated method stub  

    }  

    @Override  
    public void onPageScrolled(int arg0, float arg1, int arg2) {  
        // TODO Auto-generated method stub  

    }  

    @Override  
    public void onPageSelected(int arg0) {  
        // TODO Auto-generated method stub  
        if(widthArgs==null){  
            widthArgs = new int[]{btn_first.getWidth(),  
                                 btn_second.getWidth(),  
                                 btn_third.getWidth(),  
                                 btn_four.getWidth()};  
        }  
        //每次滑动首先重置所有按钮的颜色  
        resetButtonColor();  

        //将滑动到的当前按钮颜色设置为红色  
        btnArgs[arg0].setTextColor(Color.RED);  

        cursorAnim(arg0); 

        //把当前页面的单选按钮设置为选中状态
        ((CompoundButton) btnArgs[arg0]).setChecked(true);


    }  

  //指示器的跳转,传入当前所处的页面的下标  
    public void cursorAnim(int curItem){  
        //每次调用,就将指示器的横坐标设置0,即开始的位置  
        cursorX = 0;  
        //再根据当前的curItem来设置指示器的宽度  
        LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)cursor.getLayoutParams();    
        //首先获得当前按钮的宽度,再减去按钮左右边距距,以对齐标题栏文本  
        lp.width = widthArgs[curItem]-btnArgs[0].getPaddingLeft()*2; 
        //通过指示标签对象,将标签设置到父容器中
        cursor.setLayoutParams(lp);    
        //循环获取当前页之前的所有页面的宽度  
        for(int i=0; i<curItem; i++){  
            cursorX = cursorX + btnArgs[i].getWidth();  
        }  
        //再加上当前页面的左边距,即为指示器当前应处的位置  
        cursor.setX(cursorX+btnArgs[curItem].getPaddingLeft());   
    }  


}

这里在初始化ViewPager时,用到了一个写好的外部类。可以试下不写这步

 try {  
            Field mScroller = null;  
            mScroller = ViewPager.class.getDeclaredField("mScroller");  
            mScroller.setAccessible(true);   
            FixedSpeedScroller scroller = new FixedSpeedScroller( myviewpager.getContext());  
            mScroller.set( myviewpager, scroller);  
        }catch(NoSuchFieldException e){  

        }catch (IllegalArgumentException e){  

        }catch (IllegalAccessException e){  

        }  
你会发现,在通过点击按钮从第一个页面跳转到第三个页面时,它不是直接跳转到第三个页面,而是有一个滑动效果,就是先从第一个页面滑到第二个页面,才从第二个页面滑到第三个页面,这样非常的不美观。

6.这里我们自定义一个Scroll类,修改滑屏速度

package com.example.fragment_viewpager;

import android.content.Context;
import android.view.animation.Interpolator;
import android.widget.Scroller;

public class FixedSpeedScroller extends Scroller{
     private int mDuration = 0;  

        public FixedSpeedScroller(Context context) {  
            super(context);  
        }  

        public FixedSpeedScroller(Context context, Interpolator interpolator) {  
            super(context, interpolator);  
        }  

        public FixedSpeedScroller(Context context, Interpolator interpolator, boolean flywheel) {  
            super(context, interpolator, flywheel);  
        }  


        @Override  
        public void startScroll(int startX, int startY, int dx, int dy, int duration) {  
            super.startScroll(startX, startY, dx, dy, mDuration);  
        }  

        @Override  
        public void startScroll(int startX, int startY, int dx, int dy) {  
            super.startScroll(startX, startY, dx, dy, mDuration);  
        }  

}

这样就差不多实现了,如果大家有什么疑问就在下方留言吧!

demo下载链接:http://download.csdn.net/download/qq_35152260/9786292

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值