前言
1.从上一片文章之后已经半年没有写文章了,那篇文章之后公司进入疯狂的加班,一直到放年假。年后回来之后换了一家创业公司之后,然后又进入疯狂的加班(≧﹏ ≦) …所以一直都没有写文章(其实这都是借口⊙﹏⊙)。现在公司没有那么忙了,也该把文章捡起来了,这毕竟是百利有一害的事(一害:费时间)。
2.这半年里除了对代码的热情更加高涨(虽然它总是虐我千百遍(≧﹏ ≦) ),还深深的中了爬山的毒,对于年轻的我来说,爬山让我明白了许多、懂得了许多,也锻炼了我的身体。对于程序员来说身体是非常重要的,大家在周末的时候可以爬爬山、跑跑步或者打打球之类的,运动运动,给大家献上几张端午假期去蒙古草原拍的几张照片:
正文
进入正题,这篇博客主要讲解viewpager+fragment实现微信滑动切换页面的功能,并且附带切换效果,功能其实并不难,只是需要把知识点关联起来
1.分析用到的知识点
(1). fragment的懒加载
(2). viewpager的滑动监听事件
(3). 控件alpha的设置、fragment切换的效果
2.功能实现
2.1.fragment的懒加载
当viewpager加载第一个fragment的时候会预加载第二个fragment,当加载第二个fragment的时候,会预加载第三个fragment,同时会进行数据加载,这种做法肯定不好,当第几个fragment显示的时候才应该加载数据,这里就用到了懒加载(参考:http://blog.csdn.net/maosidiaoxian/article/details/38300627):
public abstract class LazyFragment extends Fragment{
//用于标记视图是否初始化
protected boolean isVisible;
//在onCreate方法之前调用,用来判断Fragment的UI是否是可见的
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(getUserVisibleHint()) {
isVisible = true;
onVisible();
} else {
isVisible = false;
onInvisible();
}
}
/**
* 视图可见
* */
protected void onVisible(){
lazyLoad();
}
/**
* 自定义抽象加载数据方法
* */
protected abstract void lazyLoad();
/**
* 视图不可见
* */
protected void onInvisible(){}
}
自定义LazyFragment类只需要继承Fragment,实现setUserVisibleHint方法来判断fragment视图是否可见,定义三个方法,当视图可见的时候,isVisible = true,调用lazyLoad方法,其它fragment只需要继承该fragment即可:
public class OneFragment extends LazyFragment {
// 标志fragment是否初始化完成
private boolean isPrepared;
private View view;
@Override
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
if(view == null){
view = inflater.inflate(R.layout.fragment_one , container , false);
ButterKnife.inject(this, view);
KLog.e("TAG" , "oneFragment--onCreateView");
isPrepared = true;
lazyLoad();
}
return view;
}
@Override
protected void lazyLoad() {
if(!isPrepared || !isVisible) {
return;
}
KLog.e("TAG" , "oneFragment--lazyLoad");
}
}
由于setUserVisibleHint方法在onCreateView方法之前调用,所以定义字段isPrepared 来判断fragment是否初始化完成,防止报nullpointerexception,只有当视图可见并且fragment初始化完成执行lazyLoad方法,可以理解成就是onStart方法,再进行数据加载,这也就是懒加载。
注:
a.由于每次加载fragment都会重新执行onCreateView方法,所以我用view来判断fragment是否初始化过,初始化过就不在初始化,当然要是想每次都初始化就不必判断
b.每次fragment视图可见的时候lazyLoad方法都会被调用,若是只想加载一次可自定义字段判断是否加载过数据
2.2.viewpager的滑动监听事件
首先设置viewpager的适配器,FragmentPagerAdapter的子类只要实现 getItem(int) 和 getCount()方法:
public class FragmentAdapter extends FragmentPagerAdapter{
//fragment 集合
private List<Fragment> mFragmentList = new ArrayList<>();
public FragmentAdapter(FragmentManager fm , List<Fragment> list) {
super(fm);
this.mFragmentList = list;
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
}
其次设置viewpager监听事件:
//viewpager滑动监听
mMainViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
changAlpha(position, positionOffset);
}
@Override
public void onPageSelected(int position) {
changAlpha(position);
}
@Override
public void onPageScrollStateChanged(int state) {}
});
onPageScrolled方法的表示viewpager正在滑动:
position当向右滑动的时候表示当前页面的下标,向左滑动的时候表示左边页面的下标;
positionOffset是当前页面滑动比例,如果页面向右翻动,这个值不断变大,最后在趋近1的情况后突变为0。如果页面向左翻动,这个值不断变小,最后变为0;
positionOffsetPixels是当前页面滑动像素,变化情况和positionOffset一致。
参数的变化随方向的相反正好相反,下面我们写tab的颜色渐变就不需要判断方向了
根据该方法的positionOffset和position这两个参数就可以实现tab滑动颜色渐变的效果,先看一下布局:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="horizontal"
android:paddingTop="5dp">
<FrameLayout
android:id="@+id/m_main_fw_lay"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<Button
android:id="@+id/m_main_fw_btn_false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/fragment_tab_item_false"
android:drawableTop="@mipmap/bottom1_tab_false"
android:text="服务"/>
<Button
android:id="@+id/m_main_fw_btn_true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/fragment_tab_item_true"
android:drawableTop="@mipmap/bottom1_tab_true"
android:text="服务"/>
</FrameLayout>
<FrameLayout
android:id="@+id/m_main_sj_lay"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<Button
android:id="@+id/m_main_sj_btn_false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/fragment_tab_item_false"
android:drawableTop="@mipmap/bottom2_tab_false"
android:text="社交"/>
<Button
android:id="@+id/m_main_sj_btn_true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/fragment_tab_item_true"
android:drawableTop="@mipmap/bottom2_tab_true"
android:text="社交"/>
</FrameLayout>
<FrameLayout
android:id="@+id/m_main_gz_lay"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<Button
android:id="@+id/m_main_gz_btn_false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/fragment_tab_item_false"
android:drawableTop="@mipmap/bottom3_tab_false"
android:text="工作"/>
<Button
android:id="@+id/m_main_gz_btn_true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/fragment_tab_item_true"
android:drawableTop="@mipmap/bottom3_tab_true"
android:text="工作"/>
</FrameLayout>
<FrameLayout
android:id="@+id/m_main_lxr_lay"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<Button
android:id="@+id/m_main_lxr_btn_false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/fragment_tab_item_false"
android:drawableTop="@mipmap/bottom4_tab_false"
android:text="联系人"/>
<Button
android:id="@+id/m_main_lxr_btn_true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/fragment_tab_item_true"
android:drawableTop="@mipmap/bottom4_tab_true"
android:text="联系人"/>
</FrameLayout>
<FrameLayout
android:id="@+id/m_main_wd_lay"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<Button
android:id="@+id/m_main_wd_btn_false"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/fragment_tab_item_false"
android:drawableTop="@mipmap/bottom5_tab_false"
android:text="我的"/>
<Button
android:id="@+id/m_main_wd_btn_true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/fragment_tab_item_true"
android:drawableTop="@mipmap/bottom5_tab_true"
android:text="我的"/>
</FrameLayout>
</LinearLayout>
每个tab我是使用的2个button,一个默认颜色,一个选中颜色,我们只需要根据滑动比例来改变选中颜色button的alpha即可:
/**
* 根据滑动设置透明度
*/
private void changAlpha(int pos, float posOffset) {
int nextIndex = pos + 1;
if(posOffset > 0){
//设置tab的颜色渐变效果
mButtonList.get(nextIndex).setAlpha(posOffset);
mButtonList.get(pos).setAlpha(1 - posOffset);
//设置fragment的颜色渐变效果
mFragmentList.get(nextIndex).getView().setAlpha(posOffset);
mFragmentList.get(pos).getView().setAlpha(1 - posOffset);
//设置fragment滑动视图由大到小,由小到大的效果
mFragmentList.get(nextIndex).getView().setScaleX(0.5F + posOffset/2);
mFragmentList.get(nextIndex).getView().setScaleY(0.5F + posOffset/2);
mFragmentList.get(pos).getView().setScaleX(1-(posOffset/2));
mFragmentList.get(pos).getView().setScaleY(1-(posOffset/2));
}
}
当posOffset > 0 ,说明viewpager在滑动;前面说了onPageScrolled方法参数随滑动方向的变化是相反的所以这里只需要写一个方法便可实现两个方向滑动颜色渐变的效果,道理就是改变两个button的Alpha值就可实现渐变效果,是不是挺简单;
关于fragemnt的颜色渐变和伸缩效果,在上面也已经贴出了代码,就不详细解释了,相信大家都能看懂;
onPageSelected方法表示滑动抬起手指那一刻所执行的方法,参数position代表的是当前页面的下标,所以当滑动结束之后,我们把当前页面的tab、fragment.getView()的Alpha设置为1.0f,其它tab设置为0.0f ; fragment的x、y轴设置为1.0f(需要判断fragment.getView()是否为null,防止报nullpointerexception),其他的0.0f即可:
/**
* 一开始运行、滑动和点击tab结束后设置tab的透明度,fragment的透明度和大小
*/
private void changAlpha(int postion) {
for (int i = 0; i < mButtonList.size(); i++) {
if (i == postion) {
mButtonList.get(i).setAlpha(1.0f);
if(null != mFragmentList.get(i).getView()){
mFragmentList.get(i).getView().setAlpha(1.0f);
mFragmentList.get(i).getView().setScaleX(1.0f);
mFragmentList.get(i).getView().setScaleY(1.0f);
}
} else {
mButtonList.get(i).setAlpha(0.0f);
if(null != mFragmentList.get(i).getView()){
mFragmentList.get(i).getView().setAlpha(0.0f);
mFragmentList.get(i).getView().setScaleX(0.0f);
mFragmentList.get(i).getView().setScaleY(0.0f);
}
}
}
}
把所有fragemnt放入集合中遍历判断即可;
主要代码就这些,有不解的地方请看Demo