美文网首页Android优化Android
Fragment切换重叠的问题

Fragment切换重叠的问题

作者: Alien的小窝 | 来源:发表于2016-02-18 17:44 被阅读746次

    关于切屏时重叠问题,办法的核心是给每个fragment都设置一个tag,方法是transaction.add(R.id.content, messageFragment,"message");
    这样在竖屏切横屏的时候用findFragmentByTag("message")去拿fragment,这样fragment就不会都为空了。

     if(meFragment == null){
       meFragment = new MeFragment();
       transaction.add(R.id.framelayout_content, meFragment);
    }
    

    这种写法在重建的时候有问题
    meFragment = getFragmentManager().findFragmentByTag(tag);
    然后如果null才meFragment = new MeFragment();

    解决方案

    完整Demo

    package com.example.fragmentdemo;
    
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.view.Window;
    import android.view.View.OnClickListener;
    import android.widget.ImageView;
    import android.widget.TextView;
    import android.app.Activity;
    import android.app.FragmentManager;
    import android.app.FragmentTransaction;
    import android.graphics.Color;
    
    /**
     * 项目的主Activity,所有的Fragment都嵌入在这里。
     * 
     * @author guolin
     */
    public class MainActivity extends Activity implements OnClickListener {
    
        /**
         * 用于展示消息的Fragment
         */
        private MessageFragment messageFragment;
    
        /**
         * 用于展示联系人的Fragment
         */
        private ContactsFragment contactsFragment;
    
        /**
         * 用于展示动态的Fragment
         */
        private NewsFragment newsFragment;
    
        /**
         * 用于展示设置的Fragment
         */
        private SettingFragment settingFragment;
    
        /**
         * 消息界面布局
         */
        private View messageLayout;
    
        /**
         * 联系人界面布局
         */
        private View contactsLayout;
    
        /**
         * 动态界面布局
         */
        private View newsLayout;
    
        /**
         * 设置界面布局
         */
        private View settingLayout;
    
        /**
         * 在Tab布局上显示消息图标的控件
         */
        private ImageView messageImage;
    
        /**
         * 在Tab布局上显示联系人图标的控件
         */
        private ImageView contactsImage;
    
        /**
         * 在Tab布局上显示动态图标的控件
         */
        private ImageView newsImage;
    
        /**
         * 在Tab布局上显示设置图标的控件
         */
        private ImageView settingImage;
    
        /**
         * 在Tab布局上显示消息标题的控件
         */
        private TextView messageText;
    
        /**
         * 在Tab布局上显示联系人标题的控件
         */
        private TextView contactsText;
    
        /**
         * 在Tab布局上显示动态标题的控件
         */
        private TextView newsText;
    
        /**
         * 在Tab布局上显示设置标题的控件
         */
        private TextView settingText;
    
        /**
         * 用于对Fragment进行管理
         */
        private FragmentManager fragmentManager;
        
        /**
         * 保存当前显示的是第几页
         */
        private int currentPage = 0;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Log.i("neo", "onCreate");
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.activity_main);
            if(null != savedInstanceState){
                currentPage = savedInstanceState.getInt("neo");
            }
            // 初始化布局元素
            initViews();
            fragmentManager = getFragmentManager();
            //在FragmentManager里面根据Tag去找相应的fragment. 用户屏幕发生旋转,重新调用onCreate方法。否则会发生重叠
            messageFragment = (MessageFragment) fragmentManager.findFragmentByTag("message");
            contactsFragment = (ContactsFragment) fragmentManager.findFragmentByTag("contacts");
            newsFragment = (NewsFragment) fragmentManager.findFragmentByTag("news");
            settingFragment = (SettingFragment) fragmentManager.findFragmentByTag("setting");
            // 第一次启动时选中第0个tab
            setTabSelection(currentPage);
        }
    
        /**
         * 在这里获取到每个需要用到的控件的实例,并给它们设置好必要的点击事件。
         */
        private void initViews() {
            messageLayout = findViewById(R.id.message_layout);
            contactsLayout = findViewById(R.id.contacts_layout);
            newsLayout = findViewById(R.id.news_layout);
            settingLayout = findViewById(R.id.setting_layout);
            messageImage = (ImageView) findViewById(R.id.message_image);
            contactsImage = (ImageView) findViewById(R.id.contacts_image);
            newsImage = (ImageView) findViewById(R.id.news_image);
            settingImage = (ImageView) findViewById(R.id.setting_image);
            messageText = (TextView) findViewById(R.id.message_text);
            contactsText = (TextView) findViewById(R.id.contacts_text);
            newsText = (TextView) findViewById(R.id.news_text);
            settingText = (TextView) findViewById(R.id.setting_text);
            messageLayout.setOnClickListener(this);
            contactsLayout.setOnClickListener(this);
            newsLayout.setOnClickListener(this);
            settingLayout.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
            case R.id.message_layout:
                // 当点击了消息tab时,选中第1个tab
                setTabSelection(0);
                currentPage = 0;
                break;
            case R.id.contacts_layout:
                // 当点击了联系人tab时,选中第2个tab
                setTabSelection(1);
                currentPage = 1;
                break;
            case R.id.news_layout:
                // 当点击了动态tab时,选中第3个tab
                setTabSelection(2);
                currentPage = 2;
                break;
            case R.id.setting_layout:
                // 当点击了设置tab时,选中第4个tab
                setTabSelection(3);
                currentPage = 3;
                break;
            default:
                break;
            }
        }
    
        /**
         * 根据传入的index参数来设置选中的tab页。
         * 
         * @param index
         *            每个tab页对应的下标。0表示消息,1表示联系人,2表示动态,3表示设置。
         */
        private void setTabSelection(int index) {
            // 每次选中之前先清楚掉上次的选中状态
            clearSelection();
            // 开启一个Fragment事务
            FragmentTransaction transaction = fragmentManager.beginTransaction();
            // 先隐藏掉所有的Fragment,以防止有多个Fragment显示在界面上的情况
            hideFragments(transaction);
            //Log.i("neo", "消息为空? "+messageFragment+"--联系人为空? "+contactsFragment+"-- 动态为空? "+newsFragment+"-- 设置为空? "+settingFragment);
            switch (index) {
            case 0:
                // 当点击了消息tab时,改变控件的图片和文字颜色
                messageImage.setImageResource(R.drawable.message_selected);
                messageText.setTextColor(Color.WHITE);
                //messageFragment = (MessageFragment) fragmentManager.findFragmentByTag("message");
                if (messageFragment == null) {
                    // 如果MessageFragment为空,则创建一个并添加到界面上
                    messageFragment = new MessageFragment();
                    transaction.add(R.id.content, messageFragment,"message");
                } else {
                    // 如果MessageFragment不为空,则直接将它显示出来
                    transaction.show(messageFragment);
                }
            
                break;
            case 1:
                // 当点击了联系人tab时,改变控件的图片和文字颜色
                contactsImage.setImageResource(R.drawable.contacts_selected);
                contactsText.setTextColor(Color.WHITE);
            //  contactsFragment = (ContactsFragment) fragmentManager.findFragmentByTag("contacts");
                if (contactsFragment == null) {
                    // 如果ContactsFragment为空,则创建一个并添加到界面上
                    contactsFragment = new ContactsFragment();
                    transaction.add(R.id.content, contactsFragment,"contacts");
                } else {
                    // 如果ContactsFragment不为空,则直接将它显示出来
                    transaction.show(contactsFragment);
                }
                break;
            case 2:
                // 当点击了动态tab时,改变控件的图片和文字颜色
                newsImage.setImageResource(R.drawable.news_selected);
                newsText.setTextColor(Color.WHITE);
            //  newsFragment = (NewsFragment) fragmentManager.findFragmentByTag("news");
                if (newsFragment == null) {
                    // 如果NewsFragment为空,则创建一个并添加到界面上
                    newsFragment = new NewsFragment();
                    transaction.add(R.id.content, newsFragment,"news");
                } else {
                    // 如果NewsFragment不为空,则直接将它显示出来
                    transaction.show(newsFragment);
                }
                break;
            case 3:
            default:
                // 当点击了设置tab时,改变控件的图片和文字颜色
                settingImage.setImageResource(R.drawable.setting_selected);
                settingText.setTextColor(Color.WHITE);
            //  settingFragment = (SettingFragment) fragmentManager.findFragmentByTag("setting");
                if (settingFragment == null) {
                    // 如果SettingFragment为空,则创建一个并添加到界面上
                    settingFragment = new SettingFragment();
                    transaction.add(R.id.content, settingFragment,"setting");
                } else {
                    // 如果SettingFragment不为空,则直接将它显示出来
                    transaction.show(settingFragment);
                }
                break;
            }
            transaction.commit();
        }
    
        /**
         * 清除掉所有的选中状态。
         */
        private void clearSelection() {
            messageImage.setImageResource(R.drawable.message_unselected);
            messageText.setTextColor(Color.parseColor("#82858b"));
            contactsImage.setImageResource(R.drawable.contacts_unselected);
            contactsText.setTextColor(Color.parseColor("#82858b"));
            newsImage.setImageResource(R.drawable.news_unselected);
            newsText.setTextColor(Color.parseColor("#82858b"));
            settingImage.setImageResource(R.drawable.setting_unselected);
            settingText.setTextColor(Color.parseColor("#82858b"));
        }
    
        /**
         * 将所有的Fragment都置为隐藏状态。
         * 
         * @param transaction
         *            用于对Fragment执行操作的事务
         */
        private void hideFragments(FragmentTransaction transaction) {
            
            if (messageFragment != null) {
                transaction.hide(messageFragment);
            }
            if (contactsFragment != null) {
                transaction.hide(contactsFragment);
            }
            if (newsFragment != null) {
                transaction.hide(newsFragment);
            }
            if (settingFragment != null) {
                transaction.hide(settingFragment);
            }
        }
        
        @Override
        protected void onSaveInstanceState(Bundle outState) {
            outState.putInt("neo",currentPage);
            super.onSaveInstanceState(outState);
            Log.i("neo", "onSaveInstanceState");
        }
    }
    
    

    其他项目源码样板

    AndroidFire-master

    public class MainActivity extends BaseActivity {
        @Bind(R.id.tab_layout)
        CommonTabLayout tabLayout;
    
        private String[] mTitles = {"首页", "美女","视频","关注"};
        private int[] mIconUnselectIds = {
                R.mipmap.ic_home_normal,R.mipmap.ic_girl_normal,R.mipmap.ic_video_normal,R.mipmap.ic_care_normal};
        private int[] mIconSelectIds = {
                R.mipmap.ic_home_selected,R.mipmap.ic_girl_selected, R.mipmap.ic_video_selected,R.mipmap.ic_care_selected};
        private ArrayList<CustomTabEntity> mTabEntities = new ArrayList<>();
    
        private NewsMainFragment newsMainFragment;
        private PhotosMainFragment photosMainFragment;
        private VideoMainFragment videoMainFragment;
        private CareMainFragment careMainFragment;
        private static int tabLayoutHeight;
    
        /**
         * 入口
         * @param activity
         */
        public static void startAction(Activity activity){
            Intent intent = new Intent(activity, MainActivity.class);
            activity.startActivity(intent);
            activity.overridePendingTransition(R.anim.fade_in,
                    com.jaydenxiao.common.R.anim.fade_out);
        }
    
        @Override
        public int getLayoutId() {
            return R.layout.act_main;
        }
    
        @Override
        public void initPresenter() {
    
        }
        @Override
        public void initView() {
            //此处填上在http://fir.im/注册账号后获得的API_TOKEN以及APP的应用ID
            UpdateKey.API_TOKEN = AppConfig.API_FIRE_TOKEN;
            UpdateKey.APP_ID = AppConfig.APP_FIRE_ID;
            //如果你想通过Dialog来进行下载,可以如下设置
    //        UpdateKey.DialogOrNotification=UpdateKey.WITH_DIALOG;
            UpdateFunGO.init(this);
            //初始化菜单
            initTab();
        }
        @Override
        public void onCreate(Bundle savedInstanceState) {
            //切换daynight模式要立即变色的页面
            ChangeModeController.getInstance().init(this,R.attr.class);
            super.onCreate(savedInstanceState);
            //初始化frament
            initFragment(savedInstanceState);
            tabLayout.measure(0,0);
            tabLayoutHeight=tabLayout.getMeasuredHeight();
            //监听菜单显示或隐藏
            mRxManager.on(AppConstant.MENU_SHOW_HIDE, new Action1<Boolean>() {
    
                @Override
                public void call(Boolean hideOrShow) {
                    startAnimation(hideOrShow);
                }
            });
        }
        /**
         * 初始化tab
         */
        private void initTab() {
            for (int i = 0; i < mTitles.length; i++) {
                mTabEntities.add(new TabEntity(mTitles[i], mIconSelectIds[i], mIconUnselectIds[i]));
            }
            tabLayout.setTabData(mTabEntities);
            //点击监听
            tabLayout.setOnTabSelectListener(new OnTabSelectListener() {
                @Override
                public void onTabSelect(int position) {
                    SwitchTo(position);
                }
                @Override
                public void onTabReselect(int position) {
                }
            });
        }
        /**
         * 初始化碎片
         */
        private void initFragment(Bundle savedInstanceState) {
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
            int currentTabPosition = 0;
            if (savedInstanceState != null) {
                newsMainFragment = (NewsMainFragment) getSupportFragmentManager().findFragmentByTag("newsMainFragment");
                photosMainFragment = (PhotosMainFragment) getSupportFragmentManager().findFragmentByTag("photosMainFragment");
                videoMainFragment = (VideoMainFragment) getSupportFragmentManager().findFragmentByTag("videoMainFragment");
                careMainFragment = (CareMainFragment) getSupportFragmentManager().findFragmentByTag("careMainFragment");
                currentTabPosition = savedInstanceState.getInt(AppConstant.HOME_CURRENT_TAB_POSITION);
            } else {
                newsMainFragment = new NewsMainFragment();
                photosMainFragment = new PhotosMainFragment();
                videoMainFragment = new VideoMainFragment();
                careMainFragment = new CareMainFragment();
    
                transaction.add(R.id.fl_body, newsMainFragment, "newsMainFragment");
                transaction.add(R.id.fl_body, photosMainFragment, "photosMainFragment");
                transaction.add(R.id.fl_body, videoMainFragment, "videoMainFragment");
                transaction.add(R.id.fl_body, careMainFragment, "careMainFragment");
            }
            transaction.commit();
            SwitchTo(currentTabPosition);
            tabLayout.setCurrentTab(currentTabPosition);
        }
    
        /**
         * 切换
         */
        private void SwitchTo(int position) {
            LogUtils.logd("主页菜单position" + position);
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
            switch (position) {
                //首页
                case 0:
                    transaction.hide(photosMainFragment);
                    transaction.hide(videoMainFragment);
                    transaction.hide(careMainFragment);
                    transaction.show(newsMainFragment);
                    transaction.commitAllowingStateLoss();
                    break;
                //美女
                case 1:
                    transaction.hide(newsMainFragment);
                    transaction.hide(videoMainFragment);
                    transaction.hide(careMainFragment);
                    transaction.show(photosMainFragment);
                    transaction.commitAllowingStateLoss();
                    break;
                //视频
                case 2:
                    transaction.hide(newsMainFragment);
                    transaction.hide(photosMainFragment);
                    transaction.hide(careMainFragment);
                    transaction.show(videoMainFragment);
                    transaction.commitAllowingStateLoss();
                    break;
                //关注
                case 3:
                    transaction.hide(newsMainFragment);
                    transaction.hide(photosMainFragment);
                    transaction.hide(videoMainFragment);
                    transaction.show(careMainFragment);
                    transaction.commitAllowingStateLoss();
                    break;
                default:
                    break;
            }
        }
    
        /**
         * 菜单显示隐藏动画
         * @param showOrHide
         */
        private void startAnimation(boolean showOrHide){
            final ViewGroup.LayoutParams layoutParams = tabLayout.getLayoutParams();
            ValueAnimator valueAnimator;
            ObjectAnimator alpha;
            if(!showOrHide){
                 valueAnimator = ValueAnimator.ofInt(tabLayoutHeight, 0);
                alpha = ObjectAnimator.ofFloat(tabLayout, "alpha", 1, 0);
            }else{
                 valueAnimator = ValueAnimator.ofInt(0, tabLayoutHeight);
                alpha = ObjectAnimator.ofFloat(tabLayout, "alpha", 0, 1);
            }
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    layoutParams.height= (int) valueAnimator.getAnimatedValue();
                    tabLayout.setLayoutParams(layoutParams);
                }
            });
            AnimatorSet animatorSet=new AnimatorSet();
            animatorSet.setDuration(500);
            animatorSet.playTogether(valueAnimator,alpha);
            animatorSet.start();
        }
    
        /**
         * 监听全屏视频时返回键
         */
        @Override
        public void onBackPressed() {
            if (JCVideoPlayer.backPress()) {
                return;
            }
            super.onBackPressed();
        }
        /**
         * 监听返回键
         *
         * @param keyCode
         * @param event
         * @return
         */
        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                moveTaskToBack(false);
                return true;
            }
            return super.onKeyDown(keyCode, event);
        }
    
        @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            //奔溃前保存位置
            LogUtils.loge("onSaveInstanceState进来了1");
            if (tabLayout != null) {
                LogUtils.loge("onSaveInstanceState进来了2");
                outState.putInt(AppConstant.HOME_CURRENT_TAB_POSITION, tabLayout.getCurrentTab());
            }
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            UpdateFunGO.onResume(this);
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            UpdateFunGO.onStop(this);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            ChangeModeController.onDestory();
        }
    }
    
    

    优化hideAllFragment的方式(未解决重叠)

    上面两个样板都是 先hide所有的fragment,再show,这样并不好。可以标记当前的fragment,显示下一个fragment时候仅仅隐藏当前的(old)fragment,RTVCenter中轮播图的显示也是此方式。

    public class MainActivity extends BaseActivity {
    
        private LearnFragment learnFragment;
        private YoungFragment youngFragment;
        private JokeFragment jokeFragment;
        private SuperBoonFragment superFragment;
    
        private Fragment oldFragment;
    
        @Bind(R.id.bottomBar)
        BottomBar mBottomBar;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ButterKnife.bind(this);
    
            initActionbar();
            setAppAbout();
            initBottom();
            initFragmentContent();
        }
    
        /**
         * 设置中间内容页
         */
        private void initFragmentContent() {
            learnFragment = new LearnFragment();
            getSupportFragmentManager().beginTransaction().add(R.id.fragment_content, learnFragment).commit();
            oldFragment = learnFragment;
        }
    
        /**
         * 设置底部按钮
         */
        private void initBottom() {
            mBottomBar.setOnTabSelectListener(new OnTabSelectListener() {
                @Override
                public void onTabSelected(@IdRes int tabId) {
    
                    switch (tabId) {
                        case R.id.menu_learn: //学习
                            setActTitle(R.string.menu_learn_msg);
                            toFragment(learnFragment);
                            break;
                        case R.id.menu_joke: //开心
                            checkNet(1);
                            break;
                        case R.id.menu_young: //美女
                            checkNet(2);
                            break;
                        case R.id.menu_super: //超级福利
                            checkNet(3);
                            break;
                        default:
                            setActTitle(R.string.menu_learn_msg);
                            toFragment(learnFragment);
                            break;
                    }
                }
            });
        }
    
        /**
         * 检查网络,并跳转
         */
        private void checkNet(final int position) {
            if (NetStatusUtil.isWifi(MainActivity.this)) {
                goFragment(position);
            } else {
                final MaterialDialog mMaterialDialog = new MaterialDialog(this);
                mMaterialDialog.setTitle("提示");
                mMaterialDialog.setMessage("您当前不是WIFI状态,访问会消耗大量的流量,您确定要访问吗?");
                mMaterialDialog.setPositiveButton("没事儿拼了", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        goFragment(position);
                        mMaterialDialog.dismiss();
                    }
                });
                mMaterialDialog.setNegativeButton("还是不看了", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        mMaterialDialog.dismiss();
                        showToast("(*^__^*) 没事去读书学习吧");
                        mBottomBar.selectTabWithId(R.id.menu_learn);
                    }
                });
    
                mMaterialDialog.show();
            }
        }
    
        private void goFragment(int position) {
            switch (position) {
                case 1://开心
                {
                    setActTitle(R.string.menu_joke_msg);
                    if (jokeFragment == null) {
                        jokeFragment = new JokeFragment();
                    }
                    toFragment(jokeFragment);
                    break;
                }
                case 2: //美女
                {
                    setActTitle(R.string.menu_young_msg);
                    if (youngFragment == null) {
                        youngFragment = new YoungFragment();
                    }
                    toFragment(youngFragment);
                    break;
                }
                case 3: //超级福利
                {
                    setActTitle(R.string.menu_super_msg);
                    if (superFragment == null) {
                        superFragment = new SuperBoonFragment();
                    }
                    toFragment(superFragment);
                    break;
                }
                default:
                    break;
            }
        }
    
        /**
         * 切换Fragment
         *
         * @param to 下一个Fragment页面
         */
        private void toFragment(Fragment to) {
            if (to == oldFragment) return;
    
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction().setCustomAnimations(android
                    .R.anim.fade_in, android.R.anim.fade_out);
            if (!to.isAdded()) {    // 先判断是否被add过
                transaction.hide(oldFragment).add(R.id.fragment_content, to).commit(); // 隐藏当前的fragment,add下一个到Activity中
            } else {
                transaction.hide(oldFragment).show(to).commit(); // 隐藏当前的fragment,显示下一个
            }
            oldFragment = to;
        }
    
        private void setActTitle(int res) {
            mActionTitle.setText(getString(res));
        }
    
        private long time = 0;
    
        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                if (System.currentTimeMillis() - time <= 2000) {
                    finish();
                } else {
                    time = System.currentTimeMillis();
                    Toast.makeText(getApplicationContext(), R.string.exit_app, Toast.LENGTH_SHORT).show();
                }
                return true;
            }
            return super.onKeyDown(keyCode, event);
        }
    }
    

    参考:
    http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2017/0415/7830.html

    相关文章

      网友评论

      • 根号三丶:谢谢博主。找了很多方法。= = 还有些看不懂 看了你的这篇 搞定了
        Alien的小窝:@何须丶 不客气

      本文标题:Fragment切换重叠的问题

      本文链接:https://www.haomeiwen.com/subject/hcwmkttx.html