Viewpager实现底部滑动菜单,同时取消预加载


一、FragmentTabhost + RadioGroup

RadioButton引用
 <RadioButton
            android:id="@+id/tab_rb_message"
            style="@style/navigation_bottom_radio"
            android:drawableTop="@drawable/tab_message_btn"
            android:text="消息"
            />

tab_message_btn,其中tab_message_press和tab_message_normal是两张图片
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@mipmap/tab_message_press" android:state_checked="true"/>
    <item android:drawable="@mipmap/tab_message_normal"/>

</selector>
其中对于RadioButton的样式如下:
    <style name="navigation_bottom_radio">
        <!-- 内部组件的排列 -->
        <item name="android:gravity">center_horizontal</item>
        <!-- 背景样式 -->
        <item name="android:background">@android:color/transparent</item>
        <!-- 宽度 -->
        <item name="android:layout_width">wrap_content</item>
        <!-- 高度 -->
        <item name="android:layout_height">match_parent</item>
        <!-- 设置RadioButton的原来图片为空 -->
        <item name="android:button">@null</item>
        <!-- 与其他组件宽度占相同比重 -->
        <item name="android:layout_weight">1.0</item>
        <!-- 底部的空隙 -->
        <item name="android:paddingBottom">2.0dip</item>
        <!-- 顶部的空隙 -->
        <item name="android:paddingTop">2.0dip</item>
        <!-- 图片与文字的空隙 -->
        <item name="android:drawablePadding">1.0dip</item>
        <!-- 文字的大小 -->
        <item name="android:textSize">12sp</item>
        <!-- 文字的颜色 -->
        <item name="android:textColor">@color/tab_text_color_selector</item>
    </style>
tab_text_color_selector.xml位于 res/color 文件夹下,其中tab_text_color就是菜单文字被选中的颜色
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_checked="true" android:color="@color/tab_text_color"/>
    <item android:state_checked="false" android:color="@android:color/black"/>
    <item android:color="@android:color/black"/>

</selector>




一、FragmentTabhost+Viewpager:


       虽然tabactivity已经在3.0后废弃了,但是依然不阻碍这种tab风格菜单的流行程度,代替它的则是使用了FragmentTabhost的FragmentActivity,子tab采用的是fragment,顺便在每一个tab菜单底部添加一个红线的位移动画效果,类似酷我音乐Android版顶部菜单效果,制作出来的gif图中底部红线位移动画有点卡顿,实际运行效果是很流畅的,效果图如下:

  Viewpager实现底部滑动菜单,同时取消预加载_第1张图片

看起来很简单,但是考虑到viewpager本身有预加载的机制,所以最后在实际项目中还是去掉了viewpager滑动菜单这项功能

主要类的全部代码如下


package com.example.fragmenttabhostviewpager;

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

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTabHost;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.DisplayMetrics;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.TabHost.OnTabChangeListener;
import android.widget.TabHost.TabSpec;
import android.widget.ImageView;

public class MainActivity extends FragmentActivity {
	private RadioGroup rg;
	private RadioButton firstBtn;
	private RadioButton secondBtn;
	private RadioButton thirdBtn;
	private FragmentTabHost mFragmentTabhost;
	public static final String SHOW_OF_FIRST_TAG = "first";
	public static final String SHOW_OF_SECOND_TAG = "second";
	public static final String SHOW_OF_THIRD_TAG = "third";

	private int SCREEN_WIDTH;

	private float currentX;// 当前X坐标
	private float preX;// 前一操作的X坐标
	private ImageView mRedlineIV;

	private List<Fragment> list = new ArrayList<Fragment>();
	private ViewPager mViewPager;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		DisplayMetrics metrics = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(metrics);
		SCREEN_WIDTH = metrics.widthPixels;
		setContentView(R.layout.activity_main);

