拉项目--球球世道的总结-解决了viewpager+fragment+tablayout 两个bug

Posted 童政通

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了拉项目--球球世道的总结-解决了viewpager+fragment+tablayout 两个bug相关的知识,希望对你有一定的参考价值。

一:立项

1,创新新的项目

2,引入module   (这些都是我自己项目整的)

    -----fragmentation

    -----fragmentation_swipeback

    -----uibase

    注意:所有的module的gradle文件引用的三方库文件必须和---主---项目的版本一只(重要哦)

    注意:除了四个主界面的额fragmentation extends BaseLazyMainFragment 

    其他子fragment的 extends BaseBackFragment

二:遇到的问题

TabLayout+ViewPager+Fragment 实现效果

问题一: 

1) ViewPager预加载问题,所有我们需要懒加载解决

      第一步:封装一个BaseFragment

      第二步:子Fragment集成BaseFragment

      第三步:子Frament中使用

package com.yun.yunball.base;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.View;

/**
 * Created by Lovelin on 2019/3/15
 * <p>
 * Describe:  解决预加载问题----懒加载
 */
public abstract class BaseFragment extends Fragment 

    private static final String TAG = BaseFragment.class.getSimpleName();

    private boolean isFragmentVisible;
    private boolean isReuseView;
    private boolean isFirstVisible;
    private View rootView;


    //setUserVisibleHint()在Fragment创建时会先被调用一次,传入isVisibleToUser = false
    //如果当前Fragment可见,那么setUserVisibleHint()会再次被调用一次,传入isVisibleToUser = true
    //如果Fragment从可见-&gt;不可见,那么setUserVisibleHint()也会被调用,传入isVisibleToUser = false
    //总结:setUserVisibleHint()除了Fragment的可见状态发生变化时会被回调外,在new Fragment()时也会被回调
    //如果我们需要在 Fragment 可见与不可见时干点事,用这个的话就会有多余的回调了,那么就需要重新封装一个
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) 
        super.setUserVisibleHint(isVisibleToUser);
        //setUserVisibleHint()有可能在fragment的生命周期外被调用
        if (rootView == null) 
            return;
        
        if (isFirstVisible && isVisibleToUser) 
            onFragmentFirstVisible();
            isFirstVisible = false;
        
        if (isVisibleToUser) 
            onFragmentVisibleChange(true);
            isFragmentVisible = true;
            return;
        
        if (isFragmentVisible) 
            isFragmentVisible = false;
            onFragmentVisibleChange(false);
        
    

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        initVariable();
    

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) 
        //如果setUserVisibleHint()在rootView创建前调用时,那么
        //就等到rootView创建完后才回调onFragmentVisibleChange(true)
        //保证onFragmentVisibleChange()的回调发生在rootView创建完成之后,以便支持ui操作
        if (rootView == null) 
            rootView = view;
            if (getUserVisibleHint()) 
                if (isFirstVisible) 
                    onFragmentFirstVisible();
                    isFirstVisible = false;
                
                onFragmentVisibleChange(true);
                isFragmentVisible = true;
            
        
        super.onViewCreated(isReuseView ? rootView : view, savedInstanceState);
    

    @Override
    public void onDestroyView() 
        super.onDestroyView();
    

    @Override
    public void onDestroy() 
        super.onDestroy();
        initVariable();
    

    private void initVariable() 
        isFirstVisible = true;
        isFragmentVisible = false;
        rootView = null;
        isReuseView = true;
    

    /**
     * 设置是否使用 view 的复用,默认开启
     * view 的复用是指,ViewPager 在销毁和重建 Fragment 时会不断调用 onCreateView() -&gt; onDestroyView()
     * 之间的生命函数,这样可能会出现重复创建 view 的情况,导致界面上显示多个相同的 Fragment
     * view 的复用其实就是指保存第一次创建的 view,后面再 onCreateView() 时直接返回第一次创建的 view
     *
     * @param isReuse
     */
    protected void reuseView(boolean isReuse) 
        isReuseView = isReuse;
    

    /**
     * 去除setUserVisibleHint()多余的回调场景,保证只有当fragment可见状态发生变化时才回调
     * 回调时机在view创建完后,所以支持ui操作,解决在setUserVisibleHint()里进行ui操作有可能报null异常的问题
     *
     * 可在该回调方法里进行一些ui显示与隐藏,比如加载框的显示和隐藏
     *
     * @param isVisible true  不可见 -&gt; 可见
     *                  false 可见  -&gt; 不可见
     */
    protected void onFragmentVisibleChange(boolean isVisible) 

    

    /**
     * 在fragment首次可见时回调,可在这里进行加载数据,保证只在第一次打开Fragment时才会加载数据,
     * 这样就可以防止每次进入都重复加载数据
     * 该方法会在 onFragmentVisibleChange() 之前调用,所以第一次打开时,可以用一个全局变量表示数据下载状态,
     * 然后在该方法内将状态设置为下载状态,接着去执行下载的任务
     * 最后在 onFragmentVisibleChange() 里根据数据下载状态来控制下载进度ui控件的显示与隐藏
     */
    protected void onFragmentFirstVisible() 

    

    protected boolean isFragmentVisible() 
        return isFragmentVisible;
    
