org.cowboycoders.cyclisimo.TabManager.java Source code

Java tutorial

Introduction

Here is the source code for org.cowboycoders.cyclisimo.TabManager.java

Source

/*
*    Copyright (c) 2013, Will Szumski
*    Copyright (c) 2013, Doug Szumski
*
*    This file is part of Cyclismo.
*
*    Cyclismo is free software: you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    Cyclismo is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with Cyclismo.  If not, see <http://www.gnu.org/licenses/>.
*/
/*
 * Copyright 2012 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.cowboycoders.cyclisimo;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.view.View;
import android.widget.TabHost;
import android.widget.TabHost.TabContentFactory;
import android.widget.TabHost.TabSpec;

import java.util.HashMap;

/**
 * This is a helper class that implements a generic mechanism for associating
 * fragments with the tabs in a tab host. It relies on a trick. Normally a tab
 * host has a simple API for supplying a View or Intent that each tab will show.
 * This is not sufficient for switching between fragments. So instead we make
 * the content part of the tab host 0dp high (it is not shown) and the
 * TabManager supplies its own dummy view to show as the tab content. It listens
 * to changes in tabs, and takes care of switch to the correct fragment shown in
 * a separate content area whenever the selected tab changes.
 * <p>
 * Copied from the Fragment Tabs example in the API 4+ Support Demos.
 *
 * @author Jimmy Shih
 */
public class TabManager implements TabHost.OnTabChangeListener {

    private final FragmentActivity fragmentActivity;
    private final TabHost tabHost;
    private final int containerId;
    private final HashMap<String, TabInfo> tabs = new HashMap<String, TabInfo>();
    private TabInfo lastTabInfo;

    /**
     * An object to hold a tab's info.
     *
     * @author Jimmy Shih
     */
    private static final class TabInfo {

        private final String tag;
        private final Class<?> clss;
        private final Bundle bundle;
        private Fragment fragment;

        public TabInfo(String tag, Class<?> clss, Bundle bundle) {
            this.tag = tag;
            this.clss = clss;
            this.bundle = bundle;
        }
    }

    /**
     * A dummy {@link TabContentFactory} that creates an empty view to satisfy the
     * {@link TabHost} API.
     *
     * @author Jimmy Shih
     */
    private static class DummyTabContentFactory implements TabContentFactory {

        private final Context context;

        public DummyTabContentFactory(Context context) {
            this.context = context;
        }

        @Override
        public View createTabContent(String tag) {
            View view = new View(context);
            view.setMinimumWidth(0);
            view.setMinimumHeight(0);
            return view;
        }
    }

    public TabManager(FragmentActivity fragmentActivity, TabHost tabHost, int containerId) {
        this.fragmentActivity = fragmentActivity;
        this.tabHost = tabHost;
        this.containerId = containerId;
        tabHost.setOnTabChangedListener(this);
    }

    public void addTab(TabSpec tabSpec, Class<?> clss, Bundle bundle) {
        tabSpec.setContent(new DummyTabContentFactory(fragmentActivity));

        String tag = tabSpec.getTag();
        TabInfo tabInfo = new TabInfo(tag, clss, bundle);

        /*
         * Check to see if we already have a fragment for this tab, probably from a
         * previously saved state. If so, deactivate it, because our initial state
         * is that a tab isn't shown.
         */
        tabInfo.fragment = fragmentActivity.getSupportFragmentManager().findFragmentByTag(tag);
        if (tabInfo.fragment != null && !tabInfo.fragment.isDetached()) {
            FragmentTransaction fragmentTransaction = fragmentActivity.getSupportFragmentManager()
                    .beginTransaction();
            fragmentTransaction.detach(tabInfo.fragment);
            fragmentTransaction.commit();
        }
        tabs.put(tag, tabInfo);
        tabHost.addTab(tabSpec);
    }

    @Override
    public void onTabChanged(String tabId) {
        TabInfo newTabInfo = tabs.get(tabId);
        if (lastTabInfo != newTabInfo) {
            FragmentTransaction fragmentTransaction = fragmentActivity.getSupportFragmentManager()
                    .beginTransaction();
            if (lastTabInfo != null) {
                if (lastTabInfo.fragment != null) {
                    fragmentTransaction.detach(lastTabInfo.fragment);
                }
            }
            if (newTabInfo != null) {
                if (newTabInfo.fragment == null) {
                    newTabInfo.fragment = Fragment.instantiate(fragmentActivity, newTabInfo.clss.getName(),
                            newTabInfo.bundle);
                    fragmentTransaction.add(containerId, newTabInfo.fragment, newTabInfo.tag);
                } else {
                    fragmentTransaction.attach(newTabInfo.fragment);
                }
            }

            lastTabInfo = newTabInfo;
            fragmentTransaction.commitAllowingStateLoss();
            fragmentActivity.getSupportFragmentManager().executePendingTransactions();
        }
    }
}