		mFragmentTabhost = (FragmentTabHost) findViewById(android.R.id.tabhost);
		rg = (RadioGroup) findViewById(R.id.tab_rg_menu);
		firstBtn = (RadioButton) findViewById(R.id.tab_rb_1);
		secondBtn = (RadioButton) findViewById(R.id.tab_rb_2);
		thirdBtn = (RadioButton) findViewById(R.id.tab_rb_3);
		mViewPager = (ViewPager) findViewById(R.id.pager);
		mRedlineIV = (ImageView) findViewById(R.id.tab_menu_red_line);
		LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
				SCREEN_WIDTH / 3, LinearLayout.LayoutParams.WRAP_CONTENT);
		mRedlineIV.setLayoutParams(params);
		mRedlineIV.setImageResource(R.drawable.ic_launcher);
		mFragmentTabhost.setup(this, getSupportFragmentManager(), R.id.pager);

		TabSpec tabSpec0 = mFragmentTabhost.newTabSpec(SHOW_OF_FIRST_TAG)
				.setIndicator("0");
		TabSpec tabSpec1 = mFragmentTabhost.newTabSpec(SHOW_OF_SECOND_TAG)
				.setIndicator("1");
		TabSpec tabSpec2 = mFragmentTabhost.newTabSpec(SHOW_OF_THIRD_TAG)
				.setIndicator("2");

		mFragmentTabhost.addTab(tabSpec0, Fragment1.class, null);
		mFragmentTabhost.addTab(tabSpec1, Fragment2.class, null);
		mFragmentTabhost.addTab(tabSpec2, Fragment3.class, null);

		rg.setOnCheckedChangeListener(new OnCheckedChangeListener() {

			@Override
			public void onCheckedChanged(RadioGroup group, int checkedId) {
				// TODO Auto-generated method stub
				switch (checkedId) {
				case R.id.tab_rb_1:
					preX = currentX;
					currentX = 0;
					mFragmentTabhost.setCurrentTabByTag(SHOW_OF_FIRST_TAG);
					break;
				case R.id.tab_rb_2:
					preX = currentX;
					currentX = SCREEN_WIDTH * 1 / 3;
					mFragmentTabhost.setCurrentTabByTag(SHOW_OF_SECOND_TAG);
					break;
				case R.id.tab_rb_3:
					preX = currentX;
					currentX = SCREEN_WIDTH * 2 / 3;
					mFragmentTabhost.setCurrentTabByTag(SHOW_OF_THIRD_TAG);
					break;

				default:
					break;
				}
				Animation translateAnimation = new TranslateAnimation(preX,
						currentX, 0, 0);
				translateAnimation.setFillAfter(true);
				translateAnimation.setDuration(1000);
				mRedlineIV.setAnimation(translateAnimation);
			}
		});

		mFragmentTabhost.setOnTabChangedListener(new OnTabChangeListener() {

			@Override
			public void onTabChanged(String tabId) {
				// TODO Auto-generated method stub
				int position = mFragmentTabhost.getCurrentTab();
				mViewPager.setCurrentItem(position);
			}
		});

		mFragmentTabhost.setCurrentTab(0);

		Fragment1 p1 = new Fragment1();
		Fragment2 p2 = new Fragment2();
		Fragment3 p3 = new Fragment3();
		list.add(p1);
		list.add(p2);
		list.add(p3);
		mViewPager.setAdapter(new MenuAdapter(getSupportFragmentManager()));
		mViewPager.setOnPageChangeListener(new ViewPagerListener());
	}

	class MenuAdapter extends FragmentPagerAdapter {

		public MenuAdapter(FragmentManager fm) {
			super(fm);
			// TODO Auto-generated constructor stub
		}

		@Override
		public Fragment getItem(int arg0) {
			return list.get(arg0);
		}

		@Override
		public int getCount() {
			return list.size();
		}

	}

	class ViewPagerListener implements OnPageChangeListener {
		@Override
		public void onPageScrollStateChanged(int arg0) {

		}

		@Override
		public void onPageScrolled(int arg0, float arg1, int arg2) {

		}

		@Override
		public void onPageSelected(int index) {
			if (index == 0) {
				firstBtn.setChecked(true);
			} else if (index == 1) {
				secondBtn.setChecked(true);
			} else if (index == 2) {
				thirdBtn.setChecked(true);
			}
			mFragmentTabhost.setCurrentTab(index);
		}
	}
}

DEMO1下载


二、Viewpager:


        单独用viewpager实现的底部menu效果和第一种是一样的,但是代码上却比第一种更优化了。
下面贴出主要类的代码:

package com.example.viewpagermenu;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;

public class MainActivity extends FragmentActivity {
	private RadioGroup mRadioGroup;
	private RadioButton mFirstBtn;
	private RadioButton mSecondBtn;
	private RadioButton mThirdBtn;
	private ImageView mRedlineIV;

	private ViewPager mViewPager;
	private Fragment mFragmentArray[] = { new Fragment1(), new Fragment2(), new Fragment3() };

	private int SCREEN_WIDTH;

	private float mCurrentX;// 当前X坐标
	private float mPreX;// 前一操作的X坐标

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		DisplayMetrics metrics = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(metrics);
		SCREEN_WIDTH = metrics.widthPixels;
		setContentView(R.layout.activity_main);
		Log.i("TAG", "0000");