package com.yun.yunball.base;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.View;

/**
 * Created by Lovelin on 2019/3/15
 * <p>
 * Describe:  解决预加载问题----懒加载
 */
public abstract class BaseFragment extends Fragment 

    private static final String TAG = BaseFragment.class.getSimpleName();

    private boolean isFragmentVisible;
    private boolean isReuseView;
    private boolean isFirstVisible;
    private View rootView;


    //setUserVisibleHint()在Fragment创建时会先被调用一次,传入isVisibleToUser = false
    //如果当前Fragment可见,那么setUserVisibleHint()会再次被调用一次,传入isVisibleToUser = true
    //如果Fragment从可见-&gt;不可见,那么setUserVisibleHint()也会被调用,传入isVisibleToUser = false
    //总结:setUserVisibleHint()除了Fragment的可见状态发生变化时会被回调外,在new Fragment()时也会被回调
    //如果我们需要在 Fragment 可见与不可见时干点事,用这个的话就会有多余的回调了,那么就需要重新封装一个
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) 
        super.setUserVisibleHint(isVisibleToUser);
        //setUserVisibleHint()有可能在fragment的生命周期外被调用
        if (rootView == null) 
            return;
        
        if (isFirstVisible && isVisibleToUser) 
            onFragmentFirstVisible();
            isFirstVisible = false;
        
        if (isVisibleToUser) 
            onFragmentVisibleChange(true);
            isFragmentVisible = true;
            return;
        
        if (isFragmentVisible) 
            isFragmentVisible = false;
            onFragmentVisibleChange(false);
        
    

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        initVariable();
    

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) 
        //如果setUserVisibleHint()在rootView创建前调用时,那么
        //就等到rootView创建完后才回调onFragmentVisibleChange(true)
        //保证onFragmentVisibleChange()的回调发生在rootView创建完成之后,以便支持ui操作
        if (rootView == null) 
            rootView = view;
            if (getUserVisibleHint()) 
                if (isFirstVisible) 
                    onFragmentFirstVisible();
                    isFirstVisible = false;
                
                onFragmentVisibleChange(true);
                isFragmentVisible = true;
            
        
        super.onViewCreated(isReuseView ? rootView : view, savedInstanceState);
    

    @Override
    public void onDestroyView() 
        super.onDestroyView();
    

    @Override
    public void onDestroy() 
        super.onDestroy();
        initVariable();
    

    private void initVariable() 
        isFirstVisible = true;
        isFragmentVisible = false;
        rootView = null;
        isReuseView = true;
    

    /**
     * 设置是否使用 view 的复用,默认开启
     * view 的复用是指,ViewPager 在销毁和重建 Fragment 时会不断调用 onCreateView() -&gt; onDestroyView()
     * 之间的生命函数,这样可能会出现重复创建 view 的情况,导致界面上显示多个相同的 Fragment
     * view 的复用其实就是指保存第一次创建的 view,后面再 onCreateView() 时直接返回第一次创建的 view
     *
     * @param isReuse
     */
    protected void reuseView(boolean isReuse) 
        isReuseView = isReuse;
    

    /**
     * 去除setUserVisibleHint()多余的回调场景,保证只有当fragment可见状态发生变化时才回调
     * 回调时机在view创建完后,所以支持ui操作,解决在setUserVisibleHint()里进行ui操作有可能报null异常的问题
     *
     * 可在该回调方法里进行一些ui显示与隐藏,比如加载框的显示和隐藏
     *
     * @param isVisible true  不可见 -&gt; 可见
     *                  false 可见  -&gt; 不可见
     */
    protected void onFragmentVisibleChange(boolean isVisible) 

    

    /**
     * 在fragment首次可见时回调,可在这里进行加载数据,保证只在第一次打开Fragment时才会加载数据,
     * 这样就可以防止每次进入都重复加载数据
     * 该方法会在 onFragmentVisibleChange() 之前调用,所以第一次打开时,可以用一个全局变量表示数据下载状态,
     * 然后在该方法内将状态设置为下载状态,接着去执行下载的任务
     * 最后在 onFragmentVisibleChange() 里根据数据下载状态来控制下载进度ui控件的显示与隐藏
     */
    protected void onFragmentFirstVisible() 

    

    protected boolean isFragmentVisible() 
        return isFragmentVisible;
    
