Fragment+ViewPage一步步实现底部导航栏。
2017-10-27 15:09
344 查看
首先说下这个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> < 10817 ;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(); } }2
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
相关文章推荐
- Fragment+ViewPage一步步实现底部导航栏。
- 【Android】Fragment+Viewpager实现底部导航栏(带小红点)
- Android-底部菜单Tabs 三种实现方式(ViewPager,Fragment,ViewPage+Fragment)
- Android Fragment + ViewPager 实现类微信 底部导航栏 和 显示消息提醒
- Android 用 TabLayout + ViewPager + Fragment 实现顶部、底部导航栏
- FragmentTabHost + pageView 实现可左右滑动的底部菜单 ...
- TextView+Fragment实现底部导航栏
- FragmentTabHost+ViewPager实现滑动的底部导航栏
- TextView+Fragment实现底部导航栏
- 使用ViewPager+Fragment实现底部导航栏
- TabLayout+ViewPager+Fragment实现带图标和文字的底部导航栏
- FragmentTabHost+ViewPage实现底部导航窗口切换
- Android项目ViewPager+Fragment+RadioButton实现底部导航栏切换
- 安卓开发--应用市场的界面制作(一)--viewpager+fragment实现可滑动的底部导航栏
- Android实现底部导航栏加侧滑(BottomNavigationView+ViewPager+Fragment)
- 底部导航栏实现页面的切换(三):Fragment + RadioGroup + ViewPager
- Android开发:顶部&底部Tab导航栏实现(TabLayout+ViewPager+Fragment)
- Android博客挑错系列之一FragmentTabHost和ViewPager实现底部导航栏
- Fragment和ViewPager实现底部导航栏
- FragmentTabHost+viewPager实现底部导航栏