文中調用FragmentTabHost的addTab将fragmentArray中Fragments加入FragmentTabHost中,
(注:fragment是以class的形式傳入,在FragmentTabHost的内部會将這些fragment的類執行個體化)
而在initPager函數中又建立了一遍所有的fragment,并加入到ViewPager中。
是以文中存在8個fragment的執行個體,而這個界面往往是放在應用啟動後的第一個界面,這種資源的浪費是很嚴重的。
解決方案在最下面
一.layout
1.main_activity_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/wallpaper_0"
android:orientation="vertical">
///主體内容頁
<android.support.v4.view.ViewPager
android:id="@+id/main_content_fragment"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1">
</android.support.v4.view.ViewPager>
<android.support.v4.app.FragmentTabHost
android:id="@+id/fragment_tab_host"
android:layout_width="match_parent"
android:layout_height="54dp">
//這裡搞不懂,加了不加效果都沒變,而且也沒用到它
<!--<FrameLayout-->
<!--android:id="@+id/tab_content_fragment"-->
<!--android:layout_width="0dp"-->
<!--android:layout_height="0dp"-->
<!--android:layout_weight="0" />-->
</android.support.v4.app.FragmentTabHost>
</LinearLayout>
2.tab_item_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
///FragmentTabHost菜單字型和圖示
<TextView
android:id="@+id/tab_item_textview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginTop="10dp"
android:gravity="center"
android:textColor="@drawable/tab_text_selector"
android:textSize="12sp"
android:textStyle="normal" />
</LinearLayout>
3.weather_tab_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<!--Weather内容-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/gray_background_color">
</LinearLayout>
這裡有四個菜單選項,是以有四個對應的Xml,我隻寫了一個,其他除了檔案名都一樣,記得把背景顔色改了,不然都一樣看不出來