package com.yun.yunball.base;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.View;

/**
 * Created by Lovelin on 2019/3/15
 * <p>
 * Describe:  解决预加载问题----懒加载
 */
public abstract class BaseFragment extends Fragment 

    private static final String TAG = BaseFragment.class.getSimpleName();

    private boolean isFragmentVisible;
    private boolean isReuseView;
    private boolean isFirstVisible;
    private View rootView;


    //setUserVisibleHint()在Fragment创建时会先被调用一次,传入isVisibleToUser = false
    //如果当前Fragment可见,那么setUserVisibleHint()会再次被调用一次,传入isVisibleToUser = true
    //如果Fragment从可见-&gt;不可见,那么setUserVisibleHint()也会被调用,传入isVisibleToUser = false
    //总结:setUserVisibleHint()除了Fragment的可见状态发生变化时会被回调外,在new Fragment()时也会被回调
    //如果我们需要在 Fragment 可见与不可见时干点事,用这个的话就会有多余的回调了,那么就需要重新封装一个
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) 
        super.setUserVisibleHint(isVisibleToUser);
        //setUserVisibleHint()有可能在fragment的生命周期外被调用
        if (rootView == null) 
            return;
        
        if (isFirstVisible && isVisibleToUser) 
            onFragmentFirstVisible();
            isFirstVisible = false;
        
        if (isVisibleToUser) 
            onFragmentVisibleChange(true);
            isFragmentVisible = true;
            return;
        
        if (isFragmentVisible) 
            isFragmentVisible = false;
            onFragmentVisibleChange(false);
        
    

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        initVariable();
    

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) 
        //如果setUserVisibleHint()在rootView创建前调用时,那么
        //就等到rootView创建完后才回调onFragmentVisibleChange(true)
        //保证onFragmentVisibleChange()的回调发生在rootView创建完成之后,以便支持ui操作
        if (rootView == null) 
            rootView = view;
            if (getUserVisibleHint()) 
                if (isFirstVisible) 
                    onFragmentFirstVisible();
                    isFirstVisible = false;
                
                onFragmentVisibleChange(true);
                isFragmentVisible = true;
            
        
        super.onViewCreated(isReuseView ? rootView : view, savedInstanceState);
    

    @Override
    public void onDestroyView() 
        super.onDestroyView();
    

    @Override
    public void onDestroy() 
        super.onDestroy();
        initVariable();
    

    private void initVariable() 
        isFirstVisible = true;
        isFragmentVisible = false;
        rootView = null;
        isReuseView = true;
    

    /**
     * 设置是否使用 view 的复用,默认开启
     * view 的复用是指,ViewPager 在销毁和重建 Fragment 时会不断调用 onCreateView() -&gt; onDestroyView()
     * 之间的生命函数,这样可能会出现重复创建 view 的情况,导致界面上显示多个相同的 Fragment
     * view 的复用其实就是指保存第一次创建的 view,后面再 onCreateView() 时直接返回第一次创建的 view
     *
     * @param isReuse
     */
    protected void reuseView(boolean isReuse) 
        isReuseView = isReuse;
    

    /**
     * 去除setUserVisibleHint()多余的回调场景,保证只有当fragment可见状态发生变化时才回调
     * 回调时机在view创建完后,所以支持ui操作,解决在setUserVisibleHint()里进行ui操作有可能报null异常的问题
     *
     * 可在该回调方法里进行一些ui显示与隐藏,比如加载框的显示和隐藏
     *
     * @param isVisible true  不可见 -&gt; 可见
     *                  false 可见  -&gt; 不可见
     */
    protected void onFragmentVisibleChange(boolean isVisible) 

    

    /**
     * 在fragment首次可见时回调,可在这里进行加载数据,保证只在第一次打开Fragment时才会加载数据,
     * 这样就可以防止每次进入都重复加载数据
     * 该方法会在 onFragmentVisibleChange() 之前调用,所以第一次打开时,可以用一个全局变量表示数据下载状态,
     * 然后在该方法内将状态设置为下载状态,接着去执行下载的任务
     * 最后在 onFragmentVisibleChange() 里根据数据下载状态来控制下载进度ui控件的显示与隐藏
     */
    protected void onFragmentFirstVisible() 

    

    protected boolean isFragmentVisible() 
        return isFragmentVisible;
    

