您的位置:首页 > 移动开发 > Android开发

Android重写FragmentTabHost来实现状态保存

2016-08-17 11:01 337 查看
最近要做一个类似QQ底部有气泡的功能,试了几个方案不太好,我想很多开发者使用TabHost都会知道它不保存状态,每次都要重新加载布局,为了保存状态,使用RadioGroup来实现,状态是可以保存了,问题是无法实现气泡功能,不能自定义布局,因为RadioGroup里面只能包含RadioButton,不然状态切换不起用作,这个可以查看RadioGroup源码,为了既能保存状态又能实现气泡功能,所以只能自己修改控件了或者自己写一个类似的切换功能,查看了FragmentTabHost的源码,可以知道FragmentTabHost不保存状态是因为切换fragment的时候是使用detach和attach来Fragment的隐藏和显示的,这样的话每次切换肯定要重新加载布局,处理使用detach和attach,我们还可以使用show和hide来实现显示和隐藏,这样可以保存状态,方案出来了就是修改FragmentTabHost源码将切换Fragment的方式detach和attach改为hide和show。

下面就是修改后的FragmentTabHost的源码:

FragmentTabHost工具类:

[java] view
plain copy







/*

* 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.

*

* <p>

* 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}

*

* <p>

* 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 implements

TabHost.OnTabChangeListener {

private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();

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;

}

@Override

public 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();

}

@Override

public void writeToParcel(Parcel out, int flags) {

super.writeToParcel(out, flags);

out.writeString(curTab);

}

@Override

public String toString() {

return "FragmentTabHost.SavedState{"

+ Integer.toHexString(System.identityHashCode(this))

+ " curTab=" + curTab + "}";

}

public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {

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

@Deprecated

public 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);

}

}

}

@Override

public 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);

}

@Override

protected 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();

}

}

@Override

protected void onDetachedFromWindow() {

super.onDetachedFromWindow();

mAttached = false;

}

@Override

protected Parcelable onSaveInstanceState() {

Parcelable superState = super.onSaveInstanceState();

SavedState ss = new SavedState(superState);

ss.curTab = getCurrentTabTag();

return ss;

}

@Override

protected void onRestoreInstanceState(Parcelable state) {

SavedState ss = (SavedState) state;

super.onRestoreInstanceState(ss.getSuperState());

setCurrentTabByTag(ss.curTab);

}

@Override

public 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;

}

}

xml布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >

<FrameLayout
android:id="@+id/realtabcontent"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1" />

<com.jwzhangjie.com.FragmentTabHost
android:id="@android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/maintab_toolbar_bg">

<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0" />
</com.jwzhangjie.com.FragmentTabHost>

</LinearLayout>


实现类:
package com.example.lin_tab_demo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TabHost;
import android.widget.TextView;

public class MainActivity extends FragmentActivity {
private LayoutInflater layoutinflater;
// 定义数组来存放Fragment界面
private Class mfragmentArray[] = { yi_fragment.class, er_fragment.class,san_fragment.class };
// 定义栏目的名称
private String mtextviewArray[] = { "首页", "军事", "科技" };
//定义关闭按钮的图片
private int off_mimageArray[]={R.drawable.yi_off,R.drawable.er_off,R.drawable.san_off};
//定义开启按钮的图片
private int on_mimageArray[]={R.drawable.yi_on,R.drawable.er_on,R.drawable.san_on};
FragmentTabHost tabhost;
private List<Map<String, View>> tabViews = new ArrayList<Map<String, View>>();

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initview();
}

private void initview() {
//layoutinflater.inflate(R.layout.item_layout, null);
tabhost=(FragmentTabHost) findViewById(android.R.id.tabhost);
//初始化tabhost
tabhost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
//给每一个tab添加视图(图片文字) 还有对应的fragment
for (int i = 0; i < mtextviewArray.length; i++) {
tabhost.addTab(tabhost.newTabSpec(i+"").setIndicator(createTab(i)),mfragmentArray[i],null);
}
// 设置Tab按钮的背景
tabhost.getTabWidget().setDividerDrawable(R.color.white);
// 设置Tab按钮的默认选项
tabhost.setCurrentTab(0);
// 设置Tab按钮的点击事件
tabhost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
@Override
public void onTabChanged(String tabId) {
int index = Integer.parseInt(tabId);
setTabSelectedState(index, mfragmentArray.length);
}
});
setTabSelectedState(0,3);
}

//设置每个tab的样式
private View createTab(int id) {
View tabIndicator = LayoutInflater.from(this).inflate(R.layout.item_layout, null);
TextView normal_tv = (TextView) tabIndicator.findViewById(R.id.normal_tv);
TextView selected_tv = (TextView) tabIndicator.findViewById(R.id.selected_tv);
normal_tv.setText(mtextviewArray[id]);
selected_tv.setText(mtextviewArray[id]);
ImageView normal_iv = (ImageView) tabIndicator.findViewById(R.id.normal_iv);
ImageView selected_iv = (ImageView) tabIndicator.findViewById(R.id.selected_iv);
normal_iv.setImageResource(off_mimageArray[id]);
selected_iv.setImageResource(on_mimageArray[id]);

View normal_layout = tabIndicator.findViewById(R.id.normal_layout);
normal_layout.setAlpha(1f);
View selected_layout = tabIndicator.findViewById(R.id.selected_layout);
selected_layout.setAlpha(0f);

Map<String, View> map = new HashMap<String, View>();
map.put("ALPHA_NORMAL", normal_layout);
map.put("ALPHA_SELECTED", selected_layout);
tabViews.add(map);
return tabIndicator;
}
//设置每个Tab点击样式切换
private void setTabSelectedState(int index, int tabCount) {
for (int i = 0; i < tabCount; i++) {
if (i == index) {
tabViews.get(i).get("ALPHA_NORMAL").setAlpha(0f);
tabViews.get(i).get("ALPHA_SELECTED").setAlpha(1f);
} else {
tabViews.get(i).get("ALPHA_NORMAL").setAlpha(1f);
tabViews.get(i).get("ALPHA_SELECTED").setAlpha(0f);
}
}
}

}


源码地址:http://download.csdn.net/download/jwzhangjie/7561781
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