关闭

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

标签: viewpagerfragmentTabhost预加载
6739人阅读 评论(4) 收藏 举报
分类:

有空还得重新整理。。。

一、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本身有预加载的机制,所以最后在实际项目中还是去掉了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缓存数据,就像fragment的hide和show一样,当使用FragmentTabhost + RadioButton实现的tab菜单时,只有重写FragmentTabhost才能达到想要的效果,网上已经有人写过了,直接拿来用就好,让多个Fragment 切换时不重新实例化,详见Android重写FragmentTabHost来实现状态保存


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

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

2,Android仿QQ空间底部菜单

3,fragment + fragmentTabHost实现底部菜单

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





3
0
查看评论

ViewPager 取消预加载

ViewPager在设计的时候有一个预加载的机制,也就是如果你处于当前这个page界面时,会预先加载下一个page。但是有的时候设计到网络请求,就需要取消掉这个预加载。
  • JonsTank2013
  • JonsTank2013
  • 2015-12-08 22:26
  • 4528

fragment 懒加载 viewpager 取消预加载

ViewPager在设计的时候有一个预加载的机制,也就是如果你处于当前这个page界面时,会预先加载下一个page。但是有的时候设计到网络请求,就需要取消掉这个预加载。 setOffscreenPageLimit()这一个方法是设置预加载的个数,默认为1,但是当你设置为0的时候也会强行将它设置为...
  • u012971339
  • u012971339
  • 2016-02-29 13:37
  • 2056

Android中ViewPager+Fragment取消(禁止)预加载延迟加载(懒加载)问题解决方案

在Android中我们经常会用到ViewPager+Fragment组合。然而,有一个很让人头疼的问题就是,我们去加载数据的时候由于ViewPager的内部机制所限制,所以它会默认至少预加载一个。这让人很郁闷,所以,我就想到要封装一个Fragment来解决这个问题。 这里还解决一个问题就是在[And...
  • u010785585
  • u010785585
  • 2016-11-17 19:59
  • 19044

ViewPager+Fragment取消预加载功能

在大多数项目中,在用到viewpager的时候一般也会配合使用fragment,viewpager中的预加载功能也是非常的好用,在大多数情况下,预加载提高了用户体验,在切换的时候会非常的流畅,but!任何事都有but~ 当每个fragment都需要去联网加载网络数据或者做一些耗时的操作,而且有其他...
  • LuckChouDog
  • LuckChouDog
  • 2016-04-21 10:47
  • 941

ViewPager(改好的源码,防止预加载)

package com.srm.base;/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License&...
  • dingxiong0802
  • dingxiong0802
  • 2017-02-10 16:19
  • 253

关于禁止ViewPager预加载问题,完美解决!

我最近上班又遇到一个小难题了,就是如题所述:ViewPager预加载的问题。相信用过ViewPager的人大抵都有遇到过这种情况,网上的解决办法也就那么几个,终于在我自己不断试验之下,完美解决了(禁止了)ViewPager的预加载。 好了,首先来说明一下,什么是ViewPager的预加载:View...
  • qq_21898059
  • qq_21898059
  • 2016-05-19 15:48
  • 25256

Fragment+Viewpager 取消懒加载/预加载

前言几乎每个APP都会使用Fragment+ViewPager来实现多个界面的切换。相信用过Fragment+ViewPager来实现这种需求的时候,选中当前的Fragment的时候,系统会默认加载该Fragment左右两边的Fragment。也就是我们常说的懒加载或者预加载。预加载机制懒加载的机制...
  • Alpha58
  • Alpha58
  • 2017-06-13 23:20
  • 877

ViewPager+Fragment取消预加载(延迟加载)

在项目中,都或多或少地使用的Tab布局,所以大都会用到ViewPager+Fragment,但是Fragment有个不好或者太好的地方。例如你在ViewPager中添加了三个Fragment,当加载ViewPager中第一个Fragment时,它会默认帮你预先加载了第二个Fragment,当你加载第...
  • hyq912
  • hyq912
  • 2015-01-12 16:45
  • 13425

android ViewPager预加载问题

使用ViewPager时候,PagerAdapter一般都会提前加载 前一个View + 当前View + 下一个View,达到滑动平滑的效果,这么做当然是非常好的, 但是用户只停留在第一个View上的时候,下一个View预加载了,浪费了资源怎么办? 相信各位都曾经遇到过这样的问题,viewPa...
  • qq_33445600
  • qq_33445600
  • 2017-06-16 13:56
  • 361

ViewPager取消预加载并且缓存页面

今天遇到一个问题,ViewPager+2个fragment的时候,这样就会同时访问2个页面的数据,这样虽然有时很好,但是用户只需看一个Fragment时,我们就做了一些多余工作加载了第二个Fragment。在这只需要取消Fragment的预加载即可,只有当用户切换到某个Fragment才加载..,在...
  • yewei02538
  • yewei02538
  • 2015-12-16 15:27
  • 2433
    个人资料
    • 访问:177683次
    • 积分:2802
    • 等级:
    • 排名:第15109名
    • 原创:58篇
    • 转载:5篇
    • 译文:0篇
    • 评论:52条
    联系我吧
    我的App
    博客专栏
    文章分类