		mRadioGroup = (RadioGroup) findViewById(R.id.tab_rg_menu);
		mFirstBtn = (RadioButton) findViewById(R.id.tab_rb_1);
		mSecondBtn = (RadioButton) findViewById(R.id.tab_rb_2);
		mThirdBtn = (RadioButton) findViewById(R.id.tab_rb_3);
		mViewPager = (ViewPager) findViewById(R.id.pager);
		mRedlineIV = (ImageView) findViewById(R.id.tab_menu_red_line);

		LinearLayout.LayoutParams parmas = new LinearLayout.LayoutParams(
				SCREEN_WIDTH / 3, LinearLayout.LayoutParams.WRAP_CONTENT);
		mRedlineIV.setLayoutParams(parmas);

		mRadioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {

			@Override
			public void onCheckedChanged(RadioGroup group, int checkedId) {
				// TODO Auto-generated method stub
				switch (checkedId) {
				case R.id.tab_rb_1:
					mPreX = mCurrentX;
					mCurrentX = 0;
					mViewPager.setCurrentItem(0);
					break;
				case R.id.tab_rb_2:
					mPreX = mCurrentX;
					mCurrentX = SCREEN_WIDTH * 1 / 3;
					mViewPager.setCurrentItem(1);
					break;
				case R.id.tab_rb_3:
					mPreX = mCurrentX;
					mCurrentX = SCREEN_WIDTH * 2 / 3;
					mViewPager.setCurrentItem(2);
					break;

				default:
					break;
				}
				Animation translateAnimation = new TranslateAnimation(mPreX,
						mCurrentX, 0, 0);
				translateAnimation.setFillAfter(true);
				translateAnimation.setDuration(400);
				mRedlineIV.setAnimation(translateAnimation);
			}
		});
		mViewPager.setAdapter(new MenuAdapter(getSupportFragmentManager()));
		mViewPager.setOnPageChangeListener(new ViewPagerListener());

		mViewPager.setCurrentItem(0);
	}

	class MenuAdapter extends FragmentPagerAdapter {

		public MenuAdapter(FragmentManager fm) {
			super(fm);
			// TODO Auto-generated constructor stub
		}

		@Override
		public Fragment getItem(int pos) {
			return mFragmentArray[pos];
		}

		@Override
		public int getCount() {
			return mFragmentArray.length;
		}

	}

	class ViewPagerListener implements OnPageChangeListener {
		@Override
		public void onPageScrollStateChanged(int arg0) {

		}

		@Override
		public void onPageScrolled(int arg0, float arg1, int arg2) {

		}

		@Override
		public void onPageSelected(int index) {
			if (index == 0) {
				mFirstBtn.setChecked(true);
			} else if (index == 1) {
				mSecondBtn.setChecked(true);
			} else if (index == 2) {
				mThirdBtn.setChecked(true);
			}
		}
	}
}
DEMO2下载

三、取消viewpager预加载

核心思想就是利用fragment的setUserVisibleHint()和viewpager的setOffscreenPageLimit()这两个方法,首先写一个Fragment抽象基类即BaseFragment,重写它的setUserVisibleHint,详情可参见这里,关键代码如下:

	@Override
	public void setUserVisibleHint(boolean isVisibleToUser) {
		// TODO Auto-generated method stub
		super.setUserVisibleHint(isVisibleToUser);
		if (getUserVisibleHint()) {
			isVisible = true;
			onLoad();
		} else {
			isVisible = false;
			notLoad();
		}
	}

	protected abstract void onLoad();

	protected void notLoad() {
	}

然后所有fragment继承自BaseFragment,就必须实现onLoad方法,把耗时的网络操作都放在onLoad方法里,同时在有viewpager的FragmentActivity中设置如下

mViewPage.setOffscreenPageLimit(1);
经过简单测试,的确不会再预加载了,但是还有一个问题就是缓存的问题,如果添加了缓存,那每一页就都得有下拉刷新,或者要用广播通知UI的及时更新,待解决。


附其他实现tab菜单的方式:

1,静态fragment实现底部菜单tab;

2,Android仿QQ空间底部菜单

3,fragment + fragmentTabHost实现底部菜单;

4,android viewpager+fragment仿微信底部菜单滑动效果

让多个Fragment 切换时不重新实例化

Android重写FragmentTabHost来实现状态保存


你可能感兴趣的:(viewpager,FragmentTabHost,预加载)