Android overrides FragmentTabHost to save the status.

Source: Internet
Author: User

Recently, I want to develop a function similar to the function of having bubbles at the bottom of QQ. I think many developers will know that TabHost is not saved, and the layout will be re-loaded every time, to save the status, use RadioGroup. The status can be saved. The problem is that the bubble function cannot be implemented and the layout cannot be customized. Because the RadioGroup can only contain RadioButton, or the status switch cannot be used, you can view the source code of RadioGroup. In order to save the status and implement the bubble function, you can only modify the control yourself or write a similar switchover function to view the source code of FragmentTabHost, it can be seen that FragmentTabHost does not save the status because it uses detach and attach to hide and display fragment during Fragment switching. In this way, you must re-load the layout for each switching, and use detach and attach for processing, we can also use show and hide to display and hide the data so that the State can be saved. The solution is to modify Fragm. The entTabHost source code changes the Fragment mode detach and attach to hide and show.

The source code of the modified FragmentTabHost is as follows:

/* * Copyright (C) 2012 The Android Open Source Project * * 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 com.jwzhangjie.com;import java.util.ArrayList;import android.content.Context;import android.content.res.TypedArray;import android.os.Bundle;import android.os.Parcel;import android.os.Parcelable;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentManager;import android.support.v4.app.FragmentTransaction;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;import android.widget.FrameLayout;import android.widget.LinearLayout;import android.widget.TabHost;import android.widget.TabWidget;/** * Special TabHost that allows the use of {@link Fragment} objects for its tab * content. When placing this in a view hierarchy, after inflating the hierarchy * you must call {@link #setup(Context, FragmentManager, int)} to complete the * initialization of the tab host. *  * 

* Here is a simple example of using a FragmentTabHost in an Activity: * * {@sample * development/samples/Support4Demos/src/com/example/android/supportv4/app/ * FragmentTabs.java complete} * *

* This can also be used inside of a fragment through fragment nesting: * * {@sample * development/samples/Support4Demos/src/com/example/android/supportv4/app/ * FragmentTabsFragmentSupport.java complete} */public class FragmentTabHost extends TabHost implementsTabHost.OnTabChangeListener {private final ArrayList mTabs = new ArrayList ();private FrameLayout mRealTabContent;private Context mContext;private FragmentManager mFragmentManager;private int mContainerId;private TabHost.OnTabChangeListener mOnTabChangeListener;private TabInfo mLastTab;private boolean mAttached;static final class TabInfo {private final String tag;private final Class clss;private final Bundle args;private Fragment fragment;TabInfo(String _tag, Class _class, Bundle _args) {tag = _tag;clss = _class;args = _args;}}static class DummyTabFactory implements TabHost.TabContentFactory {private final Context mContext;public DummyTabFactory(Context context) {mContext = context;}@Overridepublic View createTabContent(String tag) {View v = new View(mContext);v.setMinimumWidth(0);v.setMinimumHeight(0);return v;}}static class SavedState extends BaseSavedState {String curTab;SavedState(Parcelable superState) {super(superState);}private SavedState(Parcel in) {super(in);curTab = in.readString();}@Overridepublic void writeToParcel(Parcel out, int flags) {super.writeToParcel(out, flags);out.writeString(curTab);}@Overridepublic String toString() {return "FragmentTabHost.SavedState{"+ Integer.toHexString(System.identityHashCode(this))+ " curTab=" + curTab + "}";}public static final Parcelable.Creator CREATOR = new Parcelable.Creator () {public SavedState createFromParcel(Parcel in) {return new SavedState(in);}public SavedState[] newArray(int size) {return new SavedState[size];}};}public FragmentTabHost(Context context) {// Note that we call through to the version that takes an AttributeSet,// because the simple Context construct can result in a broken object!super(context, null);initFragmentTabHost(context, null);}public FragmentTabHost(Context context, AttributeSet attrs) {super(context, attrs);initFragmentTabHost(context, attrs);}private void initFragmentTabHost(Context context, AttributeSet attrs) {TypedArray a = context.obtainStyledAttributes(attrs,new int[] { android.R.attr.inflatedId }, 0, 0);mContainerId = a.getResourceId(0, 0);a.recycle();super.setOnTabChangedListener(this);}private void ensureHierarchy(Context context) {// If owner hasn't made its own view hierarchy, then as a convenience// we will construct a standard one here.if (findViewById(android.R.id.tabs) == null) {LinearLayout ll = new LinearLayout(context);ll.setOrientation(LinearLayout.VERTICAL);addView(ll, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));TabWidget tw = new TabWidget(context);tw.setId(android.R.id.tabs);tw.setOrientation(TabWidget.HORIZONTAL);ll.addView(tw, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT, 0));FrameLayout fl = new FrameLayout(context);fl.setId(android.R.id.tabcontent);ll.addView(fl, new LinearLayout.LayoutParams(0, 0, 0));mRealTabContent = fl = new FrameLayout(context);mRealTabContent.setId(mContainerId);ll.addView(fl, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0, 1));}}/** * @deprecated Don't call the original TabHost setup, you must instead call * {@link #setup(Context, FragmentManager)} or * {@link #setup(Context, FragmentManager, int)}. */@Override@Deprecatedpublic void setup() {throw new IllegalStateException("Must call setup() that takes a Context and FragmentManager");}public void setup(Context context, FragmentManager manager) {ensureHierarchy(context); // Ensure views required by super.setup()super.setup();mContext = context;mFragmentManager = manager;ensureContent();}public void setup(Context context, FragmentManager manager, int containerId) {ensureHierarchy(context); // Ensure views required by super.setup()super.setup();mContext = context;mFragmentManager = manager;mContainerId = containerId;ensureContent();mRealTabContent.setId(containerId);// We must have an ID to be able to save/restore our state. If// the owner hasn't set one at this point, we will set it ourself.if (getId() == View.NO_ID) {setId(android.R.id.tabhost);}}private void ensureContent() {if (mRealTabContent == null) {mRealTabContent = (FrameLayout) findViewById(mContainerId);if (mRealTabContent == null) {throw new IllegalStateException("No tab content FrameLayout found for id "+ mContainerId);}}}@Overridepublic void setOnTabChangedListener(OnTabChangeListener l) {mOnTabChangeListener = l;}public void addTab(TabHost.TabSpec tabSpec, Class clss, Bundle args) {tabSpec.setContent(new DummyTabFactory(mContext));String tag = tabSpec.getTag();TabInfo info = new TabInfo(tag, clss, args);if (mAttached) {// If we are already attached to the window, then check to make// sure this tab's fragment is inactive if it exists. This shouldn't// normally happen.info.fragment = mFragmentManager.findFragmentByTag(tag);if (info.fragment != null && !info.fragment.isDetached()) {FragmentTransaction ft = mFragmentManager.beginTransaction();//ft.detach(info.fragment);ft.hide(info.fragment);ft.commit();}}mTabs.add(info);addTab(tabSpec);}@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();String currentTab = getCurrentTabTag();// Go through all tabs and make sure their fragments match// the correct state.FragmentTransaction ft = null;for (int i = 0; i < mTabs.size(); i++) {TabInfo tab = mTabs.get(i);tab.fragment = mFragmentManager.findFragmentByTag(tab.tag);//if (tab.fragment != null && !tab.fragment.isDetached()) {if (tab.fragment != null) {if (tab.tag.equals(currentTab)) {// The fragment for this tab is already there and// active, and it is what we really want to have// as the current tab. Nothing to do.mLastTab = tab;} else {// This fragment was restored in the active state,// but is not the current tab. Deactivate it.if (ft == null) {ft = mFragmentManager.beginTransaction();}//ft.detach(tab.fragment);ft.hide(tab.fragment);}}}// We are now ready to go. Make sure we are switched to the// correct tab.mAttached = true;ft = doTabChanged(currentTab, ft);if (ft != null) {ft.commit();mFragmentManager.executePendingTransactions();}}@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();mAttached = false;}@Overrideprotected Parcelable onSaveInstanceState() {Parcelable superState = super.onSaveInstanceState();SavedState ss = new SavedState(superState);ss.curTab = getCurrentTabTag();return ss;}@Overrideprotected void onRestoreInstanceState(Parcelable state) {SavedState ss = (SavedState) state;super.onRestoreInstanceState(ss.getSuperState());setCurrentTabByTag(ss.curTab);}@Overridepublic void onTabChanged(String tabId) {if (mAttached) {FragmentTransaction ft = doTabChanged(tabId, null);if (ft != null) {ft.commit();}}if (mOnTabChangeListener != null) {mOnTabChangeListener.onTabChanged(tabId);}}private FragmentTransaction doTabChanged(String tabId,FragmentTransaction ft) {TabInfo newTab = null;for (int i = 0; i < mTabs.size(); i++) {TabInfo tab = mTabs.get(i);if (tab.tag.equals(tabId)) {newTab = tab;}}if (newTab == null) {throw new IllegalStateException("No tab known for tag " + tabId);}if (mLastTab != newTab) {if (ft == null) {ft = mFragmentManager.beginTransaction();}if (mLastTab != null) {if (mLastTab.fragment != null) {//ft.detach(mLastTab.fragment);ft.hide(mLastTab.fragment);}}if (newTab != null) {if (newTab.fragment == null) {newTab.fragment = Fragment.instantiate(mContext,newTab.clss.getName(), newTab.args);ft.add(mContainerId, newTab.fragment, newTab.tag);} else {//ft.attach(newTab.fragment);ft.show(newTab.fragment);}}mLastTab = newTab;}return ft;}}

This is a Demo

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.