二.values
colors.xml添加
<color name="black">#000000</color>
<color name="white">#ffffff</color>
<color name="grey">#888888</color>
<color name="red">#ff0000</color>
<color name="orange_light">#ffffdd</color>
<color name="transparent">#00000000</color>
<color name="blue">#0099ff</color>
<color name="green">#00ff99</color>
<color name="orange">#F9CC12</color>
<color name="blue_light">#aaaaff</color>
<color name="tab_text_selected">#0084e8</color>
<color name="tab_text_normal">#7597b3</color>
三.drawable
1.tab_text_selector.xml
<!--選中和未選中的字型顔色-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:color="@color/white" />
<item android:color="@color/white_trans50" />
</selector>
2.tab_weather_bg_selector.xml
<!--天氣選中與未選中的圖檔-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="@drawable/tab_weather_select" />
<item android:drawable="@drawable/tab_weather_unselect" />
</selector>
這裡也是有四個,每個xml設定不同的狀态圖檔樣式
四.drawable-hdpi
五.java
一個FragmentPagerAdapter
四個碎片
還有個MainActivity
WeatherFragment
package com.xinyibufang.xtool.Fragment_Dir;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.xinyibufang.xtool.R;
/**
* 作者:XinYiBuFang(心以不防)
* 時間:2018/1/10.
* QQ:1107786562
* 郵箱:[email protected]
* 說明:XTool
*/
public class WeatherFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.weather_tab_fragment, container, false);
return view;
}
}
同樣有四個對應的Fragment,注意把layout設定成不同的就行
3.SecondFragment.java
public class SecondFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.second_fragment, container, false);
return view;
}
}
ViewPagerAdapter(擴充卡)
package com.xinyibufang.xtool.Adapter;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.view.ViewGroup;
import java.util.List;
/**
* 作者: XYBF
* 時間: 2018-01-11 10:59
* QQ:1107786562
*/
public class ViewPagerAdapter extends FragmentPagerAdapter {
List<Fragment> FragmentList;
public ViewPagerAdapter(FragmentManager fm, List<Fragment> list) {
super(fm);
this.FragmentList = list;
}//寫構造方法,友善指派調用
@Override
public Fragment getItem(int arg0) {
return FragmentList.get(arg0);
}//根據Item的位置傳回對應位置的Fragment,綁定item和Fragment
@Override
public int getCount() {
return FragmentList.size();
}//設定Item的數量
}
MainActivity.java
package com.xinyibufang.xtool;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTabHost;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.TabHost;
import android.widget.TextView;
import com.xinyibufang.xtool.Adapter.ViewPagerAdapter;
import com.xinyibufang.xtool.Fragment_Dir.MoreFragment;
import com.xinyibufang.xtool.Fragment_Dir.NoteFragment;
import com.xinyibufang.xtool.Fragment_Dir.TimerFragment;
import com.xinyibufang.xtool.Fragment_Dir.WeatherFragment;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private FragmentTabHost Frag_TabHost;
private List<Fragment> FragmentList = new ArrayList<Fragment>(4); ///Fragment集合
private ViewPager ViewPagerControl; ///ViewPager
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity_layout);
//背景與狀态欄融合(狀态欄設定透明)
this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
Frag_TabHost = (FragmentTabHost) findViewById(R.id.fragment_tab_host); ///FragmentTabHost控件
Frag_TabHost.setup(this, getSupportFragmentManager(), R.id.main_content_fragment); ///内容界面
///綁定對應的碎片
Frag_TabHost.addTab(GetTabView("天氣", R.drawable.tab_weather_bg_selector), WeatherFragment
.class, null);
Frag_TabHost.addTab(GetTabView("便簽", R.drawable.tab_note_bg_selector), NoteFragment
.class, null);
Frag_TabHost.addTab(GetTabView("計時器", R.drawable.tab_timer_bg_selector), TimerFragment
.class, null);
Frag_TabHost.addTab(GetTabView("更多", R.drawable.tab_more_bg_selector), MoreFragment
.class, null);
//添加内容碎片
FragmentList.add(new WeatherFragment());
FragmentList.add(new NoteFragment());
FragmentList.add(new TimerFragment());
FragmentList.add(new MoreFragment());
ViewPagerControl = (ViewPager) findViewById(R.id.main_content_fragment);
//設定擴充卡
ViewPagerControl.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), FragmentList));
//設定監聽ViewPager
ViewPagerControl.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
//設定選中
Frag_TabHost.setCurrentTab(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
///監聽FragmentTabHost
Frag_TabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
@Override
public void onTabChanged(String tabId) {
///獲得FragmentTabHost選中
int position = Frag_TabHost.getCurrentTab();
// ViewPager滑動到對應的位置
ViewPagerControl.setCurrentItem(position);
}
});
}
///填充TabSpec
private TabHost.TabSpec GetTabView(String text, int img_id) {
Drawable drawable = ContextCompat.getDrawable(this, img_id); //擷取圖檔ID
drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight()); //設定圖檔
View item_bar = getLayoutInflater().inflate(R.layout.tab_item_fragment, null); //執行個體化單個菜單
TextView tv_item = (TextView) item_bar.findViewById(R.id.tab_item_textview); //執行個體化TextView
tv_item.setText(text); //TextView指派
tv_item.setCompoundDrawables(null, drawable, null, null); //設定圖檔位置
TabHost.TabSpec spec = Frag_TabHost.newTabSpec(text).setIndicator(item_bar); //綁定TabSpec
return spec;
}
}
六.效果
滑動切換中 切換界面
FragmenttabHost與ViewPager重複執行個體化 和多次onCreateView解決方案:重寫FragmentTabHost
解決些問題的方向是如何做到隻建立一個Fragment并切換時不走其生命周期方法
将之前要傳入的Class隻接改成Fragment例,我們是能做到Fragment隻new一次.
在切換時是通過tag去尋找的,在原碼中寫的是這樣,如果沒有就通過反射來建立一個,這就是fragment第一次執行個體化的原因
用下面重寫的XFragmentTabHost替換v4的FragmentTabHost
package com.xinyibufang.xtool.Adapter;
/*
* 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.
*/
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
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;
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.annotation.NonNull;
import android.support.annotation.Nullable;
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;
import java.util.ArrayList;
/**
* 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>
* <p>Here is a simple example of using a FragmentTabHost in an Activity:
* <p>
* {@sample frameworks/support/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabs.java
* complete}
* <p>
* <p>This can also be used inside of a fragment through fragment nesting:
* <p>
* {@sample frameworks/support/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentTabsFragmentSupport.java
* complete}
*/
public class XFragmentTabHost extends TabHost
implements TabHost.OnTabChangeListener {
private final ArrayList<XFragmentTabHost.TabInfo> mTabs = new ArrayList<>();
private FrameLayout mRealTabContent;
private Context mContext;
private FragmentManager mFragmentManager;
private int mContainerId;
private TabHost.OnTabChangeListener mOnTabChangeListener;
private XFragmentTabHost.TabInfo mLastTab;
private boolean mAttached;
static final class TabInfo {
final
@NonNull
String tag;
final
@NonNull
Fragment clss;
final
@Nullable
Bundle args;
Fragment fragment;
TabInfo(@NonNull String _tag, @NonNull Fragment _class, @Nullable 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);
}
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<XFragmentTabHost.SavedState> CREATOR
= new Parcelable.Creator<XFragmentTabHost.SavedState>() {
@Override
public XFragmentTabHost.SavedState createFromParcel(Parcel in) {
return new XFragmentTabHost.SavedState(in);
}
@Override
public XFragmentTabHost.SavedState[] newArray(int size) {
return new XFragmentTabHost.SavedState[size];
}
};
}
public XFragmentTabHost(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 XFragmentTabHost(Context context, AttributeSet attrs) {
super(context, attrs);
initFragmentTabHost(context, attrs);
}
private void initFragmentTabHost(Context context, AttributeSet attrs) {
final 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 ourselves.
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(@NonNull TabHost.TabSpec tabSpec, @NonNull Fragment clss,
@Nullable Bundle args) {
tabSpec.setContent(new XFragmentTabHost.DummyTabFactory(mContext));
final String tag = tabSpec.getTag();
final XFragmentTabHost.TabInfo info = new XFragmentTabHost.TabInfo(tag, clss, args);
mTabs.add(info);
addTab(tabSpec);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mAttached = false;
}
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
XFragmentTabHost.SavedState ss = new XFragmentTabHost.SavedState(superState);
ss.curTab = getCurrentTabTag();
return ss;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof XFragmentTabHost.SavedState)) {
super.onRestoreInstanceState(state);
return;
}
XFragmentTabHost.SavedState ss = (XFragmentTabHost.SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
setCurrentTabByTag(ss.curTab);
}
@Override
public void onTabChanged(String tabId) {
if (mAttached) {
final FragmentTransaction ft = doTabChanged(tabId, null);
if (ft != null) {
ft.commit();
}
}
if (mOnTabChangeListener != null) {
mOnTabChangeListener.onTabChanged(tabId);
}
}
@Nullable
private FragmentTransaction doTabChanged(@Nullable String tag, @Nullable FragmentTransaction ft) {
TabInfo newTab = null;
for (int i=0; i<mTabs.size(); i++) {
TabInfo tab = mTabs.get(i);
if (tab.tag.equals(tag)) {
newTab = tab;
}
}
if (newTab == null) {
throw new IllegalStateException("No tab known for tag " + tag);
}
if (mLastTab != newTab) {
if (ft == null) {
ft = mFragmentManager.beginTransaction();
}
if (mLastTab != null) {
if (mLastTab.fragment != null) {
ft.hide(mLastTab.fragment);
}
}
if (newTab != null) {
if (null == mFragmentManager.getFragments() || !mFragmentManager.getFragments().contains(newTab.fragment)) {
ft.add(mContainerId, newTab.fragment, newTab.tag);
} else {
ft.show(newTab.fragment);
}
}
mLastTab = newTab;
}
return ft;
}
@Nullable
private XFragmentTabHost.TabInfo getTabInfoForTag(String tabId) {
for (int i = 0, count = mTabs.size(); i < count; i++) {
final XFragmentTabHost.TabInfo tab = mTabs.get(i);
if (tab.tag.equals(tabId)) {
return tab;
}
}
return null;
}
}
WeatherFragment修改
package com.xinyibufang.xtool.Fragment_Dir;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.xinyibufang.xtool.R;
/**
* 作者:XinYiBuFang(心以不防)
* 時間:2018/1/10.
* QQ:1107786562
* 郵箱:[email protected]
* 說明:XTool
*/
public class WeatherFragment extends Fragment {
private View mCacheView;
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//View view = inflater.inflate(R.layout.weather_tab_fragment, container, false);
if (mCacheView == null) {
Log.i("AAAA", "Weather onCreateView");
mCacheView = inflater.inflate(R.layout.weather_tab_fragment, null);
}
ViewGroup parent = (ViewGroup) mCacheView.getParent();
if (parent != null) {
parent.removeView(mCacheView);
}
return mCacheView;
}
}
看一下日志,onCreateView隻執行了一次,切換界面也不會多次執行個體化和onCreateView
源碼:連結:https://pan.baidu.com/s/1dYvoPw 密碼:ek4y
轉載于:https://www.cnblogs.com/xinyibufang/p/8029917.html