子类使用

/ 取消预加载的回调
    @Override
    protected void onFragmentVisibleChange(boolean isVisible) 
        Log.e("TEXT", "01--足球--isVisible====" + isVisible);
        if (isVisible) 
            responseListener();
        
    
    @Override
    protected void onFragmentFirstVisible() 
        Log.e("TEXT", "01--足球--===onFragmentFirstVisible=");
        responseListener();
    

问题二:TabLayout 间隔tab点击 数据不刷新问题

 使用EventBus3解决即可

       第一步:在tablayout的addOnTabSelectedListener监听中的

                  onTabSelected中(事先注册FootBallTabEvent)

EventBus.getDefault().post(new FootBallTabEvent(tab.getPosition()));   //数据更新

      第二步:在需要刷新的---子Fragment中的onCreate和onDestroy中注册和销毁再注册监听---搞定

@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(FootBallTabEvent event) 
    Log.e("TEXT", "01--篮球--===onMessageEvent=======onMessageEvent==");

    if (0== event.getType()) 
        Log.e("TEXT", "01--篮球--===onMessageEvent=======走进来了==");
        responseListener();
    

问题三:如图---足球---篮球--下分别是两组tablayout+viewpager+fragment,嵌套的时候会出现点击--篮球--或者足球,tab数据不刷新问题,还有不在第一个子fragment的时候点击篮球足球数据也不刷新问题

解决方法:

    我们在足球和篮球的点击事件上,每次去new Adapter,然后重新设置或者请求数据,代码如下

 

private void showBasketballViewPager() 
    //每次new出来  解决数据不显示问题
    mBasketBallAdapter = new BasketBallAdapter(getChildFragmentManager(), tabBasketball);
    mFootTabLayout.setVisibility(View.GONE);
    mFootBallViewPager.setVisibility(View.GONE);
    mBasketTabLayout.setVisibility(View.VISIBLE);
    mBasketBallViewPager.setVisibility(View.VISIBLE);
    mBasketBallViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mBasketTabLayout));
    mBasketBallViewPager.setAdapter(mBasketBallAdapter);
    mBasketTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() 
        @Override
        public void onTabSelected(TabLayout.Tab tab) 
            mBasketBallViewPager.setCurrentItem(tab.getPosition());
            EventBus.getDefault().post(new FootBallTabEvent(tab.getPosition()));   //数据更新

            Log.e("TEXT", "篮球===tab===Position=====" + tab.getPosition());

        

        @Override
        public void onTabUnselected(TabLayout.Tab tab) 

        

        @Override
        public void onTabReselected(TabLayout.Tab tab) 

        
    );

 

 

 

 

以上是关于拉项目--球球世道的总结-解决了viewpager+fragment+tablayout 两个bug的主要内容,如果未能解决你的问题,请参考以下文章

websocket实现简化版球球大作战

C语言球球大作战,我用别人内卷的时间做了一个外卷的项目

C语言项目实战:《球球大作战》零基础项目 + 源码示例

跪球电脑高手帮忙了(在线等!!)

Android项目Tab类型主界面大总结 Fragment+TabPageIndicator+ViewPager

自定义ScrollView 实现上拉下拉的回弹效果--并且子控件中有Viewpager的情况